├── .DS_Store ├── README.md ├── custom_theme ├── __init__.py ├── base.html ├── content.html ├── css │ ├── base.css │ ├── bootstrap-docs.css │ ├── bootstrap.min.css │ ├── font-awesome.min.css │ └── theme.css ├── fonts │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ └── fontawesome-webfont.woff ├── github-nav-item.html ├── header.html ├── images │ ├── .DS_Store │ └── logo │ │ ├── opencan.ai │ │ ├── opencan.png │ │ └── opencan.svg ├── js │ ├── base.js │ └── bootstrap.min.js ├── keyboard-modal.html ├── main.html ├── mkdocs_theme.yml ├── nav-toggle.html ├── nav.html ├── search-modal.html ├── secondary-nav.html ├── toc.html └── twitter-nav-item.html ├── docs ├── .DS_Store ├── Cycles.md ├── ICIP-1.md ├── ICIP-20.md ├── ICIP-721.md ├── Sudograph.md ├── fungible-tokens.md ├── getting-started.md ├── img │ ├── DIP20Init.png │ ├── create-ic-app.gif │ ├── deployCanister.png │ ├── dfinity-logo.svg │ ├── example.png │ ├── opencantrailer.mp4 │ ├── setup.png │ └── sudograph.png ├── index.md ├── learn.md ├── motoko-token.md └── non-fungible-tokens.md └── mkdocs.yml /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCan-io/opencan/7f224bad5e2a7fdbace3df012ad7713efac4ec9c/.DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Installation 2 | 3 | To install MkDocs, run the following command from the command line: 4 | 5 | mac 6 | ```bash 7 | brew install mkdocs 8 | ``` 9 | 10 | linux 11 | ```bash 12 | pip install mkdocs 13 | ``` 14 | 15 | theme 16 | ```bash 17 | pip install mkdocs-material 18 | ``` 19 | 20 | run locally 21 | ```bash 22 | mkdocs serve 23 | ``` 24 | -------------------------------------------------------------------------------- /custom_theme/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCan-io/opencan/7f224bad5e2a7fdbace3df012ad7713efac4ec9c/custom_theme/__init__.py -------------------------------------------------------------------------------- /custom_theme/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 10 | {%- block site_meta %} 11 | 12 | 13 | 14 | {% if page and page.is_homepage %}{% endif %} 15 | {% if config.site_author %}{% endif %} 16 | {% if page and page.canonical_url %}{% endif %} 17 | {% if config.site_favicon %} 18 | {% else %}{% endif %} 19 | {%- endblock %} 20 | 21 | {%- block htmltitle %} 22 |TEXT
*/
14 | /* and currently .bd-example gets this treatment */
15 | /* but i'm applying now to any block */ 16 | pre { 17 | position:relative; 18 | padding:1rem; 19 | margin:1rem -.75rem 0; 20 | border:solid #dee2e6; 21 | border-width:1px 0 0; 22 | } 23 | @media (min-width: 576px) { 24 | pre { 25 | padding:1.5rem; 26 | margin-right:0; 27 | margin-left:0; 28 | border-width:1px; 29 | border-top-left-radius:.25rem; 30 | border-top-right-radius:.25rem; 31 | } 32 | } 33 | /* *************************** */ 34 | 35 | a.navbar-brand img { 36 | width: 100px; 37 | } 38 | .metadata{ 39 | list-style:none; 40 | padding:0; 41 | margin:0; 42 | margin-bottom: 15px; 43 | color: #999; 44 | font-size:0.85em; 45 | } 46 | .last-updated-holder { 47 | float: left; 48 | margin-right: 20px; 49 | } 50 | .metadata.page-metadata .last-updated-text, 51 | .metadata.page-metadata .contributors-text{ 52 | margin-right:5px 53 | } 54 | body[dir=rtl] .metadata.page-metadata .last-updated-text, 55 | body[dir=rtl] .metadata.page-metadata .contributors-text{ 56 | margin-right:0; 57 | margin-left:5px 58 | } 59 | .page-metadata .contributors{ 60 | display:inline-block; 61 | list-style:none; 62 | margin:0!important; 63 | padding:0!important 64 | } 65 | .page-metadata .contributors li{ 66 | display:inline-block; 67 | vertical-align:top; 68 | margin:0; 69 | padding:0 70 | } 71 | .page-metadata .contributors li img{ 72 | border-radius:100%; 73 | height:16px; 74 | /* margin-top:5px;*/ 75 | margin-top:-3px; 76 | overflow:hidden; 77 | width:16px 78 | } 79 | 80 | #content { 81 | padding-top: 80px; 82 | } 83 | 84 | .has-jumbotron #content { 85 | padding-top: 0px; 86 | } 87 | .jumbotron { 88 | margin-top: 30px; 89 | padding-top: 1.5rem; 90 | padding-bottom: 1rem; 91 | } 92 | .card-deck { 93 | margin-bottom: 20px; 94 | } 95 | .sticky-offset { 96 | top: 75px; 97 | } 98 | 99 | ul.nav li.main { 100 | font-weight: bold; 101 | } 102 | 103 | .dropdown-submenu{ 104 | position: relative; 105 | } 106 | .dropdown-submenu a::after{ 107 | transform: rotate(-90deg); 108 | position: absolute; 109 | right: 3px; 110 | top: 40%; 111 | } 112 | .dropdown-submenu .dropdown-menu { 113 | display: none !important; 114 | } 115 | .dropdown-submenu:hover .dropdown-menu,.dropdown-submenu:focus .dropdown-menu{ 116 | display: flex !important; 117 | flex-direction: column; 118 | position: absolute !important; 119 | margin-top: -30px; 120 | left: 100%; 121 | } 122 | @media (max-width: 992px) { 123 | .dropdown-menu{ 124 | width: 50%; 125 | } 126 | .dropdown-menu .dropdown-submenu{ 127 | width: auto; 128 | } 129 | } 130 | .btn:visited { 131 | color: white; 132 | } 133 | /* 134 | h1[id]:before, h2[id]:before, h3[id]:before, h4[id]:before, h5[id]:before, h6[id]:before { 135 | content: ""; 136 | display: block; 137 | margin-top: -75px; 138 | height: 75px; 139 | } 140 | div.col-md-9 { 141 | padding-bottom: 100px; 142 | } 143 | 144 | div.source-links { 145 | float: right; 146 | } 147 | 148 | div.col-md-9 img { 149 | max-width: 100%; 150 | } 151 | */ 152 | 153 | /* 154 | * Side navigation 155 | * 156 | * Scrollspy and affixed enhanced navigation to highlight sections and secondary 157 | * sections of docs content. 158 | */ 159 | 160 | /* By default it's not affixed in mobile views, so undo that */ 161 | .bs-sidebar.affix { 162 | /* position: static;*/ 163 | } 164 | 165 | .bs-sidebar.well { 166 | padding: 0; 167 | } 168 | 169 | /* First level of nav */ 170 | .bs-sidenav { 171 | margin-top: 0px; 172 | margin-bottom: 0px; 173 | padding-top: 10px; 174 | padding-bottom: 10px; 175 | border-radius: 5px; 176 | } 177 | 178 | /* All levels of nav */ 179 | .bs-sidebar .nav > li > a { 180 | display: block; 181 | padding: 5px 20px; 182 | z-index: 1; 183 | } 184 | .bs-sidebar .nav > li > a:hover, 185 | .bs-sidebar .nav > li > a:focus { 186 | text-decoration: none; 187 | border-right: 1px solid; 188 | } 189 | .bs-sidebar .nav > .active > a, 190 | .bs-sidebar .nav > .active:hover > a, 191 | .bs-sidebar .nav > .active:focus > a { 192 | font-weight: bold; 193 | background-color: transparent; 194 | border-right: 1px solid; 195 | } 196 | 197 | /* Nav: second level (shown on .active) */ 198 | .bs-sidebar .nav .nav { 199 | display: none; /* Hide by default, but at >768px, show it */ 200 | margin-bottom: 8px; 201 | } 202 | .bs-sidebar .nav .nav > li > a { 203 | padding-top: 3px; 204 | padding-bottom: 3px; 205 | padding-left: 30px; 206 | font-size: 90%; 207 | } 208 | 209 | /* Show and affix the side nav when space allows it */ 210 | @media (min-width: 992px) { 211 | .bs-sidebar .nav > .active > ul { 212 | display: block; 213 | } 214 | /* Widen the fixed sidebar */ 215 | .bs-sidebar.affix, 216 | .bs-sidebar.affix-bottom { 217 | width: 213px; 218 | } 219 | .bs-sidebar.affix { 220 | /*position: fixed;*/ /* Undo the static from mobile first approach */ 221 | top: 80px; 222 | } 223 | .bs-sidebar.affix-bottom { 224 | /*position: absolute;*/ /* Undo the static from mobile first approach */ 225 | } 226 | .bs-sidebar.affix-bottom .bs-sidenav, 227 | .bs-sidebar.affix .bs-sidenav { 228 | margin-top: 0; 229 | margin-bottom: 0; 230 | } 231 | } 232 | @media (min-width: 1200px) { 233 | /* Widen the fixed sidebar again */ 234 | .bs-sidebar.affix-bottom, 235 | .bs-sidebar.affix { 236 | width: 263px; 237 | } 238 | } 239 | 240 | img { 241 | height: auto; 242 | width: auto; 243 | transition: transform ease-in-out 0.3s; 244 | } 245 | 246 | img[src*="#shadow"] { 247 | box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); 248 | } 249 | 250 | img:active[src*="#zoom"] { 251 | cursor: zoom-out; 252 | transform: scale(2.0); 253 | } 254 | 255 | img[src*="#zoom"] { 256 | cursor: zoom-in; 257 | } 258 | 259 | img[src*="#center"] { 260 | display: block; 261 | margin-left: auto; 262 | margin-right: auto; 263 | } 264 | 265 | img[src*="#no-border"] { 266 | border: 0px; 267 | width: 200px; 268 | } 269 | 270 | a.md-logo img { 271 | border: none; 272 | } -------------------------------------------------------------------------------- /custom_theme/css/bootstrap-docs.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Docs (https://getbootstrap.com/) 3 | * Copyright 2011-2021 The Bootstrap Authors 4 | * Copyright 2011-2021 Twitter, Inc. 5 | * Licensed under the Creative Commons Attribution 3.0 Unported License. 6 | * For details, see https://creativecommons.org/licenses/by/3.0/. 7 | */.bd-navbar{padding:.75rem 0;background-color:#002338;}.bd-navbar .navbar-toggler{padding:0;border:0}.bd-navbar .navbar-nav .nav-link{padding-right:.25rem;padding-left:.25rem;color:rgba(255,255,255,0.85)}.bd-navbar .navbar-nav .nav-link:hover,.bd-navbar .navbar-nav .nav-link:focus{color:#fff}.bd-navbar .navbar-nav .nav-link.active{font-weight:600;color:#fff}.bd-navbar .navbar-nav-svg{width:1rem;height:1rem}.bd-subnavbar{position:relative;z-index:1020;background-color:rgba(255,255,255,0.95);box-shadow:0 0.5rem 1rem rgba(0,0,0,0.05),inset 0 -1px 0 rgba(0,0,0,0.15)}.bd-subnavbar .dropdown-menu{font-size:.875rem;box-shadow:0 0.5rem 1rem rgba(0,0,0,0.05)}.bd-subnavbar .dropdown-item.current{font-weight:600;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23292b2c' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right 1rem top 0.6rem;background-size:.75rem .75rem}@media (min-width: 768px){.bd-subnavbar{position:-webkit-sticky;position:sticky;top:0}}.bd-search{position:relative}.bd-search::after{position:absolute;top:.4rem;right:.4rem;display:flex;align-items:center;justify-content:center;height:1.5rem;padding-right:.25rem;padding-left:.25rem;font-size:.75rem;color:#6c757d;border:1px solid #dee2e6;border-radius:.125rem}@media (max-width: 767.98px){.bd-search{width:100%}}.bd-search .form-control{padding-right:3.75rem}.bd-search .form-control:focus{border-color:#7952b3;box-shadow:0 0 0 3px rgba(121,82,179,0.25)}.bd-sidebar-toggle{color:#6c757d}.bd-sidebar-toggle:hover,.bd-sidebar-toggle:focus{color:#7952b3}.bd-sidebar-toggle:focus{box-shadow:0 0 0 3px rgba(121,82,179,0.25)}.bd-sidebar-toggle .bi-collapse{display:none}.bd-sidebar-toggle:not(.collapsed) .bi-expand{display:none}.bd-sidebar-toggle:not(.collapsed) .bi-collapse{display:inline-block}.bd-masthead{padding:3rem 0;background:linear-gradient(165deg, #f7f5fb 50%, #fff 50%)}.bd-masthead h1{font-size:calc(1.525rem + 3.3vw);line-height:1}@media (min-width: 1200px){.bd-masthead h1{font-size:4rem}}.bd-masthead p:not(.lead){color:#495057}.bd-masthead .btn{padding:.8rem 2rem;font-weight:600}.bd-masthead .lead{font-size:calc(1.275rem + .3vw);font-weight:400;color:#495057}@media (min-width: 1200px){.bd-masthead .lead{font-size:1.5rem}}@media (min-width: 768px){.mw-md-75{max-width:75%}}.masthead-followup-icon{padding:.75rem;background-image:linear-gradient(to bottom right, rgba(255,255,255,0.2), rgba(255,255,255,0.01));border-radius:.75rem;box-shadow:0 0.125rem 0.25rem rgba(0,0,0,0.1)}.masthead-followup-svg{filter:drop-shadow(0 1px 0 rgba(0,0,0,0.125))}#carbonads{position:static;display:block;max-width:400px;padding:15px 15px 15px 160px;margin:2rem 0;overflow:hidden;font-size:.8125rem;line-height:1.4;text-align:left;background-color:rgba(0,0,0,0.05)}#carbonads a{color:#343a40;text-decoration:none}@media (min-width: 576px){#carbonads{max-width:330px;border-radius:4px}}.carbon-img{float:left;margin-left:-145px}.carbon-poweredby{display:block;margin-top:.75rem;color:#495057 !important}@media (min-width: 768px){:root{scroll-padding-top:4rem}}.bd-content>h2:not(:first-child){margin-top:3rem}.bd-content>h3{margin-top:2rem}.bd-content>ul li,.bd-content>ol li{margin-bottom:.25rem}.bd-content>ul li>ul,.bd-content>ol li>ul{margin-top:-.5rem;margin-bottom:1rem}.bd-content>.table{max-width:100%;margin-bottom:1.5rem;font-size:.875rem}@media (max-width: 991.98px){.bd-content>.table{display:block;overflow-x:auto}.bd-content>.table.table-bordered{border:0}}.bd-content>.table th:first-child,.bd-content>.table td:first-child{padding-left:0}.bd-content>.table th:not(:last-child),.bd-content>.table td:not(:last-child){padding-right:1.5rem}.bd-content>.table td:first-child>code{white-space:nowrap}.bd-title{font-size:calc(1.425rem + 2.1vw)}@media (min-width: 1200px){.bd-title{font-size:3rem}}.bd-lead{font-size:calc(1.275rem + .3vw);font-weight:300}@media (min-width: 1200px){.bd-lead{font-size:1.5rem}}.bd-text-purple-bright{color:#7952b3}.bd-bg-purple-bright{background-color:#7952b3}.skippy{background-color:#563d7c}.skippy a{color:#fff}@media (max-width: 767.98px){.bd-sidebar{margin:0 -.75rem 1rem}}.bd-links{overflow:auto;font-weight:600}@media (min-width: 768px){.bd-links{position:-webkit-sticky;position:sticky;top:5rem;display:block !important;height:calc(100vh - 7rem);padding-left:.25rem;margin-left:-.25rem;overflow-y:auto}}@media (max-width: 767.98px){.bd-links>ul{padding:1.5rem .75rem;background-color:#f8f9fa;border-bottom:1px solid #e9ecef}}.bd-links a{padding:.1875rem .5rem;margin-top:.125rem;margin-left:1.25rem;color:rgba(0,0,0,0.65);text-decoration:none}.bd-links a:hover,.bd-links a:focus{color:rgba(0,0,0,0.85);background-color:rgba(121,82,179,0.1)}.bd-links .btn{padding:.25rem .5rem;font-weight:600;color:rgba(0,0,0,0.65);background-color:transparent;border:0}.bd-links .btn:hover,.bd-links .btn:focus{color:rgba(0,0,0,0.85);background-color:rgba(121,82,179,0.1)}.bd-links .btn:focus{box-shadow:0 0 0 1px rgba(121,82,179,0.7)}.bd-links .btn::before{width:1.25em;line-height:0;content:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='rgba%280,0,0,.5%29' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 14l6-6-6-6'/%3e%3c/svg%3e");transition:transform 0.35s ease;transform-origin:.5em 50%}@media (prefers-reduced-motion: reduce){.bd-links .btn::before{transition:none}}.bd-links .btn[aria-expanded="true"]{color:rgba(0,0,0,0.85)}.bd-links .btn[aria-expanded="true"]::before{transform:rotate(90deg)}.bd-links .active{font-weight:600;color:rgba(0,0,0,0.85)}@media (min-width: 768px){.bd-layout{display:grid;gap:1.5rem;grid-template-areas:"sidebar main";grid-template-columns:1fr 3fr}}@media (min-width: 992px){.bd-layout{grid-template-columns:1fr 5fr}}.bd-sidebar{grid-area:sidebar}.bd-main{grid-area:main}@media (min-width: 768px){.bd-main{display:grid;gap:inherit;grid-template-areas:"intro" "toc" "content";grid-template-rows:auto auto 1fr}}@media (min-width: 992px){.bd-main{grid-template-areas:"intro toc" "content toc";grid-template-columns:4fr 1fr;grid-template-rows:auto 1fr}}.bd-intro{grid-area:intro}.bd-toc{grid-area:toc}.bd-content{grid-area:content;min-width:1px}@media (min-width: 992px){.bd-toc{position:-webkit-sticky;position:sticky;top:5rem;right:0;z-index:2;height:calc(100vh - 7rem);overflow-y:auto}}.bd-toc nav{font-size:.875rem}.bd-toc nav ul{padding-left:0;list-style:none}.bd-toc nav ul ul{padding-left:1rem;margin-top:.25rem}.bd-toc nav li{margin-bottom:.25rem}.bd-toc nav a{color:inherit}.bd-toc nav a:not(:hover){text-decoration:none}.bd-toc nav a code{font:inherit}.bd-footer a{color:#495057;text-decoration:none}.bd-footer a:hover,.bd-footer a:focus{color:#0d6efd;text-decoration:underline}.bd-example-row .row>.col,.bd-example-row .row>[class^="col-"]{padding-top:.75rem;padding-bottom:.75rem;background-color:rgba(39,41,43,0.03);border:1px solid rgba(39,41,43,0.1)}.bd-example-row .row+.row{margin-top:1rem}.bd-example-row-flex-cols .row{min-height:10rem;background-color:rgba(255,0,0,0.1)}.bd-highlight{background-color:rgba(86,61,124,0.15);border:1px solid rgba(86,61,124,0.15)}.example-container{width:800px;width:100%;padding-right:var(--bs-gutter-x, .75rem);padding-left:var(--bs-gutter-x, .75rem);margin-right:auto;margin-left:auto}.example-row{--bs-gutter-x: 1.5rem;--bs-gutter-y: 0;display:flex;flex-wrap:wrap;margin-top:calc(var(--bs-gutter-y) * -1);margin-right:calc(var(--bs-gutter-x) / -2);margin-left:calc(var(--bs-gutter-x) / -2)}.example-content-main{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) / 2);padding-left:calc(var(--bs-gutter-x) / 2);margin-top:var(--bs-gutter-y)}@media (min-width: 576px){.example-content-main{flex:0 0 auto;width:50%}}@media (min-width: 992px){.example-content-main{flex:0 0 auto;width:66.666667%}}.example-content-secondary{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) / 2);padding-left:calc(var(--bs-gutter-x) / 2);margin-top:var(--bs-gutter-y)}@media (min-width: 576px){.example-content-secondary{flex:0 0 auto;width:50%}}@media (min-width: 992px){.example-content-secondary{flex:0 0 auto;width:33.333333%}}.bd-example{position:relative;padding:1rem;margin:1rem -.75rem 0;border:solid #dee2e6;border-width:1px 0 0}.bd-example::after{display:block;clear:both;content:""}@media (min-width: 576px){.bd-example{padding:1.5rem;margin-right:0;margin-left:0;border-width:1px;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.bd-example+.bd-clipboard+.highlight{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}}.bd-example+p{margin-top:2rem}.bd-example>.form-control+.form-control{margin-top:.5rem}.bd-example>.nav+.nav,.bd-example>.alert+.alert,.bd-example>.navbar+.navbar,.bd-example>.progress+.progress{margin-top:1rem}.bd-example>.dropdown-menu{position:static;display:block}.bd-example>:last-child{margin-bottom:0}.bd-example>svg+svg,.bd-example>img+img{margin-left:.5rem}.bd-example>.btn,.bd-example>.btn-group{margin:.25rem .125rem}.bd-example>.btn-toolbar+.btn-toolbar{margin-top:.5rem}.bd-example>.list-group{max-width:400px}.bd-example>[class*="list-group-horizontal"]{max-width:100%}.bd-example .fixed-top,.bd-example .sticky-top{position:static;margin:-1rem -1rem 1rem}.bd-example .fixed-bottom{position:static;margin:1rem -1rem -1rem}@media (min-width: 576px){.bd-example .fixed-top,.bd-example .sticky-top{margin:-1.5rem -1.5rem 1rem}.bd-example .fixed-bottom{margin:1rem -1.5rem -1.5rem}}.bd-example .pagination{margin-top:.5rem;margin-bottom:.5rem}.bd-example-ratios .ratio{display:inline-block;width:10rem;color:#6c757d;background-color:#f8f9fa;border:1px solid #dee2e6}.bd-example-ratios .ratio>div{display:flex;align-items:center;justify-content:center}.bd-example-ratios-breakpoint .ratio-4x3{width:16rem}@media (min-width: 768px){.bd-example-ratios-breakpoint .ratio-4x3{--bs-aspect-ratio: 50%}}.bd-example-modal{background-color:#fafafa}.bd-example-modal .modal{position:static;display:block}.bd-example-offcanvas{border-top-left-radius:0;border-bottom-left-radius:0}.bd-example-offcanvas .offcanvas{position:static;display:block;height:200px;visibility:visible;transform:translate(0)}.tooltip-demo a{white-space:nowrap}.scrollspy-example{position:relative;height:200px;margin-top:.5rem;overflow:auto}.scrollspy-example-2{position:relative;height:350px;overflow:auto}.bd-example-border-utils [class^="border"]{display:inline-block;width:5rem;height:5rem;margin:.25rem;background-color:#f5f5f5}.bd-example-border-utils-0 [class^="border"]{border:1px solid #dee2e6}.bd-example-rounded-utils [class*="rounded"]{margin:.25rem}.bd-example-position-utils{position:relative;padding:3em}.bd-example-position-utils .position-relative{height:200px;background-color:#f5f5f5}.bd-example-position-utils .position-absolute{width:2em;height:2em;background-color:#212529;border-radius:.25rem}.bd-example-position-examples::after{content:none}.bd-example-toasts{min-height:240px}.highlight{padding:1rem;margin-bottom:1rem;background-color:#f8f9fa}@media (min-width: 576px){.highlight{padding:1rem 1.5rem}}.highlight pre{padding:0;margin-top:.65rem;margin-bottom:.65rem;white-space:pre;background-color:transparent;border:0}.highlight pre code{font-size:inherit;color:#212529;word-wrap:normal}.bd-content .highlight{margin-right:-.75rem;margin-left:-.75rem}@media (min-width: 576px){.bd-content .highlight{margin-right:0;margin-left:0}}.btn-bd-primary{font-weight:600;color:#fff;background-color:#7952b3;border-color:#7952b3}.btn-bd-primary:hover,.btn-bd-primary:active{color:#fff;background-color:#61428f;border-color:#61428f}.btn-bd-primary:focus{box-shadow:0 0 0 3px rgba(121,82,179,0.25)}.btn-bd-download{font-weight:600;color:#ffe484;border-color:#ffe484}.btn-bd-download:hover,.btn-bd-download:active{color:#2a2730;background-color:#ffe484;border-color:#ffe484}.btn-bd-download:focus{box-shadow:0 0 0 3px rgba(255,228,132,0.25)}.btn-bd-light{color:#6c757d;border-color:#dee2e6}.show>.btn-bd-light,.btn-bd-light:hover,.btn-bd-light:active{color:#7952b3;background-color:#fff;border-color:#7952b3}.btn-bd-light:focus{box-shadow:0 0 0 3px rgba(121,82,179,0.25)}.bd-callout{padding:1.25rem;margin-top:1.25rem;margin-bottom:1.25rem;border:1px solid #e9ecef;border-left-width:.25rem;border-radius:.25rem}.bd-callout h4{margin-bottom:.25rem}.bd-callout p:last-child{margin-bottom:0}.bd-callout code{border-radius:.25rem}.bd-callout+.bd-callout{margin-top:-.25rem}.bd-callout-info{border-left-color:#5bc0de}.bd-callout-warning{border-left-color:#f0ad4e}.bd-callout-danger{border-left-color:#d9534f}.bd-brand-logos{color:#7952b3}.bd-brand-logos .inverse{color:#fff;background-color:#7952b3}.bd-brand-item+.bd-brand-item{border-top:1px solid #fff}@media (min-width: 768px){.bd-brand-item+.bd-brand-item{border-top:0;border-left:1px solid #fff}}.color-swatches{margin:0 -5px}.color-swatches .bd-purple{background-color:#563d7c}.color-swatches .bd-purple-light{background-color:#cbbde2}.color-swatches .bd-purple-lighter{background-color:#e5e1ea}.color-swatches .bd-gray{background-color:#f9f9f9}.color-swatch{width:4rem;height:4rem}@media (min-width: 768px){.color-swatch{width:6rem;height:6rem}}.swatch-blue{color:#fff;background-color:#0d6efd}.swatch-blue::after{position:absolute;top:1rem;right:1rem;padding-left:1rem;font-size:.75rem;line-height:1.35;white-space:pre;content:"4.50" "\a" "4.50" "\a" "4.66";background-color:#0d6efd;background-image:linear-gradient(to bottom, transparent 0.25rem, #fff 0.25rem 0.75rem, transparent 0.75rem 1.25rem, #fff 1.25rem 1.75rem, transparent 1.75rem 2.25rem, #000 2.25rem 2.75rem, transparent 2.75rem);background-repeat:no-repeat;background-size:.5rem 100%}.swatch-indigo{color:#fff;background-color:#6610f2}.swatch-indigo::after{position:absolute;top:1rem;right:1rem;padding-left:1rem;font-size:.75rem;line-height:1.35;white-space:pre;content:"7.18" "\a" "7.18" "\a" "2.92";background-color:#6610f2;background-image:linear-gradient(to bottom, transparent 0.25rem, #fff 0.25rem 0.75rem, transparent 0.75rem 1.25rem, #fff 1.25rem 1.75rem, transparent 1.75rem 2.25rem, #000 2.25rem 2.75rem, transparent 2.75rem);background-repeat:no-repeat;background-size:.5rem 100%}.swatch-purple{color:#fff;background-color:#6f42c1}.swatch-purple::after{position:absolute;top:1rem;right:1rem;padding-left:1rem;font-size:.75rem;line-height:1.35;white-space:pre;content:"6.51" "\a" "6.51" "\a" "3.22";background-color:#6f42c1;background-image:linear-gradient(to bottom, transparent 0.25rem, #fff 0.25rem 0.75rem, transparent 0.75rem 1.25rem, #fff 1.25rem 1.75rem, transparent 1.75rem 2.25rem, #000 2.25rem 2.75rem, transparent 2.75rem);background-repeat:no-repeat;background-size:.5rem 100%}.swatch-pink{color:#fff;background-color:#d63384}.swatch-pink::after{position:absolute;top:1rem;right:1rem;padding-left:1rem;font-size:.75rem;line-height:1.35;white-space:pre;content:"4.50" "\a" "4.50" "\a" "4.66";background-color:#d63384;background-image:linear-gradient(to bottom, transparent 0.25rem, #fff 0.25rem 0.75rem, transparent 0.75rem 1.25rem, #fff 1.25rem 1.75rem, transparent 1.75rem 2.25rem, #000 2.25rem 2.75rem, transparent 2.75rem);background-repeat:no-repeat;background-size:.5rem 100%}.swatch-red{color:#fff;background-color:#dc3545}.swatch-red::after{position:absolute;top:1rem;right:1rem;padding-left:1rem;font-size:.75rem;line-height:1.35;white-space:pre;content:"4.52" "\a" "4.52" "\a" "4.63";background-color:#dc3545;background-image:linear-gradient(to bottom, transparent 0.25rem, #fff 0.25rem 0.75rem, transparent 0.75rem 1.25rem, #fff 1.25rem 1.75rem, transparent 1.75rem 2.25rem, #000 2.25rem 2.75rem, transparent 2.75rem);background-repeat:no-repeat;background-size:.5rem 100%}.swatch-orange{color:#000;background-color:#fd7e14}.swatch-orange::after{position:absolute;top:1rem;right:1rem;padding-left:1rem;font-size:.75rem;line-height:1.35;white-space:pre;content:"8.17" "\a" "2.57" "\a" "8.17";background-color:#fd7e14;background-image:linear-gradient(to bottom, transparent 0.25rem, #000 0.25rem 0.75rem, transparent 0.75rem 1.25rem, #fff 1.25rem 1.75rem, transparent 1.75rem 2.25rem, #000 2.25rem 2.75rem, transparent 2.75rem);background-repeat:no-repeat;background-size:.5rem 100%}.swatch-yellow{color:#000;background-color:#ffc107}.swatch-yellow::after{position:absolute;top:1rem;right:1rem;padding-left:1rem;font-size:.75rem;line-height:1.35;white-space:pre;content:"12.8" "\a" "1.63" "\a" "12.8";background-color:#ffc107;background-image:linear-gradient(to bottom, transparent 0.25rem, #000 0.25rem 0.75rem, transparent 0.75rem 1.25rem, #fff 1.25rem 1.75rem, transparent 1.75rem 2.25rem, #000 2.25rem 2.75rem, transparent 2.75rem);background-repeat:no-repeat;background-size:.5rem 100%}.swatch-green{color:#fff;background-color:#198754}.swatch-green::after{position:absolute;top:1rem;right:1rem;padding-left:1rem;font-size:.75rem;line-height:1.35;white-space:pre;content:"4.53" "\a" "4.53" "\a" "4.63";background-color:#198754;background-image:linear-gradient(to bottom, transparent 0.25rem, #fff 0.25rem 0.75rem, transparent 0.75rem 1.25rem, #fff 1.25rem 1.75rem, transparent 1.75rem 2.25rem, #000 2.25rem 2.75rem, transparent 2.75rem);background-repeat:no-repeat;background-size:.5rem 100%}.swatch-teal{color:#000;background-color:#20c997}.swatch-teal::after{position:absolute;top:1rem;right:1rem;padding-left:1rem;font-size:.75rem;line-height:1.35;white-space:pre;content:"9.86" "\a" "2.12" "\a" "9.86";background-color:#20c997;background-image:linear-gradient(to bottom, transparent 0.25rem, #000 0.25rem 0.75rem, transparent 0.75rem 1.25rem, #fff 1.25rem 1.75rem, transparent 1.75rem 2.25rem, #000 2.25rem 2.75rem, transparent 2.75rem);background-repeat:no-repeat;background-size:.5rem 100%}.swatch-cyan{color:#000;background-color:#0dcaf0}.swatch-cyan::after{position:absolute;top:1rem;right:1rem;padding-left:1rem;font-size:.75rem;line-height:1.35;white-space:pre;content:"10.7" "\a" "1.95" "\a" "10.7";background-color:#0dcaf0;background-image:linear-gradient(to bottom, transparent 0.25rem, #000 0.25rem 0.75rem, transparent 0.75rem 1.25rem, #fff 1.25rem 1.75rem, transparent 1.75rem 2.25rem, #000 2.25rem 2.75rem, transparent 2.75rem);background-repeat:no-repeat;background-size:.5rem 100%}.swatch-white{color:#000;background-color:#fff}.swatch-white::after{position:absolute;top:1rem;right:1rem;padding-left:1rem;font-size:.75rem;line-height:1.35;white-space:pre;content:"21" "\a" "1" "\a" "21";background-color:#fff;background-image:linear-gradient(to bottom, transparent 0.25rem, #000 0.25rem 0.75rem, transparent 0.75rem 1.25rem, #fff 1.25rem 1.75rem, transparent 1.75rem 2.25rem, #000 2.25rem 2.75rem, transparent 2.75rem);background-repeat:no-repeat;background-size:.5rem 100%}.swatch-gray{color:#fff;background-color:#6c757d}.swatch-gray::after{position:absolute;top:1rem;right:1rem;padding-left:1rem;font-size:.75rem;line-height:1.35;white-space:pre;content:"4.68" "\a" "4.68" "\a" "4.47";background-color:#6c757d;background-image:linear-gradient(to bottom, transparent 0.25rem, #fff 0.25rem 0.75rem, transparent 0.75rem 1.25rem, #fff 1.25rem 1.75rem, transparent 1.75rem 2.25rem, #000 2.25rem 2.75rem, transparent 2.75rem);background-repeat:no-repeat;background-size:.5rem 100%}.swatch-gray-dark{color:#fff;background-color:#343a40}.swatch-gray-dark::after{position:absolute;top:1rem;right:1rem;padding-left:1rem;font-size:.75rem;line-height:1.35;white-space:pre;content:"11.5" "\a" "11.5" "\a" "1.82";background-color:#343a40;background-image:linear-gradient(to bottom, transparent 0.25rem, #fff 0.25rem 0.75rem, transparent 0.75rem 1.25rem, #fff 1.25rem 1.75rem, transparent 1.75rem 2.25rem, #000 2.25rem 2.75rem, transparent 2.75rem);background-repeat:no-repeat;background-size:.5rem 100%}.swatch-gray-500{color:#000;background-color:#adb5bd}.swatch-gray-500::after{position:absolute;top:1rem;right:1rem;padding-left:1rem;font-size:.75rem;line-height:1.35;white-space:pre;content:"10.1" "\a" "2.07" "\a" "10.1";background-color:#adb5bd;background-image:linear-gradient(to bottom, transparent 0.25rem, #000 0.25rem 0.75rem, transparent 0.75rem 1.25rem, #fff 1.25rem 1.75rem, transparent 1.75rem 2.25rem, #000 2.25rem 2.75rem, transparent 2.75rem);background-repeat:no-repeat;background-size:.5rem 100%}.bd-blue-100{color:#000;background-color:#cfe2ff}.bd-blue-200{color:#000;background-color:#9ec5fe}.bd-blue-300{color:#000;background-color:#6ea8fe}.bd-blue-400{color:#000;background-color:#3d8bfd}.bd-blue-500{color:#fff;background-color:#0d6efd}.bd-blue-600{color:#fff;background-color:#0a58ca}.bd-blue-700{color:#fff;background-color:#084298}.bd-blue-800{color:#fff;background-color:#052c65}.bd-blue-900{color:#fff;background-color:#031633}.bd-indigo-100{color:#000;background-color:#e0cffc}.bd-indigo-200{color:#000;background-color:#c29ffa}.bd-indigo-300{color:#000;background-color:#a370f7}.bd-indigo-400{color:#fff;background-color:#8540f5}.bd-indigo-500{color:#fff;background-color:#6610f2}.bd-indigo-600{color:#fff;background-color:#520dc2}.bd-indigo-700{color:#fff;background-color:#3d0a91}.bd-indigo-800{color:#fff;background-color:#290661}.bd-indigo-900{color:#fff;background-color:#140330}.bd-purple-100{color:#000;background-color:#e2d9f3}.bd-purple-200{color:#000;background-color:#c5b3e6}.bd-purple-300{color:#000;background-color:#a98eda}.bd-purple-400{color:#000;background-color:#8c68cd}.bd-purple-500{color:#fff;background-color:#6f42c1}.bd-purple-600{color:#fff;background-color:#59359a}.bd-purple-700{color:#fff;background-color:#432874}.bd-purple-800{color:#fff;background-color:#2c1a4d}.bd-purple-900{color:#fff;background-color:#160d27}.bd-pink-100{color:#000;background-color:#f7d6e6}.bd-pink-200{color:#000;background-color:#efadce}.bd-pink-300{color:#000;background-color:#e685b5}.bd-pink-400{color:#000;background-color:#de5c9d}.bd-pink-500{color:#fff;background-color:#d63384}.bd-pink-600{color:#fff;background-color:#ab296a}.bd-pink-700{color:#fff;background-color:#801f4f}.bd-pink-800{color:#fff;background-color:#561435}.bd-pink-900{color:#fff;background-color:#2b0a1a}.bd-red-100{color:#000;background-color:#f8d7da}.bd-red-200{color:#000;background-color:#f1aeb5}.bd-red-300{color:#000;background-color:#ea868f}.bd-red-400{color:#000;background-color:#e35d6a}.bd-red-500{color:#fff;background-color:#dc3545}.bd-red-600{color:#fff;background-color:#b02a37}.bd-red-700{color:#fff;background-color:#842029}.bd-red-800{color:#fff;background-color:#58151c}.bd-red-900{color:#fff;background-color:#2c0b0e}.bd-orange-100{color:#000;background-color:#ffe5d0}.bd-orange-200{color:#000;background-color:#fecba1}.bd-orange-300{color:#000;background-color:#feb272}.bd-orange-400{color:#000;background-color:#fd9843}.bd-orange-500{color:#000;background-color:#fd7e14}.bd-orange-600{color:#000;background-color:#ca6510}.bd-orange-700{color:#fff;background-color:#984c0c}.bd-orange-800{color:#fff;background-color:#653208}.bd-orange-900{color:#fff;background-color:#331904}.bd-yellow-100{color:#000;background-color:#fff3cd}.bd-yellow-200{color:#000;background-color:#ffe69c}.bd-yellow-300{color:#000;background-color:#ffda6a}.bd-yellow-400{color:#000;background-color:#ffcd39}.bd-yellow-500{color:#000;background-color:#ffc107}.bd-yellow-600{color:#000;background-color:#cc9a06}.bd-yellow-700{color:#000;background-color:#997404}.bd-yellow-800{color:#fff;background-color:#664d03}.bd-yellow-900{color:#fff;background-color:#332701}.bd-green-100{color:#000;background-color:#d1e7dd}.bd-green-200{color:#000;background-color:#a3cfbb}.bd-green-300{color:#000;background-color:#75b798}.bd-green-400{color:#000;background-color:#479f76}.bd-green-500{color:#fff;background-color:#198754}.bd-green-600{color:#fff;background-color:#146c43}.bd-green-700{color:#fff;background-color:#0f5132}.bd-green-800{color:#fff;background-color:#0a3622}.bd-green-900{color:#fff;background-color:#051b11}.bd-teal-100{color:#000;background-color:#d2f4ea}.bd-teal-200{color:#000;background-color:#a6e9d5}.bd-teal-300{color:#000;background-color:#79dfc1}.bd-teal-400{color:#000;background-color:#4dd4ac}.bd-teal-500{color:#000;background-color:#20c997}.bd-teal-600{color:#000;background-color:#1aa179}.bd-teal-700{color:#fff;background-color:#13795b}.bd-teal-800{color:#fff;background-color:#0d503c}.bd-teal-900{color:#fff;background-color:#06281e}.bd-cyan-100{color:#000;background-color:#cff4fc}.bd-cyan-200{color:#000;background-color:#9eeaf9}.bd-cyan-300{color:#000;background-color:#6edff6}.bd-cyan-400{color:#000;background-color:#3dd5f3}.bd-cyan-500{color:#000;background-color:#0dcaf0}.bd-cyan-600{color:#000;background-color:#0aa2c0}.bd-cyan-700{color:#fff;background-color:#087990}.bd-cyan-800{color:#fff;background-color:#055160}.bd-cyan-900{color:#fff;background-color:#032830}.bd-gray-100{color:#000;background-color:#f8f9fa}.bd-gray-200{color:#000;background-color:#e9ecef}.bd-gray-300{color:#000;background-color:#dee2e6}.bd-gray-400{color:#000;background-color:#ced4da}.bd-gray-500{color:#000;background-color:#adb5bd}.bd-gray-600{color:#fff;background-color:#6c757d}.bd-gray-700{color:#fff;background-color:#495057}.bd-gray-800{color:#fff;background-color:#343a40}.bd-gray-900{color:#fff;background-color:#212529}.bd-white{color:#000;background-color:#fff}.bd-black{color:#fff;background-color:#000}.bd-clipboard{position:relative;display:none;float:right}.bd-clipboard+.highlight{margin-top:0}@media (min-width: 768px){.bd-clipboard{display:block}}.btn-clipboard{position:absolute;top:.65rem;right:.65rem;z-index:10;display:block;padding:.25rem .5rem;font-size:.65em;color:#0d6efd;background-color:#fff;border:1px solid;border-radius:.25rem}.btn-clipboard:hover,.btn-clipboard:focus{color:#fff;background-color:#0d6efd}.bd-placeholder-img{font-size:1.125rem;text-anchor:middle;-webkit-user-select:none;-moz-user-select:none;user-select:none}.bd-placeholder-img-lg{font-size:calc(1.475rem + 2.7vw)}@media (min-width: 1200px){.bd-placeholder-img-lg{font-size:3.5rem}}.chroma .c{color:#727272}.chroma .ch{font-style:italic;color:#60a0b0}.chroma .cm{color:#727272}.chroma .cp{color:#008085}.chroma .cpf{color:#007020}.chroma .c1{color:#727272}.chroma .cs{color:#727272}.chroma .gd{background-color:#fcc;border:1px solid #c00}.chroma .ge{font-style:italic}.chroma .gr{color:#f00}.chroma .gh{color:#030}.chroma .gi{background-color:#cfc;border:1px solid #0c0}.chroma .go{color:#aaa}.chroma .gp{color:#009}.chroma .gs{font-weight:700}.chroma .gu{color:#030}.chroma .gt{color:#9c6}.chroma .gl{text-decoration:underline}.chroma .k{color:#069}.chroma .kc{color:#069}.chroma .kd{color:#069}.chroma .kn{color:#069}.chroma .kp{color:#069}.chroma .kr{color:#069}.chroma .kt{color:#078}.chroma .m{color:#c24f19}.chroma .mb{color:#40a070}.chroma .mf{color:#c24f19}.chroma .mh{color:#c24f19}.chroma .mi{color:#c24f19}.chroma .il{color:#c24f19}.chroma .mo{color:#c24f19}.chroma .s{color:#d73038}.chroma .sa{color:#4070a0}.chroma .sb{color:#c30}.chroma .sc{color:#c30}.chroma .dl{color:#4070a0}.chroma .sd{font-style:italic;color:#c30}.chroma .s2{color:#c30}.chroma .se{color:#c30}.chroma .sh{color:#c30}.chroma .si{color:#a00}.chroma .sx{color:#c30}.chroma .sr{color:#337e7e}.chroma .s1{color:#c30}.chroma .ss{color:#fc3}.chroma .na{color:#006ee0}.chroma .nb{color:#366}.chroma .nc{color:#168174}.chroma .no{color:#360}.chroma .nd{color:#6b62de}.chroma .ni{color:#727272}.chroma .ne{color:#c00}.chroma .nf{color:#b715f4}.chroma .nl{color:#6b62de}.chroma .nn{color:#007ca5}.chroma .nt{color:#2f6f9f}.chroma .nv{color:#033}.chroma .o{color:#555}.chroma .ow{color:#000}.chroma .w{color:#bbb}.chroma .language-bash::before,.chroma .language-sh::before{color:#009;content:"$ ";-webkit-user-select:none;-moz-user-select:none;user-select:none}.chroma .language-powershell::before{color:#009;content:"PM> ";-webkit-user-select:none;-moz-user-select:none;user-select:none}.anchorjs-link{font-weight:400;color:rgba(13,110,253,0.5);transition:color 0.15s ease-in-out}@media (prefers-reduced-motion: reduce){.anchorjs-link{transition:none}}.anchorjs-link:focus,.anchorjs-link:hover{color:#0d6efd;text-decoration:none}.algolia-autocomplete{width:100%}.ds-dropdown-menu{width:100%;padding:.5rem 0;margin:.125rem 0 0;font-size:.875rem;background-color:#fff;border:1px solid rgba(0,0,0,0.15);border-radius:.25rem}@media (min-width: 768px){.ds-dropdown-menu{width:400px}}.algolia-docsearch-suggestion--category-header{padding:.125rem 1rem;font-weight:600;color:#7952b3}:not(.algolia-docsearch-suggestion__main)>.algolia-docsearch-suggestion--category-header{display:none}.ds-suggestion:not(:first-child) .algolia-docsearch-suggestion--category-header{padding-top:.75rem;margin-top:.75rem;border-top:1px solid rgba(0,0,0,0.1)}.algolia-docsearch-suggestion--content{padding:.25rem 1rem}.ds-cursor .algolia-docsearch-suggestion--content{background-color:rgba(203,189,226,0.2)}.algolia-docsearch-suggestion{display:block;text-decoration:none}.algolia-docsearch-suggestion--subcategory-column{display:none}.algolia-docsearch-suggestion--subcategory-inline{display:inline;color:#495057}.algolia-docsearch-suggestion--subcategory-inline::after{padding:0 .25rem;content:"/"}.algolia-docsearch-suggestion--title{display:inline;font-weight:500;color:#343a40}.algolia-docsearch-suggestion--text{color:#343a40;font-size:.75rem}.algolia-docsearch-suggestion--highlight{color:#6f42c1;background-color:rgba(111,66,193,0.1)}.algolia-docsearch-footer{padding:.5rem 1rem 0;margin-top:.625rem;font-size:.75rem;color:#6c757d;border-top:1px solid rgba(0,0,0,0.1)}.algolia-docsearch-footer--logo{color:inherit} 8 | -------------------------------------------------------------------------------- /custom_theme/css/font-awesome.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | @font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.3.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.3.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.3.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.3.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{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;transform:translate(0, 0)}.fa-lg{font-size:1.33333333em;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.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{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{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{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{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:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-genderless:before,.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"} -------------------------------------------------------------------------------- /custom_theme/css/theme.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 1em; 3 | } 4 | 5 | .active a { 6 | color: red; 7 | font-weight: bold; 8 | } 9 | -------------------------------------------------------------------------------- /custom_theme/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCan-io/opencan/7f224bad5e2a7fdbace3df012ad7713efac4ec9c/custom_theme/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /custom_theme/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCan-io/opencan/7f224bad5e2a7fdbace3df012ad7713efac4ec9c/custom_theme/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /custom_theme/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenCan-io/opencan/7f224bad5e2a7fdbace3df012ad7713efac4ec9c/custom_theme/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /custom_theme/github-nav-item.html: -------------------------------------------------------------------------------- 1 |
15 | type Callback = shared () -> async ();
16 |
17 |
18 | An example function that can be included in your canister is as follows:
19 |
20 | public func accept() : async () {
21 | let available = Cycles.available();
22 | let accepted = Cycles.accept(available);
23 | assert (accepted == available);
24 | };
25 |
26 |
27 | This can be submitted to the burn function in the following form:
28 |
29 | //Where ryjl3-tyaaa-aaaaa-aaaba-cai is the principal/canister id of your canister
30 | (func ryjl3-tyaaa-aaaaa-aaaba-cai.accept)
31 |
32 |
33 | ## Testing
34 | We create two canisters, our WIC canister which handles the burning/minting/token logic and a test canister which can receive returned cycles (via burning).
35 |
36 |
37 | //Clean start (if you want)
38 | dfx start --clean --background
39 |
40 | //Set identity if you need to
41 | dfx identity new me && dfx identity use me
42 |
43 | //Deploy all
44 | dfx deploy --all
45 |
46 | //Set WIC Canister ID and test canister
47 | WICCAN=$(dfx canister id wrapped_cycles)
48 | TESTCAN=$(dfx canister id test)
49 |
50 | //Check available cycles in canister and current balance
51 | dfx canister call $WICCAN availableCycles
52 | dfx canister call $WICCAN myBalance
53 |
54 | //Mint some WIC from cycles wallet (1T cycles == 1WIC)
55 | dfx canister --no-wallet call $(dfx identity get-wallet) wallet_call "(record { canister = principal \"$WICCAN\"; method_name = \"mint\"; args = blob \"DIDL\00\00\"; cycles = (1_000_000_000_000:nat64); } )"
56 |
57 | //Check new balance and available cycles (both should have increased by 1T)
58 | dfx canister call $WICCAN myBalance
59 | dfx canister call $WICCAN availableCycles
60 |
61 | //Burn WIC and send to TEST canister.
62 | dfx canister call $TESTCAN availableCycles
63 | dfx canister call $WICCAN burn "(500_000_000_000:nat, (func \"$TESTCAN\".accept))"
64 |
65 | //Check balances again
66 | dfx canister call $WICCAN myBalance
67 | dfx canister call $TESTCAN availableCycles
68 | dfx canister call $WICCAN availableCycles
69 |
70 |
71 | ##Preset Cycles Canister
72 | [Cycles](https://github.com/ALLiDoizCode/wrapped_cycles)
73 |
74 | This canister is ready to deploy without having to write any Motoko code. It can be used as-is for quick prototyping and testing, but is also suitable for production environments.
--------------------------------------------------------------------------------
/docs/ICIP-1.md:
--------------------------------------------------------------------------------
1 | ---
2 | icip: 1
3 | title: Internet Computer Token Standard
4 | status: Draft
5 | type: Financial
6 | author: Norton Wang (@floorlamp)
7 | created: 2020-09-24
8 | ---
9 |
10 | Since official "Internet Computer Improvement Proposals" (ICIPs) do not
11 | exist yet, this document refers to "ICIP-1" for convenience only.
12 |
13 | ## Table Of Contents
14 |
15 | - [Summary](#summary)
16 | - [Motivation](#motivation)
17 | - [Abstract](#abstract)
18 | - [General](#general)
19 | - [Interface Specification](#interface-specification)
20 | - [Entrypoint Semantics](#entrypoint-semantics)
21 | - [`transfer`](#transfer)
22 | - [Core Transfer Behavior](#core-transfer-behavior)
23 | - [Default Transfer Permission Policy](#default-transfer-permission-policy)
24 | - [`getBalance`](#getBalance)
25 | - [Operators](#operators)
26 | - [`updateOperator`](#updateOperator)
27 | - [`isAuthorized`](#isAuthorized)
28 | - [`getMetadata`](#getMetadata)
29 | - [Implementing Different Token Types with ICIP-1](#implementing-different-token-types-with-ICIP-1)
30 | - [Single Fungible Token](#single-fungible-token)
31 | - [Multiple Fungible Tokens](#multiple-fungible-tokens)
32 | - [Non-fungible Tokens](#non-fungible-tokens)
33 | - [Mixing Fungible and Non-fungible Tokens](#mixing-fungible-and-non-fungible-tokens)
34 | - [Non-transferable Tokens](#non-transferable-tokens)
35 | - [Additional Ideas](#additional-ideas)
36 | - [References](#references)
37 | - [Copyright](#copyright)
38 |
39 | ## Summary
40 |
41 | ICIP-1 proposes a standard for a unified token canister interface, supporting a
42 | wide range of token types and implementations. This document provides an
43 | overview and rationale for the interface, token transfer semantics, and support
44 | for various transfer permission policies.
45 |
46 | **PLEASE NOTE:** This API specification is a work-in-progress.
47 |
48 | ## Motivation
49 |
50 | There are multiple dimensions and considerations while implementing a particular
51 | token canister. Tokens might be fungible or non-fungible. A variety of transfer
52 | permission policies can be used to define how many tokens can be transferred,
53 | who can perform a transfer, and who can receive tokens. A token canister can be
54 | designed to support a single token type (e.g. ERC-20 or ERC-721) or multiple
55 | token types (e.g. ERC-1155) to optimize batch transfers and atomic swaps of the
56 | tokens.
57 |
58 | Such considerations can easily lead to the proliferation of many token
59 | standards, each optimized for a particular token type or use case. This
60 | situation is apparent in the Ethereum ecosystem, where many standards have been
61 | proposed, but ERC-20 (fungible tokens) and ERC-721 (non-fungible tokens) are
62 | dominant.
63 |
64 | Token wallets, token exchanges, and other clients then need to support multiple
65 | standards and multiple token APIs. The ICIP-1 standard proposes a unified token
66 | canister interface that accommodates all mentioned concerns. It aims to provide
67 | significant expressivity to canister developers to create new types of tokens
68 | while maintaining a common interface standard for wallet integrators and
69 | external developers.
70 |
71 | ## Abstract
72 |
73 | This standard defines the unified canister interface and its behavior to support
74 | a wide range of token types and implementations. The particular ICIP-1
75 | implementation may support either a single token type per canister or multiple
76 | tokens per canister, including hybrid implementations where multiple token kinds
77 | (fungible, non-fungible, non-transferable etc) are supported.
78 |
79 | All of the entrypoints are batch operations that allow querying or transfer of
80 | multiple token types atomically.
81 |
82 | Most token standards specify logic that validates a transfer transaction and can
83 | either approve or reject a transfer. Such logic could validate who can perform a
84 | transfer, the transfer amount and who can receive tokens. This standard calls
85 | such logic a _transfer permission policy_. The ICIP-1 standard defines the
86 | [default `TransferRequest` permission policy](#default-transfer-permission-policy)
87 | that specify who can transfer tokens. The default policy allows transfers by
88 | either token owner (an principal that holds token balance) or by an operator (an
89 | principal that is permitted to manage tokens on behalf of the token owner).
90 |
91 | Transfer permission policies can be customized.
92 |
93 | This specification defines some standard error variants to be used when
94 | implementing ICIP-1. However, some implementations MAY introduce their custom
95 | errors that MUST follow the same pattern as standard ones.
96 |
97 | ## General
98 |
99 | The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”,
100 | “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be
101 | interpreted as described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt).
102 |
103 | - Tokens are uniquely identified by a pair composed of the token canister ID and
104 | token ID, a natural number (`Nat`). If the underlying canister implementation
105 | supports only a single token type (e.g. ERC-20-like contract), the token ID
106 | MUST be `0n`. In the case when multiple token types are supported within the
107 | same ICIP-1 token canister (e. g. ERC-1155-like contract), the canister is
108 | fully responsible for assigning and managing token IDs.
109 |
110 | - The ICIP-1 batch entrypoints accept a list (batch) of parameters describing a
111 | single operation or a query. The batch MUST NOT be reordered or deduplicated
112 | and MUST be processed in the same order it is received.
113 |
114 | - Empty batch is a valid input and MUST be processed as a non-empty one. For
115 | example, an empty transfer batch will not affect token balances, but
116 | applicable transfer core behavior and permission policy MUST be applied.
117 |
118 | - If the underlying token implementation supports only a single token type, the
119 | batch may contain zero or multiple entries where token ID is a fixed `0n`
120 | value. Likewise, if multiple token types are supported, the batch may contain
121 | zero or more entries and there may be duplicate token IDs.
122 |
123 | - The choice of `Nat32` for a `tokenId` type implies each canister can store
124 | `2**32` individual tokens
125 |
126 | ## Interface Specification
127 |
128 | Token canisters implementing the ICIP-1 standard MUST have the following
129 | entrypoints. Notation is given in
130 | [Motoko](https://sdk.dfinity.org/docs/language-guide/motoko.html). Candid
131 | specifications can be generated as needed.
132 |
133 | ```
134 | type Token = actor {
135 | getBalance: query (requests: [BalanceRequest]) -> async BalanceResponse;
136 |
137 | getMetadata: query (tokenIds: [TokenId]) -> async MetadataResponse;
138 |
139 | transfer: shared (requests: [TransferRequest]) -> async TransferResponse;
140 |
141 | updateOperator: shared (requests: [OperatorRequest]) -> async OperatorResponse;
142 |
143 | isAuthorized: query (requests: [IsAuthorizedRequest]) -> async IsAuthorizedResponse;
144 | };
145 | ```
146 |
147 | ### Entrypoint Semantics
148 |
149 | #### `transfer`
150 |
151 | ```
152 | type User = Principal;
153 |
154 | type TokenId = Nat32;
155 |
156 | type Balance = Nat;
157 |
158 | type TransferRequest = {
159 | from: User;
160 | to: User;
161 | tokenId: TokenId;
162 | amount: Balance;
163 | };
164 |
165 | type TransferResponse = Result.Result<(), {
166 | #Unauthorized;
167 | #InvalidDestination: User;
168 | #InvalidToken: TokenId;
169 | #InsufficientBalance;
170 | }>;
171 |
172 | type transfer = (requests: [TransferRequest]) -> async TransferResponse;
173 | ```
174 |
175 | Each transfer in the batch is specified between one source (`from`) and
176 | destination (`to`) pair. Each `TransferRequest` specifies token ID and the
177 | amount to be transferred from the source principal to the destination principal.
178 |
179 | ICIP-1 does NOT specify an interface for mint and burn operations; however, if
180 | an ICIP-1 token canister implements mint and burn operations, it SHOULD, when
181 | possible, enforce the same logic (core transfer behavior and transfer permission
182 | logic) applied to the token transfer operation. Mint and burn can be considered
183 | special cases of the transfer. Although, it is possible that mint and burn have
184 | more or less restrictive rules than the regular transfer. For instance, mint and
185 | burn operations may be invoked by a special privileged administrative principal
186 | only. In this case, regular operator restrictions may not be applicable.
187 |
188 | ##### Core Transfer Behavior
189 |
190 | ICIP-1 token canisters MUST always implement this behavior.
191 |
192 | - Every batch transfer operation MUST happen atomically and in order. If at
193 | least one transfer in the batch cannot be completed, the whole transaction
194 | MUST fail, all token transfers MUST be reverted, and token balances MUST
195 | remain unchanged.
196 |
197 | - Each transfer in the batch MUST decrement token balance of the source (`from`)
198 | principal by the amount of the transfer and increment token balance of the
199 | destination (`to`) principal by the amount of the transfer.
200 |
201 | - If the transfer amount exceeds current token balance of the source principal,
202 | the whole transfer operation MUST fail with the error variant
203 | `InsufficientBalance`.
204 |
205 | - If the token owner does not hold any tokens of type `tokenId`, the owner's
206 | balance is interpreted as zero. No token owner can have a negative balance.
207 |
208 | - The transfer MUST update token balances exactly as the operation parameters
209 | specify it. Transfer operations MUST NOT try to adjust transfer amounts or try
210 | to add/remove additional transfers like transaction fees.
211 |
212 | - Transfers of zero amount MUST be treated as normal transfers.
213 |
214 | - Transfers with the same principal (`from` equals `to`) MUST be treated as
215 | normal transfers.
216 |
217 | - If one of the specified `tokenId`s is not defined within the ICIP-1 contract,
218 | the entrypoint MUST fail with the error variant `InvalidToken`.
219 |
220 | - Transfer implementations MUST apply transfer permission logic (either
221 | [default transfer permission policy](#default-transfer-permission-policy) or a
222 | custom one). If permission logic rejects a transfer, the whole operation MUST
223 | fail.
224 |
225 | - Core transfer behavior MAY be extended. If additional constraints on tokens
226 | transfer are required, ICIP-1 token canister implementation MAY invoke
227 | additional permission policies. If the additional permission fails, the whole
228 | transfer operation MUST fail with a custom error variant.
229 |
230 | ##### Default Transfer Permission Policy
231 |
232 | - Token owner principal MUST be able to perform a transfer of its own tokens (e.
233 | g. `caller` equals to `from` parameter in the `TransferRequest`).
234 |
235 | - An operator (a principal that performs token transfer operation on behalf of
236 | the owner) MUST be permitted to manage the specified owner's tokens before it
237 | invokes a transfer transaction (see [`updateOperator`](#updateOperator)).
238 |
239 | - If the principal that invokes a transfer operation is neither a token owner
240 | nor one of the permitted operators, the transaction MUST fail with the error
241 | variant `Unauthorized`. If at least one of the `TransferRequest`s in the batch
242 | is not permitted, the whole transaction MUST fail.
243 |
244 | #### `getBalance`
245 |
246 | ```
247 | type BalanceRequest = {
248 | user: User;
249 | tokenId: TokenId
250 | };
251 |
252 | type BalanceResponse = Result.Result<[Balance], {
253 | #InvalidToken: TokenId;
254 | }>;
255 |
256 | type getBalance = query (requests: [BalanceRequest]) -> async BalanceResponse;
257 | ```
258 |
259 | Gets the balance of multiple principal/token pairs. Accepts a list of
260 | `BalanceRequest`s and returns a `BalanceResponse`.
261 |
262 | - There may be duplicate `BalanceRequest`'s, in which case they should not be
263 | deduplicated nor reordered.
264 |
265 | - If the principal does not hold any tokens, the principal balance is
266 | interpreted as zero.
267 |
268 | - If one of the specified `tokenId`s is not defined within the ICIP-1 contract,
269 | the entrypoint MUST fail with the error variant `InvalidToken`.
270 |
271 | #### Operators
272 |
273 | **Owner** is a principal which can hold tokens.
274 |
275 | **Operator** is a principal that originates token transfer operation on behalf
276 | of the owner.
277 |
278 | An operator, other than the owner, CAN be approved to manage specific tokens
279 | held by the owner to transfer them from the owner principal.
280 |
281 | ICIP-1 interface specifies an entrypoint to update operators. Operators are
282 | permitted per specific token owner and token ID (token type). Once permitted, an
283 | operator can transfer tokens of that type belonging to the owner.
284 |
285 | ##### `updateOperator`
286 |
287 | ```
288 | type TokenIds = {
289 | #All;
290 | #Some: (TokenId, ?Balance);
291 | };
292 |
293 | type OperatorAction = {
294 | #SetOperator: TokenIds;
295 | #RemoveOperator: ?[TokenId];
296 | };
297 |
298 | type OperatorRequest = {
299 | owner: User;
300 | operators: [(User, OperatorAction)]
301 | };
302 |
303 | type OperatorResponse = Result.Result<(), {
304 | #Unauthorized;
305 | #InvalidOwner: User;
306 | }>;
307 |
308 | type updateOperator = (requests: [OperatorRequest]) -> async OperatorResponse;
309 | ```
310 |
311 | Update or Remove token operators for the specified token owners, token IDs and balances.
312 |
313 | - The entrypoint accepts a list of `OperatorRequest`s. If two different requests
314 | in the list add and remove an operator for the same token owner and token ID,
315 | the last command in the list MUST take effect.
316 |
317 | - Adding an operator for `#All` token IDs MUST grant permissions to all current
318 | and future tokens owned by the owner for ALL balances. Similarly, removing an operator for
319 | `#All` token IDs MUST remove permissions for all current and future tokens.
320 |
321 | - It is possible to update operators for a token owner that does not hold any
322 | token balances yet.
323 |
324 | - Operator relation is not transitive. If C is an operator of B and if B is an
325 | operator of A, C cannot transfer tokens that are owned by A, on behalf of B.
326 |
327 | The standard does not specify who is permitted to update operators on behalf of
328 | the token owner. Depending on the business use case, the particular
329 | implementation of the ICIP-1 contract MAY limit operator updates to a token
330 | owner (`owner == caller`) or be limited to an administrator. If so, the
331 | `Unauthorized` error variant MUST be used.
332 |
333 | ##### `isAuthorized`
334 |
335 | ```
336 | type IsAuthorizedRequest = {
337 | owner: User;
338 | operator: User;
339 | tokenId: TokenId;
340 | amount: Balance;
341 | };
342 |
343 | type IsAuthorizedResponse = [Bool];
344 |
345 | type isAuthorized = query (requests: [IsAuthorizedRequest]) -> async IsAuthorizedResponse;
346 | ```
347 |
348 | Checks whether the specified `operator` principal is authorized to transfer on
349 | behalf of the `owner` principal the token `tokenId` of `amount`.
350 |
351 | - Results MUST be consistent with authorization checks in `transfer` operations.
352 | If `isAuthorized` returns `True` for a given operator and owner pair, then
353 | that operator must be able perform `transfer`s without receiving an
354 | `Unauthorized` error. Likewise, if `isAuthorized` returns `False`, then that
355 | operator MUST NOT be able to `transfer` and should receive an `Unauthorized`
356 | error.
357 |
358 | ##### `getMetadata`
359 |
360 | ```
361 | type Metadata = Blob;
362 |
363 | type MetadataResponse = Result.Result<[Metadata], {
364 | #InvalidToken: TokenId;
365 | }>;
366 |
367 | type getMetadata = query (tokenIds: [TokenId]) -> async MetadataResponse;
368 | ```
369 |
370 | Returns token metadata for the given `tokenId`s.
371 |
372 | Token metadata is primarily useful in user-facing contexts (e.g. wallets,
373 | explorers, marketplaces). Some attributes that are commonly defined are symbol,
374 | name, description, and decimals. The specification for the metadata format is a
375 | work-in-progress.
376 |
377 | ## Implementing Different Token Types With ICIP-1
378 |
379 | The ICIP-1 interface is designed to support a wide range of token types and
380 | implementations. This section gives examples of how different types of the
381 | ICIP-1 contracts MAY be implemented and what are the expected properties of such
382 | an implementation.
383 |
384 | ### Single Fungible Token
385 |
386 | An ICIP-1 contract represents a single token similar to the ERC-20 standard.
387 |
388 | | Property | Constraints |
389 | | ----------------- | ----------- |
390 | | `tokenId` | Always `0n` |
391 | | transfer amount | Nat |
392 | | principal balance | Nat |
393 |
394 | ### Multiple Fungible Tokens
395 |
396 | An ICIP-1 contract may represent multiple tokens similar to ERC-1155 standard.
397 | The implementation can have a fixed predefined set of supported tokens or tokens
398 | can be created dynamically.
399 |
400 | | Property | Constraints |
401 | | ----------------- | ----------- |
402 | | `tokenId` | Nat |
403 | | transfer amount | Nat |
404 | | principal balance | Nat |
405 |
406 | ### Non-fungible Tokens
407 |
408 | An ICIP-1 contract may represent non-fungible tokens (NFT) similar to ERC-721
409 | standard. For each individual non-fungible token the implementation assigns a
410 | unique `tokenId`. The implementation MAY support either a single kind of NFTs or
411 | multiple kinds. If multiple kinds of NFT is supported, each kind MAY be assigned
412 | a continuous range of natural number (that does not overlap with other ranges)
413 | and have its own associated metadata.
414 |
415 | | Property | Constraints |
416 | | ----------------- | ------------ |
417 | | `tokenId` | Nat |
418 | | transfer amount | `0n` or `1n` |
419 | | principal balance | `0n` or `1n` |
420 |
421 | For any valid `tokenId` only one principal CAN hold the balance of one token
422 | (`1n`). The rest of the principals MUST hold zero balance (`0n`) for that
423 | `tokenId`.
424 |
425 | ### Mixing Fungible and Non-fungible Tokens
426 |
427 | An ICIP-1 contract MAY mix multiple fungible and non-fungible tokens within the
428 | same contract similar to ERC-1155. The implementation MAY chose to select
429 | individual natural numbers to represent `tokenId` for fungible tokens and
430 | continuous natural number ranges to represent `tokenId`s for NFTs.
431 |
432 | | Property | Constraints |
433 | | ----------------- | ------------------------------------------------ |
434 | | `tokenId` | Nat |
435 | | transfer amount | `0n` or `1n` for NFT and Nat for fungible tokens |
436 | | principal balance | `0n` or `1n` for NFT and Nat for fungible tokens |
437 |
438 | ### Non-transferable Tokens
439 |
440 | Either fungible and non-fungible tokens can be non-transferable.
441 | Non-transferable tokens can be represented by the ICIP-1 token that has custom
442 | permission logic. Tokens cannot be transferred either by the token owner or by
443 | any operator. Only privileged operations like mint and burn can assign tokens to
444 | owner principals.
445 |
446 | ## Additional Ideas
447 |
448 | The following are some other features for consideration that could offer more
449 | flexibility and UX improvements.
450 |
451 | - Receiver hooks, for token receivers to perform operations immediately after
452 | receiving tokens
453 | - More detailed transfer permission policies, such as setting a token to only be
454 | transferrable by an operator
455 | - A `Decimal` type instead of `Nat` for balances, removing the complexity of
456 | emulating precision with large exponents
457 |
458 | ## Motoko Types
459 |
460 | ```motoko
461 | import Hash "mo:base/Hash";
462 | import Nat32 "mo:base/Nat32";
463 | import Principal "mo:base/Principal";
464 | import Result "mo:base/Result";
465 | import Word32 "mo:base/Word32";
466 |
467 | // A user can be any principal or canister
468 | type User = Principal;
469 |
470 | // A Nat32 implies each canister can store 2**32 individual tokens
471 | type TokenId = Nat32;
472 |
473 | // Token amounts are unbounded
474 | type Balance = Nat;
475 |
476 | // Details for a token, eg. name, symbol, description, decimals.
477 | // Metadata format TBD, possible option is JSON blob
478 | type Metadata = Blob;
479 | type MetadataResponse = Result.Result<[Metadata], {
480 | #InvalidToken: TokenId;
481 | }>;
482 |
483 | // Request and responses for getBalance
484 | type BalanceRequest = {
485 | user: User;
486 | tokenId: TokenId;
487 | };
488 | type BalanceResponse = Result.Result<[Balance], {
489 | #InvalidToken: TokenId;
490 | }>;
491 |
492 | // Request and responses for transfer
493 | type TransferRequest = {
494 | from: User;
495 | to: User;
496 | tokenId: TokenId;
497 | amount: Balance;
498 | };
499 | type TransferResponse = Result.Result<(), {
500 | #Unauthorized;
501 | #InvalidDestination: User;
502 | #InvalidToken: TokenId;
503 | #InsufficientBalance;
504 | }>;
505 |
506 | // Request and responses for updateOperator
507 | type TokenIds = {
508 | #All;
509 | #Some: (TokenId, ?Balance);
510 | };
511 | type OperatorAction = {
512 | #SetOperator: TokenIds;
513 | #RemoveOperator: ?[TokenId];
514 | };
515 | type OperatorRequest = {
516 | owner: User;
517 | operators: [(User, OperatorAction)];
518 | };
519 | type OperatorResponse = Result.Result<(), {
520 | #Unauthorized;
521 | #InvalidOwner: User;
522 | }>;
523 |
524 | // Request and responses for isAuthorized
525 | type IsAuthorizedRequest = {
526 | owner: User;
527 | operator: User;
528 | tokenId: TokenId;
529 | amount: Balance;
530 | };
531 | type IsAuthorizedResponse = [Bool];
532 |
533 | // Utility functions for User and TokenId, useful when implementing containers
534 | module User = {
535 | public let equal = Principal.equal;
536 | public let hash = Principal.hash;
537 | };
538 |
539 | module TokenId = {
540 | public func equal(id1 : TokenId, id2 : TokenId) : Bool { id1 == id2 };
541 | public func hash(id : TokenId) : Hash.Hash { Word32.fromNat(Nat32.toNat(id)) };
542 | };
543 |
544 | // Uniquely identifies a token
545 | type TokenIdentifier = {
546 | canister: Token;
547 | tokenId: TokenId;
548 | };
549 |
550 | // Utility functions for TokenIdentifier
551 | module TokenIdentifier = {
552 | // Tokens are equal if the canister and tokenId are equal
553 | public func equal(id1 : TokenIdentifier, id2 : TokenIdentifier) : Bool {
554 | Principal.fromActor(id1.canister) == Principal.fromActor(id2.canister)
555 | and id1.tokenId == id2.tokenId
556 | };
557 | // Hash the canister and xor with tokenId
558 | public func hash(id : TokenIdentifier) : Hash.Hash {
559 | Principal.hash(Principal.fromActor(id.canister)) ^ Word32.fromNat(Nat32.toNat(id.tokenId))
560 | };
561 | // Join the principal and id with a '_'
562 | public func toText(id : TokenIdentifier) : Text {
563 | Principal.toText(Principal.fromActor(id.canister)) # "_" # Nat32.toText(id.tokenId)
564 | };
565 | };
566 |
567 | /**
568 | A token canister that can hold many tokens.
569 | */
570 | type Token = actor {
571 | /**
572 | Batch get balances.
573 | Any request with an invalid tokenId should cause the entire batch to fail.
574 | A user that has no token should default to 0.
575 | */
576 | getBalance: query (requests: [BalanceRequest]) -> async BalanceResponse;
577 |
578 | /**
579 | Batch get metadata.
580 | Any request with an invalid tokenId should cause the entire batch to fail.
581 | */
582 | getMetadata: query (tokenIds: [TokenId]) -> async MetadataResponse;
583 |
584 | /**
585 | Batch transfer.
586 | A request should fail if:
587 | - the caller is not authorized to transfer for the sender
588 | - the sender has insufficient balance
589 | Any request that fails should cause the entire batch to fail, and to
590 | rollback to the initial state.
591 | */
592 | transfer: shared (requests: [TransferRequest]) -> async TransferResponse;
593 |
594 | /**
595 | Batch update operator.
596 | A request should fail if the caller is not authorized to update operators
597 | for the owner.
598 | Any request that fails should cause the entire batch to fail, and to
599 | rollback to the initial state.
600 | */
601 | updateOperator: shared (requests: [OperatorRequest]) -> async OperatorResponse;
602 |
603 | /**
604 | Batch function to check if a user is authorized to transfer for an owner.
605 | */
606 | isAuthorized: query (requests: [IsAuthorizedRequest]) -> async IsAuthorizedResponse;
607 | };
608 | ```
609 |
610 | ## References
611 |
612 | **Standards**
613 |
614 | - [ERC-20 Token Standard](https://eips.ethereum.org/EIPS/eip-20)
615 | - [ERC-721 Non-Fungible Token Standard](https://eips.ethereum.org/EIPS/eip-721)
616 | - [ERC-1155 Multi Token Standard](https://eips.ethereum.org/EIPS/eip-1155)
617 |
618 | ## Copyright
619 |
620 | Copyright and related rights waived via
621 | [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
622 |
--------------------------------------------------------------------------------
/docs/ICIP-20.md:
--------------------------------------------------------------------------------
1 | ## ICIP-20
2 | ---
3 | ICIP-20 token canisters manage and track *[fungible tokens](https://www.markdownguide.org)*. fungible tokens are completely interchangeable with each other. They hold the same value and are used for making payments and tracking balances. This is the vast majority of crypto currencies like BTC, and ETH.
4 |
5 | ### Creating an ICIP-20 Token Canister
6 | ---
7 | *[Canisters](https://www.markdownguide.org)* allow us to easliy create our own DIP20 Token,
8 |
9 |
10 | 
11 |
12 |
13 | Here is how it might look minting your tokens
14 |
15 | dfx canister call token initialize "'(\"test token\", \"TT\", 0, 1000)'"
16 | true
17 |
18 |
19 | We're creating an inital supply of tokens that will be deposited to the *[Caller](https://www.markdownguide.org)* of the initialize method.
20 |
21 | That’s it! Once initialized, we will be able to query the total supply:
22 |
23 | dfx canister call token totalSupply '()'
24 | (1_000)
25 |
26 |
27 | We can also transfer these tokens to other accounts and query balances:
28 |
29 |
30 | dfx canister call token transfer (Principle, amount)
31 | dfx canister call token balanceOf (Principle)
32 |
33 |
34 | ##Preset DIP20 Canister
35 | [DIP20](https://github.com/ALLiDoizCode/DIP20)
36 |
37 | This canister is ready to deploy without having to write any Motoko code. It can be used as-is for quick prototyping and testing, but is also suitable for production environments.
--------------------------------------------------------------------------------
/docs/ICIP-721.md:
--------------------------------------------------------------------------------
1 | # ICIP-721
2 | ---
--------------------------------------------------------------------------------
/docs/Sudograph.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Sudograph
4 |
5 | Sudograph is a [GraphQL](https://graphql.org/) database for the [Internet Computer](https://dfinity.org/).
6 |
7 | It greatly simplifies [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) development by providing GraphQL queries and mutations derived directly from your [GraphQL schema](https://graphql.org/learn/schema/). All you have to do is define your schema using the [GraphQL SDL](https://www.digitalocean.com/community/tutorials/graphql-graphql-sdl).
8 |
9 | For example, if you created the following schema:
10 |
11 | # As an example, you might define the following types in a file called schema.graphql
12 |
13 | type BlogPost {
14 | id: String!
15 | body: String!
16 | created_at: Date!
17 | live: Boolean!
18 | num_words: Int!
19 | published_at: Date
20 | title: String!
21 | updated_at: Date!
22 | }
23 |
24 |
25 | Then Sudograph would create the following queries and mutations for you:
26 |
27 |
28 | type Query {
29 | readBlogPost(input: ReadBlogPostInput!): [BlogPost!]!
30 | }
31 |
32 | type Mutation {
33 | createBlogPost(input: CreateBlogPostInput!): [BlogPost!]!
34 | updateBlogPost(input: UpdateBlogPostInput!): [BlogPost!]!
35 | deleteBlogPost(input: DeleteBlogPostInput!): [BlogPost!]!
36 | initBlogPost: Boolean!
37 | }
38 |
39 |
40 | There's a lot more being generated for you to get the above to work, but you're seeing the most important parts (the queries and mutations themselves).
41 |
42 | With the generated queries/mutations above, you could start writing code like this in any of your clients:
43 |
44 |
45 | query {
46 | readBlogPost(input: {
47 | live: {
48 | eq: true
49 | }
50 | }) {
51 | id
52 | body
53 | created_at
54 | live
55 | num_words
56 | published_at
57 | title
58 | updated_at
59 | }
60 | }
61 |
62 |
63 | The query above will return all blog posts that are "live" (have been published).
64 |
65 | Creating a blog post would look something like this:
66 |
67 |
68 | mutation {
69 | createBlogPost(input: {
70 | id: "0"
71 | body: "This is my blog post!"
72 | created_at: "2021-03-21T05:34:31.127Z"
73 | live: false
74 | num_words: 5
75 | published_at: null
76 | title: "My Blog Post"
77 | updated_at: "2021-03-21T05:34:31.127Z"
78 | }) {
79 | id
80 | }
81 | }
82 |
83 |
84 | ## Quick Start
85 |
86 | Sudograph is a Rust crate, and thus (for now) you must create a Rust IC canister to use it. You should generally follow the official DFINITY guidance for the [Rust CDK](https://sdk.dfinity.org/docs/rust-guide/rust-intro.html).
87 |
88 | If you ever want to see a concrete example of how to implement Sudograph, simply take a look at the examples directory.
89 |
90 | Let's imagine you've created a Rust canister called `graphql` in a directory called `graphql`. In the `graphql` directory you should have a `Cargo.toml` file. You'll need to add Sudograph as a dependency. For example:
91 |
92 |
93 | [package]
94 | name = "graphql"
95 | version = "0.0.0"
96 | authors = ["Jordan Last "]
97 | edition = "2018"
98 |
99 | [lib]
100 | path = "src/graphql.rs"
101 | crate-type = ["cdylib"]
102 |
103 | [dependencies]
104 | sudograph = "0.1.0"
105 |
106 |
107 | Next let's define our schema. In the `graphql/src` directory, let's add a file called `schema.graphql`:
108 |
109 |
110 | # graphql/src/schema.graphql
111 | type BlogPost {
112 | id: String!
113 | body: String!
114 | created_at: Date!
115 | live: Boolean!
116 | num_words: Int!
117 | published_at: Date
118 | title: String!
119 | updated_at: Date!
120 | }
121 |
122 |
123 | Your canister should be implemented as a Rust library crate, in this case the source code for our canister is found in `graphql/src/graphql.rs`. You only need to add two lines of code to this file to bootstrap your GraphQL database:
124 |
125 |
126 | // graphql/src/graphql.rs
127 | use sudograph::graphql_database;
128 |
129 | graphql_database!("canisters/graphql/src/schema.graphql");
130 |
131 |
132 | You will also need to add a [Candid](https://sdk.dfinity.org/docs/candid-guide/candid-intro.html) file to `graphql/src`. Let's call it `graphql.did`:
133 |
134 |
135 | # graphql/src/graphql.did
136 | service : {
137 | "graphql_query": (text) -> (text) query;
138 | "graphql_mutation": (text) -> (text);
139 | }
140 |
141 |
142 | Sudograph will automatically create two methods on your canister, the first is called `graphql_query`, which is a query method (will return quickly). The second is called `graphql_mutation`, which is an update method (will return more slowly). You should send all queries to `graphql_query` and all mutations to `graphql_mutation`. If you want the highest security guarantees, you can send all queries to `graphql_mutation`, they will simply take a few seconds to return.
143 |
144 | If you have setup your `dfx.json` correctly, then you should be able to deploy your Sudograph canister. Open up a terminal in the root directory of your IC project and start up an IC replica with `dfx start`. Open another terminal, and from the same directory run `dfx deploy`.
145 |
146 | You should now have a GraphQL database running inside of your `graphql` canister.
147 |
148 | ##Preset Sudograph Canister
149 | [Sudograph](https://github.com/ALLiDoizCode/sudograph)
150 |
151 | This canister is ready to deploy without having to write any Motoko code. It can be used as-is for quick prototyping and testing, but is also suitable for production environments.
--------------------------------------------------------------------------------
/docs/fungible-tokens.md:
--------------------------------------------------------------------------------
1 | # Fungible Tokens
2 | ---
--------------------------------------------------------------------------------
/docs/getting-started.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | ## Getting Started
4 |
5 | ## Requirements
6 |
7 | Install the beta version of the DFINITY Canister SDK
8 |
9 |
10 | DFX_VERSION=0.7.0-beta.8 sh -ci "$(curl -fsSL https://sdk.dfinity.org/install.sh)"
11 |
19 | npx create-ic-app
20 |
27 | cd test-project
28 | npm install
29 |
32 | dfx start --background
33 | dfx canister create --all
34 | dfx build
35 | dfx canister install --all
36 |
39 | npm run dev
40 |
48 | npm run watch
49 |
67 | dfx build
68 | dfx canister install --all --mode=reinstall
69 |
http://localhost:8000?canisterId=
76 |
77 | ## Community templates / Contributions
78 | Want to contribute your own template? Find something that could be improved? Repo is open for PRs! Happy to assist you in this. You'll receive full credit for your contribution of course.
79 |
80 | ### Contributions
81 | @ferMartz (React JS + Tailwind template)
--------------------------------------------------------------------------------
/docs/img/DIP20Init.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenCan-io/opencan/7f224bad5e2a7fdbace3df012ad7713efac4ec9c/docs/img/DIP20Init.png
--------------------------------------------------------------------------------
/docs/img/create-ic-app.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenCan-io/opencan/7f224bad5e2a7fdbace3df012ad7713efac4ec9c/docs/img/create-ic-app.gif
--------------------------------------------------------------------------------
/docs/img/deployCanister.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenCan-io/opencan/7f224bad5e2a7fdbace3df012ad7713efac4ec9c/docs/img/deployCanister.png
--------------------------------------------------------------------------------
/docs/img/dfinity-logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/img/example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenCan-io/opencan/7f224bad5e2a7fdbace3df012ad7713efac4ec9c/docs/img/example.png
--------------------------------------------------------------------------------
/docs/img/opencantrailer.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenCan-io/opencan/7f224bad5e2a7fdbace3df012ad7713efac4ec9c/docs/img/opencantrailer.mp4
--------------------------------------------------------------------------------
/docs/img/setup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenCan-io/opencan/7f224bad5e2a7fdbace3df012ad7713efac4ec9c/docs/img/setup.png
--------------------------------------------------------------------------------
/docs/img/sudograph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenCan-io/opencan/7f224bad5e2a7fdbace3df012ad7713efac4ec9c/docs/img/sudograph.png
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 |