From d0eda7293bbc4011af8b05e7f62b80fd6a7abe12 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Sun, 14 Oct 2018 17:13:39 +0300 Subject: [PATCH 01/42] added wallet. added wallet/installation/npm.md --- docs/index.md | 9 +-- docs/installation/installers.md | 34 ----------- docs/wallet/installation/installers.md | 34 +++++++++++ docs/wallet/installation/npm.md | 82 ++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 38 deletions(-) delete mode 100644 docs/installation/installers.md create mode 100644 docs/wallet/installation/installers.md create mode 100644 docs/wallet/installation/npm.md diff --git a/docs/index.md b/docs/index.md index 6d3dbdf..cde48a6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,8 +2,9 @@ Contents: -* [Installation](installation.html) - * [Installers](installation/installers.html) - * npm - * From source +* [Wallet] + * [Installation](wallet/installation.html) + * [Executable Installers](wallet/installation/installers.html) + * npm + * From source * [ZF*](zfstar.html) diff --git a/docs/installation/installers.md b/docs/installation/installers.md deleted file mode 100644 index 73d18c7..0000000 --- a/docs/installation/installers.md +++ /dev/null @@ -1,34 +0,0 @@ -# Installers - -Download and installation for users without development experience. - --------------------------------------------------------------------------------- - -#### Prerequisites -Please make sure to install all of the necessary dependencies below before trying to run the Zen Wallet Software. - -#### Windows -1. Install [.NET Framework 4.7​](https://www.microsoft.com/en-us/download/details.aspx?id=55167) -2. Install [vc++ redist 2015 x64​](https://github.com/zenprotocol/zen-prerequisites-nuget/raw/master/vc_redist.x64.exe) -3. Download the most recent **zen-wallet-setup.exe** file from [Github​](https://github.com/zenprotocol/zenwallet/releases) -4. Your browser may warn that the download is not commonly downloaded. Click "keep" to download it anyway. -5. Run the installer. You'll need to click the ```More Info``` button and click ```Run anyway``` - -#### Mac OSX -1. Install [mono](http://www.mono-project.com/download/stable/#download-mac). If you choose to install via a package manager, add Mono's own repository first. -2. Download the most recent **Zen-Protocol-Wallet.dmg** file from [Github​](https://github.com/zenprotocol/zenwallet/releases) -3. After installing drag the ZPW (Zen-Protocol-Wallet) icon to the applications folder, add login credentials for authentication -4. Right click and choose 'open' -5. Confirm by clicking the 'open' button - -#### Linux -1. Install [mono-devel](https://www.mono-project.com/download/stable/#download-lin-ubuntu). If you choose to install via a package manager, add Mono's own repository first. -2. Install lmdb. The package name is liblmdb0 on Ubuntu and lmdb on Fedora. - ```sudo apt install liblmdb0``` -3. Download the most recent **zen-wallet.tar.gz** file from [Github​](https://github.com/zenprotocol/zenwallet/releases) -4. Once extracted you can run the executable named zen-wallet. - --------------------------------------------------------------------------------- - -### Link to Download Installers -[​https://github.com/zenprotocol/zenwallet/releases​](​https://github.com/zenprotocol/zenwallet/releases​) diff --git a/docs/wallet/installation/installers.md b/docs/wallet/installation/installers.md new file mode 100644 index 0000000..794c5b1 --- /dev/null +++ b/docs/wallet/installation/installers.md @@ -0,0 +1,34 @@ +# Executable Installers + +Download and installation for users without development experience. + +-------------------------------------------------------------------------------- + +#### Prerequisites + Please make sure to install all of the necessary dependencies below before trying to run the Zen Wallet Software. + +#### Windows + 1. Install [.NET Framework 4.7​](https://www.microsoft.com/en-us/download/details.aspx?id=55167) + 2. Install [vc++ redist 2015 x64​](https://github.com/zenprotocol/zen-prerequisites-nuget/raw/master/vc_redist.x64.exe) + 3. Download the most recent **zen-wallet-setup.exe** file from [Github​](https://github.com/zenprotocol/zenwallet/releases) + 4. Your browser may warn that the download is not commonly downloaded. Click "keep" to download it anyway. + 5. Run the installer. You'll need to click the ```More Info``` button and click ```Run anyway``` + +#### Mac OSX + 1. Install [mono](http://www.mono-project.com/download/stable/#download-mac). If you choose to install via a package manager, add Mono's own repository first. + 2. Download the most recent **Zen-Protocol-Wallet.dmg** file from [Github​](https://github.com/zenprotocol/zenwallet/releases) + 3. After installing drag the ZPW (Zen-Protocol-Wallet) icon to the applications folder, add login credentials for authentication + 4. Right click and choose 'open' + 5. Confirm by clicking the 'open' button + +#### Linux + 1. Install [mono-devel](https://www.mono-project.com/download/stable/#download-lin-ubuntu). If you choose to install via a package manager, add Mono's own repository first. + 2. Install lmdb. The package name is liblmdb0 on Ubuntu and lmdb on Fedora. + ```sudo apt install liblmdb0``` + 3. Download the most recent **zen-wallet.tar.gz** file from [Github​](https://github.com/zenprotocol/zenwallet/releases) + 4. Once extracted you can run the executable named zen-wallet. + +-------------------------------------------------------------------------------- + +### Link to Download Installers + [​https://github.com/zenprotocol/zenwallet/releases​](​https://github.com/zenprotocol/zenwallet/releases​) diff --git a/docs/wallet/installation/npm.md b/docs/wallet/installation/npm.md new file mode 100644 index 0000000..732734c --- /dev/null +++ b/docs/wallet/installation/npm.md @@ -0,0 +1,82 @@ +# NPM Package + +Preparing your machine to install the Zen Protocol desktop wallet and the Zen Full Node via npm packages + +-------------------------------------------------------------------------------- + +Please note that the usage of the software is only permitted to anyone who purchased a license during the license sale period. [Sale Terms​](https://www.zenprotocol.com/legal/zen_protocol_token_sale_agreement.pdf) + +## Learn how to install and use the wallet with video tutorials: + Video Tutorials + +## OSX + + 1. Install [mono-devel](http://www.mono-project.com/download). If you choose to install via a package manager, add Mono's own repository first. + + 2. Install brew (https://www.howtogeek.com/211541/homebrew-for-os-x-easily-installs-desktop-apps-and-terminal-utilities) + a. ```xcode-select --install``` + b. ```ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"``` + c. Run this to check if brew is installed properly: ```brew doctor``` + + 3. Open the **Terminal** (can be found from **search** bar) + + 4. Install lmdb. Enter the command (in terminal) ```brew install lmdb```. + + 5. [​Install Nodejs](https://nodejs.org/en/download/) (Version >= 6) + a. Recommended to install using [NVM​](https://github.com/creationix/nvm#installation) + b. Recommended to install Node LTS (8.9.4) ```nvm install 8.9.4``` + +## Windows + + 1. Install [.NET Framework 4.7](https://www.microsoft.com/en-us/download/details.aspx?id=55167). + + 2. [​Install Nodejs](https://nodejs.org/en/download/) (LTS version recommended) + + 3. Open the [Command Prompt​](https://www.lifewire.com/how-to-open-command-prompt-2618089) + +## Linux + + 1. Install [mono-devel](http://www.mono-project.com/download). If you choose to install via a package manager, add Mono's own repository first. + + 2. Install lmdb. The package name is liblmdb0 on Ubuntu and lmdb on Fedora. + ```sudo apt install liblmdb0``` + + 3. Install Nodejs (Version >= 6) + a. Recommended to install using [NVM​](https://github.com/creationix/nvm#installation) + b. Recommended to install Node LTS (8.9.4) ```nvm install 8.9.4``` + + +## Point your npm directory to our repository + + Run the following commands in the Terminal / Command Prompt: + + ```npm config set @zen:registry https://www.myget.org/F/zenprotocol/npm/``` + +## Installing / Updating + + Run the following commands in the Terminal / Command Prompt: + + ```npm install @zen/zen-wallet -g``` + +## Running the wallet + full node + + Run ```zen-wallet``` from anywhere in your command line (terminal) to start up the wallet + +## Running with arguments + +### Wipe (Clear Data) + + When we launch a new testnet sometimes you will need to wipe your local database in order to sync. + + Note that this will NOT delete any data/tokens from the wallet. + + You can do this by running: ```zen-wallet wipe``` + +### Full Wipe (Clear Data and wallet) + + To completely wipe the blockchain + the wallet from your computer run: ```zen-wallet wipefull``` + Running without full node + + If you would like to run the node independently in a separate tab you can run zen-wallet uionly to launch the wallet without the full node running in the background. + + To learn how to run the Zen Node in headless mode click here. From 0ed974b9b7cc8ca739a78b0744a4ebfb7fadbd82 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Sun, 14 Oct 2018 17:32:09 +0300 Subject: [PATCH 02/42] reorganized a bit --- docs/index.md | 12 +++++++----- docs/top/wallet.md | 17 +++++++++++++++++ docs/wallet/desktop-wallet.md | 16 ++++++++++++++++ docs/{ => wallet/desktop}/installation.md | 0 .../{ => desktop}/installation/installers.md | 0 docs/wallet/{ => desktop}/installation/npm.md | 0 docs/wallet/web-wallet.md | 3 +++ 7 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 docs/top/wallet.md create mode 100644 docs/wallet/desktop-wallet.md rename docs/{ => wallet/desktop}/installation.md (100%) rename docs/wallet/{ => desktop}/installation/installers.md (100%) rename docs/wallet/{ => desktop}/installation/npm.md (100%) create mode 100644 docs/wallet/web-wallet.md diff --git a/docs/index.md b/docs/index.md index cde48a6..0532dfd 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,9 +2,11 @@ Contents: -* [Wallet] - * [Installation](wallet/installation.html) - * [Executable Installers](wallet/installation/installers.html) - * npm - * From source +* [Wallet](top/wallet.html) + * [Desktop Wallet](wallet/desktop-wallet.html) + * [Installation](wallet/desktop/installation.html) + * [Executable Installers](wallet/desktop/installation/installers.html) + * [npm](wallet/desktop/installation/npm.html) + * From source + * [Web Wallet (Beta)](wallet/web-wallet.html) * [ZF*](zfstar.html) diff --git a/docs/top/wallet.md b/docs/top/wallet.md new file mode 100644 index 0000000..e89c81e --- /dev/null +++ b/docs/top/wallet.md @@ -0,0 +1,17 @@ +# Zen Wallet + +There are currently 2 ways to access your Zen Wallet and make transactions: + +-------------------------------------------------------------------------------- + +## Full Node Desktop Wallet + +This is the most secure way to validate the network, use your wallet to make transaction and run smart contracts. It takes more time to sync up with the network, but the result is a higher level of security. + +[Desktop Wallet](wallet/desktop-wallet.html) + +## Web Wallet (Beta) + +This option is easier to use and does not require time to sync up with the network, but is less secure and more vulnerable to attack. + +[Web Wallet (Beta)](/zen-wallet/web-wallet.html) diff --git a/docs/wallet/desktop-wallet.md b/docs/wallet/desktop-wallet.md new file mode 100644 index 0000000..2b7e59a --- /dev/null +++ b/docs/wallet/desktop-wallet.md @@ -0,0 +1,16 @@ +# Desktop Wallet + +## Installation + +There are three ways to install the Zen Protocol desktop wallet: + +-------------------------------------------------------------------------------- + +### Regular desktop installers - .exe (windows) / .dmg (mac) / linux executable +[Installers](installation/installers.html) + +### To use command-line tools: via npm +Install from npm + +### From source +Build from Source diff --git a/docs/installation.md b/docs/wallet/desktop/installation.md similarity index 100% rename from docs/installation.md rename to docs/wallet/desktop/installation.md diff --git a/docs/wallet/installation/installers.md b/docs/wallet/desktop/installation/installers.md similarity index 100% rename from docs/wallet/installation/installers.md rename to docs/wallet/desktop/installation/installers.md diff --git a/docs/wallet/installation/npm.md b/docs/wallet/desktop/installation/npm.md similarity index 100% rename from docs/wallet/installation/npm.md rename to docs/wallet/desktop/installation/npm.md diff --git a/docs/wallet/web-wallet.md b/docs/wallet/web-wallet.md new file mode 100644 index 0000000..a7a0843 --- /dev/null +++ b/docs/wallet/web-wallet.md @@ -0,0 +1,3 @@ +# Web Wallet (Beta) + +TODO From eececeb401d292608e52efe2056e7b8ef553982f Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Sun, 14 Oct 2018 18:10:33 +0300 Subject: [PATCH 03/42] reorg 2 --- docs/index.md | 14 +++++++------- docs/{top => root}/wallet.md | 8 +++----- docs/{ => root}/wallet/desktop-wallet.md | 4 ++-- docs/{ => root}/wallet/desktop/installation.md | 2 +- .../wallet/desktop/installation/installers.md | 0 docs/{ => root}/wallet/desktop/installation/npm.md | 0 docs/{ => root}/wallet/web-wallet.md | 0 docs/{ => root}/zfstar.md | 0 8 files changed, 13 insertions(+), 15 deletions(-) rename docs/{top => root}/wallet.md (73%) rename docs/{ => root}/wallet/desktop-wallet.md (76%) rename docs/{ => root}/wallet/desktop/installation.md (89%) rename docs/{ => root}/wallet/desktop/installation/installers.md (100%) rename docs/{ => root}/wallet/desktop/installation/npm.md (100%) rename docs/{ => root}/wallet/web-wallet.md (100%) rename docs/{ => root}/zfstar.md (100%) diff --git a/docs/index.md b/docs/index.md index 0532dfd..dc76cb3 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,11 +2,11 @@ Contents: -* [Wallet](top/wallet.html) - * [Desktop Wallet](wallet/desktop-wallet.html) - * [Installation](wallet/desktop/installation.html) - * [Executable Installers](wallet/desktop/installation/installers.html) - * [npm](wallet/desktop/installation/npm.html) +* [Wallet](root/wallet.html) + * [Desktop Wallet](root/wallet/desktop-wallet.html) + * [Installation](root/wallet/desktop/installation.html) + * [Executable Installers](root/wallet/desktop/installation/installers.html) + * [npm](root/wallet/desktop/installation/npm.html) * From source - * [Web Wallet (Beta)](wallet/web-wallet.html) -* [ZF*](zfstar.html) + * [Web Wallet (Beta)](root/wallet/web-wallet.html) +* [ZF*](root/zfstar.html) diff --git a/docs/top/wallet.md b/docs/root/wallet.md similarity index 73% rename from docs/top/wallet.md rename to docs/root/wallet.md index e89c81e..18fecdf 100644 --- a/docs/top/wallet.md +++ b/docs/root/wallet.md @@ -4,14 +4,12 @@ There are currently 2 ways to access your Zen Wallet and make transactions: -------------------------------------------------------------------------------- -## Full Node Desktop Wallet +## [Full Node Desktop Wallet](wallet/desktop-wallet.html) This is the most secure way to validate the network, use your wallet to make transaction and run smart contracts. It takes more time to sync up with the network, but the result is a higher level of security. -[Desktop Wallet](wallet/desktop-wallet.html) +-------------------------------------------------------------------------------- -## Web Wallet (Beta) +## [Web Wallet (Beta)](wallet/web-wallet.html) This option is easier to use and does not require time to sync up with the network, but is less secure and more vulnerable to attack. - -[Web Wallet (Beta)](/zen-wallet/web-wallet.html) diff --git a/docs/wallet/desktop-wallet.md b/docs/root/wallet/desktop-wallet.md similarity index 76% rename from docs/wallet/desktop-wallet.md rename to docs/root/wallet/desktop-wallet.md index 2b7e59a..5abdb57 100644 --- a/docs/wallet/desktop-wallet.md +++ b/docs/root/wallet/desktop-wallet.md @@ -7,10 +7,10 @@ There are three ways to install the Zen Protocol desktop wallet: -------------------------------------------------------------------------------- ### Regular desktop installers - .exe (windows) / .dmg (mac) / linux executable -[Installers](installation/installers.html) +[Installers](desktop/installation/installers.html) ### To use command-line tools: via npm -Install from npm +[Install from npm](desktop/installation/npm.html) ### From source Build from Source diff --git a/docs/wallet/desktop/installation.md b/docs/root/wallet/desktop/installation.md similarity index 89% rename from docs/wallet/desktop/installation.md rename to docs/root/wallet/desktop/installation.md index 969cd27..61ca5ea 100644 --- a/docs/wallet/desktop/installation.md +++ b/docs/root/wallet/desktop/installation.md @@ -8,7 +8,7 @@ There are three ways to install the Zen Protocol desktop wallet: [Installers](installation/installers.html) ### To use command-line tools: via npm -Install from npm +[Install from npm](installation/npm.html) ### From source Build from Source diff --git a/docs/wallet/desktop/installation/installers.md b/docs/root/wallet/desktop/installation/installers.md similarity index 100% rename from docs/wallet/desktop/installation/installers.md rename to docs/root/wallet/desktop/installation/installers.md diff --git a/docs/wallet/desktop/installation/npm.md b/docs/root/wallet/desktop/installation/npm.md similarity index 100% rename from docs/wallet/desktop/installation/npm.md rename to docs/root/wallet/desktop/installation/npm.md diff --git a/docs/wallet/web-wallet.md b/docs/root/wallet/web-wallet.md similarity index 100% rename from docs/wallet/web-wallet.md rename to docs/root/wallet/web-wallet.md diff --git a/docs/zfstar.md b/docs/root/zfstar.md similarity index 100% rename from docs/zfstar.md rename to docs/root/zfstar.md From 8c8ee2d6c1c028f704215b1d66cb961e78a10176 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Sun, 14 Oct 2018 18:16:38 +0300 Subject: [PATCH 04/42] outdent --- .../wallet/desktop/installation/installers.md | 32 ++++----- docs/root/wallet/desktop/installation/npm.md | 69 ++++++++++--------- 2 files changed, 53 insertions(+), 48 deletions(-) diff --git a/docs/root/wallet/desktop/installation/installers.md b/docs/root/wallet/desktop/installation/installers.md index 794c5b1..d69253a 100644 --- a/docs/root/wallet/desktop/installation/installers.md +++ b/docs/root/wallet/desktop/installation/installers.md @@ -5,28 +5,28 @@ Download and installation for users without development experience. -------------------------------------------------------------------------------- #### Prerequisites - Please make sure to install all of the necessary dependencies below before trying to run the Zen Wallet Software. +Please make sure to install all of the necessary dependencies below before trying to run the Zen Wallet Software. #### Windows - 1. Install [.NET Framework 4.7​](https://www.microsoft.com/en-us/download/details.aspx?id=55167) - 2. Install [vc++ redist 2015 x64​](https://github.com/zenprotocol/zen-prerequisites-nuget/raw/master/vc_redist.x64.exe) - 3. Download the most recent **zen-wallet-setup.exe** file from [Github​](https://github.com/zenprotocol/zenwallet/releases) - 4. Your browser may warn that the download is not commonly downloaded. Click "keep" to download it anyway. - 5. Run the installer. You'll need to click the ```More Info``` button and click ```Run anyway``` +1. Install [.NET Framework 4.7​](https://www.microsoft.com/en-us/download/details.aspx?id=55167) +2. Install [vc++ redist 2015 x64​](https://github.com/zenprotocol/zen-prerequisites-nuget/raw/master/vc_redist.x64.exe) +3. Download the most recent **zen-wallet-setup.exe** file from [Github​](https://github.com/zenprotocol/zenwallet/releases) +4. Your browser may warn that the download is not commonly downloaded. Click "keep" to download it anyway. +5. Run the installer. You'll need to click the ```More Info``` button and click ```Run anyway``` #### Mac OSX - 1. Install [mono](http://www.mono-project.com/download/stable/#download-mac). If you choose to install via a package manager, add Mono's own repository first. - 2. Download the most recent **Zen-Protocol-Wallet.dmg** file from [Github​](https://github.com/zenprotocol/zenwallet/releases) - 3. After installing drag the ZPW (Zen-Protocol-Wallet) icon to the applications folder, add login credentials for authentication - 4. Right click and choose 'open' - 5. Confirm by clicking the 'open' button +1. Install [mono](http://www.mono-project.com/download/stable/#download-mac). If you choose to install via a package manager, add Mono's own repository first. +2. Download the most recent **Zen-Protocol-Wallet.dmg** file from [Github​](https://github.com/zenprotocol/zenwallet/releases) +3. After installing drag the ZPW (Zen-Protocol-Wallet) icon to the applications folder, add login credentials for authentication +4. Right click and choose 'open' +5. Confirm by clicking the 'open' button #### Linux - 1. Install [mono-devel](https://www.mono-project.com/download/stable/#download-lin-ubuntu). If you choose to install via a package manager, add Mono's own repository first. - 2. Install lmdb. The package name is liblmdb0 on Ubuntu and lmdb on Fedora. - ```sudo apt install liblmdb0``` - 3. Download the most recent **zen-wallet.tar.gz** file from [Github​](https://github.com/zenprotocol/zenwallet/releases) - 4. Once extracted you can run the executable named zen-wallet. +1. Install [mono-devel](https://www.mono-project.com/download/stable/#download-lin-ubuntu). If you choose to install via a package manager, add Mono's own repository first. +2. Install lmdb. The package name is liblmdb0 on Ubuntu and lmdb on Fedora. + ```sudo apt install liblmdb0``` +3. Download the most recent **zen-wallet.tar.gz** file from [Github​](https://github.com/zenprotocol/zenwallet/releases) +4. Once extracted you can run the executable named zen-wallet. -------------------------------------------------------------------------------- diff --git a/docs/root/wallet/desktop/installation/npm.md b/docs/root/wallet/desktop/installation/npm.md index 732734c..20c1db0 100644 --- a/docs/root/wallet/desktop/installation/npm.md +++ b/docs/root/wallet/desktop/installation/npm.md @@ -7,76 +7,81 @@ Preparing your machine to install the Zen Protocol desktop wallet and the Zen Fu Please note that the usage of the software is only permitted to anyone who purchased a license during the license sale period. [Sale Terms​](https://www.zenprotocol.com/legal/zen_protocol_token_sale_agreement.pdf) ## Learn how to install and use the wallet with video tutorials: - Video Tutorials +Video Tutorials + ## OSX - 1. Install [mono-devel](http://www.mono-project.com/download). If you choose to install via a package manager, add Mono's own repository first. +1. Install [mono-devel](http://www.mono-project.com/download). If you choose to install via a package manager, add Mono's own repository first. + +2. Install brew (https://www.howtogeek.com/211541/homebrew-for-os-x-easily-installs-desktop-apps-and-terminal-utilities) + a. ```xcode-select --install``` + b. ```ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"``` + c. Run this to check if brew is installed properly: ```brew doctor``` - 2. Install brew (https://www.howtogeek.com/211541/homebrew-for-os-x-easily-installs-desktop-apps-and-terminal-utilities) - a. ```xcode-select --install``` - b. ```ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"``` - c. Run this to check if brew is installed properly: ```brew doctor``` +3. Open the **Terminal** (can be found from **search** bar) - 3. Open the **Terminal** (can be found from **search** bar) +4. Install lmdb. Enter the command (in terminal) ```brew install lmdb```. - 4. Install lmdb. Enter the command (in terminal) ```brew install lmdb```. +5. [​Install Nodejs](https://nodejs.org/en/download/) (Version >= 6) + a. Recommended to install using [NVM​](https://github.com/creationix/nvm#installation) + b. Recommended to install Node LTS (8.9.4) ```nvm install 8.9.4``` - 5. [​Install Nodejs](https://nodejs.org/en/download/) (Version >= 6) - a. Recommended to install using [NVM​](https://github.com/creationix/nvm#installation) - b. Recommended to install Node LTS (8.9.4) ```nvm install 8.9.4``` ## Windows - 1. Install [.NET Framework 4.7](https://www.microsoft.com/en-us/download/details.aspx?id=55167). +1. Install [.NET Framework 4.7](https://www.microsoft.com/en-us/download/details.aspx?id=55167). + +2. [​Install Nodejs](https://nodejs.org/en/download/) (LTS version recommended) - 2. [​Install Nodejs](https://nodejs.org/en/download/) (LTS version recommended) +3. Open the [Command Prompt​](https://www.lifewire.com/how-to-open-command-prompt-2618089) - 3. Open the [Command Prompt​](https://www.lifewire.com/how-to-open-command-prompt-2618089) ## Linux - 1. Install [mono-devel](http://www.mono-project.com/download). If you choose to install via a package manager, add Mono's own repository first. +1. Install [mono-devel](http://www.mono-project.com/download). If you choose to install via a package manager, add Mono's own repository first. - 2. Install lmdb. The package name is liblmdb0 on Ubuntu and lmdb on Fedora. - ```sudo apt install liblmdb0``` +2. Install lmdb. The package name is liblmdb0 on Ubuntu and lmdb on Fedora. + ```sudo apt install liblmdb0``` - 3. Install Nodejs (Version >= 6) - a. Recommended to install using [NVM​](https://github.com/creationix/nvm#installation) - b. Recommended to install Node LTS (8.9.4) ```nvm install 8.9.4``` +3. Install Nodejs (Version >= 6) + a. Recommended to install using [NVM​](https://github.com/creationix/nvm#installation) + b. Recommended to install Node LTS (8.9.4) ```nvm install 8.9.4``` ## Point your npm directory to our repository - Run the following commands in the Terminal / Command Prompt: +Run the following commands in the Terminal / Command Prompt: + +```npm config set @zen:registry https://www.myget.org/F/zenprotocol/npm/``` - ```npm config set @zen:registry https://www.myget.org/F/zenprotocol/npm/``` ## Installing / Updating - Run the following commands in the Terminal / Command Prompt: +Run the following commands in the Terminal / Command Prompt: + +```npm install @zen/zen-wallet -g``` - ```npm install @zen/zen-wallet -g``` ## Running the wallet + full node - Run ```zen-wallet``` from anywhere in your command line (terminal) to start up the wallet +Run ```zen-wallet``` from anywhere in your command line (terminal) to start up the wallet ## Running with arguments ### Wipe (Clear Data) - When we launch a new testnet sometimes you will need to wipe your local database in order to sync. +When we launch a new testnet sometimes you will need to wipe your local database in order to sync. - Note that this will NOT delete any data/tokens from the wallet. +Note that this will NOT delete any data/tokens from the wallet. - You can do this by running: ```zen-wallet wipe``` +You can do this by running: ```zen-wallet wipe``` ### Full Wipe (Clear Data and wallet) - To completely wipe the blockchain + the wallet from your computer run: ```zen-wallet wipefull``` - Running without full node +To completely wipe the blockchain + the wallet from your computer run: ```zen-wallet wipefull``` +Running without full node - If you would like to run the node independently in a separate tab you can run zen-wallet uionly to launch the wallet without the full node running in the background. +If you would like to run the node independently in a separate tab you can run zen-wallet uionly to launch the wallet without the full node running in the background. - To learn how to run the Zen Node in headless mode click here. +To learn how to run the Zen Node in headless mode click here. From ec7c5dca84261a1d14e4ddd692188268a06730f2 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Sun, 14 Oct 2018 18:19:08 +0300 Subject: [PATCH 05/42] outdent --- docs/root/wallet/desktop/installation/npm.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/docs/root/wallet/desktop/installation/npm.md b/docs/root/wallet/desktop/installation/npm.md index 20c1db0..66ea1a1 100644 --- a/docs/root/wallet/desktop/installation/npm.md +++ b/docs/root/wallet/desktop/installation/npm.md @@ -13,16 +13,12 @@ Video Tutorials ## OSX 1. Install [mono-devel](http://www.mono-project.com/download). If you choose to install via a package manager, add Mono's own repository first. - 2. Install brew (https://www.howtogeek.com/211541/homebrew-for-os-x-easily-installs-desktop-apps-and-terminal-utilities) a. ```xcode-select --install``` b. ```ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"``` c. Run this to check if brew is installed properly: ```brew doctor``` - 3. Open the **Terminal** (can be found from **search** bar) - 4. Install lmdb. Enter the command (in terminal) ```brew install lmdb```. - 5. [​Install Nodejs](https://nodejs.org/en/download/) (Version >= 6) a. Recommended to install using [NVM​](https://github.com/creationix/nvm#installation) b. Recommended to install Node LTS (8.9.4) ```nvm install 8.9.4``` @@ -31,19 +27,15 @@ Video Tutorials ## Windows 1. Install [.NET Framework 4.7](https://www.microsoft.com/en-us/download/details.aspx?id=55167). - 2. [​Install Nodejs](https://nodejs.org/en/download/) (LTS version recommended) - 3. Open the [Command Prompt​](https://www.lifewire.com/how-to-open-command-prompt-2618089) ## Linux 1. Install [mono-devel](http://www.mono-project.com/download). If you choose to install via a package manager, add Mono's own repository first. - 2. Install lmdb. The package name is liblmdb0 on Ubuntu and lmdb on Fedora. ```sudo apt install liblmdb0``` - 3. Install Nodejs (Version >= 6) a. Recommended to install using [NVM​](https://github.com/creationix/nvm#installation) b. Recommended to install Node LTS (8.9.4) ```nvm install 8.9.4``` From b131877187ba2e62fdb314471562b73d180a9cd9 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Sun, 14 Oct 2018 18:21:35 +0300 Subject: [PATCH 06/42] outdent --- docs/root/wallet/desktop/installation/npm.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/root/wallet/desktop/installation/npm.md b/docs/root/wallet/desktop/installation/npm.md index 66ea1a1..1236638 100644 --- a/docs/root/wallet/desktop/installation/npm.md +++ b/docs/root/wallet/desktop/installation/npm.md @@ -14,14 +14,14 @@ Video Tutorials 1. Install [mono-devel](http://www.mono-project.com/download). If you choose to install via a package manager, add Mono's own repository first. 2. Install brew (https://www.howtogeek.com/211541/homebrew-for-os-x-easily-installs-desktop-apps-and-terminal-utilities) - a. ```xcode-select --install``` - b. ```ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"``` - c. Run this to check if brew is installed properly: ```brew doctor``` + 1. ```xcode-select --install``` + 2. ```ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"``` + 3. Run this to check if brew is installed properly: ```brew doctor``` 3. Open the **Terminal** (can be found from **search** bar) 4. Install lmdb. Enter the command (in terminal) ```brew install lmdb```. 5. [​Install Nodejs](https://nodejs.org/en/download/) (Version >= 6) - a. Recommended to install using [NVM​](https://github.com/creationix/nvm#installation) - b. Recommended to install Node LTS (8.9.4) ```nvm install 8.9.4``` + 1. Recommended to install using [NVM​](https://github.com/creationix/nvm#installation) + 2. Recommended to install Node LTS (8.9.4) ```nvm install 8.9.4``` ## Windows @@ -37,8 +37,8 @@ Video Tutorials 2. Install lmdb. The package name is liblmdb0 on Ubuntu and lmdb on Fedora. ```sudo apt install liblmdb0``` 3. Install Nodejs (Version >= 6) - a. Recommended to install using [NVM​](https://github.com/creationix/nvm#installation) - b. Recommended to install Node LTS (8.9.4) ```nvm install 8.9.4``` + 1. Recommended to install using [NVM​](https://github.com/creationix/nvm#installation) + 2. Recommended to install Node LTS (8.9.4) ```nvm install 8.9.4``` ## Point your npm directory to our repository From be183f99b5e2c4e0bbaa69c29cd8830f63eb4ffe Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Sun, 14 Oct 2018 18:41:21 +0300 Subject: [PATCH 07/42] wallet from source --- docs/index.md | 2 +- docs/root/wallet/desktop-wallet.md | 2 +- docs/root/wallet/desktop/installation.md | 2 +- .../desktop/installation/from-source.md | 62 +++++++++++++++++++ .../wallet/desktop/installation/installers.md | 2 +- docs/root/wallet/desktop/installation/npm.md | 2 +- docs/root/wallet/web-wallet.md | 2 +- 7 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 docs/root/wallet/desktop/installation/from-source.md diff --git a/docs/index.md b/docs/index.md index dc76cb3..37f7c3c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -7,6 +7,6 @@ Contents: * [Installation](root/wallet/desktop/installation.html) * [Executable Installers](root/wallet/desktop/installation/installers.html) * [npm](root/wallet/desktop/installation/npm.html) - * From source + * [From source](root/wallet/desktop/installation/from-source.html) * [Web Wallet (Beta)](root/wallet/web-wallet.html) * [ZF*](root/zfstar.html) diff --git a/docs/root/wallet/desktop-wallet.md b/docs/root/wallet/desktop-wallet.md index 5abdb57..e3bad25 100644 --- a/docs/root/wallet/desktop-wallet.md +++ b/docs/root/wallet/desktop-wallet.md @@ -13,4 +13,4 @@ There are three ways to install the Zen Protocol desktop wallet: [Install from npm](desktop/installation/npm.html) ### From source -Build from Source +[Build from Source](desktop/installation/from-source.html) diff --git a/docs/root/wallet/desktop/installation.md b/docs/root/wallet/desktop/installation.md index 61ca5ea..c943df4 100644 --- a/docs/root/wallet/desktop/installation.md +++ b/docs/root/wallet/desktop/installation.md @@ -11,4 +11,4 @@ There are three ways to install the Zen Protocol desktop wallet: [Install from npm](installation/npm.html) ### From source -Build from Source +[Build from Source](installation/from-source.html) diff --git a/docs/root/wallet/desktop/installation/from-source.md b/docs/root/wallet/desktop/installation/from-source.md new file mode 100644 index 0000000..eed2d39 --- /dev/null +++ b/docs/root/wallet/desktop/installation/from-source.md @@ -0,0 +1,62 @@ +# Build from Source + +If you would like to build Zen Protocol from source you can clone https://github.com/zenprotocol/zenprotocol and build it independently + +### Linux + +1. Install mono-devel from http://www.mono-project.com/download. If you choose to install via a package manager, add Mono's own repository first. +2. Install lmdb. The package name is liblmdb0 on Ubuntu and lmdb on Fedora. +3. Run the following: +```bash +./paket restore +chmod +x packages/zen_z3_linux/output/z3 +pushd src/Zulib +./build.fsx +popd +msbuild src +``` + +### OSX + +1. Install Mono as in step 1 of the instructions for Linux. +2. Install lmdb. You can get it via brew with brew install lmdb. +3. Run the following: +```bash +./paket restore +chmod +x packages/zen_z3_osx/output/z3 +pushd src/Zulib +./build.fsx +popd +msbuild src +``` + +### Windows + +Windows is not yet supported + +-------------------------------------------------------------------------------- + +## Run + +### Linux and OSX + +```bash +cd src/Node/bin/Debug +./zen-node +``` + +### Windows + +```bash +cd src\Node\bin\Debug +zen-node.exe +``` + +### CLI + +You can communicate with the node with ```zen-cli```. Enter the ```bin``` directory of the node (```src/Node/bin/Debug```) and run: +Linux and OSX + +```bash +./zen-cli --help +``` diff --git a/docs/root/wallet/desktop/installation/installers.md b/docs/root/wallet/desktop/installation/installers.md index d69253a..086e9f4 100644 --- a/docs/root/wallet/desktop/installation/installers.md +++ b/docs/root/wallet/desktop/installation/installers.md @@ -31,4 +31,4 @@ Please make sure to install all of the necessary dependencies below before tryin -------------------------------------------------------------------------------- ### Link to Download Installers - [​https://github.com/zenprotocol/zenwallet/releases​](​https://github.com/zenprotocol/zenwallet/releases​) +<​https://github.com/zenprotocol/zenwallet/releases​> diff --git a/docs/root/wallet/desktop/installation/npm.md b/docs/root/wallet/desktop/installation/npm.md index 1236638..5b4fb46 100644 --- a/docs/root/wallet/desktop/installation/npm.md +++ b/docs/root/wallet/desktop/installation/npm.md @@ -13,7 +13,7 @@ Video Tutorials ## OSX 1. Install [mono-devel](http://www.mono-project.com/download). If you choose to install via a package manager, add Mono's own repository first. -2. Install brew (https://www.howtogeek.com/211541/homebrew-for-os-x-easily-installs-desktop-apps-and-terminal-utilities) +2. Install brew () 1. ```xcode-select --install``` 2. ```ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"``` 3. Run this to check if brew is installed properly: ```brew doctor``` diff --git a/docs/root/wallet/web-wallet.md b/docs/root/wallet/web-wallet.md index a7a0843..cf2099c 100644 --- a/docs/root/wallet/web-wallet.md +++ b/docs/root/wallet/web-wallet.md @@ -1,3 +1,3 @@ # Web Wallet (Beta) -TODO +The web wallet allows you to access your wallet and make transactions via a web browser. From a8a48b78dc9c4bb9c3686b86947beaf09dc65034 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Sun, 14 Oct 2018 19:04:15 +0300 Subject: [PATCH 08/42] wallet from source --- docs/root/wallet/desktop/installation/from-source.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/root/wallet/desktop/installation/from-source.md b/docs/root/wallet/desktop/installation/from-source.md index eed2d39..039f987 100644 --- a/docs/root/wallet/desktop/installation/from-source.md +++ b/docs/root/wallet/desktop/installation/from-source.md @@ -7,7 +7,7 @@ If you would like to build Zen Protocol from source you can clone https://github 1. Install mono-devel from http://www.mono-project.com/download. If you choose to install via a package manager, add Mono's own repository first. 2. Install lmdb. The package name is liblmdb0 on Ubuntu and lmdb on Fedora. 3. Run the following: -```bash +``` ./paket restore chmod +x packages/zen_z3_linux/output/z3 pushd src/Zulib @@ -21,7 +21,7 @@ msbuild src 1. Install Mono as in step 1 of the instructions for Linux. 2. Install lmdb. You can get it via brew with brew install lmdb. 3. Run the following: -```bash +``` ./paket restore chmod +x packages/zen_z3_osx/output/z3 pushd src/Zulib @@ -40,14 +40,14 @@ Windows is not yet supported ### Linux and OSX -```bash +``` cd src/Node/bin/Debug ./zen-node ``` ### Windows -```bash +``` cd src\Node\bin\Debug zen-node.exe ``` @@ -57,6 +57,6 @@ zen-node.exe You can communicate with the node with ```zen-cli```. Enter the ```bin``` directory of the node (```src/Node/bin/Debug```) and run: Linux and OSX -```bash +``` ./zen-cli --help ``` From 4acb6d99e008e1387dee270b909bb7b6e99d5669 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Mon, 15 Oct 2018 12:34:01 +0300 Subject: [PATCH 09/42] web wallet --- .../desktop/installation/from-source.md | 4 +-- docs/root/wallet/desktop/installation/npm.md | 3 +- docs/root/wallet/web-wallet.md | 35 +++++++++++++++++++ 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/docs/root/wallet/desktop/installation/from-source.md b/docs/root/wallet/desktop/installation/from-source.md index 039f987..55c24ae 100644 --- a/docs/root/wallet/desktop/installation/from-source.md +++ b/docs/root/wallet/desktop/installation/from-source.md @@ -1,10 +1,10 @@ # Build from Source -If you would like to build Zen Protocol from source you can clone https://github.com/zenprotocol/zenprotocol and build it independently +If you would like to build Zen Protocol from source you can clone and build it independently ### Linux -1. Install mono-devel from http://www.mono-project.com/download. If you choose to install via a package manager, add Mono's own repository first. +1. Install mono-devel from . If you choose to install via a package manager, add Mono's own repository first. 2. Install lmdb. The package name is liblmdb0 on Ubuntu and lmdb on Fedora. 3. Run the following: ``` diff --git a/docs/root/wallet/desktop/installation/npm.md b/docs/root/wallet/desktop/installation/npm.md index 5b4fb46..7633079 100644 --- a/docs/root/wallet/desktop/installation/npm.md +++ b/docs/root/wallet/desktop/installation/npm.md @@ -4,7 +4,8 @@ Preparing your machine to install the Zen Protocol desktop wallet and the Zen Fu -------------------------------------------------------------------------------- -Please note that the usage of the software is only permitted to anyone who purchased a license during the license sale period. [Sale Terms​](https://www.zenprotocol.com/legal/zen_protocol_token_sale_agreement.pdf) +Please note that the usage of the software is only permitted to anyone who purchased a license during the license sale period. +[Sale Terms​](https://www.zenprotocol.com/legal/zen_protocol_token_sale_agreement.pdf) ## Learn how to install and use the wallet with video tutorials: Video Tutorials diff --git a/docs/root/wallet/web-wallet.md b/docs/root/wallet/web-wallet.md index cf2099c..a21bed1 100644 --- a/docs/root/wallet/web-wallet.md +++ b/docs/root/wallet/web-wallet.md @@ -1,3 +1,38 @@ # Web Wallet (Beta) The web wallet allows you to access your wallet and make transactions via a web browser. + +--- +##### Security Notice + +Web wallets are inherently less secure than other forms of cryptocurrency wallets. You should not use this web wallet to secure or control any tokens or resources that you cannot afford to lose. The major weakness in any web wallet is that its code is delivered in the form of a web page, meaning that if the server is compromised, the attacker can cause it to deliver phishing code to the user, stealing private key data and using it to steal funds. An additional attack vector is the injection of malicious code into a compromised javascript dependency, for example MobX.js. Please use the Desktop Wallet if you want a higher level of security. + +--- + +### Differences between the web wallet and the [Desktop Wallet](desktop-wallet.html): + +| | Web Wallet | Desktop Wallet | +| ------------- |:-------------:| -----:| +| Storing seed | Encrypted using a password of your choice and stored in local storage | Encrypted using a password of your choice and stored in folder in your computer | +| Validation | Uses a "trusted" remote node to sync with the blockchain and validate the consensus rules, and relays signed transactions on its behalf | The client runs a full node and validates the consensus rules of the blockchain independently | +| Access | Is via a web browser, which can be compromised in multiple ways such as * having a malicious Chrome Extension​ * If the server that is serving the client gets hacked, the hacker could deliver a version of the website that steals your seed. * Phishing - someone could create a website with a domain that looks very similar to the real official wallet domain and serve a malicious version of the wallet. | You download a desktop application to your computer once from a trusted source. | + +--- + +### Steps for using the web wallet as securely as possible: + +1. Only use a computer that you are sure is not infected with a virus. Viruses such as keystroke loggers can steal your 24 word mnemonic phrase while you are typing it. +2. You should use a web browser with as little as possible extensions or none at all - and only if you completely trust those extensions. Preferably you should use a browser without any extensions. +3. Bookmark that url of the web wallet and always access it by clicking the bookmark. + +--- + +Accessing the Web Wallet - + +You should bookmark the wallet url asap (https://wallet.zp.io) and only access it by clicking the bookmark. + +You may run the web wallet client locally independently in order to remove the risk of a phishing attack - here are the instructions for doing so. + +#### Code References + +If you would like to go over the code that secures your 24 word mnemonic phrase and signs transactions you can go over the code references here. From 4972c3305683119f23a95a5fabe7bd29bd0dbe92 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Mon, 15 Oct 2018 12:41:13 +0300 Subject: [PATCH 10/42] contract-structure --- docs/root/contracts/contract-structure.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 docs/root/contracts/contract-structure.md diff --git a/docs/root/contracts/contract-structure.md b/docs/root/contracts/contract-structure.md new file mode 100644 index 0000000..1a195ec --- /dev/null +++ b/docs/root/contracts/contract-structure.md @@ -0,0 +1,11 @@ +# Contract Structure + +Each contract must contain 2 functions: ```main``` and ```cf```. + +The structure of the ```main``` function is: + +```F* +main (txSkel: txSkeleton) _ (contractId: contractId) (command: string) + (sender: sender) (messageBody: option data) (wallet: wallet) + (state: option data) +``` From 9c33f4faeb025538c06b40efb7f08b58c81b3c3a Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Mon, 15 Oct 2018 12:56:07 +0300 Subject: [PATCH 11/42] contract-structure --- docs/root/contracts/contract-structure.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/root/contracts/contract-structure.md b/docs/root/contracts/contract-structure.md index 1a195ec..a36ac2c 100644 --- a/docs/root/contracts/contract-structure.md +++ b/docs/root/contracts/contract-structure.md @@ -5,7 +5,16 @@ Each contract must contain 2 functions: ```main``` and ```cf```. The structure of the ```main``` function is: ```F* -main (txSkel: txSkeleton) _ (contractId: contractId) (command: string) - (sender: sender) (messageBody: option data) (wallet: wallet) - (state: option data) +main + ( txSkel : Zen.Types.txSkeleton ) + ( context : Zen.Types.context ) + ( contractId : Zen.Types.contractId ) + ( command : string ) + ( sender : Zen.Types.sender ) + ( messageBody : option Zen.Types.data ) + ( wallet : Zen.Types.wallet ) + ( state : option Zen.Types.data ) + : contractResult `Zen.Cost.t` n ``` + +where ```n``` must be an expression which evaluates to a natural number (```nat```). From 0f1d52674938b902ea437ca29c7f64de91b9cd81 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Mon, 15 Oct 2018 13:26:24 +0300 Subject: [PATCH 12/42] contract-structure --- docs/root/contracts/contract-structure.md | 35 ++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/docs/root/contracts/contract-structure.md b/docs/root/contracts/contract-structure.md index a36ac2c..32a7243 100644 --- a/docs/root/contracts/contract-structure.md +++ b/docs/root/contracts/contract-structure.md @@ -14,7 +14,40 @@ main ( messageBody : option Zen.Types.data ) ( wallet : Zen.Types.wallet ) ( state : option Zen.Types.data ) - : contractResult `Zen.Cost.t` n + : Zen.Types.contractResult `Zen.Cost.t` n ``` where ```n``` must be an expression which evaluates to a natural number (```nat```). + +### Parameters + +- ```txSkel : Zen.Types.txSkeleton``` + Details about the function. + +- ```context : Zen.Types.context``` + Details about the function. + +- ```contractId : Zen.Types.contractId``` + Details about the function. + +- ```command : string``` + String that the contract may use. + Contains a command which tells the contract what to do. + For example: + ```F* + match command with + | "redeem" -> redeem txSkeleton contractId returnAddress wallet + | "buy" -> buy txSkeleton contractId returnAddress + ``` + +- ```sender : Zen.Types.sender``` + Details about the function. + +- ```messageBody : option Zen.Types.data``` + Details about the function. + +- ```wallet : Zen.Types.wallet``` + Details about the function. + +- ```state : option Zen.Types.data``` + Details about the function. From 440f62ca10607733a0961f1b0902a113d7c1384d Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Mon, 15 Oct 2018 13:28:38 +0300 Subject: [PATCH 13/42] contract-structure --- docs/root/contracts/contract-structure.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/root/contracts/contract-structure.md b/docs/root/contracts/contract-structure.md index 32a7243..ef7df63 100644 --- a/docs/root/contracts/contract-structure.md +++ b/docs/root/contracts/contract-structure.md @@ -31,14 +31,14 @@ where ```n``` must be an expression which evaluates to a natural number (```nat` Details about the function. - ```command : string``` - String that the contract may use. - Contains a command which tells the contract what to do. - For example: - ```F* - match command with - | "redeem" -> redeem txSkeleton contractId returnAddress wallet - | "buy" -> buy txSkeleton contractId returnAddress - ``` + - String that the contract may use. + - Contains a command which tells the contract what to do. + - For example: + ```F* + match command with + | "redeem" -> redeem txSkeleton contractId returnAddress wallet + | "buy" -> buy txSkeleton contractId returnAddress + ``` - ```sender : Zen.Types.sender``` Details about the function. From b18d0a02e953cdabec68e5b7a230c22a8a03d0fb Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Mon, 15 Oct 2018 14:15:35 +0300 Subject: [PATCH 14/42] gitignore --- docs/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/.gitignore diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..e35d885 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +_build From 3dd7c56238df257462f212b8a2934534d3c2d4bb Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Mon, 15 Oct 2018 14:46:45 +0300 Subject: [PATCH 15/42] testing syntax highlighting --- docs/root/contracts/contract-structure.rst | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 docs/root/contracts/contract-structure.rst diff --git a/docs/root/contracts/contract-structure.rst b/docs/root/contracts/contract-structure.rst new file mode 100644 index 0000000..a464729 --- /dev/null +++ b/docs/root/contracts/contract-structure.rst @@ -0,0 +1,25 @@ +================== +Contract Structure +================== + +.. highlight:: rst + +.. role:: fstar(code) + :language: fsharp + +Each contract must contain 2 functions: :fstar:`main` and :fstar:`cf`. + +The structure of the :fstar:`main` function is: + +.. codeblock:: fstar + + main + ( txSkel : Zen.Types.txSkeleton ) + ( context : Zen.Types.context ) + ( contractId : Zen.Types.contractId ) + ( command : string ) + ( sender : Zen.Types.sender ) + ( messageBody : option Zen.Types.data ) + ( wallet : Zen.Types.wallet ) + ( state : option Zen.Types.data ) + : Zen.Types.contractResult `Zen.Cost.t` n From 239cfb548ff0844e7c43411909299f70d572340b Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Mon, 15 Oct 2018 15:00:51 +0300 Subject: [PATCH 16/42] the syntax highlighting works --- docs/conf.py | 2 +- docs/root/contracts/contract-structure.rst | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 4b0e1b2..85d0342 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -9,7 +9,7 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [] +extensions = [ 'sphinxcontrib.inlinesyntaxhighlight' ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/root/contracts/contract-structure.rst b/docs/root/contracts/contract-structure.rst index a464729..b9fe6a5 100644 --- a/docs/root/contracts/contract-structure.rst +++ b/docs/root/contracts/contract-structure.rst @@ -4,14 +4,14 @@ Contract Structure .. highlight:: rst -.. role:: fstar(code) +.. role:: fsharp(code) :language: fsharp -Each contract must contain 2 functions: :fstar:`main` and :fstar:`cf`. +Each contract must contain 2 functions: :fsharp:`main` and :fsharp:`cf`. -The structure of the :fstar:`main` function is: +The structure of the :fsharp:`main` function is: -.. codeblock:: fstar +.. code-block:: fsharp main ( txSkel : Zen.Types.txSkeleton ) From 8f764155a58f27795ddaf4b3404227e4c908d13d Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Mon, 15 Oct 2018 15:06:40 +0300 Subject: [PATCH 17/42] added some main parameters --- ...structure.md => contract-structure.md.dis} | 0 docs/root/contracts/contract-structure.rst | 37 +++++++++++++++++++ 2 files changed, 37 insertions(+) rename docs/root/contracts/{contract-structure.md => contract-structure.md.dis} (100%) diff --git a/docs/root/contracts/contract-structure.md b/docs/root/contracts/contract-structure.md.dis similarity index 100% rename from docs/root/contracts/contract-structure.md rename to docs/root/contracts/contract-structure.md.dis diff --git a/docs/root/contracts/contract-structure.rst b/docs/root/contracts/contract-structure.rst index b9fe6a5..3db36e0 100644 --- a/docs/root/contracts/contract-structure.rst +++ b/docs/root/contracts/contract-structure.rst @@ -23,3 +23,40 @@ The structure of the :fsharp:`main` function is: ( wallet : Zen.Types.wallet ) ( state : option Zen.Types.data ) : Zen.Types.contractResult `Zen.Cost.t` n + +where :fsharp:`n` must be an expression which evaluates to a natural number (:fsharp:`nat`). + +Parameters +---------- + +* :fsharp:`txSkel : Zen.Types.txSkeleton` + Details about the function. + +* :fsharp:`context : Zen.Types.context` + Details about the function. + +* :fsharp:`contractId : Zen.Types.contractId` + Details about the function. + +* :fsharp:`command : string` + String that the contract may use. + Contains a command which tells the contract what to do. + For example: + .. code-block:: fsharp + + match command with + | "redeem" -> redeem txSkeleton contractId returnAddress wallet + | "buy" -> buy txSkeleton contractId returnAddress + + +* :fsharp:`sender : Zen.Types.sender` + Details about the function. + +* :fsharp:`messageBody : option Zen.Types.data` + Details about the function. + +* :fsharp:`wallet : Zen.Types.wallet` + Details about the function. + +* :fsharp:`state : option Zen.Types.data` + Details about the function. From d93244b3184a69300c9d8f7390ddc4c5e15a148d Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Mon, 15 Oct 2018 15:08:38 +0300 Subject: [PATCH 18/42] problems with sphinxcontrib.inlinesyntaxhighlight --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 85d0342..62022b9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -9,7 +9,7 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [ 'sphinxcontrib.inlinesyntaxhighlight' ] +extensions = [ ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] From 77c3540e44f67682c0c500d6d39292d2118e3592 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Mon, 15 Oct 2018 15:28:51 +0300 Subject: [PATCH 19/42] retrying sphinxcontrib-inlinesyntaxhighlight --- docs/conf.py | 2 +- docs/requirements.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 docs/requirements.txt diff --git a/docs/conf.py b/docs/conf.py index 62022b9..85d0342 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -9,7 +9,7 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [ ] +extensions = [ 'sphinxcontrib.inlinesyntaxhighlight' ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..21894cd --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1 @@ +sphinxcontrib-inlinesyntaxhighlight From d03cc77031853a4a90fe6859dd3b0840318b3e2f Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Mon, 15 Oct 2018 16:09:14 +0300 Subject: [PATCH 20/42] fixed web wallet --- docs/index.md | 1 + .../{web-wallet.md => web-wallet.md.dis} | 0 docs/root/wallet/web-wallet.rst | 60 +++++++++++++++++++ 3 files changed, 61 insertions(+) rename docs/root/wallet/{web-wallet.md => web-wallet.md.dis} (100%) create mode 100644 docs/root/wallet/web-wallet.rst diff --git a/docs/index.md b/docs/index.md index 37f7c3c..7eb0dde 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,3 +10,4 @@ Contents: * [From source](root/wallet/desktop/installation/from-source.html) * [Web Wallet (Beta)](root/wallet/web-wallet.html) * [ZF*](root/zfstar.html) +* [Contracts](root/contracts/contract-structure.html) diff --git a/docs/root/wallet/web-wallet.md b/docs/root/wallet/web-wallet.md.dis similarity index 100% rename from docs/root/wallet/web-wallet.md rename to docs/root/wallet/web-wallet.md.dis diff --git a/docs/root/wallet/web-wallet.rst b/docs/root/wallet/web-wallet.rst new file mode 100644 index 0000000..ea43c97 --- /dev/null +++ b/docs/root/wallet/web-wallet.rst @@ -0,0 +1,60 @@ +================= +Web Wallet (Beta) +================= + +The web wallet allows you to access your wallet and make transactions via a web browser. + +---- + +Security Notice +~~~~~~~~~~~~~~~ + +Web wallets are inherently less secure than other forms of cryptocurrency wallets. You should not use this web wallet to secure or control any tokens or resources that you cannot afford to lose. The major weakness in any web wallet is that its code is delivered in the form of a web page, meaning that if the server is compromised, the attacker can cause it to deliver phishing code to the user, stealing private key data and using it to steal funds. An additional attack vector is the injection of malicious code into a compromised javascript dependency, for example MobX.js. Please use the Desktop Wallet if you want a higher level of security. + +---- + +.. _Desktop Wallet: desktop-wallet.html + +Differences between the Web Wallet and the `Desktop Wallet`_: +--------------------------------------------------------------------------------- + +.. list-table:: Differences between the Web Wallet and the `Desktop Wallet`_ + :header-rows: 1 + + * - + - Web Wallet + - Desktop Wallet + * - **Storing seed** + - Encrypted using a password of your choice and stored in local storage + - Encrypted using a password of your choice and stored in folder in your computer + * - **Validation** + - Uses a "trusted" remote node to sync with the blockchain and validate the consensus rules, and relays signed transactions on its behalf + - The client runs a full node and validates the consensus rules of the blockchain independently + * - **Access** + - Is via a web browser, which can be compromised in multiple ways such as: + * having a malicious Chrome Extension​ + * If the server that is serving the client gets hacked, the hacker could deliver a version of the website that steals your seed + * Phishing - someone could create a website with a domain that looks very similar to the real official wallet domain and serve a malicious version of the wallet + - You download a desktop application to your computer once from a trusted source + +---- + +Steps for using the web wallet as securely as possible: +------------------------------------------------------- + +1. Only use a computer that you are sure is not infected with a virus. Viruses such as keystroke loggers can steal your 24 word mnemonic phrase while you are typing it. +2. You should use a web browser with as little as possible extensions or none at all - and only if you completely trust those extensions. Preferably you should use a browser without any extensions. +3. Bookmark that url of the web wallet https://wallet.zp.io and always access it by clicking the bookmark. + +---- + +Accessing the Web Wallet - https://wallet.zp.io​ + +You should bookmark the wallet url asap (https://wallet.zp.io) and only access it by clicking the bookmark. + +You may run the web wallet client locally independently in order to remove the risk of a phishing attack - here are the instructions for doing so. + +Code References +~~~~~~~~~~~~~~~ + +If you would like to go over the code that secures your 24 word mnemonic phrase and signs transactions you can go over the code references here. From 46a0ec8f4ed9a71d619c048d8b0feafeb2e68b08 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Mon, 15 Oct 2018 17:29:40 +0300 Subject: [PATCH 21/42] trying to change style --- docs/_static/css/my_theme.css | 5 +++++ docs/conf.py | 2 ++ 2 files changed, 7 insertions(+) create mode 100644 docs/_static/css/my_theme.css diff --git a/docs/_static/css/my_theme.css b/docs/_static/css/my_theme.css new file mode 100644 index 0000000..9cc81d3 --- /dev/null +++ b/docs/_static/css/my_theme.css @@ -0,0 +1,5 @@ +@import url("theme.css"); + +.wy-nav-content { + max-width: none; +} diff --git a/docs/conf.py b/docs/conf.py index 85d0342..50ac3c1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -73,6 +73,8 @@ # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] +html_style = 'css/my_theme.css' + # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. From d2a304cbacf48f28a85f42fecbe054569b67eb3f Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Mon, 15 Oct 2018 17:39:00 +0300 Subject: [PATCH 22/42] theme doesn't really work --- docs/_static/css/theme.css | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 docs/_static/css/theme.css diff --git a/docs/_static/css/theme.css b/docs/_static/css/theme.css new file mode 100644 index 0000000..03a13df --- /dev/null +++ b/docs/_static/css/theme.css @@ -0,0 +1,6 @@ +/* sphinx_rtd_theme version 0.4.1 | MIT license */ +/* Built 20180727 10:07 */ +*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}[hidden]{display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:hover,a:active{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;color:#000;text-decoration:none}mark{background:#ff0;color:#000;font-style:italic;font-weight:bold}pre,code,.rst-content tt,.rst-content code,kbd,samp{font-family:monospace,serif;_font-family:"courier new",monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:before,q:after{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}ul,ol,dl{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:0;margin:0;padding:0}label{cursor:pointer}legend{border:0;*margin-left:-7px;padding:0;white-space:normal}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;*width:13px;*height:13px}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top;resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none !important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{html,body,section{background:none !important}*{box-shadow:none !important;text-shadow:none !important;filter:none !important;-ms-filter:none !important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:.5cm}p,h2,.rst-content .toctree-wrapper p.caption,h3{orphans:3;widows:3}h2,.rst-content .toctree-wrapper p.caption,h3{page-break-after:avoid}}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.rst-content .admonition,.btn,input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"],select,textarea,.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a,.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a,.wy-nav-top a{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url("../fonts/fontawesome-webfont.eot?v=4.7.0");src:url("../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff2?v=4.7.0") format("woff2"),url("../fonts/fontawesome-webfont.woff?v=4.7.0") format("woff"),url("../fonts/fontawesome-webfont.ttf?v=4.7.0") format("truetype"),url("../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.3333333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.2857142857em;text-align:center}.fa-ul{padding-left:0;margin-left:2.1428571429em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.1428571429em;width:2.1428571429em;top:.1428571429em;text-align:center}.fa-li.fa-lg{left:-1.8571428571em}.fa-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.wy-menu-vertical li span.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-left.toctree-expand,.wy-menu-vertical li.current>a span.fa-pull-left.toctree-expand,.rst-content .fa-pull-left.admonition-title,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content dl dt .fa-pull-left.headerlink,.rst-content p.caption .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.rst-content code.download span.fa-pull-left:first-child,.fa-pull-left.icon{margin-right:.3em}.fa.fa-pull-right,.wy-menu-vertical li span.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-right.toctree-expand,.wy-menu-vertical li.current>a span.fa-pull-right.toctree-expand,.rst-content .fa-pull-right.admonition-title,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content dl dt .fa-pull-right.headerlink,.rst-content p.caption .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.rst-content code.download span.fa-pull-right:first-child,.fa-pull-right.icon{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.wy-menu-vertical li span.pull-left.toctree-expand,.wy-menu-vertical li.on a span.pull-left.toctree-expand,.wy-menu-vertical li.current>a span.pull-left.toctree-expand,.rst-content .pull-left.admonition-title,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content dl dt .pull-left.headerlink,.rst-content p.caption .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.rst-content code.download span.pull-left:first-child,.pull-left.icon{margin-right:.3em}.fa.pull-right,.wy-menu-vertical li span.pull-right.toctree-expand,.wy-menu-vertical li.on a span.pull-right.toctree-expand,.wy-menu-vertical li.current>a span.pull-right.toctree-expand,.rst-content .pull-right.admonition-title,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content dl dt .pull-right.headerlink,.rst-content p.caption .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.rst-content code.download span.pull-right:first-child,.pull-right.icon{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-remove:before,.fa-close:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-gear:before,.fa-cog:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-rotate-right:before,.fa-repeat:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.rst-content .admonition-title:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-warning:before,.fa-exclamation-triangle:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-gears:before,.fa-cogs:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-save:before,.fa-floppy-o:before{content:""}.fa-square:before{content:""}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.wy-dropdown .caret:before,.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-unsorted:before,.fa-sort:before{content:""}.fa-sort-down:before,.fa-sort-desc:before{content:""}.fa-sort-up:before,.fa-sort-asc:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-legal:before,.fa-gavel:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-flash:before,.fa-bolt:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-paste:before,.fa-clipboard:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-unlink:before,.fa-chain-broken:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:""}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:""}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:""}.fa-euro:before,.fa-eur:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-rupee:before,.fa-inr:before{content:""}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:""}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:""}.fa-won:before,.fa-krw:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-turkish-lira:before,.fa-try:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li span.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-institution:before,.fa-bank:before,.fa-university:before{content:""}.fa-mortar-board:before,.fa-graduation-cap:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:""}.fa-file-zip-o:before,.fa-file-archive-o:before{content:""}.fa-file-sound-o:before,.fa-file-audio-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:""}.fa-ge:before,.fa-empire:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-send:before,.fa-paper-plane:before{content:""}.fa-send-o:before,.fa-paper-plane-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-hotel:before,.fa-bed:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-yc:before,.fa-y-combinator:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-tv:before,.fa-television:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:""}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-signing:before,.fa-sign-language:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-vcard:before,.fa-address-card:before{content:""}.fa-vcard-o:before,.fa-address-card-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context{font-family:inherit}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before{font-family:"FontAwesome";display:inline-block;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa,a .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,a .rst-content .admonition-title,.rst-content a .admonition-title,a .rst-content h1 .headerlink,.rst-content h1 a .headerlink,a .rst-content h2 .headerlink,.rst-content h2 a .headerlink,a .rst-content h3 .headerlink,.rst-content h3 a .headerlink,a .rst-content h4 .headerlink,.rst-content h4 a .headerlink,a .rst-content h5 .headerlink,.rst-content h5 a .headerlink,a .rst-content h6 .headerlink,.rst-content h6 a .headerlink,a .rst-content dl dt .headerlink,.rst-content dl dt a .headerlink,a .rst-content p.caption .headerlink,.rst-content p.caption a .headerlink,a .rst-content table>caption .headerlink,.rst-content table>caption a .headerlink,a .rst-content tt.download span:first-child,.rst-content tt.download a span:first-child,a .rst-content code.download span:first-child,.rst-content code.download a span:first-child,a .icon{display:inline-block;text-decoration:inherit}.btn .fa,.btn .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .btn span.toctree-expand,.btn .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .btn span.toctree-expand,.btn .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .btn span.toctree-expand,.btn .rst-content .admonition-title,.rst-content .btn .admonition-title,.btn .rst-content h1 .headerlink,.rst-content h1 .btn .headerlink,.btn .rst-content h2 .headerlink,.rst-content h2 .btn .headerlink,.btn .rst-content h3 .headerlink,.rst-content h3 .btn .headerlink,.btn .rst-content h4 .headerlink,.rst-content h4 .btn .headerlink,.btn .rst-content h5 .headerlink,.rst-content h5 .btn .headerlink,.btn .rst-content h6 .headerlink,.rst-content h6 .btn .headerlink,.btn .rst-content dl dt .headerlink,.rst-content dl dt .btn .headerlink,.btn .rst-content p.caption .headerlink,.rst-content p.caption .btn .headerlink,.btn .rst-content table>caption .headerlink,.rst-content table>caption .btn .headerlink,.btn .rst-content tt.download span:first-child,.rst-content tt.download .btn span:first-child,.btn .rst-content code.download span:first-child,.rst-content code.download .btn span:first-child,.btn .icon,.nav .fa,.nav .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .nav span.toctree-expand,.nav .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .nav span.toctree-expand,.nav .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .nav span.toctree-expand,.nav .rst-content .admonition-title,.rst-content .nav .admonition-title,.nav .rst-content h1 .headerlink,.rst-content h1 .nav .headerlink,.nav .rst-content h2 .headerlink,.rst-content h2 .nav .headerlink,.nav .rst-content h3 .headerlink,.rst-content h3 .nav .headerlink,.nav .rst-content h4 .headerlink,.rst-content h4 .nav .headerlink,.nav .rst-content h5 .headerlink,.rst-content h5 .nav .headerlink,.nav .rst-content h6 .headerlink,.rst-content h6 .nav .headerlink,.nav .rst-content dl dt .headerlink,.rst-content dl dt .nav .headerlink,.nav .rst-content p.caption .headerlink,.rst-content p.caption .nav .headerlink,.nav .rst-content table>caption .headerlink,.rst-content table>caption .nav .headerlink,.nav .rst-content tt.download span:first-child,.rst-content tt.download .nav span:first-child,.nav .rst-content code.download span:first-child,.rst-content code.download .nav span:first-child,.nav .icon{display:inline}.btn .fa.fa-large,.btn .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .btn span.fa-large.toctree-expand,.btn .rst-content .fa-large.admonition-title,.rst-content .btn .fa-large.admonition-title,.btn .rst-content h1 .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.btn .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .btn .fa-large.headerlink,.btn .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .btn .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .btn span.fa-large:first-child,.btn .rst-content code.download span.fa-large:first-child,.rst-content code.download .btn span.fa-large:first-child,.btn .fa-large.icon,.nav .fa.fa-large,.nav .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .nav span.fa-large.toctree-expand,.nav .rst-content .fa-large.admonition-title,.rst-content .nav .fa-large.admonition-title,.nav .rst-content h1 .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.nav .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.nav .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .nav .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.nav .rst-content code.download span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.nav .fa-large.icon{line-height:.9em}.btn .fa.fa-spin,.btn .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .btn span.fa-spin.toctree-expand,.btn .rst-content .fa-spin.admonition-title,.rst-content .btn .fa-spin.admonition-title,.btn .rst-content h1 .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.btn .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .btn .fa-spin.headerlink,.btn .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .btn .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .btn span.fa-spin:first-child,.btn .rst-content code.download span.fa-spin:first-child,.rst-content code.download .btn span.fa-spin:first-child,.btn .fa-spin.icon,.nav .fa.fa-spin,.nav .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .nav span.fa-spin.toctree-expand,.nav .rst-content .fa-spin.admonition-title,.rst-content .nav .fa-spin.admonition-title,.nav .rst-content h1 .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.nav .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.nav .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .nav .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.nav .rst-content code.download span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.nav .fa-spin.icon{display:inline-block}.btn.fa:before,.wy-menu-vertical li span.btn.toctree-expand:before,.rst-content .btn.admonition-title:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content dl dt .btn.headerlink:before,.rst-content p.caption .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.rst-content code.download span.btn:first-child:before,.btn.icon:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.wy-menu-vertical li span.btn.toctree-expand:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content p.caption .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.rst-content code.download span.btn:first-child:hover:before,.btn.icon:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li .btn-mini span.toctree-expand:before,.btn-mini .rst-content .admonition-title:before,.rst-content .btn-mini .admonition-title:before,.btn-mini .rst-content h1 .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.btn-mini .rst-content dl dt .headerlink:before,.rst-content dl dt .btn-mini .headerlink:before,.btn-mini .rst-content p.caption .headerlink:before,.rst-content p.caption .btn-mini .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.rst-content tt.download .btn-mini span:first-child:before,.btn-mini .rst-content code.download span:first-child:before,.rst-content code.download .btn-mini span:first-child:before,.btn-mini .icon:before{font-size:14px;vertical-align:-15%}.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.rst-content .admonition{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.wy-alert-title,.rst-content .admonition-title{color:#fff;font-weight:bold;display:block;color:#fff;background:#6ab0de;margin:-12px;padding:6px 12px;margin-bottom:12px}.wy-alert.wy-alert-danger,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.admonition{background:#fdf3f2}.wy-alert.wy-alert-danger .wy-alert-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .danger .wy-alert-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .danger .admonition-title,.rst-content .error .admonition-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition .admonition-title{background:#f29f97}.wy-alert.wy-alert-warning,.rst-content .wy-alert-warning.note,.rst-content .attention,.rst-content .caution,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.tip,.rst-content .warning,.rst-content .wy-alert-warning.seealso,.rst-content .admonition-todo,.rst-content .wy-alert-warning.admonition{background:#ffedcc}.wy-alert.wy-alert-warning .wy-alert-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .attention .wy-alert-title,.rst-content .caution .wy-alert-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .attention .admonition-title,.rst-content .caution .admonition-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .warning .admonition-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .admonition-todo .admonition-title,.rst-content .wy-alert-warning.admonition .admonition-title{background:#f0b37e}.wy-alert.wy-alert-info,.rst-content .note,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.rst-content .seealso,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.admonition{background:#e7f2fa}.wy-alert.wy-alert-info .wy-alert-title,.rst-content .note .wy-alert-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.rst-content .note .admonition-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .seealso .admonition-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition .admonition-title{background:#6ab0de}.wy-alert.wy-alert-success,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.warning,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.admonition{background:#dbfaf4}.wy-alert.wy-alert-success .wy-alert-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .hint .wy-alert-title,.rst-content .important .wy-alert-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .hint .admonition-title,.rst-content .important .admonition-title,.rst-content .tip .admonition-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition .admonition-title{background:#1abc9c}.wy-alert.wy-alert-neutral,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.admonition{background:#f3f6f6}.wy-alert.wy-alert-neutral .wy-alert-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition .admonition-title{color:#404040;background:#e1e4e5}.wy-alert.wy-alert-neutral a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a{color:#2980B9}.wy-alert p:last-child,.rst-content .note p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.rst-content .seealso p:last-child,.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0px;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,0.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27AE60}.wy-tray-container li.wy-tray-item-info{background:#2980B9}.wy-tray-container li.wy-tray-item-warning{background:#E67E22}.wy-tray-container li.wy-tray-item-danger{background:#E74C3C}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width: 768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px 12px;color:#fff;border:1px solid rgba(0,0,0,0.1);background-color:#27AE60;text-decoration:none;font-weight:normal;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:0px 1px 2px -1px rgba(255,255,255,0.5) inset,0px -2px 0px 0px rgba(0,0,0,0.1) inset;outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:0px -1px 0px 0px rgba(0,0,0,0.05) inset,0px 2px 0px 0px rgba(0,0,0,0.1) inset;padding:8px 12px 6px 12px}.btn:visited{color:#fff}.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn-disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn-disabled:hover,.btn-disabled:focus,.btn-disabled:active{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980B9 !important}.btn-info:hover{background-color:#2e8ece !important}.btn-neutral{background-color:#f3f6f6 !important;color:#404040 !important}.btn-neutral:hover{background-color:#e5ebeb !important;color:#404040}.btn-neutral:visited{color:#404040 !important}.btn-success{background-color:#27AE60 !important}.btn-success:hover{background-color:#295 !important}.btn-danger{background-color:#E74C3C !important}.btn-danger:hover{background-color:#ea6153 !important}.btn-warning{background-color:#E67E22 !important}.btn-warning:hover{background-color:#e98b39 !important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f !important}.btn-link{background-color:transparent !important;color:#2980B9;box-shadow:none;border-color:transparent !important}.btn-link:hover{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:active{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:visited{color:#9B59B6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:before,.wy-btn-group:after{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:solid 1px #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,0.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980B9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:solid 1px #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type="search"]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980B9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned input,.wy-form-aligned textarea,.wy-form-aligned select,.wy-form-aligned .wy-help-inline,.wy-form-aligned label{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{border:0;margin:0;padding:0}legend{display:block;width:100%;border:0;padding:0;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label{display:block;margin:0 0 .3125em 0;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;*zoom:1;max-width:68em;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#E74C3C}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full input[type="text"],.wy-control-group .wy-form-full input[type="password"],.wy-control-group .wy-form-full input[type="email"],.wy-control-group .wy-form-full input[type="url"],.wy-control-group .wy-form-full input[type="date"],.wy-control-group .wy-form-full input[type="month"],.wy-control-group .wy-form-full input[type="time"],.wy-control-group .wy-form-full input[type="datetime"],.wy-control-group .wy-form-full input[type="datetime-local"],.wy-control-group .wy-form-full input[type="week"],.wy-control-group .wy-form-full input[type="number"],.wy-control-group .wy-form-full input[type="search"],.wy-control-group .wy-form-full input[type="tel"],.wy-control-group .wy-form-full input[type="color"],.wy-control-group .wy-form-halves input[type="text"],.wy-control-group .wy-form-halves input[type="password"],.wy-control-group .wy-form-halves input[type="email"],.wy-control-group .wy-form-halves input[type="url"],.wy-control-group .wy-form-halves input[type="date"],.wy-control-group .wy-form-halves input[type="month"],.wy-control-group .wy-form-halves input[type="time"],.wy-control-group .wy-form-halves input[type="datetime"],.wy-control-group .wy-form-halves input[type="datetime-local"],.wy-control-group .wy-form-halves input[type="week"],.wy-control-group .wy-form-halves input[type="number"],.wy-control-group .wy-form-halves input[type="search"],.wy-control-group .wy-form-halves input[type="tel"],.wy-control-group .wy-form-halves input[type="color"],.wy-control-group .wy-form-thirds input[type="text"],.wy-control-group .wy-form-thirds input[type="password"],.wy-control-group .wy-form-thirds input[type="email"],.wy-control-group .wy-form-thirds input[type="url"],.wy-control-group .wy-form-thirds input[type="date"],.wy-control-group .wy-form-thirds input[type="month"],.wy-control-group .wy-form-thirds input[type="time"],.wy-control-group .wy-form-thirds input[type="datetime"],.wy-control-group .wy-form-thirds input[type="datetime-local"],.wy-control-group .wy-form-thirds input[type="week"],.wy-control-group .wy-form-thirds input[type="number"],.wy-control-group .wy-form-thirds input[type="search"],.wy-control-group .wy-form-thirds input[type="tel"],.wy-control-group .wy-form-thirds input[type="color"]{width:100%}.wy-control-group .wy-form-full{float:left;display:block;margin-right:2.3576515979%;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.3576515979%;width:48.821174201%}.wy-control-group .wy-form-halves:last-child{margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n+1){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.3576515979%;width:31.7615656014%}.wy-control-group .wy-form-thirds:last-child{margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control{margin:6px 0 0 0;font-size:90%}.wy-control-no-input{display:inline-block;margin:6px 0 0 0;font-size:90%}.wy-control-group.fluid-input input[type="text"],.wy-control-group.fluid-input input[type="password"],.wy-control-group.fluid-input input[type="email"],.wy-control-group.fluid-input input[type="url"],.wy-control-group.fluid-input input[type="date"],.wy-control-group.fluid-input input[type="month"],.wy-control-group.fluid-input input[type="time"],.wy-control-group.fluid-input input[type="datetime"],.wy-control-group.fluid-input input[type="datetime-local"],.wy-control-group.fluid-input input[type="week"],.wy-control-group.fluid-input input[type="number"],.wy-control-group.fluid-input input[type="search"],.wy-control-group.fluid-input input[type="tel"],.wy-control-group.fluid-input input[type="color"]{width:100%}.wy-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;*overflow:visible}input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type="datetime-local"]{padding:.34375em .625em}input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}input[type="text"]:focus,input[type="password"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus{outline:0;outline:thin dotted \9;border-color:#333}input.no-focus:focus{border-color:#ccc !important}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:1px auto #129FEA}input[type="text"][disabled],input[type="password"][disabled],input[type="email"][disabled],input[type="url"][disabled],input[type="date"][disabled],input[type="month"][disabled],input[type="time"][disabled],input[type="datetime"][disabled],input[type="datetime-local"][disabled],input[type="week"][disabled],input[type="number"][disabled],input[type="search"][disabled],input[type="tel"][disabled],input[type="color"][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#E74C3C;border:1px solid #E74C3C}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#E74C3C}input[type="file"]:focus:invalid:focus,input[type="radio"]:focus:invalid:focus,input[type="checkbox"]:focus:invalid:focus{outline-color:#E74C3C}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type="radio"][disabled],input[type="checkbox"][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:solid 1px #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{position:absolute;content:"";display:block;left:0;top:0;width:36px;height:12px;border-radius:4px;background:#ccc;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{position:absolute;content:"";display:block;width:18px;height:18px;border-radius:4px;background:#999;left:-3px;top:-3px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27AE60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#E74C3C}.wy-control-group.wy-control-group-error input[type="text"],.wy-control-group.wy-control-group-error input[type="password"],.wy-control-group.wy-control-group-error input[type="email"],.wy-control-group.wy-control-group-error input[type="url"],.wy-control-group.wy-control-group-error input[type="date"],.wy-control-group.wy-control-group-error input[type="month"],.wy-control-group.wy-control-group-error input[type="time"],.wy-control-group.wy-control-group-error input[type="datetime"],.wy-control-group.wy-control-group-error input[type="datetime-local"],.wy-control-group.wy-control-group-error input[type="week"],.wy-control-group.wy-control-group-error input[type="number"],.wy-control-group.wy-control-group-error input[type="search"],.wy-control-group.wy-control-group-error input[type="tel"],.wy-control-group.wy-control-group-error input[type="color"]{border:solid 1px #E74C3C}.wy-control-group.wy-control-group-error textarea{border:solid 1px #E74C3C}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27AE60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#E74C3C}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#E67E22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980B9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width: 480px){.wy-form button[type="submit"]{margin:.7em 0 0}.wy-form input[type="text"],.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:.3em;display:block}.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0 0}.wy-form .wy-help-inline,.wy-form-message-inline,.wy-form-message{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width: 768px){.tablet-hide{display:none}}@media screen and (max-width: 480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.wy-table,.rst-content table.docutils,.rst-content table.field-list{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.wy-table caption,.rst-content table.docutils caption,.rst-content table.field-list caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td,.wy-table th,.rst-content table.docutils th,.rst-content table.field-list th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.wy-table td:first-child,.rst-content table.docutils td:first-child,.rst-content table.field-list td:first-child,.wy-table th:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list th:first-child{border-left-width:0}.wy-table thead,.rst-content table.docutils thead,.rst-content table.field-list thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.wy-table thead th,.rst-content table.docutils thead th,.rst-content table.field-list thead th{font-weight:bold;border-bottom:solid 2px #e1e4e5}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td{background-color:transparent;vertical-align:middle}.wy-table td p,.rst-content table.docutils td p,.rst-content table.field-list td p{line-height:18px}.wy-table td p:last-child,.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child{margin-bottom:0}.wy-table .wy-table-cell-min,.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min{width:1%;padding-right:0}.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:gray;font-size:90%}.wy-table-tertiary{color:gray;font-size:80%}.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td,.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td{background-color:#f3f6f6}.wy-table-backed{background-color:#f3f6f6}.wy-table-bordered-all,.rst-content table.docutils{border:1px solid #e1e4e5}.wy-table-bordered-all td,.rst-content table.docutils td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.wy-table-bordered-all tbody>tr:last-child td,.rst-content table.docutils tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0 !important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980B9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9B59B6}html{height:100%;overflow-x:hidden}body{font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;font-weight:normal;color:#404040;min-height:100%;overflow-x:hidden;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#E67E22 !important}a.wy-text-warning:hover{color:#eb9950 !important}.wy-text-info{color:#2980B9 !important}a.wy-text-info:hover{color:#409ad5 !important}.wy-text-success{color:#27AE60 !important}a.wy-text-success:hover{color:#36d278 !important}.wy-text-danger{color:#E74C3C !important}a.wy-text-danger:hover{color:#ed7669 !important}.wy-text-neutral{color:#404040 !important}a.wy-text-neutral:hover{color:#595959 !important}h1,h2,.rst-content .toctree-wrapper p.caption,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif}p{line-height:24px;margin:0;font-size:16px;margin-bottom:24px}h1{font-size:175%}h2,.rst-content .toctree-wrapper p.caption{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}code,.rst-content tt,.rst-content code{white-space:nowrap;max-width:100%;background:#fff;border:solid 1px #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;color:#E74C3C;overflow-x:auto}code.code-large,.rst-content tt.code-large{font-size:90%}.wy-plain-list-disc,.rst-content .section ul,.rst-content .toctree-wrapper ul,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.wy-plain-list-disc li,.rst-content .section ul li,.rst-content .toctree-wrapper ul li,article ul li{list-style:disc;margin-left:24px}.wy-plain-list-disc li p:last-child,.rst-content .section ul li p:last-child,.rst-content .toctree-wrapper ul li p:last-child,article ul li p:last-child{margin-bottom:0}.wy-plain-list-disc li ul,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li ul,article ul li ul{margin-bottom:0}.wy-plain-list-disc li li,.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,article ul li li{list-style:circle}.wy-plain-list-disc li li li,.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,article ul li li li{list-style:square}.wy-plain-list-disc li ol li,.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,article ul li ol li{list-style:decimal}.wy-plain-list-decimal,.rst-content .section ol,.rst-content ol.arabic,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.wy-plain-list-decimal li,.rst-content .section ol li,.rst-content ol.arabic li,article ol li{list-style:decimal;margin-left:24px}.wy-plain-list-decimal li p:last-child,.rst-content .section ol li p:last-child,.rst-content ol.arabic li p:last-child,article ol li p:last-child{margin-bottom:0}.wy-plain-list-decimal li ul,.rst-content .section ol li ul,.rst-content ol.arabic li ul,article ol li ul{margin-bottom:0}.wy-plain-list-decimal li ul li,.rst-content .section ol li ul li,.rst-content ol.arabic li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:before,.wy-breadcrumbs:after{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.wy-breadcrumbs li code,.wy-breadcrumbs li .rst-content tt,.rst-content .wy-breadcrumbs li tt{padding:5px;border:none;background:none}.wy-breadcrumbs li code.literal,.wy-breadcrumbs li .rst-content tt.literal,.rst-content .wy-breadcrumbs li tt.literal{color:#404040}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width: 480px){.wy-breadcrumbs-extra{display:none}.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:before,.wy-menu-horiz:after{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz ul,.wy-menu-horiz li{display:inline-block}.wy-menu-horiz li:hover{background:rgba(255,255,255,0.1)}.wy-menu-horiz li.divide-left{border-left:solid 1px #404040}.wy-menu-horiz li.divide-right{border-right:solid 1px #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{height:32px;display:inline-block;line-height:32px;padding:0 1.618em;margin-bottom:0;display:block;font-weight:bold;text-transform:uppercase;font-size:80%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:solid 1px #404040}.wy-menu-vertical li.divide-bottom{border-bottom:solid 1px #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:gray;border-right:solid 1px #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.wy-menu-vertical li code,.wy-menu-vertical li .rst-content tt,.rst-content .wy-menu-vertical li tt{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li span.toctree-expand{display:block;float:left;margin-left:-1.2em;font-size:.8em;line-height:1.6em;color:#4d4d4d}.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a{color:#404040;padding:.4045em 1.618em;font-weight:bold;position:relative;background:#fcfcfc;border:none;padding-left:1.618em -4px}.wy-menu-vertical li.on a:hover,.wy-menu-vertical li.current>a:hover{background:#fcfcfc}.wy-menu-vertical li.on a:hover span.toctree-expand,.wy-menu-vertical li.current>a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand{display:block;font-size:.8em;line-height:1.6em;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:solid 1px #c9c9c9;border-top:solid 1px #c9c9c9}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a{color:#404040}.wy-menu-vertical li.toctree-l1.current li.toctree-l2>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>ul{display:none}.wy-menu-vertical li.toctree-l1.current li.toctree-l2.current>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3.current>ul{display:block}.wy-menu-vertical li.toctree-l2.current>a{background:#c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{display:block;background:#c9c9c9;padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l2 span.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3{font-size:.9em}.wy-menu-vertical li.toctree-l3.current>a{background:#bdbdbd;padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{display:block;background:#bdbdbd;padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l3 span.toctree-expand{color:#969696}.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:normal}.wy-menu-vertical a{display:inline-block;line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover span.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980B9;cursor:pointer;color:#fff}.wy-menu-vertical a:active span.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980B9;text-align:center;padding:.809em;display:block;color:#fcfcfc;margin-bottom:.809em}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em auto;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a{color:#fcfcfc;font-size:100%;font-weight:bold;display:inline-block;padding:4px 6px;margin-bottom:.809em}.wy-side-nav-search>a:hover,.wy-side-nav-search .wy-dropdown>a:hover{background:rgba(255,255,255,0.1)}.wy-side-nav-search>a img.logo,.wy-side-nav-search .wy-dropdown>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search>a.icon img.logo,.wy-side-nav-search .wy-dropdown>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:normal;color:rgba(255,255,255,0.3)}.wy-nav .wy-menu-vertical header{color:#2980B9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980B9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980B9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:before,.wy-nav-top:after{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:bold}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,0.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:gray}footer p{margin-bottom:12px}footer span.commit code,footer span.commit .rst-content tt,.rst-content footer span.commit tt{padding:0px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;font-size:1em;background:none;border:none;color:gray}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:before,.rst-footer-buttons:after{width:100%}.rst-footer-buttons:before,.rst-footer-buttons:after{display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:before,.rst-breadcrumbs-buttons:after{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:solid 1px #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:solid 1px #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:gray;font-size:90%}@media screen and (max-width: 768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-side-scroll{width:auto}.wy-side-nav-search{width:auto}.wy-menu.wy-menu-vertical{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width: 1100px){.wy-nav-content-wrap{background:rgba(0,0,0,0.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,footer,.wy-nav-side{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content p.caption .headerlink,.rst-content p.caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .icon{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up{height:auto;max-height:100%}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content img{max-width:100%;height:auto}.rst-content div.figure{margin-bottom:24px}.rst-content div.figure p.caption{font-style:italic}.rst-content div.figure p:last-child.caption{margin-bottom:0px}.rst-content div.figure.align-center{text-align:center}.rst-content .section>img,.rst-content .section>a>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px 12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;display:block;overflow:auto}.rst-content pre.literal-block,.rst-content div[class^='highlight']{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px 0}.rst-content pre.literal-block div[class^='highlight'],.rst-content div[class^='highlight'] div[class^='highlight']{padding:0px;border:none;margin:0}.rst-content div[class^='highlight'] td.code{width:100%}.rst-content .linenodiv pre{border-right:solid 1px #e6e9ea;margin:0;padding:12px 12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^='highlight'] pre{white-space:pre;margin:0;padding:12px 12px;display:block;overflow:auto}.rst-content div[class^='highlight'] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content pre.literal-block,.rst-content div[class^='highlight'] pre,.rst-content .linenodiv pre{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;font-size:12px;line-height:1.4}@media print{.rst-content .codeblock,.rst-content div[class^='highlight'],.rst-content div[class^='highlight'] pre{white-space:pre-wrap}}.rst-content .note .last,.rst-content .attention .last,.rst-content .caution .last,.rst-content .danger .last,.rst-content .error .last,.rst-content .hint .last,.rst-content .important .last,.rst-content .tip .last,.rst-content .warning .last,.rst-content .seealso .last,.rst-content .admonition-todo .last,.rst-content .admonition .last{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,0.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent !important;border-color:rgba(0,0,0,0.1) !important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha li{list-style:upper-alpha}.rst-content .section ol p,.rst-content .section ul p{margin-bottom:12px}.rst-content .section ol p:last-child,.rst-content .section ul p:last-child{margin-bottom:24px}.rst-content .line-block{margin-left:0px;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0px}.rst-content .topic-title{font-weight:bold;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0px 0px 24px 24px}.rst-content .align-left{float:left;margin:0px 24px 24px 0px}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content .toctree-wrapper p.caption .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink{visibility:hidden;font-size:14px}.rst-content h1 .headerlink:after,.rst-content h2 .headerlink:after,.rst-content .toctree-wrapper p.caption .headerlink:after,.rst-content h3 .headerlink:after,.rst-content h4 .headerlink:after,.rst-content h5 .headerlink:after,.rst-content h6 .headerlink:after,.rst-content dl dt .headerlink:after,.rst-content p.caption .headerlink:after,.rst-content table>caption .headerlink:after{content:"";font-family:FontAwesome}.rst-content h1:hover .headerlink:after,.rst-content h2:hover .headerlink:after,.rst-content .toctree-wrapper p.caption:hover .headerlink:after,.rst-content h3:hover .headerlink:after,.rst-content h4:hover .headerlink:after,.rst-content h5:hover .headerlink:after,.rst-content h6:hover .headerlink:after,.rst-content dl dt:hover .headerlink:after,.rst-content p.caption:hover .headerlink:after,.rst-content table>caption:hover .headerlink:after{visibility:visible}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:solid 1px #e1e4e5}.rst-content .sidebar p,.rst-content .sidebar ul,.rst-content .sidebar dl{font-size:90%}.rst-content .sidebar .last{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif;font-weight:bold;background:#e1e4e5;padding:6px 12px;margin:-24px;margin-bottom:24px;font-size:100%}.rst-content .highlighted{background:#F1C40F;display:inline-block;font-weight:bold;padding:0 6px}.rst-content .footnote-reference,.rst-content .citation-reference{vertical-align:baseline;position:relative;top:-0.4em;line-height:0;font-size:90%}.rst-content table.docutils.citation,.rst-content table.docutils.footnote{background:none;border:none;color:gray}.rst-content table.docutils.citation td,.rst-content table.docutils.citation tr,.rst-content table.docutils.footnote td,.rst-content table.docutils.footnote tr{border:none;background-color:transparent !important;white-space:normal}.rst-content table.docutils.citation td.label,.rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}.rst-content table.docutils.citation tt,.rst-content table.docutils.citation code,.rst-content table.docutils.footnote tt,.rst-content table.docutils.footnote code{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}.rst-content table.docutils td .last,.rst-content table.docutils td .last :last-child{margin-bottom:0}.rst-content table.field-list{border:none}.rst-content table.field-list td{border:none}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content tt,.rst-content tt,.rst-content code{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;padding:2px 5px}.rst-content tt big,.rst-content tt em,.rst-content tt big,.rst-content code big,.rst-content tt em,.rst-content code em{font-size:100% !important;line-height:normal}.rst-content tt.literal,.rst-content tt.literal,.rst-content code.literal{color:#E74C3C}.rst-content tt.xref,a .rst-content tt,.rst-content tt.xref,.rst-content code.xref,a .rst-content tt,a .rst-content code{font-weight:bold;color:#404040}.rst-content pre,.rst-content kbd,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace}.rst-content a tt,.rst-content a tt,.rst-content a code{color:#2980B9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:bold;margin-bottom:12px}.rst-content dl p,.rst-content dl table,.rst-content dl ul,.rst-content dl ol{margin-bottom:12px !important}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl:not(.docutils){margin-bottom:24px}.rst-content dl:not(.docutils) dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980B9;border-top:solid 3px #6ab0de;padding:6px;position:relative}.rst-content dl:not(.docutils) dt:before{color:#6ab0de}.rst-content dl:not(.docutils) dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dl dt{margin-bottom:6px;border:none;border-left:solid 3px #ccc;background:#f0f0f0;color:#555}.rst-content dl:not(.docutils) dl dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dt:first-child{margin-top:0}.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) code{font-weight:bold}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) code.descclassname{background-color:transparent;border:none;padding:0;font-size:100% !important}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname{font-weight:bold}.rst-content dl:not(.docutils) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:bold}.rst-content dl:not(.docutils) .property{display:inline-block;padding-right:8px}.rst-content .viewcode-link,.rst-content .viewcode-back{display:inline-block;color:#27AE60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:bold}.rst-content tt.download,.rst-content code.download{background:inherit;padding:inherit;font-weight:normal;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content tt.download span:first-child,.rst-content code.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{margin-right:4px}.rst-content .guilabel{border:1px solid #7fbbe3;background:#e7f2fa;font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .versionmodified{font-style:italic}@media screen and (max-width: 480px){.rst-content .sidebar{width:100%}}span[id*='MathJax-Span']{color:#404040}.math{text-align:center}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-regular.eot");src:url("../fonts/Lato/lato-regular.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-regular.woff2") format("woff2"),url("../fonts/Lato/lato-regular.woff") format("woff"),url("../fonts/Lato/lato-regular.ttf") format("truetype");font-weight:400;font-style:normal}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-bold.eot");src:url("../fonts/Lato/lato-bold.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-bold.woff2") format("woff2"),url("../fonts/Lato/lato-bold.woff") format("woff"),url("../fonts/Lato/lato-bold.ttf") format("truetype");font-weight:700;font-style:normal}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-bolditalic.eot");src:url("../fonts/Lato/lato-bolditalic.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-bolditalic.woff2") format("woff2"),url("../fonts/Lato/lato-bolditalic.woff") format("woff"),url("../fonts/Lato/lato-bolditalic.ttf") format("truetype");font-weight:700;font-style:italic}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-italic.eot");src:url("../fonts/Lato/lato-italic.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-italic.woff2") format("woff2"),url("../fonts/Lato/lato-italic.woff") format("woff"),url("../fonts/Lato/lato-italic.ttf") format("truetype");font-weight:400;font-style:italic}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:400;src:url("../fonts/RobotoSlab/roboto-slab.eot");src:url("../fonts/RobotoSlab/roboto-slab-v7-regular.eot?#iefix") format("embedded-opentype"),url("../fonts/RobotoSlab/roboto-slab-v7-regular.woff2") format("woff2"),url("../fonts/RobotoSlab/roboto-slab-v7-regular.woff") format("woff"),url("../fonts/RobotoSlab/roboto-slab-v7-regular.ttf") format("truetype")}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:700;src:url("../fonts/RobotoSlab/roboto-slab-v7-bold.eot");src:url("../fonts/RobotoSlab/roboto-slab-v7-bold.eot?#iefix") format("embedded-opentype"),url("../fonts/RobotoSlab/roboto-slab-v7-bold.woff2") format("woff2"),url("../fonts/RobotoSlab/roboto-slab-v7-bold.woff") format("woff"),url("../fonts/RobotoSlab/roboto-slab-v7-bold.ttf") format("truetype")} From eb1f9a2ea4b46b9a6e8351fc9a466cf5859ef600 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Mon, 15 Oct 2018 17:43:05 +0300 Subject: [PATCH 23/42] theme doesn't really work --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 50ac3c1..ffcec40 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -73,7 +73,7 @@ # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] -html_style = 'css/my_theme.css' +#html_style = 'css/my_theme.css' # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied From fdcecdfb8875225ef33388248add7df3fbf61fd0 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Mon, 15 Oct 2018 19:17:00 +0300 Subject: [PATCH 24/42] more contract parameters --- docs/root/contracts/contract-structure.rst | 49 ++++++++++++++++++---- docs/root/wallet/web-wallet.rst | 2 +- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/docs/root/contracts/contract-structure.rst b/docs/root/contracts/contract-structure.rst index 3db36e0..8ad8bcc 100644 --- a/docs/root/contracts/contract-structure.rst +++ b/docs/root/contracts/contract-structure.rst @@ -9,6 +9,8 @@ Contract Structure Each contract must contain 2 functions: :fsharp:`main` and :fsharp:`cf`. +The :fsharp:`main` function is run whenever a contract is used within a transaction. + The structure of the :fsharp:`main` function is: .. code-block:: fsharp @@ -30,13 +32,13 @@ Parameters ---------- * :fsharp:`txSkel : Zen.Types.txSkeleton` - Details about the function. + The transaction which used the contract. * :fsharp:`context : Zen.Types.context` - Details about the function. + **TODO: Details about the function.** * :fsharp:`contractId : Zen.Types.contractId` - Details about the function. + **TODO: Details about the function.** * :fsharp:`command : string` String that the contract may use. @@ -50,13 +52,46 @@ Parameters * :fsharp:`sender : Zen.Types.sender` - Details about the function. + **TODO: Details about the function.** * :fsharp:`messageBody : option Zen.Types.data` - Details about the function. + The transaction may carry a message which can be any of the following things: + + .. list-table:: + :header-rows: 0 + + * - + - + * - :fsharp:`Byte of FStar.UInt8.t` + - 8 bit unsigned integer + * - :fsharp:`U32 of FStar.UInt32.t` + - 32 bit unsigned integer + * - :fsharp:`U64 of FStar.UInt64.t` + - 64 bit unsigned integer + * - :fsharp:`I64 of FStar.Int64.t` + - 64 bit signed integer + * - :fsharp:`ByteArray: Zen.Array.t FStar.UInt8.t -> data` + - Byte array + * - :fsharp:`String of string` + - String + * - :fsharp:`Hash of hash` + - 256-bit hash value + * - :fsharp:`Lock of lock` + - Lock + * - :fsharp:`Signature of signature` + - Signature + * - :fsharp:`PublicKey of publicKey` + - Public key + * - :fsharp:`Collection of dataCollection` + - Data collection + * :fsharp:`wallet : Zen.Types.wallet` - Details about the function. + **TODO: Details about the function.** * :fsharp:`state : option Zen.Types.data` - Details about the function. + **TODO: Details about the function.** + +Output +------ +The output of the contract is a new transaction. diff --git a/docs/root/wallet/web-wallet.rst b/docs/root/wallet/web-wallet.rst index ea43c97..f7eb7f7 100644 --- a/docs/root/wallet/web-wallet.rst +++ b/docs/root/wallet/web-wallet.rst @@ -32,7 +32,7 @@ Differences between the Web Wallet and the `Desktop Wallet`_: - The client runs a full node and validates the consensus rules of the blockchain independently * - **Access** - Is via a web browser, which can be compromised in multiple ways such as: - * having a malicious Chrome Extension​ + * Having a malicious Chrome Extension​ * If the server that is serving the client gets hacked, the hacker could deliver a version of the website that steals your seed * Phishing - someone could create a website with a domain that looks very similar to the real official wallet domain and serve a malicious version of the wallet - You download a desktop application to your computer once from a trusted source From 995b729bc0a6a505097c3f6f4e4a85949bb3e1aa Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Tue, 16 Oct 2018 13:13:07 +0300 Subject: [PATCH 25/42] v1 --- docs/root/contracts/contract-structure.rst | 80 ++++++++++++++++------ 1 file changed, 60 insertions(+), 20 deletions(-) diff --git a/docs/root/contracts/contract-structure.rst b/docs/root/contracts/contract-structure.rst index 8ad8bcc..8b43d78 100644 --- a/docs/root/contracts/contract-structure.rst +++ b/docs/root/contracts/contract-structure.rst @@ -11,6 +11,8 @@ Each contract must contain 2 functions: :fsharp:`main` and :fsharp:`cf`. The :fsharp:`main` function is run whenever a contract is used within a transaction. +The function will run both at the validation and at the generation of the transaction. + The structure of the :fsharp:`main` function is: .. code-block:: fsharp @@ -35,10 +37,11 @@ Parameters The transaction which used the contract. * :fsharp:`context : Zen.Types.context` - **TODO: Details about the function.** + The blockchain context of the transaction, given by :fsharp:`blockNumber` (unsigned 32 bit integer), and :fsharp:`timestamp` - which is the UNIX Epoch time (unsigned 64 bit integer) of the block creation. * :fsharp:`contractId : Zen.Types.contractId` - **TODO: Details about the function.** + The contract identifier. + :fsharp:`(version, hash)` * :fsharp:`command : string` String that the contract may use. @@ -52,46 +55,83 @@ Parameters * :fsharp:`sender : Zen.Types.sender` - **TODO: Details about the function.** + The sender identity. + Can be any of the following: + + .. list-table:: + :header-rows: 0 + + * - :fsharp:`Contract` + - :fsharp:`of contractId` + - A contract, given by its ID + * - :fsharp:`PK` + - :fsharp:`of publicKey` + - Public key + * - :fsharp:`Anonymous` + - + - An anonymous sender * :fsharp:`messageBody : option Zen.Types.data` - The transaction may carry a message which can be any of the following things: + The transaction may carry a message which can be any of the following: .. list-table:: :header-rows: 0 - * - - - - * - :fsharp:`Byte of FStar.UInt8.t` + * - :fsharp:`Byte` + - :fsharp:`of FStar.UInt8.t` - 8 bit unsigned integer - * - :fsharp:`U32 of FStar.UInt32.t` + * - :fsharp:`U32` + - :fsharp:`of FStar.UInt32.t` - 32 bit unsigned integer - * - :fsharp:`U64 of FStar.UInt64.t` + * - :fsharp:`U64` + - :fsharp:`of FStar.UInt64.t` - 64 bit unsigned integer - * - :fsharp:`I64 of FStar.Int64.t` + * - :fsharp:`I64` + - :fsharp:`of FStar.Int64.t` - 64 bit signed integer - * - :fsharp:`ByteArray: Zen.Array.t FStar.UInt8.t -> data` + * - :fsharp:`ByteArray` + - :fsharp:`of Zen.Array.t FStar.UInt8.t` - Byte array - * - :fsharp:`String of string` + * - :fsharp:`String` + - :fsharp:`of string` - String - * - :fsharp:`Hash of hash` + * - :fsharp:`Hash` + - :fsharp:`of Zen.Types.hash` - 256-bit hash value - * - :fsharp:`Lock of lock` + * - :fsharp:`Lock` + - :fsharp:`of Zen.Types.lock` - Lock - * - :fsharp:`Signature of signature` + * - :fsharp:`Signature` + - :fsharp:`of Zen.Types.signature` - Signature - * - :fsharp:`PublicKey of publicKey` + * - :fsharp:`PublicKey` + - :fsharp:`of Zen.Types.publicKey` - Public key - * - :fsharp:`Collection of dataCollection` + * - :fsharp:`Collection` + - :fsharp:`of Zen.Types.dataCollection` - Data collection * :fsharp:`wallet : Zen.Types.wallet` - **TODO: Details about the function.** + Contains all the transaction inputs that were previously locked to the contract. + In order for a contract to spend its own funds they need to come from contract wallet. * :fsharp:`state : option Zen.Types.data` - **TODO: Details about the function.** + The contract previous state. Output ------ -The output of the contract is a new transaction. +The output of the contract is of the record type :fsharp:`contractReturn` which has 3 fields: + +.. list-table:: + :header-rows: 0 + + * - :fsharp:`state` + - :fsharp:`: stateUpdate` + - The updated state of the contract + * - :fsharp:`tx` + - :fsharp:`: txSkeleton` + - The genrated transaction + * - :fsharp:`message` + - :fsharp:`: option message` + - An optional message for invoking another contract From cbd0bbb53c0fac5510190827ce5fca2fdfd61642 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Thu, 7 Feb 2019 16:12:27 +0200 Subject: [PATCH 26/42] made the contracts doc more correct and cohesive --- docs/root/contracts/contract-structure.rst | 57 +++++++++++++++------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/docs/root/contracts/contract-structure.rst b/docs/root/contracts/contract-structure.rst index 8b43d78..afb2533 100644 --- a/docs/root/contracts/contract-structure.rst +++ b/docs/root/contracts/contract-structure.rst @@ -62,10 +62,10 @@ Parameters :header-rows: 0 * - :fsharp:`Contract` - - :fsharp:`of contractId` + - :fsharp:`of Zen.Types.contractId` - A contract, given by its ID * - :fsharp:`PK` - - :fsharp:`of publicKey` + - :fsharp:`of Zen.Types.publicKey` - Public key * - :fsharp:`Anonymous` - @@ -117,21 +117,44 @@ Parameters In order for a contract to spend its own funds they need to come from contract wallet. * :fsharp:`state : option Zen.Types.data` - The contract previous state. + The contract current state. + Can be either :fsharp:`Some` data (as the message body) or :fsharp:`None`. Output ------ -The output of the contract is of the record type :fsharp:`contractReturn` which has 3 fields: - -.. list-table:: - :header-rows: 0 - - * - :fsharp:`state` - - :fsharp:`: stateUpdate` - - The updated state of the contract - * - :fsharp:`tx` - - :fsharp:`: txSkeleton` - - The genrated transaction - * - :fsharp:`message` - - :fsharp:`: option message` - - An optional message for invoking another contract +The output of the contract is of the record type :fsharp:`Zen.Types.contractReturn` which has 3 fields: + + +* :fsharp:`state : Zen.Types.stateUpdate` + State update. + Can be any of the following: + + .. list-table:: + :header-rows: 0 + + * - :fsharp:`Delete` + - + - Delete the current state, resetting it to :fsharp:`None` + * - :fsharp:`NoChange` + - + - Keeping the current state as it is, with no change. + * - :fsharp:`Update` + - :fsharp:`of Zen.Types.data` + - Change the state to be the new given :fsharp:`data`. + +* :fsharp:`tx : Zen.Types.txSkeleton` + The genrated transaction. + +* :fsharp:`message : option Zen.Types.message` + An optional message for invoking another contract. + This is a record type which has 3 fields: + + .. list-table:: + :header-rows: 0 + + * - :fsharp:`recipient: Zen.Types.contractId` + - The recipient contract. + * - :fsharp:`command: string` + - The command given to the recipient contract. + * - :fsharp:`body: option Zen.Types.data` + - The message body of given to the recipient contract. From 5825f64839857fabaeea32f6ba9d939ae77d6793 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Thu, 2 May 2019 19:55:01 +0300 Subject: [PATCH 27/42] Added tables for cost semantics --- docs/conf.py | 4 +- docs/index.md | 2 +- docs/root/contracts.md | 9 +++ docs/root/contracts/contract-structure.rst | 4 +- docs/root/contracts/cost.rst | 79 ++++++++++++++++++++++ 5 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 docs/root/contracts.md create mode 100644 docs/root/contracts/cost.rst diff --git a/docs/conf.py b/docs/conf.py index ffcec40..a44c280 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -9,7 +9,7 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [ 'sphinxcontrib.inlinesyntaxhighlight' ] +extensions = [ 'sphinxcontrib.inlinesyntaxhighlight', 'sphinx.ext.mathjax' ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -73,7 +73,7 @@ # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] -#html_style = 'css/my_theme.css' +#html_style = 'css/my_theme.css' # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied diff --git a/docs/index.md b/docs/index.md index 7eb0dde..e427e68 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,4 +10,4 @@ Contents: * [From source](root/wallet/desktop/installation/from-source.html) * [Web Wallet (Beta)](root/wallet/web-wallet.html) * [ZF*](root/zfstar.html) -* [Contracts](root/contracts/contract-structure.html) +* [Contracts](root/contracts.html) diff --git a/docs/root/contracts.md b/docs/root/contracts.md new file mode 100644 index 0000000..8c5f19d --- /dev/null +++ b/docs/root/contracts.md @@ -0,0 +1,9 @@ +# Contracts + +## Cost Model + +[Cost Model](contracts/cost.html) + +## Contract Structure + +[Contract Structure](contracts/contract-structure.html) diff --git a/docs/root/contracts/contract-structure.rst b/docs/root/contracts/contract-structure.rst index afb2533..a921bf1 100644 --- a/docs/root/contracts/contract-structure.rst +++ b/docs/root/contracts/contract-structure.rst @@ -34,7 +34,7 @@ Parameters ---------- * :fsharp:`txSkel : Zen.Types.txSkeleton` - The transaction which used the contract. + The partial transaction supplied as input to the contract. * :fsharp:`context : Zen.Types.context` The blockchain context of the transaction, given by :fsharp:`blockNumber` (unsigned 32 bit integer), and :fsharp:`timestamp` - which is the UNIX Epoch time (unsigned 64 bit integer) of the block creation. @@ -143,7 +143,7 @@ The output of the contract is of the record type :fsharp:`Zen.Types.contractRetu - Change the state to be the new given :fsharp:`data`. * :fsharp:`tx : Zen.Types.txSkeleton` - The genrated transaction. + The generated transaction structure. * :fsharp:`message : option Zen.Types.message` An optional message for invoking another contract. diff --git a/docs/root/contracts/cost.rst b/docs/root/contracts/cost.rst new file mode 100644 index 0000000..f991fd6 --- /dev/null +++ b/docs/root/contracts/cost.rst @@ -0,0 +1,79 @@ +========== +Cost Model +========== + +.. highlight:: rst + +-------- +Notation +-------- + +.. list-table:: + :header-rows: 1 + + * - Notation + - Meaning + * - :math:`\color{red}{c\left(\color{black}{M}\right)}` + - Cost of :math:`M` + * - :math:`\color{blue}{\left[ \color{black}{M}\right]}` + - Modified (elaborated) term :math:`M` + * - :math:`\underline{\color{red}{n}}` + - The number :math:`\color{red}{n}` **as a term** + +---- +Cost +---- + +.. list-table:: + :header-rows: 1 + + * - + - Term + - Cost + * - Function Abstraction + - :math:`\color{red}{c\left(\color{black}{ \lambda x.M }\right)}` + - :math:`\color{red}{0}` + * - Function Application + - :math:`\color{red}{c\left(\color{black}{ M\:N }\right)}` + - :math:`\color{red}{1 + c\left(\color{black}{M}\right) + c\left(\color{black}{N}\right)}` + * - Conditional + - :math:`\color{red}{c\left(\color{black}{ \textbf{if}\:M\:\textbf{then}\:N_{1}\:\textbf{else}\:N_{2} }\right)}` + - :math:`\color{red}{3 + c\left(\color{black}{M}\right) + \max\left(c\left(\color{black}{N_{1}}\right),c\left(\color{black}{N_{2}}\right)\right)}` + * - Pattern Matching + - :math:`\color{red}{c\left(\color{black}{ \textbf{match}\:M\:\textbf{with}\:|\:P_{k}\rightarrow N_{k} }\right)}` + - :math:`\color{red}{c\left(\color{black}{M}\right)+\sum_{k=1}^{n}c\left(\color{black}{P_{k}}\right)+\max\left\{ c\left(\color{black}{N_{k}}\right)\right\} _{k=1}^{n}}` + * - Record Definition + - :math:`\color{red}{c\left(\color{black}{ \left\{ F_{k}=M_{k};\right\} }\right)}` + - :math:`\color{red}{n+\sum_{k=1}^{n}c\left(\color{black}{M_{k}}\right)}` + * - Record Projection + - :math:`\color{red}{c\left(\color{black}{ M.F }\right)}` + - :math:`\color{red}{1 + c\left(\color{black}{M}\right)}` + +----------- +Elaboration +----------- + +.. list-table:: + :header-rows: 1 + + * - + - Term + - Elaborated Term + * - Function Abstraction + - :math:`\color{blue}{\left[\color{black}{ \lambda x.M }\right]}` + - :math:`\lambda x . \textbf{inc}\:\underline{\color{red}{c\left(\color{black}{M}\right)}}\:\text{(}\color{blue}{\left[ \color{black}{M}\right]}\text{)}` + * - Function Application + - :math:`\color{blue}{\left[\color{black}{ M\:N }\right]}` + - :math:`\color{blue}{\left[ \color{black}{M}\right]}\:\color{blue}{\left[ \color{black}{N}\right]}` + * - Conditional + - :math:`\color{blue}{\left[\color{black}{ \textbf{if}\:M\:\textbf{then}\:N_{1}\:\textbf{else}\:N_{2} }\right]}` + - :math:`\textbf{if}\:\color{blue}{\left[ \color{black}{M}\right]}\:\textbf{then}\:\color{blue}{\left[ \color{black}{N_{1}}\right]}\:\textbf{else}\:\color{blue}{\left[ \color{black}{N_{2}}\right]}` + * - Pattern Matching + - :math:`\color{blue}{\left[\color{black}{ \textbf{match}\:M\:\textbf{with}\:|\:P_{k}\rightarrow N_{k} }\right]}` + - :math:`\textbf{match}\:\color{blue}{\left[ \color{black}{M}\right]}\:\textbf{with}\:|\:P_{k}\rightarrow \color{blue}{\left[ \color{black}{N_{k}}\right]}` + * - Record Definition + - :math:`\color{blue}{\left[\color{black}{ \left\{ F_{k}=M_{k};\right\} }\right]}` + - :math:`\left\{ F_{k}=\color{blue}{\left[ \color{black}{M_{k}}\right]};\right\}` + * - Record Projection + - :math:`\color{blue}{\left[\color{black}{ M.F }\right]}` + - :math:`\color{blue}{\left[ \color{black}{M}\right]}.F` From d297dbbfc2895e7753a52ed2a1d09fd18dbd7d36 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Thu, 2 May 2019 20:13:47 +0300 Subject: [PATCH 28/42] rendering issues --- docs/conf.py | 3 ++- docs/root/contracts/contract-structure.rst | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index a44c280..4b5c1da 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -9,7 +9,8 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [ 'sphinxcontrib.inlinesyntaxhighlight', 'sphinx.ext.mathjax' ] +# excluded: 'sphinxcontrib.inlinesyntaxhighlight' +extensions = [ 'sphinx.ext.mathjax' ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/root/contracts/contract-structure.rst b/docs/root/contracts/contract-structure.rst index a921bf1..fc99151 100644 --- a/docs/root/contracts/contract-structure.rst +++ b/docs/root/contracts/contract-structure.rst @@ -47,11 +47,12 @@ Parameters String that the contract may use. Contains a command which tells the contract what to do. For example: - .. code-block:: fsharp - match command with - | "redeem" -> redeem txSkeleton contractId returnAddress wallet - | "buy" -> buy txSkeleton contractId returnAddress + .. code-block:: fsharp + + match command with + | "redeem" -> redeem txSkeleton contractId returnAddress wallet + | "buy" -> buy txSkeleton contractId returnAddress * :fsharp:`sender : Zen.Types.sender` From bd2ebc1ee77df10b036a1e7ac1e352b6f43280a9 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Mon, 6 May 2019 17:01:08 +0300 Subject: [PATCH 29/42] began documenting the elaborator properly --- docs/index.md | 2 + docs/root/contracts.md | 4 +- docs/root/contracts/cost.rst | 134 ++++++++++++++++++++++++++++------- 3 files changed, 111 insertions(+), 29 deletions(-) diff --git a/docs/index.md b/docs/index.md index e427e68..db5ca2d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -11,3 +11,5 @@ Contents: * [Web Wallet (Beta)](root/wallet/web-wallet.html) * [ZF*](root/zfstar.html) * [Contracts](root/contracts.html) + * [Cost Analysis](root/contracts/cost.html) + * [Contract Structure](root/contracts/contract-structure.html) diff --git a/docs/root/contracts.md b/docs/root/contracts.md index 8c5f19d..2bc7584 100644 --- a/docs/root/contracts.md +++ b/docs/root/contracts.md @@ -1,8 +1,8 @@ # Contracts -## Cost Model +## Cost Analysis -[Cost Model](contracts/cost.html) +[Cost Analysis](contracts/cost.html) ## Contract Structure diff --git a/docs/root/contracts/cost.rst b/docs/root/contracts/cost.rst index f991fd6..3c0042d 100644 --- a/docs/root/contracts/cost.rst +++ b/docs/root/contracts/cost.rst @@ -1,29 +1,110 @@ -========== -Cost Model -========== +Cost Analysis +============= .. highlight:: rst --------- -Notation --------- +.. role:: fsharp(code) + :language: fsharp + +The Cost Model +-------------- + +Central to the analysis of contracts cost is the notion of a *cost model*. + +A *cost model* for a language assigns a natural number to each closed term in the language in +such a way that the term should take **at most** this number of "abstract steps" to evaluate, +this natural number is called *the cost* of that term (relative to that cost model). + +The abstract steps could be, for example, beta-reductions, so if the cost of a term :fsharp:`M` +is :fsharp:`n` it would take at most :fsharp:`n` beta-reductions to reduce :fsharp:`M` to a +normal form with the chosen evaluation strategy of the language. + +The cost is defined **recursively** on the structure of the term, and it could depend on +the **values** of some of its subterms, so we can think of the cost as a term in the language +which **evalutes** to a natural number. + +We use the notation :math:`c\left(M\right)` for the cost of the term :fsharp:`M`. + +.. list-table:: + :header-rows: 1 + + * - + - Term + - Cost + * - Function Abstraction + - :math:`c\left(\color{black}{ \lambda x.M }\right)` + - :math:`0` + * - Function Application + - :math:`c\left(\color{black}{ M\:N }\right)` + - :math:`1 + c\left(M\right) + c\left(N\right)` + * - Conditional + - :math:`c\left( \textbf{if}\:M\:\textbf{then}\:N_{1}\:\textbf{else}\:N_{2} \right)` + - :math:`3+c\left(M\right)+\textbf{if}\:M\:\textbf{then}\:c\left(N_{1}\right)\:\textbf{else}\:c\left(N_{2}\right)` + * - Pattern Matching + - :math:`c\left( \begin{array}{c}\textbf{match}\:M\:\textbf{with}\\|\:P_{k}\rightarrow N_{k}\end{array} \right)` + - :math:`c\left(M\right)+\sum_{k=1}^{n}c\left(P_{k}\right)+\begin{array}{c}\textbf{match}\:M\:\textbf{with}\\|\:P_{k}\rightarrow c\left(N_{k}\right)\end{array}` + * - Record Definition + - :math:`c\left(\color{black}{ \left\{ F_{k}=M_{k};\right\} }\right)` + - :math:`n+\sum_{k=1}^{n}c\left(\color{black}{M_{k}}\right)` + * - Record Projection + - :math:`c\left(\color{black}{ M.F }\right)` + - :math:`1 + c\left(\color{black}{M}\right)` + +The :fsharp:`cost` Type +----------------------- + +Given a cost model we can define a special type constructor :fsharp:`cost` to indicate that +a term of type :fsharp:`cost m A`, where :fsharp:`m` is a natural number and :fsharp:`A` is a +type, would take at most :fsharp:`m` steps to produce a **value** of type :fsharp:`A`. + +Dually - we use the type :fsharp:`cost m A` to indicate that a term of this type **represents +a value** of type :fsharp:`A` which **has taken** at most :fsharp:`m` steps to evaluate. + +When a **term** :fsharp:`M` has the type :fsharp:`cost m A` we say that :fsharp:`M` is a +*costed term*, with a *cost* of :fsharp:`m`. + +When a **function** :fsharp:`f` has the type :fsharp:`A -> cost m B` we say that +:fsharp:`f` is a *costed function*, with a *cost* of :fsharp:`m`, which means that when +given an input of type :fsharp:`A` it takes :fsharp:`f` at most :fsharp:`m` steps to produce +an output of type :fsharp:`B`. + +The :fsharp:`cost` type constructor should behave as a an **indexed monad**, indexed over the +additive monoid of the natural numbers, so whenever you compose (using Kleisli composition) +2 costed functions :fsharp:`f : B -> cost n C` and :fsharp:`g : A -> cost m B` +you get a function of type :fsharp:`A -> cost (m + n) C` where the cost is the sum of the costs +of :fsharp:`f` and :fsharp:`g`. + +In practice - the :fsharp:`cost` monad in *ZF\** is implemented as **the identity monad**, +where the index could be set arbitrarily, so as far as *ZF\** is concerned - **it is up to +the developer to honestly declare the costs of terms**. + +**The validity of the cost of a term is not fully enforced by the compiler!** + +The compiler only makes sure that the costs are **composed correctly**. + +To enforce the validity of the costs we combine the compiler with an **elaborator**, +which would be explained in detail later on. + +To lift a term into the monad we use the :fsharp:`ret` function, which is the unit of the +monad and has the type :fsharp:`ret : 'a -> cost 0 'a`. +Since the :fsharp:`ret` function gives a term a cost of :fsharp:`0`, we use the function +:fsharp:`inc : (m:nat) -> cost n 'a -> cost (n+m) 'a` to increase the declared cost of a term. + +Syntactic Cost +-------------- .. list-table:: :header-rows: 1 * - Notation - Meaning - * - :math:`\color{red}{c\left(\color{black}{M}\right)}` - - Cost of :math:`M` + * - :math:`\color{red}{s\left(\color{black}{M}\right)}` + - Syntactic cost of :math:`M` * - :math:`\color{blue}{\left[ \color{black}{M}\right]}` - Modified (elaborated) term :math:`M` * - :math:`\underline{\color{red}{n}}` - The number :math:`\color{red}{n}` **as a term** ----- -Cost ----- - .. list-table:: :header-rows: 1 @@ -31,25 +112,24 @@ Cost - Term - Cost * - Function Abstraction - - :math:`\color{red}{c\left(\color{black}{ \lambda x.M }\right)}` + - :math:`\color{red}{s\left(\color{black}{ \lambda x.M }\right)}` - :math:`\color{red}{0}` * - Function Application - - :math:`\color{red}{c\left(\color{black}{ M\:N }\right)}` - - :math:`\color{red}{1 + c\left(\color{black}{M}\right) + c\left(\color{black}{N}\right)}` + - :math:`\color{red}{s\left(\color{black}{ M\:N }\right)}` + - :math:`\color{red}{1 + s\left(\color{black}{M}\right) + s\left(\color{black}{N}\right)}` * - Conditional - - :math:`\color{red}{c\left(\color{black}{ \textbf{if}\:M\:\textbf{then}\:N_{1}\:\textbf{else}\:N_{2} }\right)}` - - :math:`\color{red}{3 + c\left(\color{black}{M}\right) + \max\left(c\left(\color{black}{N_{1}}\right),c\left(\color{black}{N_{2}}\right)\right)}` + - :math:`\color{red}{s\left(\color{black}{ \textbf{if}\:M\:\textbf{then}\:N_{1}\:\textbf{else}\:N_{2} }\right)}` + - :math:`\color{red}{3 + s\left(\color{black}{M}\right) + \max\left(s\left(\color{black}{N_{1}}\right),s\left(\color{black}{N_{2}}\right)\right)}` * - Pattern Matching - - :math:`\color{red}{c\left(\color{black}{ \textbf{match}\:M\:\textbf{with}\:|\:P_{k}\rightarrow N_{k} }\right)}` - - :math:`\color{red}{c\left(\color{black}{M}\right)+\sum_{k=1}^{n}c\left(\color{black}{P_{k}}\right)+\max\left\{ c\left(\color{black}{N_{k}}\right)\right\} _{k=1}^{n}}` + - :math:`\color{red}{s\left(\color{black}{ \begin{array}{c}\textbf{match}\:M\:\textbf{with}\\|\:P_{k}\rightarrow N_{k}\end{array} }\right)}` + - :math:`\color{red}{s\left(\color{black}{M}\right)+\sum_{k=1}^{n}s\left(\color{black}{P_{k}}\right)+\max\left\{ s\left(\color{black}{N_{k}}\right)\right\} _{k=1}^{n}}` * - Record Definition - - :math:`\color{red}{c\left(\color{black}{ \left\{ F_{k}=M_{k};\right\} }\right)}` - - :math:`\color{red}{n+\sum_{k=1}^{n}c\left(\color{black}{M_{k}}\right)}` + - :math:`\color{red}{s\left(\color{black}{ \left\{ F_{k}=M_{k};\right\} }\right)}` + - :math:`\color{red}{n+\sum_{k=1}^{n}s\left(\color{black}{M_{k}}\right)}` * - Record Projection - - :math:`\color{red}{c\left(\color{black}{ M.F }\right)}` - - :math:`\color{red}{1 + c\left(\color{black}{M}\right)}` + - :math:`\color{red}{s\left(\color{black}{ M.F }\right)}` + - :math:`\color{red}{1 + s\left(\color{black}{M}\right)}` ------------ Elaboration ----------- @@ -61,7 +141,7 @@ Elaboration - Elaborated Term * - Function Abstraction - :math:`\color{blue}{\left[\color{black}{ \lambda x.M }\right]}` - - :math:`\lambda x . \textbf{inc}\:\underline{\color{red}{c\left(\color{black}{M}\right)}}\:\text{(}\color{blue}{\left[ \color{black}{M}\right]}\text{)}` + - :math:`\lambda x . \textbf{inc}\:\underline{\color{red}{s\left(\color{black}{M}\right)}}\:\text{(}\color{blue}{\left[ \color{black}{M}\right]}\text{)}` * - Function Application - :math:`\color{blue}{\left[\color{black}{ M\:N }\right]}` - :math:`\color{blue}{\left[ \color{black}{M}\right]}\:\color{blue}{\left[ \color{black}{N}\right]}` @@ -69,8 +149,8 @@ Elaboration - :math:`\color{blue}{\left[\color{black}{ \textbf{if}\:M\:\textbf{then}\:N_{1}\:\textbf{else}\:N_{2} }\right]}` - :math:`\textbf{if}\:\color{blue}{\left[ \color{black}{M}\right]}\:\textbf{then}\:\color{blue}{\left[ \color{black}{N_{1}}\right]}\:\textbf{else}\:\color{blue}{\left[ \color{black}{N_{2}}\right]}` * - Pattern Matching - - :math:`\color{blue}{\left[\color{black}{ \textbf{match}\:M\:\textbf{with}\:|\:P_{k}\rightarrow N_{k} }\right]}` - - :math:`\textbf{match}\:\color{blue}{\left[ \color{black}{M}\right]}\:\textbf{with}\:|\:P_{k}\rightarrow \color{blue}{\left[ \color{black}{N_{k}}\right]}` + - :math:`\color{blue}{\left[\color{black}{ \begin{array}{c}\textbf{match}\:M\:\textbf{with}\\|\:P_{k}\rightarrow N_{k}\end{array} }\right]}` + - :math:`\begin{array}{c}\textbf{match}\:\color{blue}{\left[\color{black}{M}\right]}\:\textbf{with}\\|\:P_{k}\rightarrow \color{blue}{\left[\color{black}{N_{k}}\right]}\end{array}` * - Record Definition - :math:`\color{blue}{\left[\color{black}{ \left\{ F_{k}=M_{k};\right\} }\right]}` - :math:`\left\{ F_{k}=\color{blue}{\left[ \color{black}{M_{k}}\right]};\right\}` From 579d0479ff144691fb290d759ae5ad57014d349a Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Mon, 6 May 2019 18:02:35 +0300 Subject: [PATCH 30/42] most of the cost basics are described --- docs/root/contracts/cost.rst | 51 +++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/docs/root/contracts/cost.rst b/docs/root/contracts/cost.rst index 3c0042d..1735212 100644 --- a/docs/root/contracts/cost.rst +++ b/docs/root/contracts/cost.rst @@ -50,10 +50,29 @@ We use the notation :math:`c\left(M\right)` for the cost of the term :fsharp:`M` - :math:`c\left(\color{black}{ M.F }\right)` - :math:`1 + c\left(\color{black}{M}\right)` +In practice the actual cost (relative to the cost model) is **not computed directly**, +instead - the cost is divided into 2 components: + + 1. **Compositional Cost** - which is **declared** by the **developer** and + **verified** by the **type system** + 2. **Syntactic Cost** - which is **computed** by the **elaborator** + +In fact - given general recursion it is **impossible** to automatically compute the cost +of any arbitrary term in the language. + +Another deviation from the cost model is that the cost we give in practice is +an **upper bound** on the cost given by the cost model, because it is easier to compute, +but since the cost model itself is an upper bound on the number of steps the approximation +we use in practice still gives a valid upper bound. + +The **syntactic cost** is given to terms **by virtue of their form**, and acts as a **seed** which +the **compositional cost** later **propogates** into the program through the **type system**. + + The :fsharp:`cost` Type ----------------------- -Given a cost model we can define a special type constructor :fsharp:`cost` to indicate that +Given a cost model we define a special type constructor :fsharp:`cost` to indicate that a term of type :fsharp:`cost m A`, where :fsharp:`m` is a natural number and :fsharp:`A` is a type, would take at most :fsharp:`m` steps to produce a **value** of type :fsharp:`A`. @@ -68,7 +87,11 @@ When a **function** :fsharp:`f` has the type :fsharp:`A -> cost m B` we say that given an input of type :fsharp:`A` it takes :fsharp:`f` at most :fsharp:`m` steps to produce an output of type :fsharp:`B`. -The :fsharp:`cost` type constructor should behave as a an **indexed monad**, indexed over the + +Compositional Cost +------------------ + +The :fsharp:`cost` type constructor behaves as a an **indexed monad**, indexed over the additive monoid of the natural numbers, so whenever you compose (using Kleisli composition) 2 costed functions :fsharp:`f : B -> cost n C` and :fsharp:`g : A -> cost m B` you get a function of type :fsharp:`A -> cost (m + n) C` where the cost is the sum of the costs @@ -86,13 +109,30 @@ To enforce the validity of the costs we combine the compiler with an **elaborato which would be explained in detail later on. To lift a term into the monad we use the :fsharp:`ret` function, which is the unit of the -monad and has the type :fsharp:`ret : 'a -> cost 0 'a`. +monad and has the type :fsharp:`ret : a -> cost 0 a`. Since the :fsharp:`ret` function gives a term a cost of :fsharp:`0`, we use the function -:fsharp:`inc : (m:nat) -> cost n 'a -> cost (n+m) 'a` to increase the declared cost of a term. +:fsharp:`inc : (m:nat) -> cost n a -> cost (n+m) a` to increase the declared cost of a term. Syntactic Cost -------------- +The cost monad can only ensure that costs are composed correctly, but it cannot +enforce the declared costs to conform to the cost model - it completely trusts +the developer to declare costs honestly. + +In order to actually **enforce** the cost model, we use a device called *the elaborator*. + +The elaborator scans the syntax trees of the terms and recursively sums up the cost of +each branch, adding additional constant cost with each clause and primitive operation. + +Eventually, when the elaborator reaches either a **lambda expression**, +or a **let expression** - it embeds the accumulated cost of the body of the expression +into the body, by replacing it with an application of the :fsharp:`inc` function, along +with the accumulated cost, on the body; this ensures 2 things: + + 1. That the term returns an output which is wrapped in the :fsharp:`cost` monad. + 2. That all the syntactic cost is accounted for. + .. list-table:: :header-rows: 1 @@ -130,9 +170,6 @@ Syntactic Cost - :math:`\color{red}{s\left(\color{black}{ M.F }\right)}` - :math:`\color{red}{1 + s\left(\color{black}{M}\right)}` -Elaboration ------------ - .. list-table:: :header-rows: 1 From 3cd81df35773a4ad2bb4d404d4272e531f383f92 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Wed, 8 May 2019 13:01:31 +0300 Subject: [PATCH 31/42] added let expressions to cost model --- docs/root/contracts/cost.rst | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/docs/root/contracts/cost.rst b/docs/root/contracts/cost.rst index 1735212..6e2ea23 100644 --- a/docs/root/contracts/cost.rst +++ b/docs/root/contracts/cost.rst @@ -37,6 +37,15 @@ We use the notation :math:`c\left(M\right)` for the cost of the term :fsharp:`M` * - Function Application - :math:`c\left(\color{black}{ M\:N }\right)` - :math:`1 + c\left(M\right) + c\left(N\right)` + * - Let Expression + - :math:`c\left(\begin{array}{cc}\textbf{let} & L_{k}\\\textbf{in} & M\end{array}\right)` + - :math:`c\left(M\right) + \sum_{k=1}^{n}c\left(L_{k}\right)` + * - Nullary Let Clause + - :math:`c\left(x = N\right)` + - :math:`c\left(N\right)` + * - Applied Let Clause + - :math:`c\left(f\:x_{1}\ldots x_{n}=N\right)` + - :math:`0` * - Conditional - :math:`c\left( \textbf{if}\:M\:\textbf{then}\:N_{1}\:\textbf{else}\:N_{2} \right)` - :math:`3+c\left(M\right)+\textbf{if}\:M\:\textbf{then}\:c\left(N_{1}\right)\:\textbf{else}\:c\left(N_{2}\right)` @@ -69,8 +78,8 @@ The **syntactic cost** is given to terms **by virtue of their form**, and acts a the **compositional cost** later **propogates** into the program through the **type system**. -The :fsharp:`cost` Type ------------------------ +The Cost Type +------------- Given a cost model we define a special type constructor :fsharp:`cost` to indicate that a term of type :fsharp:`cost m A`, where :fsharp:`m` is a natural number and :fsharp:`A` is a @@ -154,6 +163,15 @@ with the accumulated cost, on the body; this ensures 2 things: * - Function Abstraction - :math:`\color{red}{s\left(\color{black}{ \lambda x.M }\right)}` - :math:`\color{red}{0}` + * - Let Expression + - :math:`\color{red}{s\left(\color{black}{\begin{array}{cc}\textbf{let} & L_{k}\\\textbf{in} & M\end{array}}\right)}` + - :math:`\color{red}{s\left(\color{black}{M}\right)} + \color{red}{\sum_{k=1}^{n}s\left(\color{black}{L_{k}}\right)}` + * - Nullary Let Clause + - :math:`\color{red}{s\left(\color{black}{x = N}\right)}` + - :math:`\color{red}{s\left(\color{black}{N}\right)}` + * - Applied Let Clause + - :math:`\color{red}{s\left(\color{black}{f\:x_{1}\ldots x_{n}=N}\right)}` + - :math:`\color{red}{0}` * - Function Application - :math:`\color{red}{s\left(\color{black}{ M\:N }\right)}` - :math:`\color{red}{1 + s\left(\color{black}{M}\right) + s\left(\color{black}{N}\right)}` @@ -182,6 +200,15 @@ with the accumulated cost, on the body; this ensures 2 things: * - Function Application - :math:`\color{blue}{\left[\color{black}{ M\:N }\right]}` - :math:`\color{blue}{\left[ \color{black}{M}\right]}\:\color{blue}{\left[ \color{black}{N}\right]}` + * - Let Expression + - :math:`\color{blue}{\left[\color{black}{\begin{array}{cc}\textbf{let} & L_{k}\\\textbf{in} & M\end{array}}\right]}` + - :math:`\begin{array}{cc}\textbf{let} & \color{blue}{\left[\color{black}{L_{k}}\right]}\\\textbf{in} & \color{blue}{\left[\color{black}{M}\right]}\end{array}` + * - Nullary Let Clause + - :math:`\color{blue}{\left[\color{black}{x = N}\right]}` + - :math:`x = \color{blue}{\left[\color{black}{N}\right]}` + * - Applied Let Clause + - :math:`\color{blue}{\left[\color{black}{f\:x_{1}\ldots x_{n}=N}\right]}` + - :math:`f\:x_{1}\ldots x_{n}=\textbf{inc}\:\underline{\color{red}{s\left(\color{black}{M}\right)}}\:\text{(}\color{blue}{\left[\color{black}{N}\right]}\:\text{)}` * - Conditional - :math:`\color{blue}{\left[\color{black}{ \textbf{if}\:M\:\textbf{then}\:N_{1}\:\textbf{else}\:N_{2} }\right]}` - :math:`\textbf{if}\:\color{blue}{\left[ \color{black}{M}\right]}\:\textbf{then}\:\color{blue}{\left[ \color{black}{N_{1}}\right]}\:\textbf{else}\:\color{blue}{\left[ \color{black}{N_{2}}\right]}` From e06cb1e24885ce0a4fddfdc445482f850ad3da1c Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Wed, 8 May 2019 13:58:41 +0300 Subject: [PATCH 32/42] added an example to the cost model --- docs/root/contracts/cost.rst | 60 ++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/docs/root/contracts/cost.rst b/docs/root/contracts/cost.rst index 6e2ea23..1d9d944 100644 --- a/docs/root/contracts/cost.rst +++ b/docs/root/contracts/cost.rst @@ -135,7 +135,7 @@ The elaborator scans the syntax trees of the terms and recursively sums up the c each branch, adding additional constant cost with each clause and primitive operation. Eventually, when the elaborator reaches either a **lambda expression**, -or a **let expression** - it embeds the accumulated cost of the body of the expression +or a **let expression** (which could be a **top-level let**) - it embeds the accumulated cost of the body of the expression into the body, by replacing it with an application of the :fsharp:`inc` function, along with the accumulated cost, on the body; this ensures 2 things: @@ -208,7 +208,7 @@ with the accumulated cost, on the body; this ensures 2 things: - :math:`x = \color{blue}{\left[\color{black}{N}\right]}` * - Applied Let Clause - :math:`\color{blue}{\left[\color{black}{f\:x_{1}\ldots x_{n}=N}\right]}` - - :math:`f\:x_{1}\ldots x_{n}=\textbf{inc}\:\underline{\color{red}{s\left(\color{black}{M}\right)}}\:\text{(}\color{blue}{\left[\color{black}{N}\right]}\:\text{)}` + - :math:`f\:x_{1}\ldots x_{n}=\textbf{inc}\:\underline{\color{red}{s\left(\color{black}{N}\right)}}\:\text{(}\color{blue}{\left[\color{black}{N}\right]}\:\text{)}` * - Conditional - :math:`\color{blue}{\left[\color{black}{ \textbf{if}\:M\:\textbf{then}\:N_{1}\:\textbf{else}\:N_{2} }\right]}` - :math:`\textbf{if}\:\color{blue}{\left[ \color{black}{M}\right]}\:\textbf{then}\:\color{blue}{\left[ \color{black}{N_{1}}\right]}\:\textbf{else}\:\color{blue}{\left[ \color{black}{N_{2}}\right]}` @@ -221,3 +221,59 @@ with the accumulated cost, on the body; this ensures 2 things: * - Record Projection - :math:`\color{blue}{\left[\color{black}{ M.F }\right]}` - :math:`\color{blue}{\left[ \color{black}{M}\right]}.F` + + +Examples +-------- + +Let's create a simple function which takes an argument and a function and applies the function on the argument: + +.. code-block:: fsharp + + val myfunc1 (#a #b:Type): a -> (a -> b) -> b + let myfunc1 #_ #_ x f = f x + +Elaborating the function will yield the following: + +.. code-block:: fsharp + + val myfunc1: #a: Type -> #b: Type -> a -> (a -> b) -> b + let myfunc1 #_ #_ x f = inc 1 (f x) + +That's because function application (:fsharp:`f x`) has a cost of 1, which is embedded into the let-expression with :fsharp:`inc`. + +However - trying to compile this function will result in a typing error - because you can only apply :fsharp:`inc` on a value of a :fsharp:`cost` type. + +To fix it we modify the function to use :fsharp:`ret` on the result, and we change the type signature to return a :fsharp:`cost` type +(with a cost of 0 since that is the cost :fsharp:`ret` gives): + +.. code-block:: fsharp + + val myfunc1 (#a #b:Type): a -> (a -> b) -> b `cost` 0 + let myfunc1 #_ #_ x f = ret (f x) + +Now elaborating the function will yield the following: + +.. code-block:: fsharp + + val myfunc1 (#a #b:Type): a -> (a -> b) -> b `cost` 0 + let myfunc1 #_ #_ x f = inc 2 (ret (f x)) + +That's because now we have **2 applications**, one of :fsharp:`f` on :fsharp:`x`, and the other of :fsharp:`ret` on the result. + +Now the compilation would **still fail** with a typing error: + +.. code-block:: none + + Subtyping check failed; expected type Zen.Cost.Realized.cost _ 0; got type Zen.Cost.Realized.cost _ (0 + 2) + +That's because while the declared cost is 0, the **inferred** cost (due to the addition of :fsharp:`inc 2`) is 2. + +To fix that we now have to declare the **correct** cost within the type, to account for the increment: + +.. code-block:: fsharp + + val myfunc1 (#a #b:Type): a -> (a -> b) -> b `cost` 2 + let myfunc1 #_ #_ x f = inc 2 (ret (f x)) + +Now that the syntactic cost is accounted for the program will compile. From ae4edd23d39b3408b0cf7ca7373c2b1550d4c66a Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Wed, 8 May 2019 15:05:53 +0300 Subject: [PATCH 33/42] added more examples to the cost model --- docs/root/contracts/cost.rst | 105 +++++++++++++++++++++++++++++++---- 1 file changed, 94 insertions(+), 11 deletions(-) diff --git a/docs/root/contracts/cost.rst b/docs/root/contracts/cost.rst index 1d9d944..5753b25 100644 --- a/docs/root/contracts/cost.rst +++ b/docs/root/contracts/cost.rst @@ -226,19 +226,19 @@ with the accumulated cost, on the body; this ensures 2 things: Examples -------- -Let's create a simple function which takes an argument and a function and applies the function on the argument: +Let's create a simple function which takes a function and an argument and applies the function on the argument: .. code-block:: fsharp - val myfunc1 (#a #b:Type): a -> (a -> b) -> b - let myfunc1 #_ #_ x f = f x + val applyOnce (#a #b:Type): (a -> b) -> a -> b + let applyOnce #_ #_ f x = f x Elaborating the function will yield the following: .. code-block:: fsharp - val myfunc1: #a: Type -> #b: Type -> a -> (a -> b) -> b - let myfunc1 #_ #_ x f = inc 1 (f x) + val applyOnce: #a: Type -> #b: Type -> (a -> b) -> a -> b + let applyOnce #_ #_ f x = inc 1 (f x) That's because function application (:fsharp:`f x`) has a cost of 1, which is embedded into the let-expression with :fsharp:`inc`. @@ -249,15 +249,15 @@ To fix it we modify the function to use :fsharp:`ret` on the result, and we chan .. code-block:: fsharp - val myfunc1 (#a #b:Type): a -> (a -> b) -> b `cost` 0 - let myfunc1 #_ #_ x f = ret (f x) + val applyOnce (#a #b:Type): (a -> b) -> a -> b `cost` 0 + let applyOnce #_ #_ f x = ret (f x) Now elaborating the function will yield the following: .. code-block:: fsharp - val myfunc1 (#a #b:Type): a -> (a -> b) -> b `cost` 0 - let myfunc1 #_ #_ x f = inc 2 (ret (f x)) + val applyOnce (#a #b:Type): (a -> b) -> a -> b `cost` 0 + let applyOnce #_ #_ f x = inc 2 (ret (f x)) That's because now we have **2 applications**, one of :fsharp:`f` on :fsharp:`x`, and the other of :fsharp:`ret` on the result. @@ -273,7 +273,90 @@ To fix that we now have to declare the **correct** cost within the type, to acco .. code-block:: fsharp - val myfunc1 (#a #b:Type): a -> (a -> b) -> b `cost` 2 - let myfunc1 #_ #_ x f = inc 2 (ret (f x)) + val applyOnce (#a #b:Type): (a -> b) -> a -> b `cost` 2 + let applyOnce #_ #_ f x = inc 2 (ret (f x)) Now that the syntactic cost is accounted for the program will compile. + +------ + +The following function takes a function :fsharp:`f` and an argument :fsharp:`x` and applies :fsharp:`f` on :fsharp:`x` and then on the result: + +.. code-block:: fsharp + + val applyTwice (#a:Type): (a -> a) -> a -> a + let applyTwice #_ f x = f (f x) + +Elaborating this function will yield the following: + +.. code-block:: fsharp + + val applyTwice (#a:Type): (a -> a) -> a -> a + let applyTwice #_ f x = inc 2 (f (f x)) + +The increment by 2 is due to the fact there are 2 applications. + +Again - this format won't do, and to be able to compile the elaborated program we have to lift the result into the cost monad and account for the +additional costs: + +.. code-block:: fsharp + + val applyTwice (#a:Type): (a -> a) -> a -> a `cost` 3 + let applyTwice #_ f x = ret (f (f x)) + +which will be elaborated as: + +.. code-block:: fsharp + + val applyTwice: #a: Type -> (a -> a) -> a -> cost a 3 + let applyTwice #_ f x = inc 3 (ret (f (f x))) + +Notice that this time we've participated the increased elaborated cost in advance, so the original code won't compile (since :fsharp:`ret` gives +a cost of 0) while the elaborated code will (since it will add :fsharp:`inc 3` to account for the costs of all the function applications). + +You can declare the correct types either **before** or **after** the elaboration, since the elaboration process **leaves the types intact**, but +in general it's preferred to correct the types **after** the elaboration, because then the original code would still compile and you won't have to +predict the elaborated costs. + +----- + +Now let's create another function - which takes a boolean :fsharp:`b`, a function :fsharp:`f`, and another argument :fsharp:`x`, +and applies :fsharp:`f` on :fsharp:`x` **once** if :fsharp:`b` is :fsharp:`true` or **twice** if :fsharp:`b` is :fsharp:`false`. + +We'll use the previously defined functions to do so: + +.. code-block:: fsharp + + val onceOrTwice (#a:Type): bool -> (a -> a) -> a -> a `cost` ? + let onceOrTwice #_ b f x = if b then applyOnce f x else applyTwice f x + +What should be the declared cost of this function? + +:fsharp:`applyOnce` gives a cost of **2**, while :fsharp:`applyTwice` gives a cost of **3**, so we have a **collision of costs**. + +To reconcile the collision we manually insert :fsharp:`inc 1` to the :fsharp:`applyOnce f x` clasue to account for the difference between the costs, +which would give both clauses of the :fsharp:`if-then-else` the cost of **3**: + +.. code-block:: fsharp + + val onceOrTwice (#a:Type): bool -> (a -> a) -> a -> a `cost` 3 + let onceOrTwice #_ b f x = if b then inc 1 (applyOnce f x) else applyTwice f x + +However - we still need to account for the syntactic cost of the :fsharp:`onceOrTwice` function itself - to do so we first elaborate the function, +which gives us: + +.. code-block:: fsharp + + val onceOrTwice (#a:Type): bool -> (a -> a) -> a -> a `cost` 3 + let onceOrTwice #_ b f x = inc 7 (if b then inc 1 (applyOnce f x) else applyTwice f x) + +That is beacuse the :fsharp:`then` clause has **4 applications**, while the :fsharp:`else` clause has **3**, and since the syntactic cost of +an :fsharp:`if-then-else` is defined as **3** + the maximal syntactic cost out of both clauses, which is **4** in this case, we get a total syntactic cost +of **7**, which is embedded with an :fsharp:`inc 7` into the let-expression. + +Now to account for the additional cost of **7** we change the declared cost of the function: + +.. code-block:: fsharp + + val onceOrTwice (#a:Type): bool -> (a -> a) -> a -> a `cost` 10 + let onceOrTwice #_ b f x = inc 7 (if b then inc 1 (applyOnce f x) else applyTwice f x) From 4fada3f1fca426133f4c1e8327aeafc82bd240bb Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Wed, 8 May 2019 15:16:51 +0300 Subject: [PATCH 34/42] remove infix cost notation and fixed its order of parameters --- docs/root/contracts/cost.rst | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/root/contracts/cost.rst b/docs/root/contracts/cost.rst index 5753b25..1525dc5 100644 --- a/docs/root/contracts/cost.rst +++ b/docs/root/contracts/cost.rst @@ -82,16 +82,16 @@ The Cost Type ------------- Given a cost model we define a special type constructor :fsharp:`cost` to indicate that -a term of type :fsharp:`cost m A`, where :fsharp:`m` is a natural number and :fsharp:`A` is a -type, would take at most :fsharp:`m` steps to produce a **value** of type :fsharp:`A`. +a term of type :fsharp:`cost A m`, where :fsharp:`A` is a type and :fsharp:`m` is a natural number, +would take at most :fsharp:`m` steps to produce a **value** of type :fsharp:`A`. -Dually - we use the type :fsharp:`cost m A` to indicate that a term of this type **represents +Dually - we use the type :fsharp:`cost A m` to indicate that a term of this type **represents a value** of type :fsharp:`A` which **has taken** at most :fsharp:`m` steps to evaluate. -When a **term** :fsharp:`M` has the type :fsharp:`cost m A` we say that :fsharp:`M` is a +When a **term** :fsharp:`M` has the type :fsharp:`cost A m` we say that :fsharp:`M` is a *costed term*, with a *cost* of :fsharp:`m`. -When a **function** :fsharp:`f` has the type :fsharp:`A -> cost m B` we say that +When a **function** :fsharp:`f` has the type :fsharp:`A -> cost B m` we say that :fsharp:`f` is a *costed function*, with a *cost* of :fsharp:`m`, which means that when given an input of type :fsharp:`A` it takes :fsharp:`f` at most :fsharp:`m` steps to produce an output of type :fsharp:`B`. @@ -102,8 +102,8 @@ Compositional Cost The :fsharp:`cost` type constructor behaves as a an **indexed monad**, indexed over the additive monoid of the natural numbers, so whenever you compose (using Kleisli composition) -2 costed functions :fsharp:`f : B -> cost n C` and :fsharp:`g : A -> cost m B` -you get a function of type :fsharp:`A -> cost (m + n) C` where the cost is the sum of the costs +2 costed functions :fsharp:`f : B -> cost C n` and :fsharp:`g : A -> cost B m` +you get a function of type :fsharp:`A -> cost C (m + n)` where the cost is the sum of the costs of :fsharp:`f` and :fsharp:`g`. In practice - the :fsharp:`cost` monad in *ZF\** is implemented as **the identity monad**, @@ -118,9 +118,9 @@ To enforce the validity of the costs we combine the compiler with an **elaborato which would be explained in detail later on. To lift a term into the monad we use the :fsharp:`ret` function, which is the unit of the -monad and has the type :fsharp:`ret : a -> cost 0 a`. +monad and has the type :fsharp:`ret : a -> cost a 0`. Since the :fsharp:`ret` function gives a term a cost of :fsharp:`0`, we use the function -:fsharp:`inc : (m:nat) -> cost n a -> cost (n+m) a` to increase the declared cost of a term. +:fsharp:`inc : (m:nat) -> cost a n -> cost a (n+m)` to increase the declared cost of a term. Syntactic Cost -------------- @@ -249,14 +249,14 @@ To fix it we modify the function to use :fsharp:`ret` on the result, and we chan .. code-block:: fsharp - val applyOnce (#a #b:Type): (a -> b) -> a -> b `cost` 0 + val applyOnce (#a #b:Type): (a -> b) -> a -> cost b 0 let applyOnce #_ #_ f x = ret (f x) Now elaborating the function will yield the following: .. code-block:: fsharp - val applyOnce (#a #b:Type): (a -> b) -> a -> b `cost` 0 + val applyOnce (#a #b:Type): (a -> b) -> a -> cost b 0 let applyOnce #_ #_ f x = inc 2 (ret (f x)) That's because now we have **2 applications**, one of :fsharp:`f` on :fsharp:`x`, and the other of :fsharp:`ret` on the result. @@ -273,7 +273,7 @@ To fix that we now have to declare the **correct** cost within the type, to acco .. code-block:: fsharp - val applyOnce (#a #b:Type): (a -> b) -> a -> b `cost` 2 + val applyOnce (#a #b:Type): (a -> b) -> a -> cost b 2 let applyOnce #_ #_ f x = inc 2 (ret (f x)) Now that the syntactic cost is accounted for the program will compile. @@ -301,7 +301,7 @@ additional costs: .. code-block:: fsharp - val applyTwice (#a:Type): (a -> a) -> a -> a `cost` 3 + val applyTwice (#a:Type): (a -> a) -> a -> cost a 3 let applyTwice #_ f x = ret (f (f x)) which will be elaborated as: @@ -327,7 +327,7 @@ We'll use the previously defined functions to do so: .. code-block:: fsharp - val onceOrTwice (#a:Type): bool -> (a -> a) -> a -> a `cost` ? + val onceOrTwice (#a:Type): bool -> (a -> a) -> a -> cost a ? let onceOrTwice #_ b f x = if b then applyOnce f x else applyTwice f x What should be the declared cost of this function? @@ -339,7 +339,7 @@ which would give both clauses of the :fsharp:`if-then-else` the cost of **3**: .. code-block:: fsharp - val onceOrTwice (#a:Type): bool -> (a -> a) -> a -> a `cost` 3 + val onceOrTwice (#a:Type): bool -> (a -> a) -> a -> cost a 3 let onceOrTwice #_ b f x = if b then inc 1 (applyOnce f x) else applyTwice f x However - we still need to account for the syntactic cost of the :fsharp:`onceOrTwice` function itself - to do so we first elaborate the function, @@ -347,7 +347,7 @@ which gives us: .. code-block:: fsharp - val onceOrTwice (#a:Type): bool -> (a -> a) -> a -> a `cost` 3 + val onceOrTwice (#a:Type): bool -> (a -> a) -> a -> cost a 3 let onceOrTwice #_ b f x = inc 7 (if b then inc 1 (applyOnce f x) else applyTwice f x) That is beacuse the :fsharp:`then` clause has **4 applications**, while the :fsharp:`else` clause has **3**, and since the syntactic cost of @@ -358,5 +358,5 @@ Now to account for the additional cost of **7** we change the declared cost of t .. code-block:: fsharp - val onceOrTwice (#a:Type): bool -> (a -> a) -> a -> a `cost` 10 + val onceOrTwice (#a:Type): bool -> (a -> a) -> a -> cost a 10 let onceOrTwice #_ b f x = inc 7 (if b then inc 1 (applyOnce f x) else applyTwice f x) From 82078b60cda449659aba550ee420a3d5b4c4fc14 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Wed, 8 May 2019 19:07:31 +0300 Subject: [PATCH 35/42] cost analysis with recursion --- docs/root/contracts/cost.rst | 181 ++++++++++++++++++++++++++++++++++- 1 file changed, 177 insertions(+), 4 deletions(-) diff --git a/docs/root/contracts/cost.rst b/docs/root/contracts/cost.rst index 1525dc5..73642f3 100644 --- a/docs/root/contracts/cost.rst +++ b/docs/root/contracts/cost.rst @@ -314,9 +314,8 @@ which will be elaborated as: Notice that this time we've participated the increased elaborated cost in advance, so the original code won't compile (since :fsharp:`ret` gives a cost of 0) while the elaborated code will (since it will add :fsharp:`inc 3` to account for the costs of all the function applications). -You can declare the correct types either **before** or **after** the elaboration, since the elaboration process **leaves the types intact**, but -in general it's preferred to correct the types **after** the elaboration, because then the original code would still compile and you won't have to -predict the elaborated costs. +In practice - **you won't be able to modify the elaborated code**, since the elaboration is done automatically when activating a contract, +so instead you need to elaborate it locally, look at the result, and then modify the **original code** so it would compile right after the elaboration. ----- @@ -354,9 +353,183 @@ That is beacuse the :fsharp:`then` clause has **4 applications**, while the :fsh an :fsharp:`if-then-else` is defined as **3** + the maximal syntactic cost out of both clauses, which is **4** in this case, we get a total syntactic cost of **7**, which is embedded with an :fsharp:`inc 7` into the let-expression. -Now to account for the additional cost of **7** we change the declared cost of the function: +Now to account for the additional cost of **7** we change the declared cost of the function to **10**: .. code-block:: fsharp val onceOrTwice (#a:Type): bool -> (a -> a) -> a -> cost a 10 let onceOrTwice #_ b f x = inc 7 (if b then inc 1 (applyOnce f x) else applyTwice f x) + +The elaborated code will now compile. + +----- + +The cost analysis becomes more complex once you introduce recursion. + +The following function computes the factorial of a natural number: + +.. code-block:: fsharp + + val fact: nat -> int + let rec fact m = + match m with + | 0 -> 1 + | _ -> m * fact (m - 1) + +Trying to elaborate this function will fail, since it doesn't return a :fsharp:`cost` type. + +.. code-block:: fsharp + + val fact: nat -> int + let rec fact m = + inc 7 + (match m with + | 0 -> 1 + | _ -> m * fact (m - 1)) + +To make sure the result is of a :fsharp:`cost` type - we apply :fsharp:`ret` on the base case, and bind the recursion step: + +.. code-block:: fsharp + + let rec fact m = + match m with + | 0 -> ret 1 + | _ -> fact (m - 1) >>= (fun r -> ret (m * r)) + +We might prefer to use some syntactic sugar to make the code look nicer: + +.. code-block:: fsharp + + let rec fact m = + match m with + | 0 -> ret 1 + | _ -> let! r = fact (m - 1) + in ret (m * r) + +What should be the return type of the new function? we can start with :fsharp:`cost int 0`: + +.. code-block:: fsharp + + val fact: nat -> cost int 0 + let rec fact m = + match m with + | 0 -> ret 1 + | _ -> let! r = fact (m - 1) + in ret (m * r) + +Now the elaborated code will not compile, but it will give us some hints on how to specify the cost correctly: + +.. code-block:: fsharp + + val fact: nat -> cost int 0 + let rec fact m = + inc 10 + (match m with + | 0 -> ret 1 + | _ -> let! r = fact (m - 1) + in ret (m * r)) + +We might be tempted to assign a cost of **10** to the function, but that won't do - +if the cost of :fsharp:`fact` is **10** then :fsharp:`fact (m - 1)` will have a cost of **10** and after accounting for the incremented syntactic cost +(which is added by :fsharp:`inc 10`) we'll get that the **actual** cost of the function is **20**. + +In fact - assuming **any** constant cost will yield a **contradiction**, since we'll always get another 10 steps added to what we've started with, +which indicates that it is impossible to assign a constant cost to the function. + +How do we resolve it? by making the cost **parametric** in the size of the input, by using **dependent types**. + +First we explicitly declare the **name** of the input parameter **in the type**: + +.. code-block:: fsharp + + val fact: (m:nat) -> cost int 0 + +Then we can use this name within the cost expression, for example like this: + +.. code-block:: fsharp + + val fact: (m:nat) -> cost int m + +But this won't do - we have to figure out the actual dependency of the cost on the parameter. + +Let's assume for now the cost is some function :fsharp:`fact_c` on :fsharp:`m`: + +.. code-block:: fsharp + + val fact: (m:nat) -> cost int (fact_c m) + +Looking at the definition of :fsharp:`cost` again - we immediately see a problem - the cost of :fsharp:`ret 1` is always **0**, +while the cost of :fsharp:`fact (m-1)` is :fsharp:`fact_c (m-1)`, which **can't be 0**, so we have 2 pattern matching clauses with different costs. + +This will result in a typing error when we try to compile the code, since all clauses of a :fsharp:`match-with` must return a result of the same type. + +To fix that we need to add the difference to the first clause, like this (notice this is a modification of the original code, **not** +the elaborated code): + +.. code-block:: fsharp + + val fact: (m:nat) -> cost int (fact_c m) + let rec fact m = + match m with + | 0 -> inc (fact_c (m-1)) (ret 1) + | _ -> let! r = fact (m-1) + in ret (m * r) + +Instead of using :fsharp:`ret` and then :fsharp:`inc` we can just use :fsharp:`incRet`, which combines the 2: + +.. code-block:: fsharp + + val fact: (m:nat) -> cost int (fact_c m) + let rec fact m = + match m with + | 0 -> incRet (fact_c (m-1)) 1 + | _ -> let! r = fact (m-1) + in ret (m * r) + +Now we have to figure out what :fsharp:`fact_c` is. + +Since the elaborator adds **10** to the cost, and this value didn't change with the addition of the :fsharp:`incRet` to the first clause +(since the total syntactic cost for a :fsharp:`match-with` is determined only by the syntactically heaviest clause, which is still the second clause), +we get **10** added to the cost **with each call to the function**, which means that both the **base case** has **at least** a cost of **10**, +and with each **recursion step** another **10** is added, so we get the following recurrence relation: + +.. code-block:: fsharp + + fact_c m = 10 + fact_c (m - 1) + +What is the base case (for :fsharp:`m = 0`)? + +Since we know it is **at least 10** (since the cost is increased by 10 and it can never be decreased), we can try assigning it to be 10, +which gives us the solution: + +.. code-block:: fsharp + + fact_c m = 10 * (m + 1) + +So let's try it: + +.. code-block:: fsharp + + val fact: (m:nat) -> cost int (10 * (m+1)) + let rec fact m = + match m with + | 0 -> incRet (10 * m) 1 + | _ -> let! r = fact (m-1) + in ret (m * r) + +Now the function is elaborated to: + +.. code-block:: fsharp + + val fact: m: nat -> cost int (10 * (m + 1)) + let rec fact m = + inc 10 + (match m with + | 0 -> incRet (10 * m) 1 + | _ -> let! r = fact (m - 1) in ret (m * r)) + +The program now compiles successfully, which indicates that the cost is now correct. + +The keen-sighted reader will notice that the first clause :fsharp:`incRet (10 * m) 1` is operationally equivalent to :fsharp:`ret 1`, since the only +case in which this clause is executed is when :fsharp:`m = 0`, but since all clauses must return a result of the same type, no matter if they are +executed or not, the only way to pass the type checker is by explicitly handling the cost for all possible values of :fsharp:`m`. From efadd2ba2f1fc93b8acf35960df4fb35f1a2e193 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Sun, 12 May 2019 13:33:28 +0300 Subject: [PATCH 36/42] separated the examples into their own page --- docs/index.md | 1 + docs/root/contracts.md | 4 + docs/root/contracts/cost.rst | 310 +---------------------------- docs/root/contracts/examples.rst | 322 +++++++++++++++++++++++++++++++ 4 files changed, 329 insertions(+), 308 deletions(-) create mode 100644 docs/root/contracts/examples.rst diff --git a/docs/index.md b/docs/index.md index db5ca2d..0402536 100644 --- a/docs/index.md +++ b/docs/index.md @@ -12,4 +12,5 @@ Contents: * [ZF*](root/zfstar.html) * [Contracts](root/contracts.html) * [Cost Analysis](root/contracts/cost.html) + * [Cost Analysis Examples](root/contracts/examples.html) * [Contract Structure](root/contracts/contract-structure.html) diff --git a/docs/root/contracts.md b/docs/root/contracts.md index 2bc7584..9c77d8f 100644 --- a/docs/root/contracts.md +++ b/docs/root/contracts.md @@ -4,6 +4,10 @@ [Cost Analysis](contracts/cost.html) +### Examples + +[Cost Analysis Examples](contracts/examples.html) + ## Contract Structure [Contract Structure](contracts/contract-structure.html) diff --git a/docs/root/contracts/cost.rst b/docs/root/contracts/cost.rst index 73642f3..cb68821 100644 --- a/docs/root/contracts/cost.rst +++ b/docs/root/contracts/cost.rst @@ -222,314 +222,8 @@ with the accumulated cost, on the body; this ensures 2 things: - :math:`\color{blue}{\left[\color{black}{ M.F }\right]}` - :math:`\color{blue}{\left[ \color{black}{M}\right]}.F` - -Examples --------- - -Let's create a simple function which takes a function and an argument and applies the function on the argument: - -.. code-block:: fsharp - - val applyOnce (#a #b:Type): (a -> b) -> a -> b - let applyOnce #_ #_ f x = f x - -Elaborating the function will yield the following: - -.. code-block:: fsharp - - val applyOnce: #a: Type -> #b: Type -> (a -> b) -> a -> b - let applyOnce #_ #_ f x = inc 1 (f x) - -That's because function application (:fsharp:`f x`) has a cost of 1, which is embedded into the let-expression with :fsharp:`inc`. - -However - trying to compile this function will result in a typing error - because you can only apply :fsharp:`inc` on a value of a :fsharp:`cost` type. - -To fix it we modify the function to use :fsharp:`ret` on the result, and we change the type signature to return a :fsharp:`cost` type -(with a cost of 0 since that is the cost :fsharp:`ret` gives): - -.. code-block:: fsharp - - val applyOnce (#a #b:Type): (a -> b) -> a -> cost b 0 - let applyOnce #_ #_ f x = ret (f x) - -Now elaborating the function will yield the following: - -.. code-block:: fsharp - - val applyOnce (#a #b:Type): (a -> b) -> a -> cost b 0 - let applyOnce #_ #_ f x = inc 2 (ret (f x)) - -That's because now we have **2 applications**, one of :fsharp:`f` on :fsharp:`x`, and the other of :fsharp:`ret` on the result. - -Now the compilation would **still fail** with a typing error: - -.. code-block:: none - - Subtyping check failed; expected type Zen.Cost.Realized.cost _ 0; got type Zen.Cost.Realized.cost _ (0 + 2) - -That's because while the declared cost is 0, the **inferred** cost (due to the addition of :fsharp:`inc 2`) is 2. - -To fix that we now have to declare the **correct** cost within the type, to account for the increment: - -.. code-block:: fsharp - - val applyOnce (#a #b:Type): (a -> b) -> a -> cost b 2 - let applyOnce #_ #_ f x = inc 2 (ret (f x)) - -Now that the syntactic cost is accounted for the program will compile. - ------- - -The following function takes a function :fsharp:`f` and an argument :fsharp:`x` and applies :fsharp:`f` on :fsharp:`x` and then on the result: - -.. code-block:: fsharp - - val applyTwice (#a:Type): (a -> a) -> a -> a - let applyTwice #_ f x = f (f x) - -Elaborating this function will yield the following: - -.. code-block:: fsharp - - val applyTwice (#a:Type): (a -> a) -> a -> a - let applyTwice #_ f x = inc 2 (f (f x)) - -The increment by 2 is due to the fact there are 2 applications. - -Again - this format won't do, and to be able to compile the elaborated program we have to lift the result into the cost monad and account for the -additional costs: - -.. code-block:: fsharp - - val applyTwice (#a:Type): (a -> a) -> a -> cost a 3 - let applyTwice #_ f x = ret (f (f x)) - -which will be elaborated as: - -.. code-block:: fsharp - - val applyTwice: #a: Type -> (a -> a) -> a -> cost a 3 - let applyTwice #_ f x = inc 3 (ret (f (f x))) - -Notice that this time we've participated the increased elaborated cost in advance, so the original code won't compile (since :fsharp:`ret` gives -a cost of 0) while the elaborated code will (since it will add :fsharp:`inc 3` to account for the costs of all the function applications). - -In practice - **you won't be able to modify the elaborated code**, since the elaboration is done automatically when activating a contract, -so instead you need to elaborate it locally, look at the result, and then modify the **original code** so it would compile right after the elaboration. - ------ - -Now let's create another function - which takes a boolean :fsharp:`b`, a function :fsharp:`f`, and another argument :fsharp:`x`, -and applies :fsharp:`f` on :fsharp:`x` **once** if :fsharp:`b` is :fsharp:`true` or **twice** if :fsharp:`b` is :fsharp:`false`. - -We'll use the previously defined functions to do so: - -.. code-block:: fsharp - - val onceOrTwice (#a:Type): bool -> (a -> a) -> a -> cost a ? - let onceOrTwice #_ b f x = if b then applyOnce f x else applyTwice f x - -What should be the declared cost of this function? - -:fsharp:`applyOnce` gives a cost of **2**, while :fsharp:`applyTwice` gives a cost of **3**, so we have a **collision of costs**. - -To reconcile the collision we manually insert :fsharp:`inc 1` to the :fsharp:`applyOnce f x` clasue to account for the difference between the costs, -which would give both clauses of the :fsharp:`if-then-else` the cost of **3**: - -.. code-block:: fsharp - - val onceOrTwice (#a:Type): bool -> (a -> a) -> a -> cost a 3 - let onceOrTwice #_ b f x = if b then inc 1 (applyOnce f x) else applyTwice f x - -However - we still need to account for the syntactic cost of the :fsharp:`onceOrTwice` function itself - to do so we first elaborate the function, -which gives us: - -.. code-block:: fsharp - - val onceOrTwice (#a:Type): bool -> (a -> a) -> a -> cost a 3 - let onceOrTwice #_ b f x = inc 7 (if b then inc 1 (applyOnce f x) else applyTwice f x) - -That is beacuse the :fsharp:`then` clause has **4 applications**, while the :fsharp:`else` clause has **3**, and since the syntactic cost of -an :fsharp:`if-then-else` is defined as **3** + the maximal syntactic cost out of both clauses, which is **4** in this case, we get a total syntactic cost -of **7**, which is embedded with an :fsharp:`inc 7` into the let-expression. - -Now to account for the additional cost of **7** we change the declared cost of the function to **10**: - -.. code-block:: fsharp - - val onceOrTwice (#a:Type): bool -> (a -> a) -> a -> cost a 10 - let onceOrTwice #_ b f x = inc 7 (if b then inc 1 (applyOnce f x) else applyTwice f x) - -The elaborated code will now compile. - ----- -The cost analysis becomes more complex once you introduce recursion. - -The following function computes the factorial of a natural number: - -.. code-block:: fsharp - - val fact: nat -> int - let rec fact m = - match m with - | 0 -> 1 - | _ -> m * fact (m - 1) - -Trying to elaborate this function will fail, since it doesn't return a :fsharp:`cost` type. - -.. code-block:: fsharp - - val fact: nat -> int - let rec fact m = - inc 7 - (match m with - | 0 -> 1 - | _ -> m * fact (m - 1)) - -To make sure the result is of a :fsharp:`cost` type - we apply :fsharp:`ret` on the base case, and bind the recursion step: - -.. code-block:: fsharp - - let rec fact m = - match m with - | 0 -> ret 1 - | _ -> fact (m - 1) >>= (fun r -> ret (m * r)) - -We might prefer to use some syntactic sugar to make the code look nicer: - -.. code-block:: fsharp - - let rec fact m = - match m with - | 0 -> ret 1 - | _ -> let! r = fact (m - 1) - in ret (m * r) - -What should be the return type of the new function? we can start with :fsharp:`cost int 0`: - -.. code-block:: fsharp - - val fact: nat -> cost int 0 - let rec fact m = - match m with - | 0 -> ret 1 - | _ -> let! r = fact (m - 1) - in ret (m * r) - -Now the elaborated code will not compile, but it will give us some hints on how to specify the cost correctly: - -.. code-block:: fsharp - - val fact: nat -> cost int 0 - let rec fact m = - inc 10 - (match m with - | 0 -> ret 1 - | _ -> let! r = fact (m - 1) - in ret (m * r)) - -We might be tempted to assign a cost of **10** to the function, but that won't do - -if the cost of :fsharp:`fact` is **10** then :fsharp:`fact (m - 1)` will have a cost of **10** and after accounting for the incremented syntactic cost -(which is added by :fsharp:`inc 10`) we'll get that the **actual** cost of the function is **20**. - -In fact - assuming **any** constant cost will yield a **contradiction**, since we'll always get another 10 steps added to what we've started with, -which indicates that it is impossible to assign a constant cost to the function. - -How do we resolve it? by making the cost **parametric** in the size of the input, by using **dependent types**. - -First we explicitly declare the **name** of the input parameter **in the type**: - -.. code-block:: fsharp - - val fact: (m:nat) -> cost int 0 - -Then we can use this name within the cost expression, for example like this: - -.. code-block:: fsharp - - val fact: (m:nat) -> cost int m - -But this won't do - we have to figure out the actual dependency of the cost on the parameter. - -Let's assume for now the cost is some function :fsharp:`fact_c` on :fsharp:`m`: - -.. code-block:: fsharp - - val fact: (m:nat) -> cost int (fact_c m) - -Looking at the definition of :fsharp:`cost` again - we immediately see a problem - the cost of :fsharp:`ret 1` is always **0**, -while the cost of :fsharp:`fact (m-1)` is :fsharp:`fact_c (m-1)`, which **can't be 0**, so we have 2 pattern matching clauses with different costs. - -This will result in a typing error when we try to compile the code, since all clauses of a :fsharp:`match-with` must return a result of the same type. - -To fix that we need to add the difference to the first clause, like this (notice this is a modification of the original code, **not** -the elaborated code): - -.. code-block:: fsharp - - val fact: (m:nat) -> cost int (fact_c m) - let rec fact m = - match m with - | 0 -> inc (fact_c (m-1)) (ret 1) - | _ -> let! r = fact (m-1) - in ret (m * r) - -Instead of using :fsharp:`ret` and then :fsharp:`inc` we can just use :fsharp:`incRet`, which combines the 2: - -.. code-block:: fsharp - - val fact: (m:nat) -> cost int (fact_c m) - let rec fact m = - match m with - | 0 -> incRet (fact_c (m-1)) 1 - | _ -> let! r = fact (m-1) - in ret (m * r) - -Now we have to figure out what :fsharp:`fact_c` is. - -Since the elaborator adds **10** to the cost, and this value didn't change with the addition of the :fsharp:`incRet` to the first clause -(since the total syntactic cost for a :fsharp:`match-with` is determined only by the syntactically heaviest clause, which is still the second clause), -we get **10** added to the cost **with each call to the function**, which means that both the **base case** has **at least** a cost of **10**, -and with each **recursion step** another **10** is added, so we get the following recurrence relation: - -.. code-block:: fsharp - - fact_c m = 10 + fact_c (m - 1) - -What is the base case (for :fsharp:`m = 0`)? - -Since we know it is **at least 10** (since the cost is increased by 10 and it can never be decreased), we can try assigning it to be 10, -which gives us the solution: - -.. code-block:: fsharp - - fact_c m = 10 * (m + 1) - -So let's try it: - -.. code-block:: fsharp - - val fact: (m:nat) -> cost int (10 * (m+1)) - let rec fact m = - match m with - | 0 -> incRet (10 * m) 1 - | _ -> let! r = fact (m-1) - in ret (m * r) - -Now the function is elaborated to: - -.. code-block:: fsharp - - val fact: m: nat -> cost int (10 * (m + 1)) - let rec fact m = - inc 10 - (match m with - | 0 -> incRet (10 * m) 1 - | _ -> let! r = fact (m - 1) in ret (m * r)) - -The program now compiles successfully, which indicates that the cost is now correct. +Proceed to the examples_ -The keen-sighted reader will notice that the first clause :fsharp:`incRet (10 * m) 1` is operationally equivalent to :fsharp:`ret 1`, since the only -case in which this clause is executed is when :fsharp:`m = 0`, but since all clauses must return a result of the same type, no matter if they are -executed or not, the only way to pass the type checker is by explicitly handling the cost for all possible values of :fsharp:`m`. +.. _examples: examples.html diff --git a/docs/root/contracts/examples.rst b/docs/root/contracts/examples.rst new file mode 100644 index 0000000..3c7cc92 --- /dev/null +++ b/docs/root/contracts/examples.rst @@ -0,0 +1,322 @@ +Examples +======== + +.. highlight:: rst + +.. role:: fsharp(code) + :language: fsharp + +Simple Example +-------------- + +Let's create a simple function which takes a function and an argument and applies the function on the argument: + +.. code-block:: fsharp + + val applyOnce (#a #b:Type): (a -> b) -> a -> b + let applyOnce #_ #_ f x = f x + +Elaborating the function will yield the following: + +.. code-block:: fsharp + + val applyOnce: #a: Type -> #b: Type -> (a -> b) -> a -> b + let applyOnce #_ #_ f x = inc 1 (f x) + +That's because function application (:fsharp:`f x`) has a cost of 1, which is embedded into the let-expression with :fsharp:`inc`. + +However - trying to compile this function will result in a typing error - because you can only apply :fsharp:`inc` on a value of a :fsharp:`cost` type. + +To fix it we modify the function to use :fsharp:`ret` on the result, and we change the type signature to return a :fsharp:`cost` type +(with a cost of 0 since that is the cost :fsharp:`ret` gives): + +.. code-block:: fsharp + + val applyOnce (#a #b:Type): (a -> b) -> a -> cost b 0 + let applyOnce #_ #_ f x = ret (f x) + +Now elaborating the function will yield the following: + +.. code-block:: fsharp + + val applyOnce (#a #b:Type): (a -> b) -> a -> cost b 0 + let applyOnce #_ #_ f x = inc 2 (ret (f x)) + +That's because now we have **2 applications**, one of :fsharp:`f` on :fsharp:`x`, and the other of :fsharp:`ret` on the result. + +Now the compilation would **still fail** with a typing error: + +.. code-block:: none + + Subtyping check failed; expected type Zen.Cost.Realized.cost _ 0; got type Zen.Cost.Realized.cost _ (0 + 2) + +That's because while the declared cost is 0, the **inferred** cost (due to the addition of :fsharp:`inc 2`) is 2. + +To fix that we now have to declare the **correct** cost within the type, to account for the increment: + +.. code-block:: fsharp + + val applyOnce (#a #b:Type): (a -> b) -> a -> cost b 2 + let applyOnce #_ #_ f x = inc 2 (ret (f x)) + +Now that the syntactic cost is accounted for the program will compile. + + +Aggregated Syntactic Cost +------------------------- + +The following function takes a function :fsharp:`f` and an argument :fsharp:`x` and applies :fsharp:`f` on :fsharp:`x` and then on the result: + +.. code-block:: fsharp + + val applyTwice (#a:Type): (a -> a) -> a -> a + let applyTwice #_ f x = f (f x) + +Elaborating this function will yield the following: + +.. code-block:: fsharp + + val applyTwice (#a:Type): (a -> a) -> a -> a + let applyTwice #_ f x = inc 2 (f (f x)) + +The increment by 2 is due to the fact there are 2 applications. + +Again - this format won't do, and to be able to compile the elaborated program we have to lift the result into the cost monad and account for the +additional costs: + +.. code-block:: fsharp + + val applyTwice (#a:Type): (a -> a) -> a -> cost a 3 + let applyTwice #_ f x = ret (f (f x)) + +which will be elaborated as: + +.. code-block:: fsharp + + val applyTwice: #a: Type -> (a -> a) -> a -> cost a 3 + let applyTwice #_ f x = inc 3 (ret (f (f x))) + +Notice that this time we've participated the increased elaborated cost in advance, so the original code won't compile (since :fsharp:`ret` gives +a cost of 0) while the elaborated code will (since it will add :fsharp:`inc 3` to account for the costs of all the function applications). + +In practice - **you won't be able to modify the elaborated code**, since the elaboration is done automatically when activating a contract, +so instead you need to elaborate it locally, look at the result, and then modify the **original code** so it would compile right after the elaboration. + +Multiple Clauses +---------------- + +Now let's create another function - which takes a boolean :fsharp:`b`, a function :fsharp:`f`, and another argument :fsharp:`x`, +and applies :fsharp:`f` on :fsharp:`x` **once** if :fsharp:`b` is :fsharp:`true` or **twice** if :fsharp:`b` is :fsharp:`false`. + +We'll use the previously defined functions to do so: + +.. code-block:: fsharp + + val onceOrTwice (#a:Type): bool -> (a -> a) -> a -> cost a ? + let onceOrTwice #_ b f x = if b then applyOnce f x else applyTwice f x + +What should be the declared cost of this function? + +:fsharp:`applyOnce` gives a cost of **2**, while :fsharp:`applyTwice` gives a cost of **3**, so we have a **collision of costs**. + +To reconcile the collision we manually insert :fsharp:`inc 1` to the :fsharp:`applyOnce f x` clasue to account for the difference between the costs, +which would give both clauses of the :fsharp:`if-then-else` a cost of **3**: + +.. code-block:: fsharp + + val onceOrTwice (#a:Type): bool -> (a -> a) -> a -> cost a 3 + let onceOrTwice #_ b f x = if b then inc 1 (applyOnce f x) else applyTwice f x + +However - we still need to account for the syntactic cost of the :fsharp:`onceOrTwice` function itself - to do so we first elaborate the function, +which gives us: + +.. code-block:: fsharp + + val onceOrTwice (#a:Type): bool -> (a -> a) -> a -> cost a 3 + let onceOrTwice #_ b f x = inc 7 (if b then inc 1 (applyOnce f x) else applyTwice f x) + +That is beacuse the :fsharp:`then` clause has **4 applications**, while the :fsharp:`else` clause has **3**, and since the syntactic cost of +an :fsharp:`if-then-else` is defined as **3** + the maximal syntactic cost out of both clauses, which is **4** in this case, we get a total syntactic cost +of **7**, which is embedded with an :fsharp:`inc 7` into the let-expression. + +Now to account for the additional cost of **7** we change the declared cost of the function to **10**: + +.. code-block:: fsharp + + val onceOrTwice (#a:Type): bool -> (a -> a) -> a -> cost a 10 + let onceOrTwice #_ b f x = inc 7 (if b then inc 1 (applyOnce f x) else applyTwice f x) + +The elaborated code will now compile. + +Recursion +--------- + +The cost analysis becomes more complex once you introduce recursion. + +The following function computes the factorial of a natural number: + +.. code-block:: fsharp + + val fact: nat -> int + let rec fact m = + match m with + | 0 -> 1 + | _ -> m * fact (m - 1) + +Trying to elaborate this function will fail, since it doesn't return a :fsharp:`cost` type. + +.. code-block:: fsharp + + val fact: nat -> int + let rec fact m = + inc 7 + (match m with + | 0 -> 1 + | _ -> m * fact (m - 1)) + +To make sure the result is of a :fsharp:`cost` type - we apply :fsharp:`ret` on the base case, and bind the recursion step: + +.. code-block:: fsharp + + let rec fact m = + match m with + | 0 -> ret 1 + | _ -> fact (m - 1) >>= (fun r -> ret (m * r)) + +We might prefer to use some syntactic sugar to make the code look nicer: + +.. code-block:: fsharp + + let rec fact m = + match m with + | 0 -> ret 1 + | _ -> let! r = fact (m - 1) + in ret (m * r) + +What should be the return type of the new function? we can start with :fsharp:`cost int 0`: + +.. code-block:: fsharp + + val fact: nat -> cost int 0 + let rec fact m = + match m with + | 0 -> ret 1 + | _ -> let! r = fact (m - 1) + in ret (m * r) + +Now the elaborated code will not compile, but it will give us some hints on how to specify the cost correctly: + +.. code-block:: fsharp + + val fact: nat -> cost int 0 + let rec fact m = + inc 10 + (match m with + | 0 -> ret 1 + | _ -> let! r = fact (m - 1) + in ret (m * r)) + +We might be tempted to assign a cost of **10** to the function, but that won't do - +if the cost of :fsharp:`fact` is **10** then :fsharp:`fact (m - 1)` will have a cost of **10** and after accounting for the incremented syntactic cost +(which is added by :fsharp:`inc 10`) we'll get that the **actual** cost of the function is **20**. + +In fact - assuming **any** constant cost will yield a **contradiction**, since we'll always get another 10 steps added to what we've started with, +which indicates that it is impossible to assign a constant cost to the function. + +How do we resolve it? by making the cost **parametric** in the size of the input, by using **dependent types**. + +First we explicitly declare the **name** of the input parameter **in the type**: + +.. code-block:: fsharp + + val fact: (m:nat) -> cost int 0 + +Then we can use this name within the cost expression, for example like this: + +.. code-block:: fsharp + + val fact: (m:nat) -> cost int m + +But this won't do - we have to figure out the actual dependency of the cost on the parameter. + +Let's assume for now the cost is some function :fsharp:`fact_c` on :fsharp:`m`: + +.. code-block:: fsharp + + val fact: (m:nat) -> cost int (fact_c m) + +Looking at the definition of :fsharp:`cost` again - we immediately see a problem - the cost of :fsharp:`ret 1` is always **0**, +while the cost of :fsharp:`fact (m-1)` is :fsharp:`fact_c (m-1)`, which **can't be 0**, so we have 2 pattern matching clauses with different costs. + +This will result in a typing error when we try to compile the code, since all clauses of a :fsharp:`match-with` must return a result of the same type. + +To fix that we need to add the difference to the first clause, like this (notice this is a modification of the original code, **not** +the elaborated code): + +.. code-block:: fsharp + + val fact: (m:nat) -> cost int (fact_c m) + let rec fact m = + match m with + | 0 -> inc (fact_c (m-1)) (ret 1) + | _ -> let! r = fact (m-1) + in ret (m * r) + +Instead of using :fsharp:`ret` and then :fsharp:`inc` we can just use :fsharp:`incRet`, which combines the 2: + +.. code-block:: fsharp + + val fact: (m:nat) -> cost int (fact_c m) + let rec fact m = + match m with + | 0 -> incRet (fact_c (m-1)) 1 + | _ -> let! r = fact (m-1) + in ret (m * r) + +Now we have to figure out what :fsharp:`fact_c` is. + +Since the elaborator adds **10** to the cost, and this value didn't change with the addition of the :fsharp:`incRet` to the first clause +(since the total syntactic cost for a :fsharp:`match-with` is determined only by the syntactically heaviest clause, which is still the second clause), +we get **10** added to the cost **with each call to the function**, which means that the **base case** has **at least** a cost of **10**, +and with each **recursion step** another **10** is added, so we get the following recurrence relation: + +.. code-block:: fsharp + + fact_c m = 10 + fact_c (m - 1) + +What is the base case (for :fsharp:`m = 0`)? + +Since we know it is **at least 10** (since the cost is increased by 10 and it can never be decreased), we can try assigning it to be 10, +which gives us the solution: + +.. code-block:: fsharp + + fact_c m = 10 * (m + 1) + +So let's try it: + +.. code-block:: fsharp + + val fact: (m:nat) -> cost int (10 * (m+1)) + let rec fact m = + match m with + | 0 -> incRet (10 * m) 1 + | _ -> let! r = fact (m-1) + in ret (m * r) + +Now the function is elaborated to: + +.. code-block:: fsharp + + val fact: m: nat -> cost int (10 * (m + 1)) + let rec fact m = + inc 10 + (match m with + | 0 -> incRet (10 * m) 1 + | _ -> let! r = fact (m - 1) in ret (m * r)) + +The program now compiles successfully, which indicates that the cost is now correct. + +The keen-sighted reader will notice that the first clause :fsharp:`incRet (10 * m) 1` is operationally equivalent to :fsharp:`ret 1`, since the only +case in which this clause is executed is when :fsharp:`m = 0`, but since all clauses must return a result of the same type, no matter if they are +executed or not, the only way to pass the type checker is by explicitly handling the cost for all possible values of :fsharp:`m`. From 41e89f001c22e71802c642cd62d225f3232af106 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Sun, 12 May 2019 15:00:41 +0300 Subject: [PATCH 37/42] cost composition example --- docs/root/contracts/cost.rst | 10 ++- docs/root/contracts/examples.rst | 135 +++++++++++++++++++++++++++++-- 2 files changed, 139 insertions(+), 6 deletions(-) diff --git a/docs/root/contracts/cost.rst b/docs/root/contracts/cost.rst index cb68821..0dfa593 100644 --- a/docs/root/contracts/cost.rst +++ b/docs/root/contracts/cost.rst @@ -60,12 +60,14 @@ We use the notation :math:`c\left(M\right)` for the cost of the term :fsharp:`M` - :math:`1 + c\left(\color{black}{M}\right)` In practice the actual cost (relative to the cost model) is **not computed directly**, -instead - the cost is divided into 2 components: +instead - the cost is decomposed into 2 components: 1. **Compositional Cost** - which is **declared** by the **developer** and **verified** by the **type system** 2. **Syntactic Cost** - which is **computed** by the **elaborator** +:math:`\textbf{total cost}=\textbf{compositional cost}+\textbf{syntactic cost}` + In fact - given general recursion it is **impossible** to automatically compute the cost of any arbitrary term in the language. @@ -106,6 +108,12 @@ additive monoid of the natural numbers, so whenever you compose (using Kleisli c you get a function of type :fsharp:`A -> cost C (m + n)` where the cost is the sum of the costs of :fsharp:`f` and :fsharp:`g`. +The **bind** operator (:fsharp:`>>=`) has the type signature: + +.. code-block:: fsharp + + bind: cost a m -> (a -> cost b n) -> cost b (m+n) + In practice - the :fsharp:`cost` monad in *ZF\** is implemented as **the identity monad**, where the index could be set arbitrarily, so as far as *ZF\** is concerned - **it is up to the developer to honestly declare the costs of terms**. diff --git a/docs/root/contracts/examples.rst b/docs/root/contracts/examples.rst index 3c7cc92..0bd3e6a 100644 --- a/docs/root/contracts/examples.rst +++ b/docs/root/contracts/examples.rst @@ -6,6 +6,37 @@ Examples .. role:: fsharp(code) :language: fsharp +.. role:: bash(code) + :language: bash + +Preliminary Notes +----------------- + +To **verify** the following examples use: + +.. code-block:: none + + zebra -v Filename.fst + +To **elaborate** and verify the elaborated result use: + +.. code-block:: none + + zebra -e Filename.fst + +The elaborated file will appear withing the :bash:`output` subdirectory of your current directory. + +In order for most of the examples to work you need to add the following lines at the beginning of your code: + +.. code-block:: fsharp + + open Zen.Cost + + let main txSkeleton _ _ _ _ _ _ _ = Zen.ContractResult.ofTxSkel txSkeleton + + let cf _ _ _ _ _ _ _ = ret #nat 4 + + Simple Example -------------- @@ -27,8 +58,8 @@ That's because function application (:fsharp:`f x`) has a cost of 1, which is em However - trying to compile this function will result in a typing error - because you can only apply :fsharp:`inc` on a value of a :fsharp:`cost` type. -To fix it we modify the function to use :fsharp:`ret` on the result, and we change the type signature to return a :fsharp:`cost` type -(with a cost of 0 since that is the cost :fsharp:`ret` gives): +To fix it we modify the function to use :fsharp:`ret` on the result, to lift it into the :fsharp:`cost` monad, +and we change the type signature to return a :fsharp:`cost` type (with a cost of 0 since that is the cost :fsharp:`ret` gives): .. code-block:: fsharp @@ -52,7 +83,7 @@ Now the compilation would **still fail** with a typing error: That's because while the declared cost is 0, the **inferred** cost (due to the addition of :fsharp:`inc 2`) is 2. -To fix that we now have to declare the **correct** cost within the type, to account for the increment: +To fix that we now have to declare the **correct** cost within the type, to account for the increment, so :fsharp:`cost b 0` becomes :fsharp:`cost b 2`: .. code-block:: fsharp @@ -65,7 +96,8 @@ Now that the syntactic cost is accounted for the program will compile. Aggregated Syntactic Cost ------------------------- -The following function takes a function :fsharp:`f` and an argument :fsharp:`x` and applies :fsharp:`f` on :fsharp:`x` and then on the result: +The following function takes a function :fsharp:`f` and an argument :fsharp:`x` and applies :fsharp:`f` on :fsharp:`x` +and then applies it again on the result: .. code-block:: fsharp @@ -96,7 +128,7 @@ which will be elaborated as: val applyTwice: #a: Type -> (a -> a) -> a -> cost a 3 let applyTwice #_ f x = inc 3 (ret (f (f x))) -Notice that this time we've participated the increased elaborated cost in advance, so the original code won't compile (since :fsharp:`ret` gives +Notice that this time we've predicted the increased elaborated cost in advance, so the original code won't compile (since :fsharp:`ret` gives a cost of 0) while the elaborated code will (since it will add :fsharp:`inc 3` to account for the costs of all the function applications). In practice - **you won't be able to modify the elaborated code**, since the elaboration is done automatically when activating a contract, @@ -148,6 +180,99 @@ Now to account for the additional cost of **7** we change the declared cost of t The elaborated code will now compile. + +Composition +----------- + +Let's define 2 simple functions on the natural numbers - a function which takes a number and doubles it and a function which adds 7 to a number: + +.. code-block:: fsharp + + val double : nat -> nat + let double x = 2 * x + + val add7 : nat -> nat + let add7 x = x + 7 + +We'll also define a function :fsharp:`foo` which would first double a number and then add 7 to the result, by composing the above functions: + +.. code-block:: fsharp + + val foo : nat -> nat + let foo x = add7 (double x) + +The code will compile just fine, but not the elaboration. + +To pass the elaboration we need to make sure all the functions are costed by lifting the results into the :fsharp:`cost` monad: + +.. code-block:: fsharp + + val double : nat -> cost nat 0 + let double x = ret (2 * x) + + val add7 : nat -> cost nat 0 + let add7 x = ret (x + 7) + +What about :fsharp:`foo`? trying to simply compose :fsharp:`add7` and :fsharp:`double` and lifting the result will now fail to typecheck: + +.. code-block:: fsharp + + val foo : nat -> cost nat 0 + let foo x = ret (add7 (double x)) + +That's because we've changed the return type of the functions, so to compose them we have to use the **bind operator** (:fsharp:`>>=`): + +.. code-block:: fsharp + + val foo : nat -> cost nat 0 + let foo x = ret x >>= double >>= add7 + +Now elaboration would still fail, so we have to account for the syntactic cost as well - let's look at the elaborated code: + +.. code-block:: fsharp + + val double: nat -> cost nat 0 + let double x = (inc 3 (ret (2 * x))) + + val add7: nat -> cost nat 0 + let add7 x = (inc 3 (ret (x + 7))) + + val foo: nat -> cost nat 0 + let foo x = (inc 5 (ret x >>= double >>= add7)) + +By looking at the :fsharp:`inc`s we know that the cost of both :fsharp:`double` and :fsharp:`add7` is 3, so we modify their types +in the original code: + +.. code-block:: fsharp + + val double : nat -> cost nat 3 + let double x = ret (2 * x) + + val add7 : nat -> cost nat 3 + let add7 x = ret (x + 7) + +What is the cost of :fsharp:`foo`? trying to simply give it a cost of 5 will **fail**: + +.. code-block:: fsharp + + val foo: nat -> cost nat 5 + let foo x = (inc 5 (ret x >>= double >>= add7)) + +That's because we now have to take the costs of :fsharp:`double` and :fsharp:`add7` into account as well. + +Recall that the type of the bind operator is: :fsharp:`cost a m -> (a -> cost b n) -> cost b (m+n)`, +so it sums up the costs, which means that's exactly what we have to do. + +Since the cost of :fsharp:`double` is **3**, the cost of :fsharp:`add7` is **3**, and the syntactic cost of :fsharp:`foo` is **5**, +adding them all together gives us a cost of **11**: + +.. code-block:: fsharp + + val foo: nat -> cost nat 11 + let foo x = (inc 5 (ret x >>= double >>= add7)) + +Now the elaborated code will compile. + Recursion --------- From 901abeb3c532a46763f83318c0d771ac7917208b Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Sun, 12 May 2019 18:41:00 +0300 Subject: [PATCH 38/42] added a bit about why the cost of lambdas and applied lets is 0 --- docs/root/contracts/cost.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/root/contracts/cost.rst b/docs/root/contracts/cost.rst index 0dfa593..cbd0fde 100644 --- a/docs/root/contracts/cost.rst +++ b/docs/root/contracts/cost.rst @@ -59,6 +59,16 @@ We use the notation :math:`c\left(M\right)` for the cost of the term :fsharp:`M` - :math:`c\left(\color{black}{ M.F }\right)` - :math:`1 + c\left(\color{black}{M}\right)` +Notice how the cost of both **function abstraction** and **applied let clause** is **0** - +that's because function abstraction is in a **weak head normal form** - it's not evaluated further until +it is applied on an argument, so as far as the execution environment is concerned it is **already a value**, +so it won't be evaluated further; +The cost of applied let clause is **0** as well, since an applied let expression if equivalent to a beta redex +where the argument is itself a lambda (:math:`\textbf{let} \: f \: x = N \: \textbf{in} \: M` is equivalent to +:math:`\left(\lambda f.M\right) \: \left(\lambda x.N\right)`), so it is considered the same; +In both cases the cost of the body of the function is **internalized**, through the use of :fsharp:`inc` +(which would be explained later). + In practice the actual cost (relative to the cost model) is **not computed directly**, instead - the cost is decomposed into 2 components: From a6a3a239913886ef4380fcfbbcfefb6b9980f8fb Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Tue, 11 Jun 2019 16:54:28 +0300 Subject: [PATCH 39/42] began named token tutorial --- docs/index.md | 1 + docs/root/contracts.md | 5 + docs/root/contracts/tutorial.rst | 257 +++++++++++++++++++++++++++++++ 3 files changed, 263 insertions(+) create mode 100644 docs/root/contracts/tutorial.rst diff --git a/docs/index.md b/docs/index.md index 0402536..754374d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -14,3 +14,4 @@ Contents: * [Cost Analysis](root/contracts/cost.html) * [Cost Analysis Examples](root/contracts/examples.html) * [Contract Structure](root/contracts/contract-structure.html) + * [Tutorial](root/contracts/tutorial.html) diff --git a/docs/root/contracts.md b/docs/root/contracts.md index 9c77d8f..65e369e 100644 --- a/docs/root/contracts.md +++ b/docs/root/contracts.md @@ -11,3 +11,8 @@ ## Contract Structure [Contract Structure](contracts/contract-structure.html) + + +## Tutorial + +[Tutorial](contracts/tutorial.html) diff --git a/docs/root/contracts/tutorial.rst b/docs/root/contracts/tutorial.rst new file mode 100644 index 0000000..0269a18 --- /dev/null +++ b/docs/root/contracts/tutorial.rst @@ -0,0 +1,257 @@ +Tutorial +======== + +.. highlight:: rst + +.. role:: fsharp(code) + :language: fsharp + +.. role:: bash(code) + :language: bash + +Named Token +----------- + +First we'll learn how to write a very simple contract, +called the "Named Token" contract. +The contract simply mints a token with an identifier specified by the issuer, +and locks the specified amount of the token to the specified return address. + +Let's specify the contract. + +First - the issuer executes the contract, giving it the following data: + +.. list-table:: + :header-rows: 0 + + * - 1. **name** + - :fsharp:`: Zen.Types.lock` + - The name of the issued token + * - 2. **amount** + - :fsharp:`: uint64` + - The issed amount of the token + * - 3. **returnAddress** + - :fsharp:`: string` + - The recipient of the token + +Then - the contract mints the specified amount of the token using the given name as a subidentifier, +and locks it to the specified return address. + +The whole process looks like this: + +.. math:: + + \begin{array}{ccc} + \text{Issuer} & \xrightarrow[\left\langle \text{name},\:\text{amount},\:\text{returnAddress}\right\rangle ]{} & \text{Contract}\\ + \\ + \text{Contract} & \xrightarrow{\left[\text{name}\right]\times\text{amount}} & \text{returnAddress} + \end{array} + +Let's write the contract. + +Create a text file called *"NamedToken.fst"*, the *"fst"* suffix is the standard suffix for **F\*** files. + +At the top of the file put the module name - it should be identical to the file name (excluding the suffix): + +.. code-block:: fsharp + + module NamedToken + +We should also load (using the :fsharp:`open` directive) a couple of useful modules (:fsharp:`Zen.Base`, :fsharp:`Zen.Cost`, and :fsharp:`Zen.Data`) +into the namespace, which we'll use later on. + +The file should now look like this: + +.. code-block:: fsharp + + module NamedToken + + open Zen.Base + open Zen.Cost + open Zen.Data + +Each contract should have at least 2 top-level functions: :fsharp:`main`, and :fsharp:`cf`. + +The :fsharp:`main` function is the function which runs with each execution of the contract, +and :fsharp:`cf` function is the function which describes the cost of the :fsharp:`main` function. + +Let's write the :fsharp:`main` function, it should always have the following type signature: + +.. code-block:: fsharp + + main + ( txSkel : Zen.Types.txSkeleton ) + ( context : Zen.Types.context ) + ( contractId : Zen.Types.contractId ) + ( command : string ) + ( sender : Zen.Types.sender ) + ( messageBody : option Zen.Types.data ) + ( wallet : Zen.Types.wallet ) + ( state : option Zen.Types.data ) + : Zen.Types.contractResult `Zen.Cost.t` n + +where :fsharp:`n` is the cost of the function and equal to :fsharp:`cf txSkel context contractId command sender messageBody wallet state`. + +In practice we usually don't actually have to specify the times of the parameters, as they would be inferred by the compiler. + +It should look like this: + +.. code-block:: fsharp + + let main txSkel context contractId command sender messageBody wallet state = + +We haven't supplied the body of the function yet, which should go below that line. + +The first thing we need to do is to parse the data - to extract the name, amount, and return address out of it. + +The data should be sent to the contract through the :fsharp:`messageBody` parameter, in the form of a dictionary, +which will contain the specified data as *(key,value)* pairs, where each key corresponds to one of the specified fields +(**"name"**, **"amount"**, and **"returnAddress"**). + +Since we assume :fsharp:`messageBody` is a dictionary, we need to try to extract a dictionary out of it - +this is is done with the :fsharp:`tryDict` function, defined in :fsharp:`Zen.Data`. + +The :fsharp:`tryDict` function has the following type signature: + +.. code-block:: fsharp + + tryDict: data -> option (Dict.t data) `cost` 4 + +Recall that the :fsharp:`data` type is a discriminated union of the following: + +.. code-block:: fsharp + + type data = + | I64 of I64.t + | Byte of U8.t + | ByteArray: A.t U8.t -> data + | U32 of U32.t + | U64 of U64.t + | String of string + | Hash of hash + | Lock of lock + | Signature of signature + | PublicKey of publicKey + | Collection of dataCollection + + and dataCollection = + | Array of A.t data + | Dict of dictionary data + | List of list data + +So what :fsharp:`tryDict` does, is taking a value of type :fsharp:`data`, and if that value is a :fsharp:`Collection(Dict(d))` +- it returns :fsharp:`Some d`, and otherwise it returns :fsharp:`None`. + +Now - since the :fsharp:`messageBody` is already an :fsharp:`option data`, we can't apply :fsharp:`tryDict` on it directly +(since it expects a :fsharp:`data`), so instead we use the :fsharp:`(>!=)` operator from :fsharp:`Zen.Data` which have the following +type signature: + +.. code-block:: fsharp + + (>!=) : option a -> (a -> cost (option b) n) -> cost (option b) n + +The dictionary extraction should look like this: + +.. code-block:: fsharp + + messageBody >!= tryDict + +Let's name the result as :fsharp:`dict`, using a :fsharp:`let` expression, so the :fsharp:`main` function should now look like this: + +.. code-block:: fsharp + + let main txSkel context contractId command sender messageBody wallet state = + + let dict = messageBody >!= tryDict in + +Now :fsharp:`dict` will either contain a :fsharp:`Some d` (where :fsharp:`d` is a dictionary) or :fsharp:`None`. + +Now that we have the dictionary, let's extract the required fields out of it, using the :fsharp:`tryFind` function (from :fsharp:`Zen.Dictionary`). + +The :fsharp:`tryFind` function has the following type signature: + +.. code-block:: fsharp + + tryFind : string -> dictionary a -> option a `cost` 64 + +It takes a key name as an argument, and a dictionary, and if that dictionary has a value with the specified key name it returns it +(within a :fsharp:`Some`), and otherwise returns :fsharp:`None`. + +Since :fsharp:`dict` is an ``option (dictionary data) `cost` 64`` we can't use :fsharp:`tryFind` on it directly, +so we'll use the :fsharp:`(>?=)` operator (defined in :fsharp:`Zen.Data`) instead. + +The :fsharp:`(>?=)` operator has the following type signature: + +.. code-block:: fsharp + + (>?=) : option a `cost` m -> (a -> option b `cost` n) -> option b `cost` (m+n) + +To extract the value of the **"returnAddress"** key, we'll do: + +.. code-block:: fsharp + + dict + >?= Zen.Dictionary.tryFind "returnAddress" + +(notice we use the full qualified name here, since we didn't load the :fsharp:`Zen.Dictionary` module into the namespace +with the :fsharp:`open` directive) + +This will give us a (costed) :fsharp:`option data` value; +to extract an actual lock out of that value we'll use the :fsharp:`tryLock` function (defined in :fsharp:`Zen.Data`): + +.. code-block:: fsharp + + dict + >?= Zen.Dictionary.tryFind "returnAddress" + >?= tryLock + +Let's give a name to the extracted lock, using a :fsharp:`let!` expression. + +.. code-block:: fsharp + + let! returnAddress = + dict + >?= Zen.Dictionary.tryFind "returnAddress" + >?= tryLock + in + +Now the whole :fsharp:`main` function should look like this: + +.. code-block:: fsharp + + let main txSkeleton context contractId command sender messageBody wallet state = + + let dict = messageBody >!= tryDict in + + let! returnAddress = + dict + >?= Zen.Dictionary.tryFind "returnAddress" + >?= tryLock + in + +To extract the **"amount"** and **"name"** keys we'll do something similar +(using the :fsharp:`tryU64` and :fsharp:`tryString`, respectively, instead of :fsharp:`tryLock`): + +.. code-block:: fsharp + + let main txSkeleton context contractId command sender messageBody wallet state = + + let dict = messageBody >!= tryDict in + + let! returnAddress = + dict + >?= Zen.Dictionary.tryFind "returnAddress" + >?= tryLock + in + + let! amount = + dict + >?= Zen.Dictionary.tryFind "amount" + >?= tryU64 + in + + let! name = + dict + >?= Zen.Dictionary.tryFind "name" + >?= tryString + in From 024f19564db1444b81f5e14532d57f981765eb31 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Wed, 12 Jun 2019 15:35:14 +0300 Subject: [PATCH 40/42] finished named token tutorial --- docs/root/contracts/tutorial.rst | 320 ++++++++++++++++++++++++++++++- 1 file changed, 316 insertions(+), 4 deletions(-) diff --git a/docs/root/contracts/tutorial.rst b/docs/root/contracts/tutorial.rst index 0269a18..79af0c2 100644 --- a/docs/root/contracts/tutorial.rst +++ b/docs/root/contracts/tutorial.rst @@ -90,7 +90,8 @@ Let's write the :fsharp:`main` function, it should always have the following typ ( state : option Zen.Types.data ) : Zen.Types.contractResult `Zen.Cost.t` n -where :fsharp:`n` is the cost of the function and equal to :fsharp:`cf txSkel context contractId command sender messageBody wallet state`. +where :fsharp:`n` is the cost of the function and equal to :fsharp:`cf txSkel context command sender messageBody wallet state` +(notice that :fsharp:`cf` doesn't take the :fsharp:`contractId` as an argument, since the cost shouldn't depend on it). In practice we usually don't actually have to specify the times of the parameters, as they would be inferred by the compiler. @@ -215,11 +216,14 @@ Let's give a name to the extracted lock, using a :fsharp:`let!` expression. >?= tryLock in +The :fsharp:`let!` usage strips the cost out of the declared variable (using the cost monad), so it would be easier to work with - +the type of :fsharp:`returnAddress` will be :fsharp:`option lock`, instead of ``option lock `cost` m``. + Now the whole :fsharp:`main` function should look like this: .. code-block:: fsharp - let main txSkeleton context contractId command sender messageBody wallet state = + let main txSkel context contractId command sender messageBody wallet state = let dict = messageBody >!= tryDict in @@ -230,11 +234,11 @@ Now the whole :fsharp:`main` function should look like this: in To extract the **"amount"** and **"name"** keys we'll do something similar -(using the :fsharp:`tryU64` and :fsharp:`tryString`, respectively, instead of :fsharp:`tryLock`): +(using :fsharp:`tryU64` and :fsharp:`tryString`, respectively, instead of :fsharp:`tryLock`): .. code-block:: fsharp - let main txSkeleton context contractId command sender messageBody wallet state = + let main txSkel context contractId command sender messageBody wallet state = let dict = messageBody >!= tryDict in @@ -255,3 +259,311 @@ To extract the **"amount"** and **"name"** keys we'll do something similar >?= Zen.Dictionary.tryFind "name" >?= tryString in + +Now that we have all of the data, we can use it assuming everything was provided by the issuer. + +To consider both the case where the issuer has provided everything and the case where there is missing information, +we pattern match on the data, like this: + +.. code-block:: fsharp + + match returnAddress,amount,name with + | Some returnAddress, Some amount, Some name -> + ... + | _ -> + ... + +The 1st case will be executed when all the data was provided, and the 2nd case will be executed if any of the required parameters wasn't provided. + +Let's throw an error when some of the parameters are missing. + +.. code-block:: fsharp + + match returnAddress,amount,name with + | Some returnAddress, Some amount, Some name -> + ... + | _ -> + Zen.ResultT.autoFailw "parameters are missing" + +The function :fsharp:`autoFailw` in :fsharp:`Zen.ResultT` throws an error (within a :fsharp:`ResultT`) and infers the cost automatically. + +If all the parameters were provided - we need to check that the provided name of the token is at most 32 characters, because that's the +maximum size an asset subidentifier can have. + +If the name is longer than 32 characters - we throw an error: + +.. code-block:: fsharp + + match returnAddress,amount,name with + | Some returnAddress, Some amount, Some name -> + if FStar.String.length name <= 32 then + ... + else + Zen.ResultT.autoFailw "name is too long" + | _ -> + Zen.ResultT.autoFailw "parameters are missing" + +If the name is short enough to fit as an asset subidentifier - we can define a token with the give name as a subidentifier and the +contract ID of this contract as the main identifier (using the :fsharp:`fromSubtypeString` function from :fsharp:`Zen.Asset`): + +.. code-block:: fsharp + + match returnAddress,amount,name with + | Some returnAddress, Some amount, Some name -> + if FStar.String.length name <= 32 then + begin + let! token = Zen.Asset.fromSubtypeString contractId name in + ... + end + else + Zen.ResultT.autoFailw "name is too long" + | _ -> + Zen.ResultT.autoFailw "parameters are missing" + +(Note that we're use :fsharp:`begin` and :fsharp:`end` here instead of parentheses, to make the code cleaner) + +Now that we have defined the named token - we **mint** the specified amount of it, +and then **lock** the minted tokens to the specified return address - +this is done by modifying the supplied transaction (:fsharp:`txSkel`) with :fsharp:`mint`, +and then modifying the result with :fsharp:`lockToAddress` (both are defined in :fsharp:`Zen.TxSkeleton`): + +.. code-block:: fsharp + + match returnAddress,amount,name with + | Some returnAddress, Some amount, Some name -> + if FStar.String.length name <= 32 then + begin + let! token = Zen.Asset.fromSubtypeString contractId name in + + let! txSkel = + Zen.TxSkeleton.mint amount token txSkel + >>= Zen.TxSkeleton.lockToAddress token amount returnAddress in + + ... + end + else + Zen.ResultT.autoFailw "name is too long" + | _ -> + Zen.ResultT.autoFailw "parameters are missing" + +Notice the syntax we're using here - both :fsharp:`mint` and :fsharp:`lockToAddress` return a costed :fsharp:`txSkeleton`, +so to chain them we're using the :fsharp:`(>>=)` operator (bind) of the cost monad, and then we name the result using a +:fsharp:`let!` so we can use it as a "pure" :fsharp:`txSkeleton` (instead of a **costed** :fsharp:`txSkeleton`). + +Now that we've prepared the transaction - all that is left is to return it (using :fsharp:`ofTxSkel` from :fsharp:`Zen.ContractResult`), +and the contract is done: + +.. code-block:: fsharp + + match returnAddress,amount,name with + | Some returnAddress, Some amount, Some name -> + if FStar.String.length name <= 32 then + begin + let! token = Zen.Asset.fromSubtypeString contractId name in + + let! txSkel = + Zen.TxSkeleton.mint amount token txSkel + >>= Zen.TxSkeleton.lockToAddress token amount returnAddress in + + Zen.ContractResult.ofTxSkel txSkel + end + else + Zen.ResultT.autoFailw "name is too long" + | _ -> + Zen.ResultT.autoFailw "parameters are missing" + +The whole file should now look like this: + +.. code-block:: fsharp + + module NamedToken + + open Zen.Base + open Zen.Cost + open Zen.Data + + let main txSkel context contractId command sender messageBody wallet state = + + let dict = messageBody >!= tryDict in + + let! returnAddress = + dict + >?= Zen.Dictionary.tryFind "returnAddress" + >?= tryLock + in + + let! amount = + dict + >?= Zen.Dictionary.tryFind "amount" + >?= tryU64 + in + + let! name = + dict + >?= Zen.Dictionary.tryFind "name" + >?= tryString + in + + match returnAddress,amount,name with + | Some returnAddress, Some amount, Some name -> + if FStar.String.length name <= 32 then + begin + let! token = Zen.Asset.fromSubtypeString contractId name in + + let! txSkel = + Zen.TxSkeleton.mint amount token txSkel + >>= Zen.TxSkeleton.lockToAddress token amount returnAddress in + + Zen.ContractResult.ofTxSkel txSkel + end + else + Zen.ResultT.autoFailw "name is too long" + | _ -> + Zen.ResultT.autoFailw "parameters are missing" + +Now we can verify the validity of this file with: + +.. code-block:: bash + + zebra -v NamedToken.fst + +It should verify successfully, returning: + +.. code-block:: bash + + > zebra -v NamedToken.fst + SDK: Verified + +But hold on - **we aren't done yet!** + +We have finished with the :fsharp:`main` function, but we still need to define the :fsharp:`cf` function. + +The type signature of :fsharp:`cf` is: + +.. code-block:: fsharp + + cf + ( txSkel : Zen.Types.txSkeleton ) + ( context : Zen.Types.context ) + ( command : string ) + ( sender : Zen.Types.sender ) + ( messageBody : option Zen.Types.data ) + ( wallet : Zen.Types.wallet ) + ( state : option Zen.Types.data ) + : nat `cost` n + +So we should add the :fsharp:`cf` function to the end of the file, like this: + +.. code-block:: fsharp + + let cf txSkel context command sender messageBody wallet state = + +To start - let's give assign it to :fsharp:`0` and then lift it into the cost monad with :fsharp:`Zen.Cost.ret`: + +.. code-block:: fsharp + + let cf txSkel context command sender messageBody wallet state = + 0 + |> Zen.Cost.ret + +Let's try to **elaborate** the contract, to make sure the cost is correct. + +.. code-block:: bash + + zebra -e NamedToken.fst + +You should get the following error: + +.. code-block:: bash + + (Error 19) Subtyping check failed; expected type + _: Zen.Types.Realized.txSkeleton -> + context: Zen.Types.Main.context -> + command: Prims.string -> + _: Zen.Types.Main.sender -> + messageBody: FStar.Pervasives.Native.option Zen.Types.Data.data -> + _: Zen.Types.Realized.wallet -> + state: FStar.Pervasives.Native.option Zen.Types.Data.data -> + Prims.Tot (Zen.Cost.Realized.cost Prims.nat (0 + 2)); got type + txSkel: Zen.Types.Realized.txSkeleton -> + context: Zen.Types.Main.context -> + command: Prims.string -> + sender: Zen.Types.Main.sender -> + messageBody: FStar.Pervasives.Native.option Zen.Types.Data.data -> + wallet: Zen.Types.Realized.wallet -> + state: FStar.Pervasives.Native.option Zen.Types.Data.data -> + Prims.Tot (Zen.Cost.Realized.cost Prims.int (0 + 2)) + +Notice how it infers that :fsharp:`cf` returns an :fsharp:`int`, while it should return a :fsharp:`nat`. + +To solve it we need to **cast** the value of :fsharp:`cf` into a :fsharp:`nat`, using the :fsharp:`cast` function: + +.. code-block:: fsharp + + let cf txSkel context command sender messageBody wallet state = + 0 + |> cast nat + |> Zen.Cost.ret + +Let's elaborate it again, now we get the following error: + +.. code-block:: bash + + (Error 19) Subtyping check failed; expected type + txSkel: Zen.Types.Realized.txSkeleton -> + context: Zen.Types.Main.context -> + _: Zen.Types.Extracted.contractId -> + command: Prims.string -> + sender: Zen.Types.Main.sender -> + messageBody: FStar.Pervasives.Native.option Zen.Types.Data.data -> + wallet: Zen.Types.Realized.wallet -> + state: FStar.Pervasives.Native.option Zen.Types.Data.data -> + Prims.Tot + (Zen.Cost.Realized.cost Zen.Types.Main.contractResult + (Zen.Cost.Realized.force (CostFunc?.f (Zen.Types.Main.CostFunc NamedToken.cf) + txSkel + context + command + sender + messageBody + wallet + state))); got type + txSkel: Zen.Types.Realized.txSkeleton -> + context: Zen.Types.Main.context -> + contractId: Zen.Types.Extracted.contractId -> + command: Prims.string -> + sender: Zen.Types.Main.sender -> + messageBody: FStar.Pervasives.Native.option Zen.Types.Data.data -> + wallet: Zen.Types.Realized.wallet -> + state: FStar.Pervasives.Native.option Zen.Types.Data.data -> + Prims.Tot + (Zen.Cost.Realized.cost Zen.Types.Main.contractResult + (4 + 64 + 2 + (4 + 64 + 2 + (4 + 64 + 2 + (64 + (64 + 64 + 3)))) + 54)) + +Look at the number at the bottom - this is the cost that was **inferred** by the compiler, +so let's try to paste it into the function: + +.. code-block:: fsharp + + let cf txSkel context command sender messageBody wallet state = + (4 + 64 + 2 + (4 + 64 + 2 + (4 + 64 + 2 + (64 + (64 + 64 + 3)))) + 54) + |> cast nat + |> Zen.Cost.ret + +Let's try to elaborate again: + +.. code-block:: bash + + > zebra -e NamedToken.fst + SDK: Elaborating NamedToken.fst ... + SDK: Wrote elaborated source to NamedToken.fst + SDK: Verified + +**Congratulations!** + +You have written, elaborated, and verified your very first contract. + +This time we were lucky - we didn't have to explicitly type our terms and the code was simple enough for the compiler to infer its cost. + +With more complex contracts it might not be so easy - in many cases you'll have to explicitly type your terms to convince the compiler +that the cost of the contract is what you claim it is. From 7a9d06c83b481a1298a10def04ee37418d144b0c Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Wed, 12 Jun 2019 17:26:25 +0300 Subject: [PATCH 41/42] tutorial: ellipsis, typos, and grammar --- docs/root/contracts/tutorial.rst | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/docs/root/contracts/tutorial.rst b/docs/root/contracts/tutorial.rst index 79af0c2..6636a70 100644 --- a/docs/root/contracts/tutorial.rst +++ b/docs/root/contracts/tutorial.rst @@ -25,13 +25,13 @@ First - the issuer executes the contract, giving it the following data: :header-rows: 0 * - 1. **name** - - :fsharp:`: Zen.Types.lock` + - :fsharp:`: string` - The name of the issued token * - 2. **amount** - :fsharp:`: uint64` - The issed amount of the token * - 3. **returnAddress** - - :fsharp:`: string` + - :fsharp:`: Zen.Types.lock` - The recipient of the token Then - the contract mints the specified amount of the token using the given name as a subidentifier, @@ -93,20 +93,21 @@ Let's write the :fsharp:`main` function, it should always have the following typ where :fsharp:`n` is the cost of the function and equal to :fsharp:`cf txSkel context command sender messageBody wallet state` (notice that :fsharp:`cf` doesn't take the :fsharp:`contractId` as an argument, since the cost shouldn't depend on it). -In practice we usually don't actually have to specify the times of the parameters, as they would be inferred by the compiler. +In practice we usually don't actually have to specify the types of the parameters, as they would be inferred by the compiler. It should look like this: .. code-block:: fsharp let main txSkel context contractId command sender messageBody wallet state = + ... -We haven't supplied the body of the function yet, which should go below that line. +We haven't supplied the body of the function yet, which should go below that line (instead of the ellipsis). The first thing we need to do is to parse the data - to extract the name, amount, and return address out of it. The data should be sent to the contract through the :fsharp:`messageBody` parameter, in the form of a dictionary, -which will contain the specified data as *(key,value)* pairs, where each key corresponds to one of the specified fields +which will contain the specified data as *(key, value)* pairs, where each key corresponds to one of the specified fields (**"name"**, **"amount"**, and **"returnAddress"**). Since we assume :fsharp:`messageBody` is a dictionary, we need to try to extract a dictionary out of it - @@ -165,7 +166,9 @@ Let's name the result as :fsharp:`dict`, using a :fsharp:`let` expression, so th let dict = messageBody >!= tryDict in -Now :fsharp:`dict` will either contain a :fsharp:`Some d` (where :fsharp:`d` is a dictionary) or :fsharp:`None`. + ... + +:fsharp:`dict` will either contain a :fsharp:`Some d` (where :fsharp:`d` is a dictionary) or :fsharp:`None`. Now that we have the dictionary, let's extract the required fields out of it, using the :fsharp:`tryFind` function (from :fsharp:`Zen.Dictionary`). @@ -233,6 +236,8 @@ Now the whole :fsharp:`main` function should look like this: >?= tryLock in + ... + To extract the **"amount"** and **"name"** keys we'll do something similar (using :fsharp:`tryU64` and :fsharp:`tryString`, respectively, instead of :fsharp:`tryLock`): @@ -260,6 +265,8 @@ To extract the **"amount"** and **"name"** keys we'll do something similar >?= tryString in + ... + Now that we have all of the data, we can use it assuming everything was provided by the issuer. To consider both the case where the issuer has provided everything and the case where there is missing information, @@ -303,7 +310,12 @@ If the name is longer than 32 characters - we throw an error: | _ -> Zen.ResultT.autoFailw "parameters are missing" -If the name is short enough to fit as an asset subidentifier - we can define a token with the give name as a subidentifier and the +In Zen Protocol assets are defined by 2 parts: + + 1. Main Identifier - The contract ID of the contract which have minted the asset. + 2. Subidentifier - The unique ID of the asset, given by 32 bytes. + +If the name is short enough to fit as an asset subidentifier - we can define a token with the given name as the subidentifier and the contract ID of this contract as the main identifier (using the :fsharp:`fromSubtypeString` function from :fsharp:`Zen.Asset`): .. code-block:: fsharp @@ -320,7 +332,7 @@ contract ID of this contract as the main identifier (using the :fsharp:`fromSubt | _ -> Zen.ResultT.autoFailw "parameters are missing" -(Note that we're use :fsharp:`begin` and :fsharp:`end` here instead of parentheses, to make the code cleaner) +(Notice that we're using :fsharp:`begin` and :fsharp:`end` here instead of parentheses, to make the code cleaner) Now that we have defined the named token - we **mint** the specified amount of it, and then **lock** the minted tokens to the specified return address - From f8f66196d9fc9a72527c80a5b257064a95b6dc92 Mon Sep 17 00:00:00 2001 From: arielzenprotocol Date: Wed, 12 Jun 2019 18:35:06 +0300 Subject: [PATCH 42/42] named token tutorial - more typos --- docs/root/contracts/tutorial.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/root/contracts/tutorial.rst b/docs/root/contracts/tutorial.rst index 6636a70..c1ea848 100644 --- a/docs/root/contracts/tutorial.rst +++ b/docs/root/contracts/tutorial.rst @@ -470,7 +470,7 @@ So we should add the :fsharp:`cf` function to the end of the file, like this: let cf txSkel context command sender messageBody wallet state = -To start - let's give assign it to :fsharp:`0` and then lift it into the cost monad with :fsharp:`Zen.Cost.ret`: +To start - let's give it to the value of :fsharp:`0` and then lift it into the cost monad with :fsharp:`Zen.Cost.ret`: .. code-block:: fsharp