');padding-left:2rem!important}input:not([class*=" btn-"]):disabled:hover,input:not([class*=btn-]):disabled,select:disabled,textarea:disabled{background-color:#f3f3f6;cursor:not-allowed;border:1px solid #f3f3f6}label:first-child:not(:last-child):not(.form-group-label){margin-right:.5rem}label:not(:first-child):not(:last-child):not(.form-group-label){margin:0 .5rem}label:last-child:not(:first-child):not(.form-group-label){margin-left:.5rem}.required{position:relative;top:1px;font-weight:700;color:#f03c69;padding-left:.1rem}.label:not(:last-child){margin-bottom:0}.label{color:#4a4a4a;display:inline-block;font-weight:700;margin-top:.8rem}.input-success{background-color:rgba(0,224,0,.05)!important;border-color:var(--cirrus-success)!important}.btn-success:focus,.input-success:not([type=checkbox]):not([type=radio]):not([type=submit]):focus{box-shadow:0 0 0 .2rem rgba(76,175,80,.45),inset 0 1px 8px rgba(0,0,0,.07)}.input-error{background-color:rgba(244,67,54,.05)!important;border-color:var(--cirrus-danger)!important}.btn-error:focus,.input-error:not([type=checkbox]):not([type=radio]):not([type=submit]):focus{box-shadow:0 0 0 .2rem rgba(244,67,54,.45),inset 0 1px 8px rgba(0,0,0,.07)}input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-xsmall,select.input-xsmall{font-size:.65rem;padding:.35rem .9rem}input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-small,select.input-small{font-size:.75rem;padding:.55rem 1rem}input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-large,select.input-large{font-size:1.5rem}input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-xlarge,select.input-xlarge{font-size:2rem}select.input-xsmall{padding:.65rem .9rem}select.input-small{padding:.75rem 1rem}select.input-large{padding:.95rem 1.2rem}select.input-xlarge{padding:1.05rem 1.3rem}.input-control{position:relative;margin:.5rem 0}input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon,input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon-left{padding-left:2.75rem}input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon-right{padding-right:2.75rem}input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon-right.input-xsmall,input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon.input-xsmall{padding-left:2rem}input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon-left.input-xsmall~.icon,input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon-right.input-xsmall~.icon.icon-right,input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon.input-xsmall~.icon{line-height:1.75rem;width:1.75rem;font-size:7px}input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon-right.input-small,input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon.input-small{padding-left:2.5rem}input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon-left.input-small~.icon,input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon-right.input-small~.icon.icon-right,input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon.input-small~.icon{line-height:2rem;width:2.5rem;font-size:14px}input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon-right.input-large,input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon.input-large{padding-left:3rem}input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon-left.input-large~.icon,input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon-right.input-large~.icon.icon-right,input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon.input-large~.icon{line-height:3.5rem;width:3.5rem;font-size:28px}input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon-right.input-xlarge,input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon.input-xlarge{padding-left:3.5rem}input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon-left.input-xlarge~.icon,input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon-right.input-xlarge~.icon.icon-right,input:not([type=checkbox]):not([type=radio]):not([type=submit]).input-contains-icon.input-xlarge~.icon{line-height:2.5rem;width:3.75rem;font-size:35px}.input-contains-icon~.icon{display:flex;align-items:center;justify-content:center;height:100%}.input-contains-icon-left~.icon.icon-left,.input-contains-icon~.icon:not(.icon-right){position:absolute;left:0;top:0;width:3rem;z-index:1}.input-contains-icon-right~.icon.icon-right{position:absolute;pointer-events:none;line-height:2.75rem;vertical-align:baseline;top:0;right:0;width:3rem;z-index:1}.form-section:not(:last-child){margin-bottom:.5rem}.form-section.section-inline{display:flex}.form-section.section-inline button,.form-section.section-inline label:not(.form-group-label){align-items:center;flex-grow:0;display:flex;flex-shrink:0}.form-section.section-inline .section-body,.form-section.section-inline input{align-items:center;flex-grow:1}.form-group{display:flex;display:-ms-flexbox;margin:.5rem 0}.form-group .form-group-btn{flex:1 0 auto;margin-bottom:0}.form-group .form-group-btn:first-child:not(:last-child),.form-group .form-group-input:first-child:not(:last-child),.form-group .form-group-label:first-child:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.form-group .form-group-btn:not(:first-child):not(:last-child),.form-group .form-group-input:not(:first-child):not(:last-child),.form-group .form-group-label:not(:first-child):not(:last-child){border-radius:0;margin-left:-.1rem;margin-right:-.1rem}.form-group .form-group-btn:last-child:not(:first-child),.form-group .form-group-input:last-child:not(:first-child),.form-group .form-group-label:last-child:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0;margin-left:-.1rem}.form-group-label{background-color:var(--cirrus-form-group-bg);border:1px solid #ddd;border-radius:.2rem;color:var(--cirrus-form-group-fg);margin:0;padding:.8rem;-webkit-user-select:none;-ms-user-select:none;user-select:none}.form-group-label.label-xsmall{font-size:.55rem;padding:.35rem .9rem}.form-group-label.label-small{font-size:.75rem;padding:.55rem 1rem}.form-group-label.label-large{font-size:1.5rem}.form-group-label.label-xlarge{font-size:2rem}.form-group-input{z-index:1}::-moz-placeholder{color:#a9a9a9}::-webkit-input-placeholder{color:#a9a9a9}.frame{display:flex;display:-ms-flexbox;flex-direction:column;border-radius:3px;box-shadow:0 .05rem .2rem rgba(69,77,93,.3)}.frame .frame__footer,.frame .frame__header{padding:1rem}.frame .frame__footer,.frame .frame__header,.frame .frame__nav{flex:0 0 auto;-webkit-flex:0 0 auto;-ms-flex:0 0 auto}.frame .frame__body{flex:1 1 auto;-webkit-flex:1 1 auto;-ms-flex:1 1 auto;overflow-y:auto;padding:0 1.5rem}.frame .frame__title{color:var(--cirrus-fg);font-size:1rem;margin:.75rem auto 0}.frame .frame__subtitle{color:rgba(55,64,84,.6);font-size:.85rem;margin:.25rem auto .75rem}.header{flex-grow:1;-ms-flex-negative:0;width:100%;z-index:100;margin-bottom:20px;box-shadow:0 3px 15px rgba(57,63,72,.1);background-color:var(--cirrus-bg);max-height:100vh;padding:0 2rem;transition:.3s}.header a{color:#8292a2}.header a:hover{color:#697888}.header-dark{background-color:rgba(0,0,0,.87);color:#fff}.header-clear{background-color:transparent;box-shadow:none}.header.header-animated .header-nav{transition:background .4s,height .4s;transition-property:background,height;transition-duration:.4s,.4s;transition-timing-function:ease,ease;transition-delay:initial,initial;transition:.3s}.header-brand{-webkit-overflow-scrolling:touch;align-items:stretch;display:flex;flex-shrink:0;max-width:100vw;min-height:3.25rem;overflow-x:auto;overflow-y:hidden}.header-nav{overflow:auto}.nav-menu{transition:.3s}.nav-overflow-x{justify-content:inherit;overflow-x:scroll}.header-fixed{position:fixed;top:0}.nav-item{flex-grow:0;flex-shrink:0;justify-content:center;transition:.3s;padding:0 .3rem;cursor:pointer}.nav-item,.nav-item a{align-items:center;display:flex}.nav-item a{height:100%}.header:not(.header-clear) .nav-item:not(.no-hover).hovered,.header:not(.header-clear) .nav-item:not(.no-hover):hover{transition:.3s;background-color:hsla(0,0%,84.7%,.15)}.header:not(.header-clear) .nav-item.active,.header:not(.header-clear) .nav-item.active:hover{background-color:hsla(0,0%,84.7%,.35)}.nav-item .dropdown-menu{background-color:var(--cirrus-bg);position:absolute;top:95%;z-index:1000;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-clip:padding-box;border:1px solid #eee;border-radius:0 0 4px 4px;box-shadow:0 .5rem 1rem rgba(10,10,10,.1)}.header.header-clear .nav-item .dropdown-menu{border-radius:4px}.nav-item .dropdown-menu.dropdown-animated{transition:all var(--animation-duration)}.nav-item.has-sub .nav-dropdown-link:after{border:2px solid var(--cirrus-primary);border-right:0;border-top:0;display:block;height:.5em;width:.5em;content:" ";transform:rotate(-45deg);pointer-events:none;margin-top:-.435em;right:1.125em;top:50%;position:absolute}.nav-item.has-sub .nav-dropdown-link{padding-right:2.5rem;position:relative}.header-dark .dropdown-menu,.nav-item .dropdown-menu.dropdown-dark{background-color:rgba(0,0,0,.87);border:1px solid #333;color:#fff}.dropdown-menu.dropdown-shown,.nav-item.active{opacity:1}.dropdown-menu>li>a{display:block;padding:.5rem 1rem;clear:both;line-height:1.42857143;white-space:nowrap}.header-dark .dropdown-menu>li>a,.header-dark .nav-item a{color:#fff}.dropdown-menu>li{margin:0;transition:.3s}.dropdown-menu>li:hover{transition:.3s;background-color:hsla(0,0%,84.7%,.15)}.dropdown-menu>li:active{transition:.3s;background-color:hsla(0,0%,84.7%,.25)}.dropdown-menu>li:last-child{margin-bottom:0}.dropdown-menu .dropdown-menu-divider{border:none;background-color:hsla(0,0%,84.7%,.15);height:1px;margin:.5rem 0}.nav-btn{cursor:pointer;display:block;height:3.5rem;position:relative;width:3.5rem}.header .btn,.header button,.header input[type=submit]{margin:0}@media screen and (min-width:769px){.header{align-items:stretch;display:-ms-flexbox}.header-nav{flex-grow:1;-ms-flex-negative:0;align-items:stretch;display:flex;position:relative;text-align:center;width:100%;top:0;overflow:visible}.nav-left,.nav-right{-webkit-box-align:stretch;-ms-flex-align:stretch;-ms-grid-row-align:stretch;align-items:stretch;flex-basis:0;flex-grow:1;flex-shrink:0}.nav-left{display:flex;justify-content:flex-start;white-space:nowrap}.nav-right{display:-ms-flexbox;justify-content:flex-end;white-space:nowrap}.nav-center{align-items:stretch;display:flex;flex-grow:0;flex-shrink:0;justify-content:center;margin-left:auto;margin-right:auto}.nav-btn{display:none}.nav-item{position:relative}.nav-item a{padding:.5rem 1rem}.nav-item .dropdown-menu{opacity:0;pointer-events:none}.nav-item .dropdown-menu.dropdown-animated{transform:translateY(-5px)}.nav-item .dropdown-menu.dropdown-animated.dropdown-shown,.nav-item .dropdown-menu.dropdown-shown,.nav-item.toggle-hover:hover .dropdown-animated.dropdown-menu,.nav-item.toggle-hover:hover .dropdown-menu{opacity:1;transform:none;pointer-events:auto}.nav-left .has-sub .dropdown-menu{left:0;right:auto}.nav-right .has-sub .dropdown-menu{left:auto;right:0}}@media screen and (max-width:768px){.grid{--grid-template-column:repeat(1,minmax(0,1fr))}.form-section.section-inline{display:inherit}.header{display:flex;flex-direction:column}.header-brand .nav-item:first-child{padding:0 1rem}.header-nav{height:0}.header-nav.active{height:100vh}.nav-item.has-sub{display:block}.nav-item.has-sub .dropdown-menu.dropdown-shown{border-radius:0;box-shadow:none;display:block;position:relative;top:1rem;float:none;border:none;background-color:transparent;margin-bottom:1rem}.nav-item.has-sub .dropdown-menu.dropdown-dark{background-color:rgba(0,0,0,.17);border:0;color:#fff}.nav-item.has-sub .dropdown-menu{display:none}.header-nav .nav-item{padding:1rem}.header-nav .nav-item>a{padding:0;width:100%}.nav-btn{cursor:pointer;display:block;position:relative;margin-left:auto}.nav-btn span{background-color:#4d565f;display:block;height:2px;left:50%;margin-left:-7px;position:absolute;top:50%;transition:none 86ms ease-out;transition-property:background,left,opacity,transform;width:15px}.header-dark .nav-btn span{background-color:#fff}.nav-btn span:first-child{margin-top:-6px}.nav-btn span:nth-child(2){margin-top:-1px}.nav-btn span:nth-child(3){margin-top:4px}.nav-btn.active span:first-child{margin-left:-5px;transform:rotate(45deg);transform-origin:left top}.nav-btn.active span:nth-child(2){opacity:0}.nav-btn.active span:nth-child(3){margin-left:-5px;transform:rotate(-45deg);transform-origin:left bottom}.nav-center,.nav-left,.nav-right{overflow:hidden}}@media screen and (min-width:1023px){.header{padding:0 2rem}}.content{max-width:60em;margin:0 auto 1.5em;width:80%}.fullscreen{top:0;right:0;bottom:0;left:0;height:100vh}section{display:block}.panel{padding:2.5em 0}.divider{border-top:.05rem solid hsla(0,0%,67.8%,.5);height:.1rem;margin:1.8rem 0 1.6rem}.divider[data-content]{margin:.8rem 0}.divider--v:before{border-left:.05rem solid hsla(0,0%,67.8%,.5);bottom:.4rem;content:"";display:block;left:50%;position:absolute;top:0;transform:translateX(-50%)}.divider--v[data-content]:after,.divider[data-content]:after{background:#fff;color:#bcc3ce;content:attr(data-content);left:50%;display:inline-block;padding:0 .4rem;position:absolute;transform:translate(-50%,-50%);top:50%}.divider--v[data-content]{display:block;left:50%;padding:.2rem 0;position:absolute;top:50%;transform:translate(-50%,-50%)}.hero-img{background-size:cover}.parallax-img{background-attachment:fixed!important}.hero{align-items:stretch;display:flex;-webkit-box-orient:vertical;justify-content:space-between}.hero-body{flex-grow:1;flex-shrink:0;padding:3rem 1.5rem;align-items:center;display:flex;width:100%}space{display:block;width:100%;height:1rem}space.large{padding:1rem 0}space.x-large{padding:2rem 0}.row{flex:1 1;flex-wrap:wrap}.r,.row{padding:.5rem}.r{max-width:100%}.row.row--no-wrap{flex-wrap:nowrap;overflow-x:auto}.row:after{content:"";clear:both;display:table}.row .col{display:block;flex:1 1;padding:.15rem .75rem}.row .col-1{width:8.33333333%}.row .col-2{width:16.66666667%}.row .col-3{width:25%}.row .col-4{width:33.33333333%}.row .col-5{width:41.66666667%}.row .col-6{width:50%}.row .col-7{width:58.33333333%}.row .col-8{width:66.66666667%}.row .col-9{width:75%}.row .col-10{width:83.33333333%}.row .col-11{width:91.66666667%}.row .col-12{width:100%}.row .offset-1{margin-left:8.33333333%}.row .offset-2{margin-left:16.66666667%}.row .offset-3{margin-left:25%}.row .offset-4{margin-left:33.33333333%}.row .offset-5{margin-left:41.66666667%}.row .offset-6{margin-left:50%}.row .offset-7{margin-left:58.33333333%}.row .offset-8{margin-left:66.66666667%}.row .offset-9{margin-left:75%}.row .offset-10{margin-left:83.33333333%}.row .offset-11{margin-left:91.66666667%}.row .offset-12{margin-left:100%}.row .offset-right{margin-left:0;margin-right:auto}.row .offset-center{margin-left:auto;margin-right:auto}.row .offset-left{margin-left:auto;margin-right:0}.row [class*=" col-"],.row [class^=col-]{float:left;padding:0 .5rem}.row.no-space [class*=" col-"],.row.no-space [class^=col-]{padding:0}.row.has-controls{display:flex;justify-content:flex-start}.level{justify-content:space-between}.level,.level-left{-webkit-box-align:center;-ms-flex-align:center;-ms-grid-row-align:center;align-items:center}.level-left{justify-content:flex-start;margin-right:1rem}.level-right{-webkit-box-align:center;-ms-flex-align:center;-ms-grid-row-align:center;align-items:center;justify-content:flex-end}.level-item{align-items:center;display:flex;flex-basis:auto;flex-grow:0;flex-shrink:0;justify-content:center}.level-content{flex-basis:auto;flex-grow:1;flex-shrink:1;text-align:left;width:100%}.w-10{width:10%}.w-20{width:20%}.w-30{width:30%}.w-40{width:40%}.w-50{width:50%}.w-60{width:60%}.w-70{width:70%}.w-80{width:80%}.w-90{width:90%}.w-100{width:100%}.h-10{height:10%}.h-20{height:20%}.h-30{height:30%}.h-40{height:40%}.h-50{height:50%}.h-60{height:60%}.h-70{height:70%}.h-80{height:80%}.h-90{height:90%}.h-100{height:100%}@media screen and (min-width:769px){.row{display:flex}.level-right{margin-left:1rem}.level.fill-height{align-items:stretch;display:flex}}@media screen and (max-width:768px){.row{margin-top:0}.row [class*=" col-"]:not(.ignore-screen),.row [class^=col-]:not(.ignore-screen){width:100%;margin-left:0;padding:0}.divided>.row [class*=" col-"],.divided>.row [class^=col-]{box-shadow:0 -1px 0 0 rgba(34,36,38,.15)}.level-left.ignore-screen,.level-right.ignore-screen,.level.ignore-screen{display:flex}.level.fill-height{display:inherit}}a{color:var(--cirrus-link);display:block;font-weight:600;padding:2px;text-decoration:none}a,a:hover{transition:.3s}a:hover{color:var(--cirrus-link-dark)}a:active,a:hover,a:visited{-webkit-backface-visibility:hidden;backface-visibility:hidden;text-decoration:none}.subtitle a{padding:0}a.underline{text-decoration:underline}article a,blockquote a,h1 a,h2 a,h3 a,h4 a,h5 a,h6 a,p a{display:inline}a .btn,a button{margin-bottom:0}ol,ul{margin:1rem 0 1rem 1rem;-webkit-padding-start:.5rem;padding-inline-start:.5rem}ol ol,ol ul,ul ol,ul ul{margin:0 0 0 1rem}ul ul{list-style-type:circle}ul ul ul{list-style-type:square}ol ol{list-style:lower-alpha}ol ol ol{list-style:upper-roman}dl{margin:1rem 0}dt{font-weight:700}dd{margin-bottom:.5rem}li{margin:.25rem 0}li:not(".dropdown-menu li"):last-child{margin-bottom:1em}ul.no-bullets{list-style:none}.menu{font-size:1rem}ul.menu{list-style:none;margin:.5rem 0}.menu-title:not(:first-child){margin-bottom:1rem}.menu-title:not(:last-child){margin-top:1rem}.menu .menu-item a{color:#555;display:block;padding:.5em .75em;border-radius:3px;font-size:.85rem;cursor:pointer;transition:all var(--animation-duration)}.menu .menu-item:hover>a{background-color:hsla(0,0%,81.6%,.3);color:#d43644;transition:all var(--animation-duration)}.menu .menu-item.selected>a{color:#fff;background-color:var(--cirrus-primary)}.menu .menu-item .menu-addon{padding:.3rem;z-index:1;position:relative;color:var(--cirrus-fg);cursor:pointer;float:left;margin-right:.1rem;transition:all var(--animation-duration)}.menu .menu-item .menu-addon .icon{font-size:inherit}.menu .menu-item .menu-addon:hover{background-color:rgba(60,60,60,.25);transition:all var(--animation-duration)}.menu .menu-item .menu-addon.right{float:right;margin-right:0;margin-left:.1rem}.menu .menu-item.selected .menu-addon{color:#fff}.menu .menu-item ul{border-left:1px solid #dbdbdb;margin:.75rem;padding-left:.75rem}.menu .divider{border-top:.1rem solid #eee;height:.1rem;margin:1rem 0}.menu .divider:after{content:attr(data-label);background-color:var(--cirrus-bg);color:#b7b7b7;display:inline-block;padding:0 .7rem;margin:.5rem;font-size:.7rem;transform:translateY(-1.1rem)}.list-dropdown{display:inline-block;position:relative}.list-dropdown .menu{position:absolute;top:75%;left:0;animation:slide-down .1s;background-color:var(--cirrus-bg);border-radius:.2rem;box-shadow:0 .1rem .4rem rgba(69,77,93,.3);margin:0;opacity:0;min-width:15rem;padding:.25rem .5rem;transform:translateY(.5rem);z-index:10;pointer-events:none;overflow:hidden;transition:all var(--animation-duration)}.list-dropdown.dropdown-right .menu{left:auto;right:0}.list-dropdown .btn-dropdown:focus+.menu,.list-dropdown .menu:hover,.list-dropdown.shown .menu{display:block;opacity:1;top:100%;z-index:100;pointer-events:auto;height:auto;transition:all var(--animation-duration)}.list-dropdown .btn-group .btn-dropdown:nth-last-child(2){border-bottom-right-radius:3px;border-top-right-radius:3px}.tree{margin:0}.tree .tree-item .tree-item-header{display:block;padding:.25rem .5rem;cursor:pointer;font-size:.95rem;font-weight:600}.tree .tree-item .tree-item-header .icon{transition:all var(--animation-duration)}.tree .tree-item input:checked~.tree-item-body{max-height:100vh}.tree .tree-item input:checked~.tree-item-header .icon{transform:rotate(90deg)}.tree .tree-item .tree-item-body{max-height:0;margin-left:1.5rem;overflow:hidden;transition:all var(--animation-duration)}.tree-nav-body{display:flex;height:100vh;flex-wrap:nowrap}.tree-nav{flex-grow:0;flex-shrink:1;padding:2rem 1rem 2rem 2rem;min-width:15rem;height:100vh;overflow:auto}.tree-nav .tree-nav-container{overflow-y:auto;top:4rem;bottom:1rem}.tree-nav+.tree-nav-close{display:none}.tree-nav+.tree-nav-content{max-width:100%;padding:2rem;flex:1 0 auto;overflow:auto;margin:0}.tree-nav-content{width:100%;overflow:auto;margin:0;padding:2rem}.tree-item-body .menu .menu-item a{font-weight:400}@media screen and (max-width:768px){.tree-nav{height:100%;left:0;overflow-y:auto;padding:3rem 1.5rem;position:fixed;top:0;transform:translateX(-100%);z-index:400}.tree-nav,.tree-nav:target{transition:transform var(--animation-duration) ease}.tree-nav:target{transform:translateX(0)}.tree-nav .tree-nav-close{display:none}.tree-nav .tree-nav-close,.tree-nav:target+.tree-nav-close{background-color:rgba(0,0,0,.15);height:100%;left:0;position:fixed;right:0;top:0;width:100%;z-index:300}.tree-nav:target+.tree-nav-close{display:block}.tree-nav+.tree-nav-body{max-width:inherit}.tree-nav-header{position:fixed;top:0;left:0;right:0;background-color:rgba(248,249,250,.8);height:3.5rem;padding:.75rem .5rem;text-align:center;z-index:300}.nav-item.has-sub .list-dropdown,.nav-item.has-sub .list-dropdown .btn-group{width:100%}.nav-item.has-sub .list-dropdown .btn-group .btn-dropdown{flex-grow:0}.list-dropdown .btn-dropdown:focus+.menu{position:relative;width:100%}}video.video-fullscreen{position:absolute;height:100vh;-o-object-fit:cover;object-fit:cover;width:100%;z-index:-1}.media-stretch{display:block;padding:0;overflow:hidden;width:100%;position:relative}.media-stretch:before{content:"";display:block;padding-bottom:56.25%}.media-stretch embed,.media-stretch iframe,.media-stretch object{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%}.media-stretch video{height:auto;max-width:100%;width:100%}.media-stretch.rat-4-3:before{padding-bottom:75%}.media-stretch.rat-1-1:before{padding-bottom:100%}.fig{margin:0 0 .5rem}.fig .fig-caption{margin-top:1rem}.img-stretch{max-width:100%;height:auto;display:block}.img-cover{-o-object-fit:cover;object-fit:cover}.img-contain{-o-object-fit:contain;object-fit:contain}.modal{position:fixed;top:0;left:0;right:0;bottom:0;opacity:0;padding:1rem;display:none;align-items:center;justify-content:center;pointer-events:none}.modal.shown,.modal:target{display:flex;opacity:1;z-index:999;pointer-events:auto}.modal.shown .modal-overlay,.modal:target .modal-overlay{position:absolute;top:0;left:0;right:0;bottom:0;display:block;background-color:rgba(54,59,68,.5)}.modal-content{background-color:var(--cirrus-bg);padding:0;display:block;border-radius:3px;box-shadow:0 .4rem 1rem rgba(54,59,68,.3);z-index:1;color:var(--cirrus-fg);max-width:40rem}.modal.modal-small .modal-content{max-width:20rem}.modal.modal-large .modal-content{max-width:60rem}.modal-content h1,.modal-content h2,.modal-content h3,.modal-content h4,.modal-content h5,.modal-content h6{color:var(--cirrus-fg)}.modal.shown .modal-container,.modal:target .modal-container{animation:slide-down var(--animation-duration) ease 1;z-index:1}.modal-content.small{max-width:32rem}.modal-content .modal-header{padding:1rem 3rem}.modal-content .modal-header .modal-title{font-weight:bolder;font-size:1.4rem}.modal-content .modal-body{padding:1rem 3rem;overflow-y:auto;max-height:50vh;position:relative}.modal-content .modal-footer{padding:1rem 3rem;text-align:right}.modal.modal-animated--dropdown{animation:slide-down var(--animation-duration) ease 1}.modal.modal-animated--zoom-in,.modal.modal-animated--zoom-out{display:flex;opacity:0;transition:.3s}.modal:target.modal-animated--zoom-in,.modal:target.modal-animated--zoom-out{opacity:1;transition:.3s}.modal.modal-animated--zoom-in .modal-content{transform:scale(.8);transition:.3s}.modal:target.modal-animated--zoom-in .modal-content,.modal:target.modal-animated--zoom-out .modal-content{transform:scale(1);transition:.3s}.modal.modal-animated--zoom-out .modal-content{transform:scale(1.2);transition:.3s}@keyframes slide-down{0%{opacity:0;transform:translateY(-3rem)}to{opacity:1;transform:translateY(0)}}@media only screen and (max-width:768px){.modal-content{max-width:90%}}.table{margin-bottom:1.5rem;width:100%;border-collapse:collapse;border-spacing:0;text-align:center}.table td,.table th{border:solid hsla(0,0%,85.9%,.5);border-width:0 0 1px;padding:.75rem;vertical-align:top;text-align:inherit;margin:0}.table tr{transition:.3s}.table caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}.table.striped tbody tr:nth-child(2n):hover,.table tr:hover{background-color:hsla(0,0%,84.7%,.15)}.table thead,.table thead th{border-bottom:2px solid hsla(0,0%,85.9%,.49)}.table.bordered thead,.table.bordered thead th{border-bottom:1px solid hsla(0,0%,85.9%,.5)}.table tfoot th,.table thead th{padding:1rem}.table tfoot th{border-top:2px solid hsla(0,0%,85.9%,.5);border-bottom:none}.table.bordered td,.table.bordered th{border:1px solid hsla(0,0%,85.9%,.5)}.table.borderd thead,.table.bordered thead td{border-width:1px}.table.striped tbody tr:nth-child(2n){background-color:rgba(0,0,0,.05)}.table.small td,.table.small th{padding:.25rem .75rem}.table.fixed-head thead{position:relative;display:block}.table.fixed-head tbody{height:200px;display:block;overflow:auto}.table.fixed-head tr{display:table;width:100%}.table tr.selected{background-color:var(--cirrus-primary);color:#fff}.table.borderless td,.table.borderless th,.table.borderless thead th{border:none}.u-inline{display:inline}.u-inline-block{display:inline-block}.u-flex{display:flex}.u-flex-column{flex-direction:column}.u-flex-row{flex-direction:row}.u-inline-flex{display:inline-flex}.u-block{display:block}.u-clearfix:after{clear:both;content:" ";display:table}.u-clear-left{clear:left}.u-clear-right{clear:right}.u-clear-both{clear:both}.u-pull-left{float:left}.u-pull-right{float:right}.u-center{display:flex;align-items:center;justify-content:center;margin:0 auto;flex-wrap:wrap}.u-center-alt,.u-center-alt:active,.u-center-alt:hover{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.u-vertical-center{justify-content:center;vertical-align:middle}.u-horizontal-center,.u-vertical-center{display:flex;align-items:center}.u-this-overlay{bottom:0;left:0;right:0;top:0;position:absolute}.u-hide-overflow{overflow:hidden!important;overflow-x:hidden;overflow-y:hidden}.u-text-center{text-align:center}.u-text-left{text-align:left}.u-text-right{text-align:right}.u-hide{display:none!important}.u-disabled{cursor:not-allowed}.u-unselectable{-webkit-touch-callout:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.u-box{background-color:#fff;border-radius:3px;box-shadow:0 2px 3px rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.1);display:block;padding:1rem}.u-box:not(:last-child){margin-bottom:1rem}.u-fill-width{width:100%}.u-no-margin{margin:0!important}.u-no-padding{padding:0!important}.u-margin-auto{margin:0 auto!important}.u-round{border-radius:.1rem}.u-circle{border-radius:50%}.u-no-shadow{box-shadow:none}@media screen and (min-width:769px){.level,.level-left,.level-right{display:flex}}@media screen and (max-width:768px){.u-hide-mobile{display:none!important}}@media screen and (min-width:768px){.u-hide-tablet{display:none!important}}@media screen and (min-width:769px) and (max-width:1023px){.u-hide-tablet-only{display:none!important}}@media screen and (min-width:1024px){.u-hide-desktop{display:none!important}}footer{background-color:#fff}footer a{display:inline;color:#000;text-decoration:none;outline:none;font-weight:400;border:none}footer a:hover{transition:.1s}
An Introduction to Crystal | Oisin's Blog
An Introduction to Crystal February 21, 2021
One of my favourite programming languages in the last few years has been Crystal . While the language has not yet reached its 1.0 version, it has been widely used in production and has a growing ecosystem. Crystal provides an easy setup and allows you to jump straight into developing your own Crystal programs. I’m going to walk you through getting it setup and how you can get started!
puts "Hello World"
Crystal is a general purpose, Ruby-inspired compiled programming language, making it extremely fast and easy to program with. The syntax is strongly inspired by Ruby, but also provides static typechecking. Crystal sits somewhere in the top 100 programming languages according to TIOBE , not widely used but don’t let that put you off!
I was originally interested in Crystal due to its expressive syntax and the claims on its speed. I am likely in the minority in that I came into Crystal with no prior Ruby experience. Crystal soon became my go-to language for personal programming projects. My project Azula (WIP programming language) was built entirely in Crystal - a choice a made due to Crystal’s nice macro system and built-in LLVM bindings. Crystal was an excellent choice, allowing rapid development and producing a small binary (1.9mb in Crystal vs 3mb in Go).
Shards The Crystal ecosystem is powered by its Shard system. Shards is Crystal’s dependency manager that is usually installed along with Crystal. It aims to allow reproducible installs across platforms by declaring dependencies and their versions. You can read more about Shards here .
Installing Crystal On Ubuntu, installing Crystal is as easy as running:
$ curl -fsSL https://crystal-lang.org/install.sh | sudo bash
For other platforms, have a look at the Crystal install guide !
First Crystal Program Crystal provides a nice scaffolding tool to setup a new project, including a README template, license and gitignore.
$ crystal init app myproject
If we open up myproject/src/myproject.cr
, we can start writing our Crystal program!
def say(message : String)
puts message
end
say "Hello!"
In this example, we create a function called say
that accepts a string and passes it to puts
. As you can see, almost identical to Ruby except for the typing of the parameter in the function.
Project Structure src Inside the src/
directory is where all the Crystal files will go. It can contain subdirectories, allowing you to divide up your code. You can include separate files by using the require
keyword.
spec The spec/
directory is the home for your tests. Using the crystal spec
subcommand, we can run all our tests.
it "works" do
i = 5 + 10
i.should eq 15
end
shard.yml shard.yml
is used to define our project. In here, we define the name, version, authors, Crystal version, licence & dependencies.
name: myproject
version: 0.1.0
authors:
- OisinA
targets:
myproject:
main: src/myproject.cr
crystal: 0.36.1
license: MIT
Building & Running Running
$ crystal run src/myproject.cr
Hello!
Running your Crystal project is as simple as running crystal run [file]
.
Building
$ crystal build src/myproject.cr
$ ./myproject
Hello!
To build your project, you use crystal build [file]
producing an executable. You can optionally use the --release
optimising the executable. This flag will significantly increase the build time but the produced binary should be smaller and faster.
Crystal’s build times are reasonable. Compiling my project Azula takes ~16s with the release flag. Compiling our barebones project above takes ~8s.
Example Simple Web Server In this example, I am using Kemal , a HTTP framework for Crystal, to set up a really simple web server to return some JSON on a request. Kemal makes it really easy to quickly write a web application and has built-in JSON support, static file serving and templating. Kemal is installed using Crystal Shards, adding it to the shards.yml
.
require "kemal"
require "json"
get "/" do |env|
env.response.content_type = "application/json"
{name: "Oisin", time: Time.local}.to_json
end
Kemal.run
Running this will start up a HTTP server on port 3000, returning JSON containing name and the current time.
$ curl http://localhost:3000
{"name":"Oisin","time":"2021-02-21T18:07:46+00:00"}
It’s as simple as that!
The Future of Crystal With Crystal being in a nice place at the moment - what are the next steps? The next step for Crystal is to reach a 1.0 release. This version of Crystal will be completely stable and fully ready for production. The Crystal team are currently working towards this goal currently. While there is no timeline in place, its an exciting prospect! I am excited for the future of Crystal and hope to see it more widely used.
Resources If you’ve enjoyed this blog post, you might be interested in reading more about Crystal and its ecosystem. I’ll list some links here and feel free to reach out to me on Twitter if you have any questions!
Footnotes: @osslate
For proof-reading and giving nice criticism <3Towards 1.0
Information about Crystal’s upcoming 1.0 release