diff options
Diffstat (limited to 'app')
50 files changed, 3342 insertions, 0 deletions
diff --git a/app/assets/css/styles.css b/app/assets/css/styles.css new file mode 100644 index 0000000..ec0a393 --- /dev/null +++ b/app/assets/css/styles.css @@ -0,0 +1,4 @@ +html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font:inherit;font-size:100%;vertical-align:baseline}html{line-height:1}ol,ul{list-style:none}table{border-collapse:collapse;border-spacing:0}caption,th,td{text-align:left;font-weight:normal;vertical-align:middle}q,blockquote{quotes:none}q:before,q:after,blockquote:before,blockquote:after{content:"";content:none}a img{border:none}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}/*! + * Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url("../fonts/fontawesome-webfont.eot?v=4.5.0");src:url("../fonts/fontawesome-webfont.eot?#iefix&v=4.5.0") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff2?v=4.5.0") format("woff2"),url("../fonts/fontawesome-webfont.woff?v=4.5.0") format("woff"),url("../fonts/fontawesome-webfont.ttf?v=4.5.0") format("truetype"),url("../fonts/fontawesome-webfont.svg?v=4.5.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}.fa-lg{font-size:1.33333em;line-height:0.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.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:0.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.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);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-remove:before,.fa-close:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-gear:before,.fa-cog:before{content:""}.fa-trash-o:before{content:""}.fa-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-rotate-right:before,.fa-repeat:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before{content:""}.fa-check-circle:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-warning:before,.fa-exclamation-triangle:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-gears:before,.fa-cogs:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before{content:""}.fa-arrow-circle-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-save:before,.fa-floppy-o:before{content:""}.fa-square:before{content:""}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-unsorted:before,.fa-sort:before{content:""}.fa-sort-down:before,.fa-sort-desc:before{content:""}.fa-sort-up:before,.fa-sort-asc:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-legal:before,.fa-gavel:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-flash:before,.fa-bolt:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-paste:before,.fa-clipboard:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-unlink:before,.fa-chain-broken:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:""}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:""}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:""}.fa-euro:before,.fa-eur:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-rupee:before,.fa-inr:before{content:""}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:""}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:""}.fa-won:before,.fa-krw:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-turkish-lira:before,.fa-try:before{content:""}.fa-plus-square-o:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-institution:before,.fa-bank:before,.fa-university:before{content:""}.fa-mortar-board:before,.fa-graduation-cap:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:""}.fa-file-zip-o:before,.fa-file-archive-o:before{content:""}.fa-file-sound-o:before,.fa-file-audio-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before{content:""}.fa-ge:before,.fa-empire:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-send:before,.fa-paper-plane:before{content:""}.fa-send-o:before,.fa-paper-plane-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-hotel:before,.fa-bed:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-yc:before,.fa-y-combinator:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-tv:before,.fa-television:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}html{height:100%}body{font-size:13px;font-weight:300;color:#4d525a;height:100%;width:100%;background-color:#f7f7f7;line-height:1.3}strong{font-weight:600}body,input,a,button,textarea{font-family:"noto sans";font-weight:300}.text-muted{color:#999ea7}.hero-container{margin:30px;font-size:22px;text-align:center}.pull-right{float:right}.align-right{text-align:right}a{color:#00B5E2;text-decoration:none}.fa{margin-right:3px}.clickable{cursor:pointer}.btn{border-radius:3px;padding:6px 10px;font-size:13px;line-height:1.2;text-decoration:none;text-transform:uppercase}.btn-default{border:1px solid #00B5E2;color:#00B5E2;background-color:#fff}.btn-default:hover{background-color:#65DDFB}.btn-lg{padding:6px 20px;font-size:16px}.btn-danger{border:1px solid #AF2F11;color:#AF2F11;text-transform:uppercase;background-color:#fff}.btn-danger:hover{background-color:#FB8165}.btn-primary{border:0;background:#00B5E2;box-shadow:1px 1px 1px #ababab;color:#ffffff}.btn-primary:hover{background:#008CAF}.input-box:-moz-placeholder{color:#ababab;font-size:18px}.input-box::-moz-placeholder{color:#ababab;font-size:18px}.input-box:-ms-input-placeholder{color:#ababab;font-size:18px}.input-box::-webkit-input-placeholder{color:#ababab;font-size:18px}.input-box:focus{box-shadow:0 0 5px #51cbee}.input-box-main{font-size:18px;width:700px;border:0;border-bottom:2px solid #00B5E2;padding:10px;margin-top:10px;margin-bottom:10px}.input-box-lg{width:100%;height:280px;margin-bottom:6px;margin-bottom:10px;border-radius:3px;border:1px solid #dedede;padding:10px}nav{font-size:17px;background-color:#fff;padding:15px}nav .nav-container{width:1000px;margin:auto}.plan{padding-bottom:30px;overflow:auto;height:100%;width:100%}.plan ul{display:flex;padding-top:12px;position:relative;margin:auto;transition:all 0.5s;margin-top:-5px}.plan ul ul::before{content:'';position:absolute;top:0;left:50%;border-left:2px solid #c4c4c4;height:12px;width:0}.plan ul li{float:left;text-align:center;list-style-type:none;position:relative;padding:12px 3px 0 3px;transition:all 0.5s}.plan ul li:before,.plan ul li:after{content:'';position:absolute;top:0;right:50%;border-top:2px solid #c4c4c4;width:50%;height:12px}.plan ul li:after{right:auto;left:50%;border-left:2px solid #c4c4c4}.plan ul li:only-child{padding-top:0}.plan ul li:only-child:after,.plan ul li:only-child:before{display:none}.plan ul li:first-child::before,.plan ul li:last-child::after{border:0 none}.plan ul li:last-child::before{border-right:2px solid #c4c4c4;border-radius:0 6px 0 0}.plan ul li:first-child::after{border-radius:6px 0 0 0}.plan ul li .plan-node:hover+ul::before{border-color:#00B5E2}.plan ul li .plan-node:hover+ul li::after,.plan ul li .plan-node:hover+ul li::before,.plan ul li .plan-node:hover+ul ul::before{border-color:#008CAF}.plan-stats{display:flex;font-size:13px;margin:0 auto 10px auto;padding-bottom:10px;border-bottom:1px solid #dedede;border-radius:12px;width:650px;position:relative}.plan-stats div{padding-right:10px;flex-grow:1}.plan-stats .stat-value{display:block;text-align:center;font-size:17px}.plan-stats .stat-label{display:block;text-align:center;font-size:12px}.plan-stats:after{content:'';position:absolute;top:100%;left:50%;margin-left:-9px;width:0;height:0;border-top:solid 9px #dedede;border-left:solid 9px transparent;border-right:solid 9px transparent}.plan-node{text-decoration:none;color:#4d525a;display:inline-block;transition:all 0.5s;position:relative;padding:6px 10px;background-color:#fff;font-size:12px;border:2px solid #dedede;border-radius:3px;overflow:hidden;overflow-wrap:break-word;word-wrap:break-word;word-break:break-all;min-width:220px}.plan-node header{margin-bottom:6px;overflow:hidden;cursor:pointer}.plan-node header:hover{background-color:#f7f7f7}.plan-node header h4{font-size:13px;float:left;font-weight:600}.plan-node header .node-duration{float:right;margin-left:10px;font-size:13px}.plan-node .prop-list{float:left;text-align:left;width:400px;overflow-wrap:break-word;word-wrap:break-word;word-break:break-all;margin-top:10px;margin-bottom:6px}.plan-node .relation-name{text-align:left;max-width:220px}.plan-node .planner-estimate{float:left;clear:both;text-align:left;margin-top:6px;width:100%}.plan-node .tags{margin-top:6px;text-align:left}.plan-node .tags span{display:inline-block;background-color:#FB4418;color:#fff;font-size:10px;font-weight:600;margin-right:3px;padding:3px;border-radius:3px;line-height:1.1}.plan-node:hover{border-color:#00B5E2}.node-bar-container{float:left;height:5px;margin-top:6px;margin-left:auto;margin-right:auto;border:1px solid #dedede;border-radius:3px;color:#fff;background-color:#454545;position:relative}.node-bar-container .node-bar{height:100%;text-align:left;position:absolute;left:0;top:0}.node-bar-label{text-align:left;display:block}.menu{width:190px;height:200px;position:absolute;font-size:12px;top:115px;left:0;background-color:#777;box-shadow:1px 1px 2px 1px rgba(0,0,0,0.5);color:#fff;border-top-right-radius:3px;border-bottom-right-radius:3px;z-index:1;transition:all 0.3s}.menu header h3{padding-top:10px;margin-bottom:20px;font-size:16px;font-weight:600;line-height:2;text-align:right;padding-right:20px}.menu ul{margin-left:10px}.menu ul li{line-height:2.5}.menu-toggle{font-size:26px;float:left;padding-left:10px;line-height:2;cursor:pointer}.menu-hidden{width:50px;height:50px;border-top-right-radius:50%;border-bottom-right-radius:50%}.menu-hidden ul,.menu-hidden h3{visibility:hidden}.menu button{border:1px solid #fff;background-color:#544D4D;color:#fff;padding:2px;border-radius:3px}.page,.page-stretch{padding-top:10px;margin:auto;width:1000px;min-height:600px}.page h2,.page-stretch h2{font-size:26px;margin-bottom:6px}.page-stretch{margin:auto;width:95%}.table{width:100%}.table td{border-bottom:1px solid #dedede;padding:6px}.table tr:hover{background-color:#f7f7f7}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000;opacity:0.7}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050}.modal .modal-dialog{position:relative;transform:translate(0);margin:30px auto;width:500px;opacity:1}.modal .modal-dialog .modal-content{padding:30px;position:relative;background-color:#fff;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;outline:0;box-shadow:0 3px 9px rgba(0,0,0,0.5);display:block}.modal .modal-dialog .modal-content .modal-body{padding:3px}.modal .modal-dialog .modal-content .modal-footer{text-align:right}.modal .modal-dialog .modal-content .modal-footer button{margin-left:3px}footer{border-top:2px solid #dedede;margin:20px;padding:20px;color:#ababab;text-align:center;width:600px;margin:auto}footer .fa{font-size:17px;margin-left:6px} diff --git a/app/assets/fonts/FontAwesome.otf b/app/assets/fonts/FontAwesome.otf Binary files differnew file mode 100644 index 0000000..3ed7f8b --- /dev/null +++ b/app/assets/fonts/FontAwesome.otf diff --git a/app/assets/fonts/fontawesome-webfont.eot b/app/assets/fonts/fontawesome-webfont.eot Binary files differnew file mode 100644 index 0000000..9b6afae --- /dev/null +++ b/app/assets/fonts/fontawesome-webfont.eot diff --git a/app/assets/fonts/fontawesome-webfont.ttf b/app/assets/fonts/fontawesome-webfont.ttf Binary files differnew file mode 100644 index 0000000..26dea79 --- /dev/null +++ b/app/assets/fonts/fontawesome-webfont.ttf diff --git a/app/assets/fonts/fontawesome-webfont.woff b/app/assets/fonts/fontawesome-webfont.woff Binary files differnew file mode 100644 index 0000000..dc35ce3 --- /dev/null +++ b/app/assets/fonts/fontawesome-webfont.woff diff --git a/app/assets/fonts/fontawesome-webfont.woff2 b/app/assets/fonts/fontawesome-webfont.woff2 Binary files differnew file mode 100644 index 0000000..500e517 --- /dev/null +++ b/app/assets/fonts/fontawesome-webfont.woff2 diff --git a/app/assets/sass/_buttons.scss b/app/assets/sass/_buttons.scss new file mode 100644 index 0000000..760d5ec --- /dev/null +++ b/app/assets/sass/_buttons.scss @@ -0,0 +1,47 @@ +.btn { + border-radius: $border-radius-base; + padding: $padding-base $padding-lg; + font-size: $font-size-base; + line-height: 1.2; + text-decoration: none; + text-transform: uppercase; + + &-default { + border: 1px solid $blue; + color: $blue; + background-color: #fff; + + &:hover { + background-color: $light-blue; + } + } + + &-lg { + padding: $padding-base $padding-lg*2; + font-size: round($font-size-base * 1.2); + } + + &-danger { + border: 1px solid $red; + color: $red; + text-transform: uppercase; + background-color: #fff; + + &:hover { + background-color: $light-red; + } + } + + &-primary { + border: 0; + background: $blue; + // background-image: linear-gradient(to bottom, $blue, $dark-blue); + box-shadow: 1px 1px 1px $gray; + color: #ffffff; + + &:hover { + background: $dark-blue; + // background-image: linear-gradient(to bottom, $dark-blue, $blue); + } + } +} diff --git a/app/assets/sass/_common.scss b/app/assets/sass/_common.scss new file mode 100644 index 0000000..5d38773 --- /dev/null +++ b/app/assets/sass/_common.scss @@ -0,0 +1,53 @@ +html { + height: 100%; +} + +body { + font-size: $font-size-base; + font-weight: 300; + color: $text-color; + height: 100%; + width: 100%; + background-color: $bg-color; + line-height: $line-height-base; +} + +strong { + font-weight: 600; +} + +body, input, a, button, textarea { + font-family: $font-family-sans-serif; + font-weight: 300; +} + +.text-muted { + color: $text-color-light; +} + +.hero-container { + margin: $padding-lg * 3; + font-size: $font-size-xl; + text-align: center; +} + +.pull-right { + float: right; +} + +.align-right { + text-align: right; +} + +a { + color: $link-color; + text-decoration: none; +} + +.fa { + margin-right: $padding-sm; +} + +.clickable { + cursor: pointer; +} diff --git a/app/assets/sass/_footer.scss b/app/assets/sass/_footer.scss new file mode 100644 index 0000000..603ff5a --- /dev/null +++ b/app/assets/sass/_footer.scss @@ -0,0 +1,14 @@ +footer { + border-top: 2px solid $gray-light; + margin: round($padding-lg * 2); + padding: round($padding-lg * 2); + color: $gray; + text-align: center; + width: 600px; + margin: auto; + + .fa { + font-size: $font-size-lg; + margin-left: $padding-base; + } +} diff --git a/app/assets/sass/_forms.scss b/app/assets/sass/_forms.scss new file mode 100644 index 0000000..4ab4dfe --- /dev/null +++ b/app/assets/sass/_forms.scss @@ -0,0 +1,33 @@ +@import "compass/css3/user-interface"; + +.input-box { + @include input-placeholder { + color: $gray; + font-size: round($font-size-base * 1.4); + } + + &:focus { + box-shadow: 0 0 5px rgba(81, 203, 238, 1); + } + + &-main { + font-size: round($font-size-base * 1.4); + width: 700px; + border: 0; + border-bottom: 2px solid $blue; + padding: $padding-lg; + margin-top: $padding-lg; + margin-bottom: $padding-lg; + } + + &-lg { + width: 100%; + height: 280px; + margin-bottom: $padding-base; + margin-bottom: $padding-lg; + border-radius: $border-radius-base; + border: 1px solid $line-color; + padding: $padding-lg; + } + +} diff --git a/app/assets/sass/_menu.scss b/app/assets/sass/_menu.scss new file mode 100644 index 0000000..d294686 --- /dev/null +++ b/app/assets/sass/_menu.scss @@ -0,0 +1,65 @@ +$menu-offset: 120px; +$menu-toggle-height: 45px; + +.menu { + width: 190px; + height: 200px; + position: absolute; + font-size: $font-size-sm; + top: $menu-offset - 5; + left: 0; + background-color: $gray-dark; + box-shadow: 1px 1px 2px 1px rgba(0,0,0,0.5); + color: #fff; + border-top-right-radius: $border-radius-base; + border-bottom-right-radius: $border-radius-base; + z-index: 1; + transition: all 0.3s; + + header { + h3 { + padding-top: $padding-lg; + margin-bottom: $padding-lg * 2; + font-size: round($font-size-base * 1.2); + font-weight: 600; + line-height: 2; + text-align: right; + padding-right: $padding-lg * 2; + } + } + + ul { + margin-left: $padding-lg; + + li { + line-height: 2.5; + } + } + + &-toggle { + font-size: round($font-size-lg * 1.5); + float: left; + padding-left: $padding-lg; + line-height: 2; + cursor: pointer; + } + + &-hidden { + width: 50px; + height: 50px; + border-top-right-radius: 50%; + border-bottom-right-radius: 50%; + + ul, h3 { + visibility: hidden; + } + } +} + +.menu button { + border: 1px solid #fff; + background-color: #544D4D; + color: #fff; + padding: 2px; + border-radius: 3px; +} diff --git a/app/assets/sass/_modal.scss b/app/assets/sass/_modal.scss new file mode 100644 index 0000000..19d4bfc --- /dev/null +++ b/app/assets/sass/_modal.scss @@ -0,0 +1,52 @@ +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000; + opacity: 0.7; +} + +.modal { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1050; + + .modal-dialog { + position: relative; + transform: translate(0); + margin: 30px auto; + width: 500px; + opacity: 1; + + .modal-content { + padding: 30px; + position: relative; + background-color: #fff; + background-clip: padding-box; + border: 1px solid #999; + border: 1px solid rgba(0,0,0,.2); + border-radius: 6px; + outline: 0; + box-shadow: 0 3px 9px rgba(0,0,0,.5); + display: block; + + .modal-body { + padding: $padding-sm; + } + + .modal-footer { + text-align: right; + + button { + margin-left: $padding-sm; + } + } + } + } +} diff --git a/app/assets/sass/_nav.scss b/app/assets/sass/_nav.scss new file mode 100644 index 0000000..496213b --- /dev/null +++ b/app/assets/sass/_nav.scss @@ -0,0 +1,10 @@ +nav { + font-size: round($font-size-base * 1.3); + background-color: #fff; + padding: round($padding-lg * 1.5); + + .nav-container { + width: $page-width; + margin: auto; + } +} diff --git a/app/assets/sass/_page.scss b/app/assets/sass/_page.scss new file mode 100644 index 0000000..64e1891 --- /dev/null +++ b/app/assets/sass/_page.scss @@ -0,0 +1,17 @@ +.page { + padding-top: $padding-lg; + margin: auto; + width: $page-width; + min-height: 600px; + + h2 { + font-size: round($font-size-base * 2); + margin-bottom: $padding-base; + } +} + +.page-stretch { + @extend .page; + margin: auto; + width: 95%; +} diff --git a/app/assets/sass/_plan-node.scss b/app/assets/sass/_plan-node.scss new file mode 100644 index 0000000..25b3a05 --- /dev/null +++ b/app/assets/sass/_plan-node.scss @@ -0,0 +1,111 @@ +.plan-node { + text-decoration: none; + color: $text-color; + display: inline-block; + transition: all 0.5s; + position: relative; + padding: $padding-base $padding-lg; + background-color: #fff; + font-size: $font-size-sm; + border: 2px solid $line-color; + border-radius: $border-radius-base; + overflow: hidden; + overflow-wrap: break-word; + word-wrap: break-word; + word-break: break-all; + min-width: 220px; + + header { + margin-bottom: $padding-base; + overflow: hidden; + cursor: pointer; + + &:hover { + background-color: $gray-lightest; + } + + h4 { + font-size: $font-size-base; + float: left; + font-weight: 600; + } + + .node-duration { + float: right; + margin-left: $padding-lg; + font-size: $font-size-base; + } + } + + .prop-list { + float: left; + text-align: left; + width: 400px; + overflow-wrap: break-word; + word-wrap: break-word; + word-break: break-all; + margin-top: $padding-lg; + margin-bottom: $padding-base; + } + + .relation-name { + text-align: left; + max-width: 220px; + } + + .planner-estimate { + float: left; + clear: both; + text-align: left; + margin-top: $padding-base; + width: 100%; + } + + .tags { + margin-top: $padding-base; + text-align: left; + + span { + display: inline-block; + background-color: $alert-color; + color: #fff; + font-size: round($font-size-sm * 0.8); + font-weight: 600; + margin-right: $padding-sm; + padding: $padding-sm; + border-radius: $border-radius-base; + line-height: 1.1; + } + } + + //hovers + &:hover { + border-color: $highlight-color; + } +} + +.node-bar-container { + float: left; + height: 5px; + margin-top: $padding-base; + margin-left: auto; + margin-right: auto; + border: 1px solid $line-color; + border-radius: $border-radius-base; + color: #fff; + background-color: $gray-darkest; + position: relative; + + .node-bar { + height: 100%; + text-align: left; + position: absolute; + left: 0; + top: 0; + } +} + +.node-bar-label { + text-align: left; + display: block; +} diff --git a/app/assets/sass/_plan.scss b/app/assets/sass/_plan.scss new file mode 100644 index 0000000..7b8808d --- /dev/null +++ b/app/assets/sass/_plan.scss @@ -0,0 +1,121 @@ +$connector-height: 12px; +$connector-line: 2px solid darken($line-color, 10%); + +.plan { + padding-bottom: $padding-lg * 3; + overflow: auto; + height: 100%; + width: 100%; + + ul { + display: flex; + padding-top: $connector-height; + position: relative; + margin: auto; + transition: all 0.5s; + margin-top: -5px; + + // vertical connector + ul::before { + content: ''; + position: absolute; top: 0; left: 50%; + border-left: $connector-line; + height: $connector-height; + width: 0; + } + + li { + float: left; text-align: center; + list-style-type: none; + position: relative; + padding: $connector-height $padding-sm 0 $padding-sm; + transition: all 0.5s; + + // connectors + &:before, &:after { + content: ''; + position: absolute; top: 0; right: 50%; + border-top: $connector-line; + width: 50%; height: $connector-height; + } + + &:after { + right: auto; left: 50%; + border-left: $connector-line; + } + + &:only-child { + padding-top: 0; + &:after, &:before { + display: none; + } + } + + &:first-child::before, &:last-child::after { + border: 0 none; + } + + &:last-child::before { + border-right: $connector-line; + border-radius: 0 $border-radius-lg 0 0; + } + + &:first-child::after { + border-radius: $border-radius-lg 0 0 0; + } + + //hovers + .plan-node:hover+ul::before { + border-color: $highlight-color; + } + + .plan-node:hover+ul li::after, + .plan-node:hover+ul li::before, + .plan-node:hover+ul ul::before{ + border-color: $highlight-color-dark; + } + } + } +} + +.plan-stats { + display: flex; + font-size: $font-size-base; + margin: 0 auto $padding-lg auto; + padding-bottom: $padding-lg; + border-bottom: 1px solid $line-color; + border-radius: $border-radius-lg*2; + width: 650px; + position: relative; + + div { + padding-right: $padding-lg; + flex-grow: 1; + } + + .stat-value { + display: block; + text-align: center; + font-size: $font-size-lg; + } + + .stat-label { + display: block; + text-align: center; + font-size: $font-size-sm; + } + + $triangle-size: 9px; + &:after { + content:''; + position: absolute; + top: 100%; + left: 50%; + margin-left: $triangle-size*-1; + width: 0; + height: 0; + border-top: solid $triangle-size $line-color; + border-left: solid $triangle-size transparent; + border-right: solid $triangle-size transparent; + } +} diff --git a/app/assets/sass/_table.scss b/app/assets/sass/_table.scss new file mode 100644 index 0000000..d3e6e63 --- /dev/null +++ b/app/assets/sass/_table.scss @@ -0,0 +1,12 @@ +.table { + width: 100%; + + td { + border-bottom: 1px solid $line-color; + padding: $padding-base; + } + + tr:hover { + background-color: $gray-lightest; + } +} diff --git a/app/assets/sass/_variables.scss b/app/assets/sass/_variables.scss new file mode 100644 index 0000000..cfdb166 --- /dev/null +++ b/app/assets/sass/_variables.scss @@ -0,0 +1,51 @@ +//vars +$page-width: 1000px; + +$padding-base: 6px; +$padding-sm: 3px; +$padding-lg: 10px; + +$font-size-base: 13px; +$font-size-xs: round($font-size-base * 0.7); +$font-size-sm: round($font-size-base * 0.9); +$font-size-lg: round($font-size-base * 1.3); +$font-size-xl: round($font-size-base * 1.7); + +$font-family-sans-serif: 'noto sans'; + +$line-height-base: 1.3; + +$gray-lightest: #f7f7f7; +$gray-light: darken($gray-lightest, 10%); +$gray: darken(#f7f7f7, 30%); +$gray-dark: darken(#f7f7f7, 50%); +$gray-darkest: darken($gray-lightest, 70%); + +$blue: #00B5E2; +$dark-blue: #008CAF; +$light-blue: #65DDFB; + +$red: #AF2F11; +$dark-red: #7C210C; +$light-red: #FB8165; + +$bg-color: $gray-lightest; + +$text-color: #4d525a; +$text-color-light: lighten($text-color, 30%); + +$line-color: $gray-light; +$line-color-light: lighten($gray-light, 20%); + +$link-color: $blue; + +$border-radius-base: 3px; +$border-radius-lg: 6px; + +$main-color: $blue; +$main-color-dark: $blue; + +$highlight-color: $blue; +$highlight-color-dark: $dark-blue; + +$alert-color: #FB4418; diff --git a/app/assets/sass/font-awesome/_animated.scss b/app/assets/sass/font-awesome/_animated.scss new file mode 100644 index 0000000..8a020db --- /dev/null +++ b/app/assets/sass/font-awesome/_animated.scss @@ -0,0 +1,34 @@ +// Spinning Icons +// -------------------------- + +.#{$fa-css-prefix}-spin { + -webkit-animation: fa-spin 2s infinite linear; + animation: fa-spin 2s infinite linear; +} + +.#{$fa-css-prefix}-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); + } +} diff --git a/app/assets/sass/font-awesome/_bordered-pulled.scss b/app/assets/sass/font-awesome/_bordered-pulled.scss new file mode 100644 index 0000000..d4b85a0 --- /dev/null +++ b/app/assets/sass/font-awesome/_bordered-pulled.scss @@ -0,0 +1,25 @@ +// Bordered & Pulled +// ------------------------- + +.#{$fa-css-prefix}-border { + padding: .2em .25em .15em; + border: solid .08em $fa-border-color; + border-radius: .1em; +} + +.#{$fa-css-prefix}-pull-left { float: left; } +.#{$fa-css-prefix}-pull-right { float: right; } + +.#{$fa-css-prefix} { + &.#{$fa-css-prefix}-pull-left { margin-right: .3em; } + &.#{$fa-css-prefix}-pull-right { margin-left: .3em; } +} + +/* Deprecated as of 4.4.0 */ +.pull-right { float: right; } +.pull-left { float: left; } + +.#{$fa-css-prefix} { + &.pull-left { margin-right: .3em; } + &.pull-right { margin-left: .3em; } +} diff --git a/app/assets/sass/font-awesome/_core.scss b/app/assets/sass/font-awesome/_core.scss new file mode 100644 index 0000000..7425ef8 --- /dev/null +++ b/app/assets/sass/font-awesome/_core.scss @@ -0,0 +1,12 @@ +// Base Class Definition +// ------------------------- + +.#{$fa-css-prefix} { + display: inline-block; + font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration + font-size: inherit; // can't have font-size inherit on line above, so need to override + text-rendering: auto; // optimizelegibility throws things off #1094 + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + +} diff --git a/app/assets/sass/font-awesome/_fixed-width.scss b/app/assets/sass/font-awesome/_fixed-width.scss new file mode 100644 index 0000000..b221c98 --- /dev/null +++ b/app/assets/sass/font-awesome/_fixed-width.scss @@ -0,0 +1,6 @@ +// Fixed Width Icons +// ------------------------- +.#{$fa-css-prefix}-fw { + width: (18em / 14); + text-align: center; +} diff --git a/app/assets/sass/font-awesome/_icons.scss b/app/assets/sass/font-awesome/_icons.scss new file mode 100644 index 0000000..6f93759 --- /dev/null +++ b/app/assets/sass/font-awesome/_icons.scss @@ -0,0 +1,697 @@ +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ + +.#{$fa-css-prefix}-glass:before { content: $fa-var-glass; } +.#{$fa-css-prefix}-music:before { content: $fa-var-music; } +.#{$fa-css-prefix}-search:before { content: $fa-var-search; } +.#{$fa-css-prefix}-envelope-o:before { content: $fa-var-envelope-o; } +.#{$fa-css-prefix}-heart:before { content: $fa-var-heart; } +.#{$fa-css-prefix}-star:before { content: $fa-var-star; } +.#{$fa-css-prefix}-star-o:before { content: $fa-var-star-o; } +.#{$fa-css-prefix}-user:before { content: $fa-var-user; } +.#{$fa-css-prefix}-film:before { content: $fa-var-film; } +.#{$fa-css-prefix}-th-large:before { content: $fa-var-th-large; } +.#{$fa-css-prefix}-th:before { content: $fa-var-th; } +.#{$fa-css-prefix}-th-list:before { content: $fa-var-th-list; } +.#{$fa-css-prefix}-check:before { content: $fa-var-check; } +.#{$fa-css-prefix}-remove:before, +.#{$fa-css-prefix}-close:before, +.#{$fa-css-prefix}-times:before { content: $fa-var-times; } +.#{$fa-css-prefix}-search-plus:before { content: $fa-var-search-plus; } +.#{$fa-css-prefix}-search-minus:before { content: $fa-var-search-minus; } +.#{$fa-css-prefix}-power-off:before { content: $fa-var-power-off; } +.#{$fa-css-prefix}-signal:before { content: $fa-var-signal; } +.#{$fa-css-prefix}-gear:before, +.#{$fa-css-prefix}-cog:before { content: $fa-var-cog; } +.#{$fa-css-prefix}-trash-o:before { content: $fa-var-trash-o; } +.#{$fa-css-prefix}-home:before { content: $fa-var-home; } +.#{$fa-css-prefix}-file-o:before { content: $fa-var-file-o; } +.#{$fa-css-prefix}-clock-o:before { content: $fa-var-clock-o; } +.#{$fa-css-prefix}-road:before { content: $fa-var-road; } +.#{$fa-css-prefix}-download:before { content: $fa-var-download; } +.#{$fa-css-prefix}-arrow-circle-o-down:before { content: $fa-var-arrow-circle-o-down; } +.#{$fa-css-prefix}-arrow-circle-o-up:before { content: $fa-var-arrow-circle-o-up; } +.#{$fa-css-prefix}-inbox:before { content: $fa-var-inbox; } +.#{$fa-css-prefix}-play-circle-o:before { content: $fa-var-play-circle-o; } +.#{$fa-css-prefix}-rotate-right:before, +.#{$fa-css-prefix}-repeat:before { content: $fa-var-repeat; } +.#{$fa-css-prefix}-refresh:before { content: $fa-var-refresh; } +.#{$fa-css-prefix}-list-alt:before { content: $fa-var-list-alt; } +.#{$fa-css-prefix}-lock:before { content: $fa-var-lock; } +.#{$fa-css-prefix}-flag:before { content: $fa-var-flag; } +.#{$fa-css-prefix}-headphones:before { content: $fa-var-headphones; } +.#{$fa-css-prefix}-volume-off:before { content: $fa-var-volume-off; } +.#{$fa-css-prefix}-volume-down:before { content: $fa-var-volume-down; } +.#{$fa-css-prefix}-volume-up:before { content: $fa-var-volume-up; } +.#{$fa-css-prefix}-qrcode:before { content: $fa-var-qrcode; } +.#{$fa-css-prefix}-barcode:before { content: $fa-var-barcode; } +.#{$fa-css-prefix}-tag:before { content: $fa-var-tag; } +.#{$fa-css-prefix}-tags:before { content: $fa-var-tags; } +.#{$fa-css-prefix}-book:before { content: $fa-var-book; } +.#{$fa-css-prefix}-bookmark:before { content: $fa-var-bookmark; } +.#{$fa-css-prefix}-print:before { content: $fa-var-print; } +.#{$fa-css-prefix}-camera:before { content: $fa-var-camera; } +.#{$fa-css-prefix}-font:before { content: $fa-var-font; } +.#{$fa-css-prefix}-bold:before { content: $fa-var-bold; } +.#{$fa-css-prefix}-italic:before { content: $fa-var-italic; } +.#{$fa-css-prefix}-text-height:before { content: $fa-var-text-height; } +.#{$fa-css-prefix}-text-width:before { content: $fa-var-text-width; } +.#{$fa-css-prefix}-align-left:before { content: $fa-var-align-left; } +.#{$fa-css-prefix}-align-center:before { content: $fa-var-align-center; } +.#{$fa-css-prefix}-align-right:before { content: $fa-var-align-right; } +.#{$fa-css-prefix}-align-justify:before { content: $fa-var-align-justify; } +.#{$fa-css-prefix}-list:before { content: $fa-var-list; } +.#{$fa-css-prefix}-dedent:before, +.#{$fa-css-prefix}-outdent:before { content: $fa-var-outdent; } +.#{$fa-css-prefix}-indent:before { content: $fa-var-indent; } +.#{$fa-css-prefix}-video-camera:before { content: $fa-var-video-camera; } +.#{$fa-css-prefix}-photo:before, +.#{$fa-css-prefix}-image:before, +.#{$fa-css-prefix}-picture-o:before { content: $fa-var-picture-o; } +.#{$fa-css-prefix}-pencil:before { content: $fa-var-pencil; } +.#{$fa-css-prefix}-map-marker:before { content: $fa-var-map-marker; } +.#{$fa-css-prefix}-adjust:before { content: $fa-var-adjust; } +.#{$fa-css-prefix}-tint:before { content: $fa-var-tint; } +.#{$fa-css-prefix}-edit:before, +.#{$fa-css-prefix}-pencil-square-o:before { content: $fa-var-pencil-square-o; } +.#{$fa-css-prefix}-share-square-o:before { content: $fa-var-share-square-o; } +.#{$fa-css-prefix}-check-square-o:before { content: $fa-var-check-square-o; } +.#{$fa-css-prefix}-arrows:before { content: $fa-var-arrows; } +.#{$fa-css-prefix}-step-backward:before { content: $fa-var-step-backward; } +.#{$fa-css-prefix}-fast-backward:before { content: $fa-var-fast-backward; } +.#{$fa-css-prefix}-backward:before { content: $fa-var-backward; } +.#{$fa-css-prefix}-play:before { content: $fa-var-play; } +.#{$fa-css-prefix}-pause:before { content: $fa-var-pause; } +.#{$fa-css-prefix}-stop:before { content: $fa-var-stop; } +.#{$fa-css-prefix}-forward:before { content: $fa-var-forward; } +.#{$fa-css-prefix}-fast-forward:before { content: $fa-var-fast-forward; } +.#{$fa-css-prefix}-step-forward:before { content: $fa-var-step-forward; } +.#{$fa-css-prefix}-eject:before { content: $fa-var-eject; } +.#{$fa-css-prefix}-chevron-left:before { content: $fa-var-chevron-left; } +.#{$fa-css-prefix}-chevron-right:before { content: $fa-var-chevron-right; } +.#{$fa-css-prefix}-plus-circle:before { content: $fa-var-plus-circle; } +.#{$fa-css-prefix}-minus-circle:before { content: $fa-var-minus-circle; } +.#{$fa-css-prefix}-times-circle:before { content: $fa-var-times-circle; } +.#{$fa-css-prefix}-check-circle:before { content: $fa-var-check-circle; } +.#{$fa-css-prefix}-question-circle:before { content: $fa-var-question-circle; } +.#{$fa-css-prefix}-info-circle:before { content: $fa-var-info-circle; } +.#{$fa-css-prefix}-crosshairs:before { content: $fa-var-crosshairs; } +.#{$fa-css-prefix}-times-circle-o:before { content: $fa-var-times-circle-o; } +.#{$fa-css-prefix}-check-circle-o:before { content: $fa-var-check-circle-o; } +.#{$fa-css-prefix}-ban:before { content: $fa-var-ban; } +.#{$fa-css-prefix}-arrow-left:before { content: $fa-var-arrow-left; } +.#{$fa-css-prefix}-arrow-right:before { content: $fa-var-arrow-right; } +.#{$fa-css-prefix}-arrow-up:before { content: $fa-var-arrow-up; } +.#{$fa-css-prefix}-arrow-down:before { content: $fa-var-arrow-down; } +.#{$fa-css-prefix}-mail-forward:before, +.#{$fa-css-prefix}-share:before { content: $fa-var-share; } +.#{$fa-css-prefix}-expand:before { content: $fa-var-expand; } +.#{$fa-css-prefix}-compress:before { content: $fa-var-compress; } +.#{$fa-css-prefix}-plus:before { content: $fa-var-plus; } +.#{$fa-css-prefix}-minus:before { content: $fa-var-minus; } +.#{$fa-css-prefix}-asterisk:before { content: $fa-var-asterisk; } +.#{$fa-css-prefix}-exclamation-circle:before { content: $fa-var-exclamation-circle; } +.#{$fa-css-prefix}-gift:before { content: $fa-var-gift; } +.#{$fa-css-prefix}-leaf:before { content: $fa-var-leaf; } +.#{$fa-css-prefix}-fire:before { content: $fa-var-fire; } +.#{$fa-css-prefix}-eye:before { content: $fa-var-eye; } +.#{$fa-css-prefix}-eye-slash:before { content: $fa-var-eye-slash; } +.#{$fa-css-prefix}-warning:before, +.#{$fa-css-prefix}-exclamation-triangle:before { content: $fa-var-exclamation-triangle; } +.#{$fa-css-prefix}-plane:before { content: $fa-var-plane; } +.#{$fa-css-prefix}-calendar:before { content: $fa-var-calendar; } +.#{$fa-css-prefix}-random:before { content: $fa-var-random; } +.#{$fa-css-prefix}-comment:before { content: $fa-var-comment; } +.#{$fa-css-prefix}-magnet:before { content: $fa-var-magnet; } +.#{$fa-css-prefix}-chevron-up:before { content: $fa-var-chevron-up; } +.#{$fa-css-prefix}-chevron-down:before { content: $fa-var-chevron-down; } +.#{$fa-css-prefix}-retweet:before { content: $fa-var-retweet; } +.#{$fa-css-prefix}-shopping-cart:before { content: $fa-var-shopping-cart; } +.#{$fa-css-prefix}-folder:before { content: $fa-var-folder; } +.#{$fa-css-prefix}-folder-open:before { content: $fa-var-folder-open; } +.#{$fa-css-prefix}-arrows-v:before { content: $fa-var-arrows-v; } +.#{$fa-css-prefix}-arrows-h:before { content: $fa-var-arrows-h; } +.#{$fa-css-prefix}-bar-chart-o:before, +.#{$fa-css-prefix}-bar-chart:before { content: $fa-var-bar-chart; } +.#{$fa-css-prefix}-twitter-square:before { content: $fa-var-twitter-square; } +.#{$fa-css-prefix}-facebook-square:before { content: $fa-var-facebook-square; } +.#{$fa-css-prefix}-camera-retro:before { content: $fa-var-camera-retro; } +.#{$fa-css-prefix}-key:before { content: $fa-var-key; } +.#{$fa-css-prefix}-gears:before, +.#{$fa-css-prefix}-cogs:before { content: $fa-var-cogs; } +.#{$fa-css-prefix}-comments:before { content: $fa-var-comments; } +.#{$fa-css-prefix}-thumbs-o-up:before { content: $fa-var-thumbs-o-up; } +.#{$fa-css-prefix}-thumbs-o-down:before { content: $fa-var-thumbs-o-down; } +.#{$fa-css-prefix}-star-half:before { content: $fa-var-star-half; } +.#{$fa-css-prefix}-heart-o:before { content: $fa-var-heart-o; } +.#{$fa-css-prefix}-sign-out:before { content: $fa-var-sign-out; } +.#{$fa-css-prefix}-linkedin-square:before { content: $fa-var-linkedin-square; } +.#{$fa-css-prefix}-thumb-tack:before { content: $fa-var-thumb-tack; } +.#{$fa-css-prefix}-external-link:before { content: $fa-var-external-link; } +.#{$fa-css-prefix}-sign-in:before { content: $fa-var-sign-in; } +.#{$fa-css-prefix}-trophy:before { content: $fa-var-trophy; } +.#{$fa-css-prefix}-github-square:before { content: $fa-var-github-square; } +.#{$fa-css-prefix}-upload:before { content: $fa-var-upload; } +.#{$fa-css-prefix}-lemon-o:before { content: $fa-var-lemon-o; } +.#{$fa-css-prefix}-phone:before { content: $fa-var-phone; } +.#{$fa-css-prefix}-square-o:before { content: $fa-var-square-o; } +.#{$fa-css-prefix}-bookmark-o:before { content: $fa-var-bookmark-o; } +.#{$fa-css-prefix}-phone-square:before { content: $fa-var-phone-square; } +.#{$fa-css-prefix}-twitter:before { content: $fa-var-twitter; } +.#{$fa-css-prefix}-facebook-f:before, +.#{$fa-css-prefix}-facebook:before { content: $fa-var-facebook; } +.#{$fa-css-prefix}-github:before { content: $fa-var-github; } +.#{$fa-css-prefix}-unlock:before { content: $fa-var-unlock; } +.#{$fa-css-prefix}-credit-card:before { content: $fa-var-credit-card; } +.#{$fa-css-prefix}-feed:before, +.#{$fa-css-prefix}-rss:before { content: $fa-var-rss; } +.#{$fa-css-prefix}-hdd-o:before { content: $fa-var-hdd-o; } +.#{$fa-css-prefix}-bullhorn:before { content: $fa-var-bullhorn; } +.#{$fa-css-prefix}-bell:before { content: $fa-var-bell; } +.#{$fa-css-prefix}-certificate:before { content: $fa-var-certificate; } +.#{$fa-css-prefix}-hand-o-right:before { content: $fa-var-hand-o-right; } +.#{$fa-css-prefix}-hand-o-left:before { content: $fa-var-hand-o-left; } +.#{$fa-css-prefix}-hand-o-up:before { content: $fa-var-hand-o-up; } +.#{$fa-css-prefix}-hand-o-down:before { content: $fa-var-hand-o-down; } +.#{$fa-css-prefix}-arrow-circle-left:before { content: $fa-var-arrow-circle-left; } +.#{$fa-css-prefix}-arrow-circle-right:before { content: $fa-var-arrow-circle-right; } +.#{$fa-css-prefix}-arrow-circle-up:before { content: $fa-var-arrow-circle-up; } +.#{$fa-css-prefix}-arrow-circle-down:before { content: $fa-var-arrow-circle-down; } +.#{$fa-css-prefix}-globe:before { content: $fa-var-globe; } +.#{$fa-css-prefix}-wrench:before { content: $fa-var-wrench; } +.#{$fa-css-prefix}-tasks:before { content: $fa-var-tasks; } +.#{$fa-css-prefix}-filter:before { content: $fa-var-filter; } +.#{$fa-css-prefix}-briefcase:before { content: $fa-var-briefcase; } +.#{$fa-css-prefix}-arrows-alt:before { content: $fa-var-arrows-alt; } +.#{$fa-css-prefix}-group:before, +.#{$fa-css-prefix}-users:before { content: $fa-var-users; } +.#{$fa-css-prefix}-chain:before, +.#{$fa-css-prefix}-link:before { content: $fa-var-link; } +.#{$fa-css-prefix}-cloud:before { content: $fa-var-cloud; } +.#{$fa-css-prefix}-flask:before { content: $fa-var-flask; } +.#{$fa-css-prefix}-cut:before, +.#{$fa-css-prefix}-scissors:before { content: $fa-var-scissors; } +.#{$fa-css-prefix}-copy:before, +.#{$fa-css-prefix}-files-o:before { content: $fa-var-files-o; } +.#{$fa-css-prefix}-paperclip:before { content: $fa-var-paperclip; } +.#{$fa-css-prefix}-save:before, +.#{$fa-css-prefix}-floppy-o:before { content: $fa-var-floppy-o; } +.#{$fa-css-prefix}-square:before { content: $fa-var-square; } +.#{$fa-css-prefix}-navicon:before, +.#{$fa-css-prefix}-reorder:before, +.#{$fa-css-prefix}-bars:before { content: $fa-var-bars; } +.#{$fa-css-prefix}-list-ul:before { content: $fa-var-list-ul; } +.#{$fa-css-prefix}-list-ol:before { content: $fa-var-list-ol; } +.#{$fa-css-prefix}-strikethrough:before { content: $fa-var-strikethrough; } +.#{$fa-css-prefix}-underline:before { content: $fa-var-underline; } +.#{$fa-css-prefix}-table:before { content: $fa-var-table; } +.#{$fa-css-prefix}-magic:before { content: $fa-var-magic; } +.#{$fa-css-prefix}-truck:before { content: $fa-var-truck; } +.#{$fa-css-prefix}-pinterest:before { content: $fa-var-pinterest; } +.#{$fa-css-prefix}-pinterest-square:before { content: $fa-var-pinterest-square; } +.#{$fa-css-prefix}-google-plus-square:before { content: $fa-var-google-plus-square; } +.#{$fa-css-prefix}-google-plus:before { content: $fa-var-google-plus; } +.#{$fa-css-prefix}-money:before { content: $fa-var-money; } +.#{$fa-css-prefix}-caret-down:before { content: $fa-var-caret-down; } +.#{$fa-css-prefix}-caret-up:before { content: $fa-var-caret-up; } +.#{$fa-css-prefix}-caret-left:before { content: $fa-var-caret-left; } +.#{$fa-css-prefix}-caret-right:before { content: $fa-var-caret-right; } +.#{$fa-css-prefix}-columns:before { content: $fa-var-columns; } +.#{$fa-css-prefix}-unsorted:before, +.#{$fa-css-prefix}-sort:before { content: $fa-var-sort; } +.#{$fa-css-prefix}-sort-down:before, +.#{$fa-css-prefix}-sort-desc:before { content: $fa-var-sort-desc; } +.#{$fa-css-prefix}-sort-up:before, +.#{$fa-css-prefix}-sort-asc:before { content: $fa-var-sort-asc; } +.#{$fa-css-prefix}-envelope:before { content: $fa-var-envelope; } +.#{$fa-css-prefix}-linkedin:before { content: $fa-var-linkedin; } +.#{$fa-css-prefix}-rotate-left:before, +.#{$fa-css-prefix}-undo:before { content: $fa-var-undo; } +.#{$fa-css-prefix}-legal:before, +.#{$fa-css-prefix}-gavel:before { content: $fa-var-gavel; } +.#{$fa-css-prefix}-dashboard:before, +.#{$fa-css-prefix}-tachometer:before { content: $fa-var-tachometer; } +.#{$fa-css-prefix}-comment-o:before { content: $fa-var-comment-o; } +.#{$fa-css-prefix}-comments-o:before { content: $fa-var-comments-o; } +.#{$fa-css-prefix}-flash:before, +.#{$fa-css-prefix}-bolt:before { content: $fa-var-bolt; } +.#{$fa-css-prefix}-sitemap:before { content: $fa-var-sitemap; } +.#{$fa-css-prefix}-umbrella:before { content: $fa-var-umbrella; } +.#{$fa-css-prefix}-paste:before, +.#{$fa-css-prefix}-clipboard:before { content: $fa-var-clipboard; } +.#{$fa-css-prefix}-lightbulb-o:before { content: $fa-var-lightbulb-o; } +.#{$fa-css-prefix}-exchange:before { content: $fa-var-exchange; } +.#{$fa-css-prefix}-cloud-download:before { content: $fa-var-cloud-download; } +.#{$fa-css-prefix}-cloud-upload:before { content: $fa-var-cloud-upload; } +.#{$fa-css-prefix}-user-md:before { content: $fa-var-user-md; } +.#{$fa-css-prefix}-stethoscope:before { content: $fa-var-stethoscope; } +.#{$fa-css-prefix}-suitcase:before { content: $fa-var-suitcase; } +.#{$fa-css-prefix}-bell-o:before { content: $fa-var-bell-o; } +.#{$fa-css-prefix}-coffee:before { content: $fa-var-coffee; } +.#{$fa-css-prefix}-cutlery:before { content: $fa-var-cutlery; } +.#{$fa-css-prefix}-file-text-o:before { content: $fa-var-file-text-o; } +.#{$fa-css-prefix}-building-o:before { content: $fa-var-building-o; } +.#{$fa-css-prefix}-hospital-o:before { content: $fa-var-hospital-o; } +.#{$fa-css-prefix}-ambulance:before { content: $fa-var-ambulance; } +.#{$fa-css-prefix}-medkit:before { content: $fa-var-medkit; } +.#{$fa-css-prefix}-fighter-jet:before { content: $fa-var-fighter-jet; } +.#{$fa-css-prefix}-beer:before { content: $fa-var-beer; } +.#{$fa-css-prefix}-h-square:before { content: $fa-var-h-square; } +.#{$fa-css-prefix}-plus-square:before { content: $fa-var-plus-square; } +.#{$fa-css-prefix}-angle-double-left:before { content: $fa-var-angle-double-left; } +.#{$fa-css-prefix}-angle-double-right:before { content: $fa-var-angle-double-right; } +.#{$fa-css-prefix}-angle-double-up:before { content: $fa-var-angle-double-up; } +.#{$fa-css-prefix}-angle-double-down:before { content: $fa-var-angle-double-down; } +.#{$fa-css-prefix}-angle-left:before { content: $fa-var-angle-left; } +.#{$fa-css-prefix}-angle-right:before { content: $fa-var-angle-right; } +.#{$fa-css-prefix}-angle-up:before { content: $fa-var-angle-up; } +.#{$fa-css-prefix}-angle-down:before { content: $fa-var-angle-down; } +.#{$fa-css-prefix}-desktop:before { content: $fa-var-desktop; } +.#{$fa-css-prefix}-laptop:before { content: $fa-var-laptop; } +.#{$fa-css-prefix}-tablet:before { content: $fa-var-tablet; } +.#{$fa-css-prefix}-mobile-phone:before, +.#{$fa-css-prefix}-mobile:before { content: $fa-var-mobile; } +.#{$fa-css-prefix}-circle-o:before { content: $fa-var-circle-o; } +.#{$fa-css-prefix}-quote-left:before { content: $fa-var-quote-left; } +.#{$fa-css-prefix}-quote-right:before { content: $fa-var-quote-right; } +.#{$fa-css-prefix}-spinner:before { content: $fa-var-spinner; } +.#{$fa-css-prefix}-circle:before { content: $fa-var-circle; } +.#{$fa-css-prefix}-mail-reply:before, +.#{$fa-css-prefix}-reply:before { content: $fa-var-reply; } +.#{$fa-css-prefix}-github-alt:before { content: $fa-var-github-alt; } +.#{$fa-css-prefix}-folder-o:before { content: $fa-var-folder-o; } +.#{$fa-css-prefix}-folder-open-o:before { content: $fa-var-folder-open-o; } +.#{$fa-css-prefix}-smile-o:before { content: $fa-var-smile-o; } +.#{$fa-css-prefix}-frown-o:before { content: $fa-var-frown-o; } +.#{$fa-css-prefix}-meh-o:before { content: $fa-var-meh-o; } +.#{$fa-css-prefix}-gamepad:before { content: $fa-var-gamepad; } +.#{$fa-css-prefix}-keyboard-o:before { content: $fa-var-keyboard-o; } +.#{$fa-css-prefix}-flag-o:before { content: $fa-var-flag-o; } +.#{$fa-css-prefix}-flag-checkered:before { content: $fa-var-flag-checkered; } +.#{$fa-css-prefix}-terminal:before { content: $fa-var-terminal; } +.#{$fa-css-prefix}-code:before { content: $fa-var-code; } +.#{$fa-css-prefix}-mail-reply-all:before, +.#{$fa-css-prefix}-reply-all:before { content: $fa-var-reply-all; } +.#{$fa-css-prefix}-star-half-empty:before, +.#{$fa-css-prefix}-star-half-full:before, +.#{$fa-css-prefix}-star-half-o:before { content: $fa-var-star-half-o; } +.#{$fa-css-prefix}-location-arrow:before { content: $fa-var-location-arrow; } +.#{$fa-css-prefix}-crop:before { content: $fa-var-crop; } +.#{$fa-css-prefix}-code-fork:before { content: $fa-var-code-fork; } +.#{$fa-css-prefix}-unlink:before, +.#{$fa-css-prefix}-chain-broken:before { content: $fa-var-chain-broken; } +.#{$fa-css-prefix}-question:before { content: $fa-var-question; } +.#{$fa-css-prefix}-info:before { content: $fa-var-info; } +.#{$fa-css-prefix}-exclamation:before { content: $fa-var-exclamation; } +.#{$fa-css-prefix}-superscript:before { content: $fa-var-superscript; } +.#{$fa-css-prefix}-subscript:before { content: $fa-var-subscript; } +.#{$fa-css-prefix}-eraser:before { content: $fa-var-eraser; } +.#{$fa-css-prefix}-puzzle-piece:before { content: $fa-var-puzzle-piece; } +.#{$fa-css-prefix}-microphone:before { content: $fa-var-microphone; } +.#{$fa-css-prefix}-microphone-slash:before { content: $fa-var-microphone-slash; } +.#{$fa-css-prefix}-shield:before { content: $fa-var-shield; } +.#{$fa-css-prefix}-calendar-o:before { content: $fa-var-calendar-o; } +.#{$fa-css-prefix}-fire-extinguisher:before { content: $fa-var-fire-extinguisher; } +.#{$fa-css-prefix}-rocket:before { content: $fa-var-rocket; } +.#{$fa-css-prefix}-maxcdn:before { content: $fa-var-maxcdn; } +.#{$fa-css-prefix}-chevron-circle-left:before { content: $fa-var-chevron-circle-left; } +.#{$fa-css-prefix}-chevron-circle-right:before { content: $fa-var-chevron-circle-right; } +.#{$fa-css-prefix}-chevron-circle-up:before { content: $fa-var-chevron-circle-up; } +.#{$fa-css-prefix}-chevron-circle-down:before { content: $fa-var-chevron-circle-down; } +.#{$fa-css-prefix}-html5:before { content: $fa-var-html5; } +.#{$fa-css-prefix}-css3:before { content: $fa-var-css3; } +.#{$fa-css-prefix}-anchor:before { content: $fa-var-anchor; } +.#{$fa-css-prefix}-unlock-alt:before { content: $fa-var-unlock-alt; } +.#{$fa-css-prefix}-bullseye:before { content: $fa-var-bullseye; } +.#{$fa-css-prefix}-ellipsis-h:before { content: $fa-var-ellipsis-h; } +.#{$fa-css-prefix}-ellipsis-v:before { content: $fa-var-ellipsis-v; } +.#{$fa-css-prefix}-rss-square:before { content: $fa-var-rss-square; } +.#{$fa-css-prefix}-play-circle:before { content: $fa-var-play-circle; } +.#{$fa-css-prefix}-ticket:before { content: $fa-var-ticket; } +.#{$fa-css-prefix}-minus-square:before { content: $fa-var-minus-square; } +.#{$fa-css-prefix}-minus-square-o:before { content: $fa-var-minus-square-o; } +.#{$fa-css-prefix}-level-up:before { content: $fa-var-level-up; } +.#{$fa-css-prefix}-level-down:before { content: $fa-var-level-down; } +.#{$fa-css-prefix}-check-square:before { content: $fa-var-check-square; } +.#{$fa-css-prefix}-pencil-square:before { content: $fa-var-pencil-square; } +.#{$fa-css-prefix}-external-link-square:before { content: $fa-var-external-link-square; } +.#{$fa-css-prefix}-share-square:before { content: $fa-var-share-square; } +.#{$fa-css-prefix}-compass:before { content: $fa-var-compass; } +.#{$fa-css-prefix}-toggle-down:before, +.#{$fa-css-prefix}-caret-square-o-down:before { content: $fa-var-caret-square-o-down; } +.#{$fa-css-prefix}-toggle-up:before, +.#{$fa-css-prefix}-caret-square-o-up:before { content: $fa-var-caret-square-o-up; } +.#{$fa-css-prefix}-toggle-right:before, +.#{$fa-css-prefix}-caret-square-o-right:before { content: $fa-var-caret-square-o-right; } +.#{$fa-css-prefix}-euro:before, +.#{$fa-css-prefix}-eur:before { content: $fa-var-eur; } +.#{$fa-css-prefix}-gbp:before { content: $fa-var-gbp; } +.#{$fa-css-prefix}-dollar:before, +.#{$fa-css-prefix}-usd:before { content: $fa-var-usd; } +.#{$fa-css-prefix}-rupee:before, +.#{$fa-css-prefix}-inr:before { content: $fa-var-inr; } +.#{$fa-css-prefix}-cny:before, +.#{$fa-css-prefix}-rmb:before, +.#{$fa-css-prefix}-yen:before, +.#{$fa-css-prefix}-jpy:before { content: $fa-var-jpy; } +.#{$fa-css-prefix}-ruble:before, +.#{$fa-css-prefix}-rouble:before, +.#{$fa-css-prefix}-rub:before { content: $fa-var-rub; } +.#{$fa-css-prefix}-won:before, +.#{$fa-css-prefix}-krw:before { content: $fa-var-krw; } +.#{$fa-css-prefix}-bitcoin:before, +.#{$fa-css-prefix}-btc:before { content: $fa-var-btc; } +.#{$fa-css-prefix}-file:before { content: $fa-var-file; } +.#{$fa-css-prefix}-file-text:before { content: $fa-var-file-text; } +.#{$fa-css-prefix}-sort-alpha-asc:before { content: $fa-var-sort-alpha-asc; } +.#{$fa-css-prefix}-sort-alpha-desc:before { content: $fa-var-sort-alpha-desc; } +.#{$fa-css-prefix}-sort-amount-asc:before { content: $fa-var-sort-amount-asc; } +.#{$fa-css-prefix}-sort-amount-desc:before { content: $fa-var-sort-amount-desc; } +.#{$fa-css-prefix}-sort-numeric-asc:before { content: $fa-var-sort-numeric-asc; } +.#{$fa-css-prefix}-sort-numeric-desc:before { content: $fa-var-sort-numeric-desc; } +.#{$fa-css-prefix}-thumbs-up:before { content: $fa-var-thumbs-up; } +.#{$fa-css-prefix}-thumbs-down:before { content: $fa-var-thumbs-down; } +.#{$fa-css-prefix}-youtube-square:before { content: $fa-var-youtube-square; } +.#{$fa-css-prefix}-youtube:before { content: $fa-var-youtube; } +.#{$fa-css-prefix}-xing:before { content: $fa-var-xing; } +.#{$fa-css-prefix}-xing-square:before { content: $fa-var-xing-square; } +.#{$fa-css-prefix}-youtube-play:before { content: $fa-var-youtube-play; } +.#{$fa-css-prefix}-dropbox:before { content: $fa-var-dropbox; } +.#{$fa-css-prefix}-stack-overflow:before { content: $fa-var-stack-overflow; } +.#{$fa-css-prefix}-instagram:before { content: $fa-var-instagram; } +.#{$fa-css-prefix}-flickr:before { content: $fa-var-flickr; } +.#{$fa-css-prefix}-adn:before { content: $fa-var-adn; } +.#{$fa-css-prefix}-bitbucket:before { content: $fa-var-bitbucket; } +.#{$fa-css-prefix}-bitbucket-square:before { content: $fa-var-bitbucket-square; } +.#{$fa-css-prefix}-tumblr:before { content: $fa-var-tumblr; } +.#{$fa-css-prefix}-tumblr-square:before { content: $fa-var-tumblr-square; } +.#{$fa-css-prefix}-long-arrow-down:before { content: $fa-var-long-arrow-down; } +.#{$fa-css-prefix}-long-arrow-up:before { content: $fa-var-long-arrow-up; } +.#{$fa-css-prefix}-long-arrow-left:before { content: $fa-var-long-arrow-left; } +.#{$fa-css-prefix}-long-arrow-right:before { content: $fa-var-long-arrow-right; } +.#{$fa-css-prefix}-apple:before { content: $fa-var-apple; } +.#{$fa-css-prefix}-windows:before { content: $fa-var-windows; } +.#{$fa-css-prefix}-android:before { content: $fa-var-android; } +.#{$fa-css-prefix}-linux:before { content: $fa-var-linux; } +.#{$fa-css-prefix}-dribbble:before { content: $fa-var-dribbble; } +.#{$fa-css-prefix}-skype:before { content: $fa-var-skype; } +.#{$fa-css-prefix}-foursquare:before { content: $fa-var-foursquare; } +.#{$fa-css-prefix}-trello:before { content: $fa-var-trello; } +.#{$fa-css-prefix}-female:before { content: $fa-var-female; } +.#{$fa-css-prefix}-male:before { content: $fa-var-male; } +.#{$fa-css-prefix}-gittip:before, +.#{$fa-css-prefix}-gratipay:before { content: $fa-var-gratipay; } +.#{$fa-css-prefix}-sun-o:before { content: $fa-var-sun-o; } +.#{$fa-css-prefix}-moon-o:before { content: $fa-var-moon-o; } +.#{$fa-css-prefix}-archive:before { content: $fa-var-archive; } +.#{$fa-css-prefix}-bug:before { content: $fa-var-bug; } +.#{$fa-css-prefix}-vk:before { content: $fa-var-vk; } +.#{$fa-css-prefix}-weibo:before { content: $fa-var-weibo; } +.#{$fa-css-prefix}-renren:before { content: $fa-var-renren; } +.#{$fa-css-prefix}-pagelines:before { content: $fa-var-pagelines; } +.#{$fa-css-prefix}-stack-exchange:before { content: $fa-var-stack-exchange; } +.#{$fa-css-prefix}-arrow-circle-o-right:before { content: $fa-var-arrow-circle-o-right; } +.#{$fa-css-prefix}-arrow-circle-o-left:before { content: $fa-var-arrow-circle-o-left; } +.#{$fa-css-prefix}-toggle-left:before, +.#{$fa-css-prefix}-caret-square-o-left:before { content: $fa-var-caret-square-o-left; } +.#{$fa-css-prefix}-dot-circle-o:before { content: $fa-var-dot-circle-o; } +.#{$fa-css-prefix}-wheelchair:before { content: $fa-var-wheelchair; } +.#{$fa-css-prefix}-vimeo-square:before { content: $fa-var-vimeo-square; } +.#{$fa-css-prefix}-turkish-lira:before, +.#{$fa-css-prefix}-try:before { content: $fa-var-try; } +.#{$fa-css-prefix}-plus-square-o:before { content: $fa-var-plus-square-o; } +.#{$fa-css-prefix}-space-shuttle:before { content: $fa-var-space-shuttle; } +.#{$fa-css-prefix}-slack:before { content: $fa-var-slack; } +.#{$fa-css-prefix}-envelope-square:before { content: $fa-var-envelope-square; } +.#{$fa-css-prefix}-wordpress:before { content: $fa-var-wordpress; } +.#{$fa-css-prefix}-openid:before { content: $fa-var-openid; } +.#{$fa-css-prefix}-institution:before, +.#{$fa-css-prefix}-bank:before, +.#{$fa-css-prefix}-university:before { content: $fa-var-university; } +.#{$fa-css-prefix}-mortar-board:before, +.#{$fa-css-prefix}-graduation-cap:before { content: $fa-var-graduation-cap; } +.#{$fa-css-prefix}-yahoo:before { content: $fa-var-yahoo; } +.#{$fa-css-prefix}-google:before { content: $fa-var-google; } +.#{$fa-css-prefix}-reddit:before { content: $fa-var-reddit; } +.#{$fa-css-prefix}-reddit-square:before { content: $fa-var-reddit-square; } +.#{$fa-css-prefix}-stumbleupon-circle:before { content: $fa-var-stumbleupon-circle; } +.#{$fa-css-prefix}-stumbleupon:before { content: $fa-var-stumbleupon; } +.#{$fa-css-prefix}-delicious:before { content: $fa-var-delicious; } +.#{$fa-css-prefix}-digg:before { content: $fa-var-digg; } +.#{$fa-css-prefix}-pied-piper:before { content: $fa-var-pied-piper; } +.#{$fa-css-prefix}-pied-piper-alt:before { content: $fa-var-pied-piper-alt; } +.#{$fa-css-prefix}-drupal:before { content: $fa-var-drupal; } +.#{$fa-css-prefix}-joomla:before { content: $fa-var-joomla; } +.#{$fa-css-prefix}-language:before { content: $fa-var-language; } +.#{$fa-css-prefix}-fax:before { content: $fa-var-fax; } +.#{$fa-css-prefix}-building:before { content: $fa-var-building; } +.#{$fa-css-prefix}-child:before { content: $fa-var-child; } +.#{$fa-css-prefix}-paw:before { content: $fa-var-paw; } +.#{$fa-css-prefix}-spoon:before { content: $fa-var-spoon; } +.#{$fa-css-prefix}-cube:before { content: $fa-var-cube; } +.#{$fa-css-prefix}-cubes:before { content: $fa-var-cubes; } +.#{$fa-css-prefix}-behance:before { content: $fa-var-behance; } +.#{$fa-css-prefix}-behance-square:before { content: $fa-var-behance-square; } +.#{$fa-css-prefix}-steam:before { content: $fa-var-steam; } +.#{$fa-css-prefix}-steam-square:before { content: $fa-var-steam-square; } +.#{$fa-css-prefix}-recycle:before { content: $fa-var-recycle; } +.#{$fa-css-prefix}-automobile:before, +.#{$fa-css-prefix}-car:before { content: $fa-var-car; } +.#{$fa-css-prefix}-cab:before, +.#{$fa-css-prefix}-taxi:before { content: $fa-var-taxi; } +.#{$fa-css-prefix}-tree:before { content: $fa-var-tree; } +.#{$fa-css-prefix}-spotify:before { content: $fa-var-spotify; } +.#{$fa-css-prefix}-deviantart:before { content: $fa-var-deviantart; } +.#{$fa-css-prefix}-soundcloud:before { content: $fa-var-soundcloud; } +.#{$fa-css-prefix}-database:before { content: $fa-var-database; } +.#{$fa-css-prefix}-file-pdf-o:before { content: $fa-var-file-pdf-o; } +.#{$fa-css-prefix}-file-word-o:before { content: $fa-var-file-word-o; } +.#{$fa-css-prefix}-file-excel-o:before { content: $fa-var-file-excel-o; } +.#{$fa-css-prefix}-file-powerpoint-o:before { content: $fa-var-file-powerpoint-o; } +.#{$fa-css-prefix}-file-photo-o:before, +.#{$fa-css-prefix}-file-picture-o:before, +.#{$fa-css-prefix}-file-image-o:before { content: $fa-var-file-image-o; } +.#{$fa-css-prefix}-file-zip-o:before, +.#{$fa-css-prefix}-file-archive-o:before { content: $fa-var-file-archive-o; } +.#{$fa-css-prefix}-file-sound-o:before, +.#{$fa-css-prefix}-file-audio-o:before { content: $fa-var-file-audio-o; } +.#{$fa-css-prefix}-file-movie-o:before, +.#{$fa-css-prefix}-file-video-o:before { content: $fa-var-file-video-o; } +.#{$fa-css-prefix}-file-code-o:before { content: $fa-var-file-code-o; } +.#{$fa-css-prefix}-vine:before { content: $fa-var-vine; } +.#{$fa-css-prefix}-codepen:before { content: $fa-var-codepen; } +.#{$fa-css-prefix}-jsfiddle:before { content: $fa-var-jsfiddle; } +.#{$fa-css-prefix}-life-bouy:before, +.#{$fa-css-prefix}-life-buoy:before, +.#{$fa-css-prefix}-life-saver:before, +.#{$fa-css-prefix}-support:before, +.#{$fa-css-prefix}-life-ring:before { content: $fa-var-life-ring; } +.#{$fa-css-prefix}-circle-o-notch:before { content: $fa-var-circle-o-notch; } +.#{$fa-css-prefix}-ra:before, +.#{$fa-css-prefix}-rebel:before { content: $fa-var-rebel; } +.#{$fa-css-prefix}-ge:before, +.#{$fa-css-prefix}-empire:before { content: $fa-var-empire; } +.#{$fa-css-prefix}-git-square:before { content: $fa-var-git-square; } +.#{$fa-css-prefix}-git:before { content: $fa-var-git; } +.#{$fa-css-prefix}-y-combinator-square:before, +.#{$fa-css-prefix}-yc-square:before, +.#{$fa-css-prefix}-hacker-news:before { content: $fa-var-hacker-news; } +.#{$fa-css-prefix}-tencent-weibo:before { content: $fa-var-tencent-weibo; } +.#{$fa-css-prefix}-qq:before { content: $fa-var-qq; } +.#{$fa-css-prefix}-wechat:before, +.#{$fa-css-prefix}-weixin:before { content: $fa-var-weixin; } +.#{$fa-css-prefix}-send:before, +.#{$fa-css-prefix}-paper-plane:before { content: $fa-var-paper-plane; } +.#{$fa-css-prefix}-send-o:before, +.#{$fa-css-prefix}-paper-plane-o:before { content: $fa-var-paper-plane-o; } +.#{$fa-css-prefix}-history:before { content: $fa-var-history; } +.#{$fa-css-prefix}-circle-thin:before { content: $fa-var-circle-thin; } +.#{$fa-css-prefix}-header:before { content: $fa-var-header; } +.#{$fa-css-prefix}-paragraph:before { content: $fa-var-paragraph; } +.#{$fa-css-prefix}-sliders:before { content: $fa-var-sliders; } +.#{$fa-css-prefix}-share-alt:before { content: $fa-var-share-alt; } +.#{$fa-css-prefix}-share-alt-square:before { content: $fa-var-share-alt-square; } +.#{$fa-css-prefix}-bomb:before { content: $fa-var-bomb; } +.#{$fa-css-prefix}-soccer-ball-o:before, +.#{$fa-css-prefix}-futbol-o:before { content: $fa-var-futbol-o; } +.#{$fa-css-prefix}-tty:before { content: $fa-var-tty; } +.#{$fa-css-prefix}-binoculars:before { content: $fa-var-binoculars; } +.#{$fa-css-prefix}-plug:before { content: $fa-var-plug; } +.#{$fa-css-prefix}-slideshare:before { content: $fa-var-slideshare; } +.#{$fa-css-prefix}-twitch:before { content: $fa-var-twitch; } +.#{$fa-css-prefix}-yelp:before { content: $fa-var-yelp; } +.#{$fa-css-prefix}-newspaper-o:before { content: $fa-var-newspaper-o; } +.#{$fa-css-prefix}-wifi:before { content: $fa-var-wifi; } +.#{$fa-css-prefix}-calculator:before { content: $fa-var-calculator; } +.#{$fa-css-prefix}-paypal:before { content: $fa-var-paypal; } +.#{$fa-css-prefix}-google-wallet:before { content: $fa-var-google-wallet; } +.#{$fa-css-prefix}-cc-visa:before { content: $fa-var-cc-visa; } +.#{$fa-css-prefix}-cc-mastercard:before { content: $fa-var-cc-mastercard; } +.#{$fa-css-prefix}-cc-discover:before { content: $fa-var-cc-discover; } +.#{$fa-css-prefix}-cc-amex:before { content: $fa-var-cc-amex; } +.#{$fa-css-prefix}-cc-paypal:before { content: $fa-var-cc-paypal; } +.#{$fa-css-prefix}-cc-stripe:before { content: $fa-var-cc-stripe; } +.#{$fa-css-prefix}-bell-slash:before { content: $fa-var-bell-slash; } +.#{$fa-css-prefix}-bell-slash-o:before { content: $fa-var-bell-slash-o; } +.#{$fa-css-prefix}-trash:before { content: $fa-var-trash; } +.#{$fa-css-prefix}-copyright:before { content: $fa-var-copyright; } +.#{$fa-css-prefix}-at:before { content: $fa-var-at; } +.#{$fa-css-prefix}-eyedropper:before { content: $fa-var-eyedropper; } +.#{$fa-css-prefix}-paint-brush:before { content: $fa-var-paint-brush; } +.#{$fa-css-prefix}-birthday-cake:before { content: $fa-var-birthday-cake; } +.#{$fa-css-prefix}-area-chart:before { content: $fa-var-area-chart; } +.#{$fa-css-prefix}-pie-chart:before { content: $fa-var-pie-chart; } +.#{$fa-css-prefix}-line-chart:before { content: $fa-var-line-chart; } +.#{$fa-css-prefix}-lastfm:before { content: $fa-var-lastfm; } +.#{$fa-css-prefix}-lastfm-square:before { content: $fa-var-lastfm-square; } +.#{$fa-css-prefix}-toggle-off:before { content: $fa-var-toggle-off; } +.#{$fa-css-prefix}-toggle-on:before { content: $fa-var-toggle-on; } +.#{$fa-css-prefix}-bicycle:before { content: $fa-var-bicycle; } +.#{$fa-css-prefix}-bus:before { content: $fa-var-bus; } +.#{$fa-css-prefix}-ioxhost:before { content: $fa-var-ioxhost; } +.#{$fa-css-prefix}-angellist:before { content: $fa-var-angellist; } +.#{$fa-css-prefix}-cc:before { content: $fa-var-cc; } +.#{$fa-css-prefix}-shekel:before, +.#{$fa-css-prefix}-sheqel:before, +.#{$fa-css-prefix}-ils:before { content: $fa-var-ils; } +.#{$fa-css-prefix}-meanpath:before { content: $fa-var-meanpath; } +.#{$fa-css-prefix}-buysellads:before { content: $fa-var-buysellads; } +.#{$fa-css-prefix}-connectdevelop:before { content: $fa-var-connectdevelop; } +.#{$fa-css-prefix}-dashcube:before { content: $fa-var-dashcube; } +.#{$fa-css-prefix}-forumbee:before { content: $fa-var-forumbee; } +.#{$fa-css-prefix}-leanpub:before { content: $fa-var-leanpub; } +.#{$fa-css-prefix}-sellsy:before { content: $fa-var-sellsy; } +.#{$fa-css-prefix}-shirtsinbulk:before { content: $fa-var-shirtsinbulk; } +.#{$fa-css-prefix}-simplybuilt:before { content: $fa-var-simplybuilt; } +.#{$fa-css-prefix}-skyatlas:before { content: $fa-var-skyatlas; } +.#{$fa-css-prefix}-cart-plus:before { content: $fa-var-cart-plus; } +.#{$fa-css-prefix}-cart-arrow-down:before { content: $fa-var-cart-arrow-down; } +.#{$fa-css-prefix}-diamond:before { content: $fa-var-diamond; } +.#{$fa-css-prefix}-ship:before { content: $fa-var-ship; } +.#{$fa-css-prefix}-user-secret:before { content: $fa-var-user-secret; } +.#{$fa-css-prefix}-motorcycle:before { content: $fa-var-motorcycle; } +.#{$fa-css-prefix}-street-view:before { content: $fa-var-street-view; } +.#{$fa-css-prefix}-heartbeat:before { content: $fa-var-heartbeat; } +.#{$fa-css-prefix}-venus:before { content: $fa-var-venus; } +.#{$fa-css-prefix}-mars:before { content: $fa-var-mars; } +.#{$fa-css-prefix}-mercury:before { content: $fa-var-mercury; } +.#{$fa-css-prefix}-intersex:before, +.#{$fa-css-prefix}-transgender:before { content: $fa-var-transgender; } +.#{$fa-css-prefix}-transgender-alt:before { content: $fa-var-transgender-alt; } +.#{$fa-css-prefix}-venus-double:before { content: $fa-var-venus-double; } +.#{$fa-css-prefix}-mars-double:before { content: $fa-var-mars-double; } +.#{$fa-css-prefix}-venus-mars:before { content: $fa-var-venus-mars; } +.#{$fa-css-prefix}-mars-stroke:before { content: $fa-var-mars-stroke; } +.#{$fa-css-prefix}-mars-stroke-v:before { content: $fa-var-mars-stroke-v; } +.#{$fa-css-prefix}-mars-stroke-h:before { content: $fa-var-mars-stroke-h; } +.#{$fa-css-prefix}-neuter:before { content: $fa-var-neuter; } +.#{$fa-css-prefix}-genderless:before { content: $fa-var-genderless; } +.#{$fa-css-prefix}-facebook-official:before { content: $fa-var-facebook-official; } +.#{$fa-css-prefix}-pinterest-p:before { content: $fa-var-pinterest-p; } +.#{$fa-css-prefix}-whatsapp:before { content: $fa-var-whatsapp; } +.#{$fa-css-prefix}-server:before { content: $fa-var-server; } +.#{$fa-css-prefix}-user-plus:before { content: $fa-var-user-plus; } +.#{$fa-css-prefix}-user-times:before { content: $fa-var-user-times; } +.#{$fa-css-prefix}-hotel:before, +.#{$fa-css-prefix}-bed:before { content: $fa-var-bed; } +.#{$fa-css-prefix}-viacoin:before { content: $fa-var-viacoin; } +.#{$fa-css-prefix}-train:before { content: $fa-var-train; } +.#{$fa-css-prefix}-subway:before { content: $fa-var-subway; } +.#{$fa-css-prefix}-medium:before { content: $fa-var-medium; } +.#{$fa-css-prefix}-yc:before, +.#{$fa-css-prefix}-y-combinator:before { content: $fa-var-y-combinator; } +.#{$fa-css-prefix}-optin-monster:before { content: $fa-var-optin-monster; } +.#{$fa-css-prefix}-opencart:before { content: $fa-var-opencart; } +.#{$fa-css-prefix}-expeditedssl:before { content: $fa-var-expeditedssl; } +.#{$fa-css-prefix}-battery-4:before, +.#{$fa-css-prefix}-battery-full:before { content: $fa-var-battery-full; } +.#{$fa-css-prefix}-battery-3:before, +.#{$fa-css-prefix}-battery-three-quarters:before { content: $fa-var-battery-three-quarters; } +.#{$fa-css-prefix}-battery-2:before, +.#{$fa-css-prefix}-battery-half:before { content: $fa-var-battery-half; } +.#{$fa-css-prefix}-battery-1:before, +.#{$fa-css-prefix}-battery-quarter:before { content: $fa-var-battery-quarter; } +.#{$fa-css-prefix}-battery-0:before, +.#{$fa-css-prefix}-battery-empty:before { content: $fa-var-battery-empty; } +.#{$fa-css-prefix}-mouse-pointer:before { content: $fa-var-mouse-pointer; } +.#{$fa-css-prefix}-i-cursor:before { content: $fa-var-i-cursor; } +.#{$fa-css-prefix}-object-group:before { content: $fa-var-object-group; } +.#{$fa-css-prefix}-object-ungroup:before { content: $fa-var-object-ungroup; } +.#{$fa-css-prefix}-sticky-note:before { content: $fa-var-sticky-note; } +.#{$fa-css-prefix}-sticky-note-o:before { content: $fa-var-sticky-note-o; } +.#{$fa-css-prefix}-cc-jcb:before { content: $fa-var-cc-jcb; } +.#{$fa-css-prefix}-cc-diners-club:before { content: $fa-var-cc-diners-club; } +.#{$fa-css-prefix}-clone:before { content: $fa-var-clone; } +.#{$fa-css-prefix}-balance-scale:before { content: $fa-var-balance-scale; } +.#{$fa-css-prefix}-hourglass-o:before { content: $fa-var-hourglass-o; } +.#{$fa-css-prefix}-hourglass-1:before, +.#{$fa-css-prefix}-hourglass-start:before { content: $fa-var-hourglass-start; } +.#{$fa-css-prefix}-hourglass-2:before, +.#{$fa-css-prefix}-hourglass-half:before { content: $fa-var-hourglass-half; } +.#{$fa-css-prefix}-hourglass-3:before, +.#{$fa-css-prefix}-hourglass-end:before { content: $fa-var-hourglass-end; } +.#{$fa-css-prefix}-hourglass:before { content: $fa-var-hourglass; } +.#{$fa-css-prefix}-hand-grab-o:before, +.#{$fa-css-prefix}-hand-rock-o:before { content: $fa-var-hand-rock-o; } +.#{$fa-css-prefix}-hand-stop-o:before, +.#{$fa-css-prefix}-hand-paper-o:before { content: $fa-var-hand-paper-o; } +.#{$fa-css-prefix}-hand-scissors-o:before { content: $fa-var-hand-scissors-o; } +.#{$fa-css-prefix}-hand-lizard-o:before { content: $fa-var-hand-lizard-o; } +.#{$fa-css-prefix}-hand-spock-o:before { content: $fa-var-hand-spock-o; } +.#{$fa-css-prefix}-hand-pointer-o:before { content: $fa-var-hand-pointer-o; } +.#{$fa-css-prefix}-hand-peace-o:before { content: $fa-var-hand-peace-o; } +.#{$fa-css-prefix}-trademark:before { content: $fa-var-trademark; } +.#{$fa-css-prefix}-registered:before { content: $fa-var-registered; } +.#{$fa-css-prefix}-creative-commons:before { content: $fa-var-creative-commons; } +.#{$fa-css-prefix}-gg:before { content: $fa-var-gg; } +.#{$fa-css-prefix}-gg-circle:before { content: $fa-var-gg-circle; } +.#{$fa-css-prefix}-tripadvisor:before { content: $fa-var-tripadvisor; } +.#{$fa-css-prefix}-odnoklassniki:before { content: $fa-var-odnoklassniki; } +.#{$fa-css-prefix}-odnoklassniki-square:before { content: $fa-var-odnoklassniki-square; } +.#{$fa-css-prefix}-get-pocket:before { content: $fa-var-get-pocket; } +.#{$fa-css-prefix}-wikipedia-w:before { content: $fa-var-wikipedia-w; } +.#{$fa-css-prefix}-safari:before { content: $fa-var-safari; } +.#{$fa-css-prefix}-chrome:before { content: $fa-var-chrome; } +.#{$fa-css-prefix}-firefox:before { content: $fa-var-firefox; } +.#{$fa-css-prefix}-opera:before { content: $fa-var-opera; } +.#{$fa-css-prefix}-internet-explorer:before { content: $fa-var-internet-explorer; } +.#{$fa-css-prefix}-tv:before, +.#{$fa-css-prefix}-television:before { content: $fa-var-television; } +.#{$fa-css-prefix}-contao:before { content: $fa-var-contao; } +.#{$fa-css-prefix}-500px:before { content: $fa-var-500px; } +.#{$fa-css-prefix}-amazon:before { content: $fa-var-amazon; } +.#{$fa-css-prefix}-calendar-plus-o:before { content: $fa-var-calendar-plus-o; } +.#{$fa-css-prefix}-calendar-minus-o:before { content: $fa-var-calendar-minus-o; } +.#{$fa-css-prefix}-calendar-times-o:before { content: $fa-var-calendar-times-o; } +.#{$fa-css-prefix}-calendar-check-o:before { content: $fa-var-calendar-check-o; } +.#{$fa-css-prefix}-industry:before { content: $fa-var-industry; } +.#{$fa-css-prefix}-map-pin:before { content: $fa-var-map-pin; } +.#{$fa-css-prefix}-map-signs:before { content: $fa-var-map-signs; } +.#{$fa-css-prefix}-map-o:before { content: $fa-var-map-o; } +.#{$fa-css-prefix}-map:before { content: $fa-var-map; } +.#{$fa-css-prefix}-commenting:before { content: $fa-var-commenting; } +.#{$fa-css-prefix}-commenting-o:before { content: $fa-var-commenting-o; } +.#{$fa-css-prefix}-houzz:before { content: $fa-var-houzz; } +.#{$fa-css-prefix}-vimeo:before { content: $fa-var-vimeo; } +.#{$fa-css-prefix}-black-tie:before { content: $fa-var-black-tie; } +.#{$fa-css-prefix}-fonticons:before { content: $fa-var-fonticons; } +.#{$fa-css-prefix}-reddit-alien:before { content: $fa-var-reddit-alien; } +.#{$fa-css-prefix}-edge:before { content: $fa-var-edge; } +.#{$fa-css-prefix}-credit-card-alt:before { content: $fa-var-credit-card-alt; } +.#{$fa-css-prefix}-codiepie:before { content: $fa-var-codiepie; } +.#{$fa-css-prefix}-modx:before { content: $fa-var-modx; } +.#{$fa-css-prefix}-fort-awesome:before { content: $fa-var-fort-awesome; } +.#{$fa-css-prefix}-usb:before { content: $fa-var-usb; } +.#{$fa-css-prefix}-product-hunt:before { content: $fa-var-product-hunt; } +.#{$fa-css-prefix}-mixcloud:before { content: $fa-var-mixcloud; } +.#{$fa-css-prefix}-scribd:before { content: $fa-var-scribd; } +.#{$fa-css-prefix}-pause-circle:before { content: $fa-var-pause-circle; } +.#{$fa-css-prefix}-pause-circle-o:before { content: $fa-var-pause-circle-o; } +.#{$fa-css-prefix}-stop-circle:before { content: $fa-var-stop-circle; } +.#{$fa-css-prefix}-stop-circle-o:before { content: $fa-var-stop-circle-o; } +.#{$fa-css-prefix}-shopping-bag:before { content: $fa-var-shopping-bag; } +.#{$fa-css-prefix}-shopping-basket:before { content: $fa-var-shopping-basket; } +.#{$fa-css-prefix}-hashtag:before { content: $fa-var-hashtag; } +.#{$fa-css-prefix}-bluetooth:before { content: $fa-var-bluetooth; } +.#{$fa-css-prefix}-bluetooth-b:before { content: $fa-var-bluetooth-b; } +.#{$fa-css-prefix}-percent:before { content: $fa-var-percent; } diff --git a/app/assets/sass/font-awesome/_larger.scss b/app/assets/sass/font-awesome/_larger.scss new file mode 100644 index 0000000..41e9a81 --- /dev/null +++ b/app/assets/sass/font-awesome/_larger.scss @@ -0,0 +1,13 @@ +// Icon Sizes +// ------------------------- + +/* makes the font 33% larger relative to the icon container */ +.#{$fa-css-prefix}-lg { + font-size: (4em / 3); + line-height: (3em / 4); + vertical-align: -15%; +} +.#{$fa-css-prefix}-2x { font-size: 2em; } +.#{$fa-css-prefix}-3x { font-size: 3em; } +.#{$fa-css-prefix}-4x { font-size: 4em; } +.#{$fa-css-prefix}-5x { font-size: 5em; } diff --git a/app/assets/sass/font-awesome/_list.scss b/app/assets/sass/font-awesome/_list.scss new file mode 100644 index 0000000..7d1e4d5 --- /dev/null +++ b/app/assets/sass/font-awesome/_list.scss @@ -0,0 +1,19 @@ +// List Icons +// ------------------------- + +.#{$fa-css-prefix}-ul { + padding-left: 0; + margin-left: $fa-li-width; + list-style-type: none; + > li { position: relative; } +} +.#{$fa-css-prefix}-li { + position: absolute; + left: -$fa-li-width; + width: $fa-li-width; + top: (2em / 14); + text-align: center; + &.#{$fa-css-prefix}-lg { + left: -$fa-li-width + (4em / 14); + } +} diff --git a/app/assets/sass/font-awesome/_mixins.scss b/app/assets/sass/font-awesome/_mixins.scss new file mode 100644 index 0000000..f96719b --- /dev/null +++ b/app/assets/sass/font-awesome/_mixins.scss @@ -0,0 +1,26 @@ +// Mixins +// -------------------------- + +@mixin fa-icon() { + display: inline-block; + font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration + font-size: inherit; // can't have font-size inherit on line above, so need to override + text-rendering: auto; // optimizelegibility throws things off #1094 + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + +} + +@mixin fa-icon-rotate($degrees, $rotation) { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}); + -webkit-transform: rotate($degrees); + -ms-transform: rotate($degrees); + transform: rotate($degrees); +} + +@mixin fa-icon-flip($horiz, $vert, $rotation) { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}); + -webkit-transform: scale($horiz, $vert); + -ms-transform: scale($horiz, $vert); + transform: scale($horiz, $vert); +} diff --git a/app/assets/sass/font-awesome/_path.scss b/app/assets/sass/font-awesome/_path.scss new file mode 100644 index 0000000..bb457c2 --- /dev/null +++ b/app/assets/sass/font-awesome/_path.scss @@ -0,0 +1,15 @@ +/* FONT PATH + * -------------------------- */ + +@font-face { + font-family: 'FontAwesome'; + src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}'); + src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), + url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'), + url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), + url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), + url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); +// src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts + font-weight: normal; + font-style: normal; +} diff --git a/app/assets/sass/font-awesome/_rotated-flipped.scss b/app/assets/sass/font-awesome/_rotated-flipped.scss new file mode 100644 index 0000000..a3558fd --- /dev/null +++ b/app/assets/sass/font-awesome/_rotated-flipped.scss @@ -0,0 +1,20 @@ +// Rotated & Flipped Icons +// ------------------------- + +.#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } +.#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } +.#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } + +.#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } +.#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } + +// Hook for IE8-9 +// ------------------------- + +:root .#{$fa-css-prefix}-rotate-90, +:root .#{$fa-css-prefix}-rotate-180, +:root .#{$fa-css-prefix}-rotate-270, +:root .#{$fa-css-prefix}-flip-horizontal, +:root .#{$fa-css-prefix}-flip-vertical { + filter: none; +} diff --git a/app/assets/sass/font-awesome/_stacked.scss b/app/assets/sass/font-awesome/_stacked.scss new file mode 100644 index 0000000..aef7403 --- /dev/null +++ b/app/assets/sass/font-awesome/_stacked.scss @@ -0,0 +1,20 @@ +// Stacked Icons +// ------------------------- + +.#{$fa-css-prefix}-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.#{$fa-css-prefix}-stack-1x { line-height: inherit; } +.#{$fa-css-prefix}-stack-2x { font-size: 2em; } +.#{$fa-css-prefix}-inverse { color: $fa-inverse; } diff --git a/app/assets/sass/font-awesome/_styles.scss b/app/assets/sass/font-awesome/_styles.scss new file mode 100644 index 0000000..f4668a5 --- /dev/null +++ b/app/assets/sass/font-awesome/_styles.scss @@ -0,0 +1,17 @@ +/*! + * Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ + +@import "variables"; +@import "mixins"; +@import "path"; +@import "core"; +@import "larger"; +@import "fixed-width"; +@import "list"; +@import "bordered-pulled"; +@import "animated"; +@import "rotated-flipped"; +@import "stacked"; +@import "icons"; diff --git a/app/assets/sass/font-awesome/_variables.scss b/app/assets/sass/font-awesome/_variables.scss new file mode 100644 index 0000000..0a47110 --- /dev/null +++ b/app/assets/sass/font-awesome/_variables.scss @@ -0,0 +1,708 @@ +// Variables +// -------------------------- + +$fa-font-path: "../fonts" !default; +$fa-font-size-base: 14px !default; +$fa-line-height-base: 1 !default; +//$fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.5.0/fonts" !default; // for referencing Bootstrap CDN font files directly +$fa-css-prefix: fa !default; +$fa-version: "4.5.0" !default; +$fa-border-color: #eee !default; +$fa-inverse: #fff !default; +$fa-li-width: (30em / 14) !default; + +$fa-var-500px: "\f26e"; +$fa-var-adjust: "\f042"; +$fa-var-adn: "\f170"; +$fa-var-align-center: "\f037"; +$fa-var-align-justify: "\f039"; +$fa-var-align-left: "\f036"; +$fa-var-align-right: "\f038"; +$fa-var-amazon: "\f270"; +$fa-var-ambulance: "\f0f9"; +$fa-var-anchor: "\f13d"; +$fa-var-android: "\f17b"; +$fa-var-angellist: "\f209"; +$fa-var-angle-double-down: "\f103"; +$fa-var-angle-double-left: "\f100"; +$fa-var-angle-double-right: "\f101"; +$fa-var-angle-double-up: "\f102"; +$fa-var-angle-down: "\f107"; +$fa-var-angle-left: "\f104"; +$fa-var-angle-right: "\f105"; +$fa-var-angle-up: "\f106"; +$fa-var-apple: "\f179"; +$fa-var-archive: "\f187"; +$fa-var-area-chart: "\f1fe"; +$fa-var-arrow-circle-down: "\f0ab"; +$fa-var-arrow-circle-left: "\f0a8"; +$fa-var-arrow-circle-o-down: "\f01a"; +$fa-var-arrow-circle-o-left: "\f190"; +$fa-var-arrow-circle-o-right: "\f18e"; +$fa-var-arrow-circle-o-up: "\f01b"; +$fa-var-arrow-circle-right: "\f0a9"; +$fa-var-arrow-circle-up: "\f0aa"; +$fa-var-arrow-down: "\f063"; +$fa-var-arrow-left: "\f060"; +$fa-var-arrow-right: "\f061"; +$fa-var-arrow-up: "\f062"; +$fa-var-arrows: "\f047"; +$fa-var-arrows-alt: "\f0b2"; +$fa-var-arrows-h: "\f07e"; +$fa-var-arrows-v: "\f07d"; +$fa-var-asterisk: "\f069"; +$fa-var-at: "\f1fa"; +$fa-var-automobile: "\f1b9"; +$fa-var-backward: "\f04a"; +$fa-var-balance-scale: "\f24e"; +$fa-var-ban: "\f05e"; +$fa-var-bank: "\f19c"; +$fa-var-bar-chart: "\f080"; +$fa-var-bar-chart-o: "\f080"; +$fa-var-barcode: "\f02a"; +$fa-var-bars: "\f0c9"; +$fa-var-battery-0: "\f244"; +$fa-var-battery-1: "\f243"; +$fa-var-battery-2: "\f242"; +$fa-var-battery-3: "\f241"; +$fa-var-battery-4: "\f240"; +$fa-var-battery-empty: "\f244"; +$fa-var-battery-full: "\f240"; +$fa-var-battery-half: "\f242"; +$fa-var-battery-quarter: "\f243"; +$fa-var-battery-three-quarters: "\f241"; +$fa-var-bed: "\f236"; +$fa-var-beer: "\f0fc"; +$fa-var-behance: "\f1b4"; +$fa-var-behance-square: "\f1b5"; +$fa-var-bell: "\f0f3"; +$fa-var-bell-o: "\f0a2"; +$fa-var-bell-slash: "\f1f6"; +$fa-var-bell-slash-o: "\f1f7"; +$fa-var-bicycle: "\f206"; +$fa-var-binoculars: "\f1e5"; +$fa-var-birthday-cake: "\f1fd"; +$fa-var-bitbucket: "\f171"; +$fa-var-bitbucket-square: "\f172"; +$fa-var-bitcoin: "\f15a"; +$fa-var-black-tie: "\f27e"; +$fa-var-bluetooth: "\f293"; +$fa-var-bluetooth-b: "\f294"; +$fa-var-bold: "\f032"; +$fa-var-bolt: "\f0e7"; +$fa-var-bomb: "\f1e2"; +$fa-var-book: "\f02d"; +$fa-var-bookmark: "\f02e"; +$fa-var-bookmark-o: "\f097"; +$fa-var-briefcase: "\f0b1"; +$fa-var-btc: "\f15a"; +$fa-var-bug: "\f188"; +$fa-var-building: "\f1ad"; +$fa-var-building-o: "\f0f7"; +$fa-var-bullhorn: "\f0a1"; +$fa-var-bullseye: "\f140"; +$fa-var-bus: "\f207"; +$fa-var-buysellads: "\f20d"; +$fa-var-cab: "\f1ba"; +$fa-var-calculator: "\f1ec"; +$fa-var-calendar: "\f073"; +$fa-var-calendar-check-o: "\f274"; +$fa-var-calendar-minus-o: "\f272"; +$fa-var-calendar-o: "\f133"; +$fa-var-calendar-plus-o: "\f271"; +$fa-var-calendar-times-o: "\f273"; +$fa-var-camera: "\f030"; +$fa-var-camera-retro: "\f083"; +$fa-var-car: "\f1b9"; +$fa-var-caret-down: "\f0d7"; +$fa-var-caret-left: "\f0d9"; +$fa-var-caret-right: "\f0da"; +$fa-var-caret-square-o-down: "\f150"; +$fa-var-caret-square-o-left: "\f191"; +$fa-var-caret-square-o-right: "\f152"; +$fa-var-caret-square-o-up: "\f151"; +$fa-var-caret-up: "\f0d8"; +$fa-var-cart-arrow-down: "\f218"; +$fa-var-cart-plus: "\f217"; +$fa-var-cc: "\f20a"; +$fa-var-cc-amex: "\f1f3"; +$fa-var-cc-diners-club: "\f24c"; +$fa-var-cc-discover: "\f1f2"; +$fa-var-cc-jcb: "\f24b"; +$fa-var-cc-mastercard: "\f1f1"; +$fa-var-cc-paypal: "\f1f4"; +$fa-var-cc-stripe: "\f1f5"; +$fa-var-cc-visa: "\f1f0"; +$fa-var-certificate: "\f0a3"; +$fa-var-chain: "\f0c1"; +$fa-var-chain-broken: "\f127"; +$fa-var-check: "\f00c"; +$fa-var-check-circle: "\f058"; +$fa-var-check-circle-o: "\f05d"; +$fa-var-check-square: "\f14a"; +$fa-var-check-square-o: "\f046"; +$fa-var-chevron-circle-down: "\f13a"; +$fa-var-chevron-circle-left: "\f137"; +$fa-var-chevron-circle-right: "\f138"; +$fa-var-chevron-circle-up: "\f139"; +$fa-var-chevron-down: "\f078"; +$fa-var-chevron-left: "\f053"; +$fa-var-chevron-right: "\f054"; +$fa-var-chevron-up: "\f077"; +$fa-var-child: "\f1ae"; +$fa-var-chrome: "\f268"; +$fa-var-circle: "\f111"; +$fa-var-circle-o: "\f10c"; +$fa-var-circle-o-notch: "\f1ce"; +$fa-var-circle-thin: "\f1db"; +$fa-var-clipboard: "\f0ea"; +$fa-var-clock-o: "\f017"; +$fa-var-clone: "\f24d"; +$fa-var-close: "\f00d"; +$fa-var-cloud: "\f0c2"; +$fa-var-cloud-download: "\f0ed"; +$fa-var-cloud-upload: "\f0ee"; +$fa-var-cny: "\f157"; +$fa-var-code: "\f121"; +$fa-var-code-fork: "\f126"; +$fa-var-codepen: "\f1cb"; +$fa-var-codiepie: "\f284"; +$fa-var-coffee: "\f0f4"; +$fa-var-cog: "\f013"; +$fa-var-cogs: "\f085"; +$fa-var-columns: "\f0db"; +$fa-var-comment: "\f075"; +$fa-var-comment-o: "\f0e5"; +$fa-var-commenting: "\f27a"; +$fa-var-commenting-o: "\f27b"; +$fa-var-comments: "\f086"; +$fa-var-comments-o: "\f0e6"; +$fa-var-compass: "\f14e"; +$fa-var-compress: "\f066"; +$fa-var-connectdevelop: "\f20e"; +$fa-var-contao: "\f26d"; +$fa-var-copy: "\f0c5"; +$fa-var-copyright: "\f1f9"; +$fa-var-creative-commons: "\f25e"; +$fa-var-credit-card: "\f09d"; +$fa-var-credit-card-alt: "\f283"; +$fa-var-crop: "\f125"; +$fa-var-crosshairs: "\f05b"; +$fa-var-css3: "\f13c"; +$fa-var-cube: "\f1b2"; +$fa-var-cubes: "\f1b3"; +$fa-var-cut: "\f0c4"; +$fa-var-cutlery: "\f0f5"; +$fa-var-dashboard: "\f0e4"; +$fa-var-dashcube: "\f210"; +$fa-var-database: "\f1c0"; +$fa-var-dedent: "\f03b"; +$fa-var-delicious: "\f1a5"; +$fa-var-desktop: "\f108"; +$fa-var-deviantart: "\f1bd"; +$fa-var-diamond: "\f219"; +$fa-var-digg: "\f1a6"; +$fa-var-dollar: "\f155"; +$fa-var-dot-circle-o: "\f192"; +$fa-var-download: "\f019"; +$fa-var-dribbble: "\f17d"; +$fa-var-dropbox: "\f16b"; +$fa-var-drupal: "\f1a9"; +$fa-var-edge: "\f282"; +$fa-var-edit: "\f044"; +$fa-var-eject: "\f052"; +$fa-var-ellipsis-h: "\f141"; +$fa-var-ellipsis-v: "\f142"; +$fa-var-empire: "\f1d1"; +$fa-var-envelope: "\f0e0"; +$fa-var-envelope-o: "\f003"; +$fa-var-envelope-square: "\f199"; +$fa-var-eraser: "\f12d"; +$fa-var-eur: "\f153"; +$fa-var-euro: "\f153"; +$fa-var-exchange: "\f0ec"; +$fa-var-exclamation: "\f12a"; +$fa-var-exclamation-circle: "\f06a"; +$fa-var-exclamation-triangle: "\f071"; +$fa-var-expand: "\f065"; +$fa-var-expeditedssl: "\f23e"; +$fa-var-external-link: "\f08e"; +$fa-var-external-link-square: "\f14c"; +$fa-var-eye: "\f06e"; +$fa-var-eye-slash: "\f070"; +$fa-var-eyedropper: "\f1fb"; +$fa-var-facebook: "\f09a"; +$fa-var-facebook-f: "\f09a"; +$fa-var-facebook-official: "\f230"; +$fa-var-facebook-square: "\f082"; +$fa-var-fast-backward: "\f049"; +$fa-var-fast-forward: "\f050"; +$fa-var-fax: "\f1ac"; +$fa-var-feed: "\f09e"; +$fa-var-female: "\f182"; +$fa-var-fighter-jet: "\f0fb"; +$fa-var-file: "\f15b"; +$fa-var-file-archive-o: "\f1c6"; +$fa-var-file-audio-o: "\f1c7"; +$fa-var-file-code-o: "\f1c9"; +$fa-var-file-excel-o: "\f1c3"; +$fa-var-file-image-o: "\f1c5"; +$fa-var-file-movie-o: "\f1c8"; +$fa-var-file-o: "\f016"; +$fa-var-file-pdf-o: "\f1c1"; +$fa-var-file-photo-o: "\f1c5"; +$fa-var-file-picture-o: "\f1c5"; +$fa-var-file-powerpoint-o: "\f1c4"; +$fa-var-file-sound-o: "\f1c7"; +$fa-var-file-text: "\f15c"; +$fa-var-file-text-o: "\f0f6"; +$fa-var-file-video-o: "\f1c8"; +$fa-var-file-word-o: "\f1c2"; +$fa-var-file-zip-o: "\f1c6"; +$fa-var-files-o: "\f0c5"; +$fa-var-film: "\f008"; +$fa-var-filter: "\f0b0"; +$fa-var-fire: "\f06d"; +$fa-var-fire-extinguisher: "\f134"; +$fa-var-firefox: "\f269"; +$fa-var-flag: "\f024"; +$fa-var-flag-checkered: "\f11e"; +$fa-var-flag-o: "\f11d"; +$fa-var-flash: "\f0e7"; +$fa-var-flask: "\f0c3"; +$fa-var-flickr: "\f16e"; +$fa-var-floppy-o: "\f0c7"; +$fa-var-folder: "\f07b"; +$fa-var-folder-o: "\f114"; +$fa-var-folder-open: "\f07c"; +$fa-var-folder-open-o: "\f115"; +$fa-var-font: "\f031"; +$fa-var-fonticons: "\f280"; +$fa-var-fort-awesome: "\f286"; +$fa-var-forumbee: "\f211"; +$fa-var-forward: "\f04e"; +$fa-var-foursquare: "\f180"; +$fa-var-frown-o: "\f119"; +$fa-var-futbol-o: "\f1e3"; +$fa-var-gamepad: "\f11b"; +$fa-var-gavel: "\f0e3"; +$fa-var-gbp: "\f154"; +$fa-var-ge: "\f1d1"; +$fa-var-gear: "\f013"; +$fa-var-gears: "\f085"; +$fa-var-genderless: "\f22d"; +$fa-var-get-pocket: "\f265"; +$fa-var-gg: "\f260"; +$fa-var-gg-circle: "\f261"; +$fa-var-gift: "\f06b"; +$fa-var-git: "\f1d3"; +$fa-var-git-square: "\f1d2"; +$fa-var-github: "\f09b"; +$fa-var-github-alt: "\f113"; +$fa-var-github-square: "\f092"; +$fa-var-gittip: "\f184"; +$fa-var-glass: "\f000"; +$fa-var-globe: "\f0ac"; +$fa-var-google: "\f1a0"; +$fa-var-google-plus: "\f0d5"; +$fa-var-google-plus-square: "\f0d4"; +$fa-var-google-wallet: "\f1ee"; +$fa-var-graduation-cap: "\f19d"; +$fa-var-gratipay: "\f184"; +$fa-var-group: "\f0c0"; +$fa-var-h-square: "\f0fd"; +$fa-var-hacker-news: "\f1d4"; +$fa-var-hand-grab-o: "\f255"; +$fa-var-hand-lizard-o: "\f258"; +$fa-var-hand-o-down: "\f0a7"; +$fa-var-hand-o-left: "\f0a5"; +$fa-var-hand-o-right: "\f0a4"; +$fa-var-hand-o-up: "\f0a6"; +$fa-var-hand-paper-o: "\f256"; +$fa-var-hand-peace-o: "\f25b"; +$fa-var-hand-pointer-o: "\f25a"; +$fa-var-hand-rock-o: "\f255"; +$fa-var-hand-scissors-o: "\f257"; +$fa-var-hand-spock-o: "\f259"; +$fa-var-hand-stop-o: "\f256"; +$fa-var-hashtag: "\f292"; +$fa-var-hdd-o: "\f0a0"; +$fa-var-header: "\f1dc"; +$fa-var-headphones: "\f025"; +$fa-var-heart: "\f004"; +$fa-var-heart-o: "\f08a"; +$fa-var-heartbeat: "\f21e"; +$fa-var-history: "\f1da"; +$fa-var-home: "\f015"; +$fa-var-hospital-o: "\f0f8"; +$fa-var-hotel: "\f236"; +$fa-var-hourglass: "\f254"; +$fa-var-hourglass-1: "\f251"; +$fa-var-hourglass-2: "\f252"; +$fa-var-hourglass-3: "\f253"; +$fa-var-hourglass-end: "\f253"; +$fa-var-hourglass-half: "\f252"; +$fa-var-hourglass-o: "\f250"; +$fa-var-hourglass-start: "\f251"; +$fa-var-houzz: "\f27c"; +$fa-var-html5: "\f13b"; +$fa-var-i-cursor: "\f246"; +$fa-var-ils: "\f20b"; +$fa-var-image: "\f03e"; +$fa-var-inbox: "\f01c"; +$fa-var-indent: "\f03c"; +$fa-var-industry: "\f275"; +$fa-var-info: "\f129"; +$fa-var-info-circle: "\f05a"; +$fa-var-inr: "\f156"; +$fa-var-instagram: "\f16d"; +$fa-var-institution: "\f19c"; +$fa-var-internet-explorer: "\f26b"; +$fa-var-intersex: "\f224"; +$fa-var-ioxhost: "\f208"; +$fa-var-italic: "\f033"; +$fa-var-joomla: "\f1aa"; +$fa-var-jpy: "\f157"; +$fa-var-jsfiddle: "\f1cc"; +$fa-var-key: "\f084"; +$fa-var-keyboard-o: "\f11c"; +$fa-var-krw: "\f159"; +$fa-var-language: "\f1ab"; +$fa-var-laptop: "\f109"; +$fa-var-lastfm: "\f202"; +$fa-var-lastfm-square: "\f203"; +$fa-var-leaf: "\f06c"; +$fa-var-leanpub: "\f212"; +$fa-var-legal: "\f0e3"; +$fa-var-lemon-o: "\f094"; +$fa-var-level-down: "\f149"; +$fa-var-level-up: "\f148"; +$fa-var-life-bouy: "\f1cd"; +$fa-var-life-buoy: "\f1cd"; +$fa-var-life-ring: "\f1cd"; +$fa-var-life-saver: "\f1cd"; +$fa-var-lightbulb-o: "\f0eb"; +$fa-var-line-chart: "\f201"; +$fa-var-link: "\f0c1"; +$fa-var-linkedin: "\f0e1"; +$fa-var-linkedin-square: "\f08c"; +$fa-var-linux: "\f17c"; +$fa-var-list: "\f03a"; +$fa-var-list-alt: "\f022"; +$fa-var-list-ol: "\f0cb"; +$fa-var-list-ul: "\f0ca"; +$fa-var-location-arrow: "\f124"; +$fa-var-lock: "\f023"; +$fa-var-long-arrow-down: "\f175"; +$fa-var-long-arrow-left: "\f177"; +$fa-var-long-arrow-right: "\f178"; +$fa-var-long-arrow-up: "\f176"; +$fa-var-magic: "\f0d0"; +$fa-var-magnet: "\f076"; +$fa-var-mail-forward: "\f064"; +$fa-var-mail-reply: "\f112"; +$fa-var-mail-reply-all: "\f122"; +$fa-var-male: "\f183"; +$fa-var-map: "\f279"; +$fa-var-map-marker: "\f041"; +$fa-var-map-o: "\f278"; +$fa-var-map-pin: "\f276"; +$fa-var-map-signs: "\f277"; +$fa-var-mars: "\f222"; +$fa-var-mars-double: "\f227"; +$fa-var-mars-stroke: "\f229"; +$fa-var-mars-stroke-h: "\f22b"; +$fa-var-mars-stroke-v: "\f22a"; +$fa-var-maxcdn: "\f136"; +$fa-var-meanpath: "\f20c"; +$fa-var-medium: "\f23a"; +$fa-var-medkit: "\f0fa"; +$fa-var-meh-o: "\f11a"; +$fa-var-mercury: "\f223"; +$fa-var-microphone: "\f130"; +$fa-var-microphone-slash: "\f131"; +$fa-var-minus: "\f068"; +$fa-var-minus-circle: "\f056"; +$fa-var-minus-square: "\f146"; +$fa-var-minus-square-o: "\f147"; +$fa-var-mixcloud: "\f289"; +$fa-var-mobile: "\f10b"; +$fa-var-mobile-phone: "\f10b"; +$fa-var-modx: "\f285"; +$fa-var-money: "\f0d6"; +$fa-var-moon-o: "\f186"; +$fa-var-mortar-board: "\f19d"; +$fa-var-motorcycle: "\f21c"; +$fa-var-mouse-pointer: "\f245"; +$fa-var-music: "\f001"; +$fa-var-navicon: "\f0c9"; +$fa-var-neuter: "\f22c"; +$fa-var-newspaper-o: "\f1ea"; +$fa-var-object-group: "\f247"; +$fa-var-object-ungroup: "\f248"; +$fa-var-odnoklassniki: "\f263"; +$fa-var-odnoklassniki-square: "\f264"; +$fa-var-opencart: "\f23d"; +$fa-var-openid: "\f19b"; +$fa-var-opera: "\f26a"; +$fa-var-optin-monster: "\f23c"; +$fa-var-outdent: "\f03b"; +$fa-var-pagelines: "\f18c"; +$fa-var-paint-brush: "\f1fc"; +$fa-var-paper-plane: "\f1d8"; +$fa-var-paper-plane-o: "\f1d9"; +$fa-var-paperclip: "\f0c6"; +$fa-var-paragraph: "\f1dd"; +$fa-var-paste: "\f0ea"; +$fa-var-pause: "\f04c"; +$fa-var-pause-circle: "\f28b"; +$fa-var-pause-circle-o: "\f28c"; +$fa-var-paw: "\f1b0"; +$fa-var-paypal: "\f1ed"; +$fa-var-pencil: "\f040"; +$fa-var-pencil-square: "\f14b"; +$fa-var-pencil-square-o: "\f044"; +$fa-var-percent: "\f295"; +$fa-var-phone: "\f095"; +$fa-var-phone-square: "\f098"; +$fa-var-photo: "\f03e"; +$fa-var-picture-o: "\f03e"; +$fa-var-pie-chart: "\f200"; +$fa-var-pied-piper: "\f1a7"; +$fa-var-pied-piper-alt: "\f1a8"; +$fa-var-pinterest: "\f0d2"; +$fa-var-pinterest-p: "\f231"; +$fa-var-pinterest-square: "\f0d3"; +$fa-var-plane: "\f072"; +$fa-var-play: "\f04b"; +$fa-var-play-circle: "\f144"; +$fa-var-play-circle-o: "\f01d"; +$fa-var-plug: "\f1e6"; +$fa-var-plus: "\f067"; +$fa-var-plus-circle: "\f055"; +$fa-var-plus-square: "\f0fe"; +$fa-var-plus-square-o: "\f196"; +$fa-var-power-off: "\f011"; +$fa-var-print: "\f02f"; +$fa-var-product-hunt: "\f288"; +$fa-var-puzzle-piece: "\f12e"; +$fa-var-qq: "\f1d6"; +$fa-var-qrcode: "\f029"; +$fa-var-question: "\f128"; +$fa-var-question-circle: "\f059"; +$fa-var-quote-left: "\f10d"; +$fa-var-quote-right: "\f10e"; +$fa-var-ra: "\f1d0"; +$fa-var-random: "\f074"; +$fa-var-rebel: "\f1d0"; +$fa-var-recycle: "\f1b8"; +$fa-var-reddit: "\f1a1"; +$fa-var-reddit-alien: "\f281"; +$fa-var-reddit-square: "\f1a2"; +$fa-var-refresh: "\f021"; +$fa-var-registered: "\f25d"; +$fa-var-remove: "\f00d"; +$fa-var-renren: "\f18b"; +$fa-var-reorder: "\f0c9"; +$fa-var-repeat: "\f01e"; +$fa-var-reply: "\f112"; +$fa-var-reply-all: "\f122"; +$fa-var-retweet: "\f079"; +$fa-var-rmb: "\f157"; +$fa-var-road: "\f018"; +$fa-var-rocket: "\f135"; +$fa-var-rotate-left: "\f0e2"; +$fa-var-rotate-right: "\f01e"; +$fa-var-rouble: "\f158"; +$fa-var-rss: "\f09e"; +$fa-var-rss-square: "\f143"; +$fa-var-rub: "\f158"; +$fa-var-ruble: "\f158"; +$fa-var-rupee: "\f156"; +$fa-var-safari: "\f267"; +$fa-var-save: "\f0c7"; +$fa-var-scissors: "\f0c4"; +$fa-var-scribd: "\f28a"; +$fa-var-search: "\f002"; +$fa-var-search-minus: "\f010"; +$fa-var-search-plus: "\f00e"; +$fa-var-sellsy: "\f213"; +$fa-var-send: "\f1d8"; +$fa-var-send-o: "\f1d9"; +$fa-var-server: "\f233"; +$fa-var-share: "\f064"; +$fa-var-share-alt: "\f1e0"; +$fa-var-share-alt-square: "\f1e1"; +$fa-var-share-square: "\f14d"; +$fa-var-share-square-o: "\f045"; +$fa-var-shekel: "\f20b"; +$fa-var-sheqel: "\f20b"; +$fa-var-shield: "\f132"; +$fa-var-ship: "\f21a"; +$fa-var-shirtsinbulk: "\f214"; +$fa-var-shopping-bag: "\f290"; +$fa-var-shopping-basket: "\f291"; +$fa-var-shopping-cart: "\f07a"; +$fa-var-sign-in: "\f090"; +$fa-var-sign-out: "\f08b"; +$fa-var-signal: "\f012"; +$fa-var-simplybuilt: "\f215"; +$fa-var-sitemap: "\f0e8"; +$fa-var-skyatlas: "\f216"; +$fa-var-skype: "\f17e"; +$fa-var-slack: "\f198"; +$fa-var-sliders: "\f1de"; +$fa-var-slideshare: "\f1e7"; +$fa-var-smile-o: "\f118"; +$fa-var-soccer-ball-o: "\f1e3"; +$fa-var-sort: "\f0dc"; +$fa-var-sort-alpha-asc: "\f15d"; +$fa-var-sort-alpha-desc: "\f15e"; +$fa-var-sort-amount-asc: "\f160"; +$fa-var-sort-amount-desc: "\f161"; +$fa-var-sort-asc: "\f0de"; +$fa-var-sort-desc: "\f0dd"; +$fa-var-sort-down: "\f0dd"; +$fa-var-sort-numeric-asc: "\f162"; +$fa-var-sort-numeric-desc: "\f163"; +$fa-var-sort-up: "\f0de"; +$fa-var-soundcloud: "\f1be"; +$fa-var-space-shuttle: "\f197"; +$fa-var-spinner: "\f110"; +$fa-var-spoon: "\f1b1"; +$fa-var-spotify: "\f1bc"; +$fa-var-square: "\f0c8"; +$fa-var-square-o: "\f096"; +$fa-var-stack-exchange: "\f18d"; +$fa-var-stack-overflow: "\f16c"; +$fa-var-star: "\f005"; +$fa-var-star-half: "\f089"; +$fa-var-star-half-empty: "\f123"; +$fa-var-star-half-full: "\f123"; +$fa-var-star-half-o: "\f123"; +$fa-var-star-o: "\f006"; +$fa-var-steam: "\f1b6"; +$fa-var-steam-square: "\f1b7"; +$fa-var-step-backward: "\f048"; +$fa-var-step-forward: "\f051"; +$fa-var-stethoscope: "\f0f1"; +$fa-var-sticky-note: "\f249"; +$fa-var-sticky-note-o: "\f24a"; +$fa-var-stop: "\f04d"; +$fa-var-stop-circle: "\f28d"; +$fa-var-stop-circle-o: "\f28e"; +$fa-var-street-view: "\f21d"; +$fa-var-strikethrough: "\f0cc"; +$fa-var-stumbleupon: "\f1a4"; +$fa-var-stumbleupon-circle: "\f1a3"; +$fa-var-subscript: "\f12c"; +$fa-var-subway: "\f239"; +$fa-var-suitcase: "\f0f2"; +$fa-var-sun-o: "\f185"; +$fa-var-superscript: "\f12b"; +$fa-var-support: "\f1cd"; +$fa-var-table: "\f0ce"; +$fa-var-tablet: "\f10a"; +$fa-var-tachometer: "\f0e4"; +$fa-var-tag: "\f02b"; +$fa-var-tags: "\f02c"; +$fa-var-tasks: "\f0ae"; +$fa-var-taxi: "\f1ba"; +$fa-var-television: "\f26c"; +$fa-var-tencent-weibo: "\f1d5"; +$fa-var-terminal: "\f120"; +$fa-var-text-height: "\f034"; +$fa-var-text-width: "\f035"; +$fa-var-th: "\f00a"; +$fa-var-th-large: "\f009"; +$fa-var-th-list: "\f00b"; +$fa-var-thumb-tack: "\f08d"; +$fa-var-thumbs-down: "\f165"; +$fa-var-thumbs-o-down: "\f088"; +$fa-var-thumbs-o-up: "\f087"; +$fa-var-thumbs-up: "\f164"; +$fa-var-ticket: "\f145"; +$fa-var-times: "\f00d"; +$fa-var-times-circle: "\f057"; +$fa-var-times-circle-o: "\f05c"; +$fa-var-tint: "\f043"; +$fa-var-toggle-down: "\f150"; +$fa-var-toggle-left: "\f191"; +$fa-var-toggle-off: "\f204"; +$fa-var-toggle-on: "\f205"; +$fa-var-toggle-right: "\f152"; +$fa-var-toggle-up: "\f151"; +$fa-var-trademark: "\f25c"; +$fa-var-train: "\f238"; +$fa-var-transgender: "\f224"; +$fa-var-transgender-alt: "\f225"; +$fa-var-trash: "\f1f8"; +$fa-var-trash-o: "\f014"; +$fa-var-tree: "\f1bb"; +$fa-var-trello: "\f181"; +$fa-var-tripadvisor: "\f262"; +$fa-var-trophy: "\f091"; +$fa-var-truck: "\f0d1"; +$fa-var-try: "\f195"; +$fa-var-tty: "\f1e4"; +$fa-var-tumblr: "\f173"; +$fa-var-tumblr-square: "\f174"; +$fa-var-turkish-lira: "\f195"; +$fa-var-tv: "\f26c"; +$fa-var-twitch: "\f1e8"; +$fa-var-twitter: "\f099"; +$fa-var-twitter-square: "\f081"; +$fa-var-umbrella: "\f0e9"; +$fa-var-underline: "\f0cd"; +$fa-var-undo: "\f0e2"; +$fa-var-university: "\f19c"; +$fa-var-unlink: "\f127"; +$fa-var-unlock: "\f09c"; +$fa-var-unlock-alt: "\f13e"; +$fa-var-unsorted: "\f0dc"; +$fa-var-upload: "\f093"; +$fa-var-usb: "\f287"; +$fa-var-usd: "\f155"; +$fa-var-user: "\f007"; +$fa-var-user-md: "\f0f0"; +$fa-var-user-plus: "\f234"; +$fa-var-user-secret: "\f21b"; +$fa-var-user-times: "\f235"; +$fa-var-users: "\f0c0"; +$fa-var-venus: "\f221"; +$fa-var-venus-double: "\f226"; +$fa-var-venus-mars: "\f228"; +$fa-var-viacoin: "\f237"; +$fa-var-video-camera: "\f03d"; +$fa-var-vimeo: "\f27d"; +$fa-var-vimeo-square: "\f194"; +$fa-var-vine: "\f1ca"; +$fa-var-vk: "\f189"; +$fa-var-volume-down: "\f027"; +$fa-var-volume-off: "\f026"; +$fa-var-volume-up: "\f028"; +$fa-var-warning: "\f071"; +$fa-var-wechat: "\f1d7"; +$fa-var-weibo: "\f18a"; +$fa-var-weixin: "\f1d7"; +$fa-var-whatsapp: "\f232"; +$fa-var-wheelchair: "\f193"; +$fa-var-wifi: "\f1eb"; +$fa-var-wikipedia-w: "\f266"; +$fa-var-windows: "\f17a"; +$fa-var-won: "\f159"; +$fa-var-wordpress: "\f19a"; +$fa-var-wrench: "\f0ad"; +$fa-var-xing: "\f168"; +$fa-var-xing-square: "\f169"; +$fa-var-y-combinator: "\f23b"; +$fa-var-y-combinator-square: "\f1d4"; +$fa-var-yahoo: "\f19e"; +$fa-var-yc: "\f23b"; +$fa-var-yc-square: "\f1d4"; +$fa-var-yelp: "\f1e9"; +$fa-var-yen: "\f157"; +$fa-var-youtube: "\f167"; +$fa-var-youtube-play: "\f16a"; +$fa-var-youtube-square: "\f166"; + diff --git a/app/assets/sass/styles.scss b/app/assets/sass/styles.scss new file mode 100644 index 0000000..4dec9e5 --- /dev/null +++ b/app/assets/sass/styles.scss @@ -0,0 +1,16 @@ +@import "compass/reset"; +@import "font-awesome/styles"; + +@import "variables"; +@import "common"; +@import "buttons"; +@import "forms"; +@import "nav"; + +@import "plan"; +@import "plan-node"; +@import "menu"; +@import "page"; +@import "table"; +@import "modal"; +@import "footer"; diff --git a/app/assets/styles.css b/app/assets/styles.css new file mode 100644 index 0000000..ec0a393 --- /dev/null +++ b/app/assets/styles.css @@ -0,0 +1,4 @@ +html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font:inherit;font-size:100%;vertical-align:baseline}html{line-height:1}ol,ul{list-style:none}table{border-collapse:collapse;border-spacing:0}caption,th,td{text-align:left;font-weight:normal;vertical-align:middle}q,blockquote{quotes:none}q:before,q:after,blockquote:before,blockquote:after{content:"";content:none}a img{border:none}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}/*! + * Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url("../fonts/fontawesome-webfont.eot?v=4.5.0");src:url("../fonts/fontawesome-webfont.eot?#iefix&v=4.5.0") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff2?v=4.5.0") format("woff2"),url("../fonts/fontawesome-webfont.woff?v=4.5.0") format("woff"),url("../fonts/fontawesome-webfont.ttf?v=4.5.0") format("truetype"),url("../fonts/fontawesome-webfont.svg?v=4.5.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}.fa-lg{font-size:1.33333em;line-height:0.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.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:0.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.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);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-remove:before,.fa-close:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-gear:before,.fa-cog:before{content:""}.fa-trash-o:before{content:""}.fa-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-rotate-right:before,.fa-repeat:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before{content:""}.fa-check-circle:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-warning:before,.fa-exclamation-triangle:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-gears:before,.fa-cogs:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before{content:""}.fa-arrow-circle-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-save:before,.fa-floppy-o:before{content:""}.fa-square:before{content:""}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-unsorted:before,.fa-sort:before{content:""}.fa-sort-down:before,.fa-sort-desc:before{content:""}.fa-sort-up:before,.fa-sort-asc:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-legal:before,.fa-gavel:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-flash:before,.fa-bolt:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-paste:before,.fa-clipboard:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-unlink:before,.fa-chain-broken:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:""}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:""}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:""}.fa-euro:before,.fa-eur:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-rupee:before,.fa-inr:before{content:""}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:""}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:""}.fa-won:before,.fa-krw:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-turkish-lira:before,.fa-try:before{content:""}.fa-plus-square-o:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-institution:before,.fa-bank:before,.fa-university:before{content:""}.fa-mortar-board:before,.fa-graduation-cap:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:""}.fa-file-zip-o:before,.fa-file-archive-o:before{content:""}.fa-file-sound-o:before,.fa-file-audio-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before{content:""}.fa-ge:before,.fa-empire:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-send:before,.fa-paper-plane:before{content:""}.fa-send-o:before,.fa-paper-plane-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-hotel:before,.fa-bed:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-yc:before,.fa-y-combinator:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-tv:before,.fa-television:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}html{height:100%}body{font-size:13px;font-weight:300;color:#4d525a;height:100%;width:100%;background-color:#f7f7f7;line-height:1.3}strong{font-weight:600}body,input,a,button,textarea{font-family:"noto sans";font-weight:300}.text-muted{color:#999ea7}.hero-container{margin:30px;font-size:22px;text-align:center}.pull-right{float:right}.align-right{text-align:right}a{color:#00B5E2;text-decoration:none}.fa{margin-right:3px}.clickable{cursor:pointer}.btn{border-radius:3px;padding:6px 10px;font-size:13px;line-height:1.2;text-decoration:none;text-transform:uppercase}.btn-default{border:1px solid #00B5E2;color:#00B5E2;background-color:#fff}.btn-default:hover{background-color:#65DDFB}.btn-lg{padding:6px 20px;font-size:16px}.btn-danger{border:1px solid #AF2F11;color:#AF2F11;text-transform:uppercase;background-color:#fff}.btn-danger:hover{background-color:#FB8165}.btn-primary{border:0;background:#00B5E2;box-shadow:1px 1px 1px #ababab;color:#ffffff}.btn-primary:hover{background:#008CAF}.input-box:-moz-placeholder{color:#ababab;font-size:18px}.input-box::-moz-placeholder{color:#ababab;font-size:18px}.input-box:-ms-input-placeholder{color:#ababab;font-size:18px}.input-box::-webkit-input-placeholder{color:#ababab;font-size:18px}.input-box:focus{box-shadow:0 0 5px #51cbee}.input-box-main{font-size:18px;width:700px;border:0;border-bottom:2px solid #00B5E2;padding:10px;margin-top:10px;margin-bottom:10px}.input-box-lg{width:100%;height:280px;margin-bottom:6px;margin-bottom:10px;border-radius:3px;border:1px solid #dedede;padding:10px}nav{font-size:17px;background-color:#fff;padding:15px}nav .nav-container{width:1000px;margin:auto}.plan{padding-bottom:30px;overflow:auto;height:100%;width:100%}.plan ul{display:flex;padding-top:12px;position:relative;margin:auto;transition:all 0.5s;margin-top:-5px}.plan ul ul::before{content:'';position:absolute;top:0;left:50%;border-left:2px solid #c4c4c4;height:12px;width:0}.plan ul li{float:left;text-align:center;list-style-type:none;position:relative;padding:12px 3px 0 3px;transition:all 0.5s}.plan ul li:before,.plan ul li:after{content:'';position:absolute;top:0;right:50%;border-top:2px solid #c4c4c4;width:50%;height:12px}.plan ul li:after{right:auto;left:50%;border-left:2px solid #c4c4c4}.plan ul li:only-child{padding-top:0}.plan ul li:only-child:after,.plan ul li:only-child:before{display:none}.plan ul li:first-child::before,.plan ul li:last-child::after{border:0 none}.plan ul li:last-child::before{border-right:2px solid #c4c4c4;border-radius:0 6px 0 0}.plan ul li:first-child::after{border-radius:6px 0 0 0}.plan ul li .plan-node:hover+ul::before{border-color:#00B5E2}.plan ul li .plan-node:hover+ul li::after,.plan ul li .plan-node:hover+ul li::before,.plan ul li .plan-node:hover+ul ul::before{border-color:#008CAF}.plan-stats{display:flex;font-size:13px;margin:0 auto 10px auto;padding-bottom:10px;border-bottom:1px solid #dedede;border-radius:12px;width:650px;position:relative}.plan-stats div{padding-right:10px;flex-grow:1}.plan-stats .stat-value{display:block;text-align:center;font-size:17px}.plan-stats .stat-label{display:block;text-align:center;font-size:12px}.plan-stats:after{content:'';position:absolute;top:100%;left:50%;margin-left:-9px;width:0;height:0;border-top:solid 9px #dedede;border-left:solid 9px transparent;border-right:solid 9px transparent}.plan-node{text-decoration:none;color:#4d525a;display:inline-block;transition:all 0.5s;position:relative;padding:6px 10px;background-color:#fff;font-size:12px;border:2px solid #dedede;border-radius:3px;overflow:hidden;overflow-wrap:break-word;word-wrap:break-word;word-break:break-all;min-width:220px}.plan-node header{margin-bottom:6px;overflow:hidden;cursor:pointer}.plan-node header:hover{background-color:#f7f7f7}.plan-node header h4{font-size:13px;float:left;font-weight:600}.plan-node header .node-duration{float:right;margin-left:10px;font-size:13px}.plan-node .prop-list{float:left;text-align:left;width:400px;overflow-wrap:break-word;word-wrap:break-word;word-break:break-all;margin-top:10px;margin-bottom:6px}.plan-node .relation-name{text-align:left;max-width:220px}.plan-node .planner-estimate{float:left;clear:both;text-align:left;margin-top:6px;width:100%}.plan-node .tags{margin-top:6px;text-align:left}.plan-node .tags span{display:inline-block;background-color:#FB4418;color:#fff;font-size:10px;font-weight:600;margin-right:3px;padding:3px;border-radius:3px;line-height:1.1}.plan-node:hover{border-color:#00B5E2}.node-bar-container{float:left;height:5px;margin-top:6px;margin-left:auto;margin-right:auto;border:1px solid #dedede;border-radius:3px;color:#fff;background-color:#454545;position:relative}.node-bar-container .node-bar{height:100%;text-align:left;position:absolute;left:0;top:0}.node-bar-label{text-align:left;display:block}.menu{width:190px;height:200px;position:absolute;font-size:12px;top:115px;left:0;background-color:#777;box-shadow:1px 1px 2px 1px rgba(0,0,0,0.5);color:#fff;border-top-right-radius:3px;border-bottom-right-radius:3px;z-index:1;transition:all 0.3s}.menu header h3{padding-top:10px;margin-bottom:20px;font-size:16px;font-weight:600;line-height:2;text-align:right;padding-right:20px}.menu ul{margin-left:10px}.menu ul li{line-height:2.5}.menu-toggle{font-size:26px;float:left;padding-left:10px;line-height:2;cursor:pointer}.menu-hidden{width:50px;height:50px;border-top-right-radius:50%;border-bottom-right-radius:50%}.menu-hidden ul,.menu-hidden h3{visibility:hidden}.menu button{border:1px solid #fff;background-color:#544D4D;color:#fff;padding:2px;border-radius:3px}.page,.page-stretch{padding-top:10px;margin:auto;width:1000px;min-height:600px}.page h2,.page-stretch h2{font-size:26px;margin-bottom:6px}.page-stretch{margin:auto;width:95%}.table{width:100%}.table td{border-bottom:1px solid #dedede;padding:6px}.table tr:hover{background-color:#f7f7f7}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000;opacity:0.7}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050}.modal .modal-dialog{position:relative;transform:translate(0);margin:30px auto;width:500px;opacity:1}.modal .modal-dialog .modal-content{padding:30px;position:relative;background-color:#fff;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;outline:0;box-shadow:0 3px 9px rgba(0,0,0,0.5);display:block}.modal .modal-dialog .modal-content .modal-body{padding:3px}.modal .modal-dialog .modal-content .modal-footer{text-align:right}.modal .modal-dialog .modal-content .modal-footer button{margin-left:3px}footer{border-top:2px solid #dedede;margin:20px;padding:20px;color:#ababab;text-align:center;width:600px;margin:auto}footer .fa{font-size:17px;margin-left:6px} diff --git a/app/bootstrap.ts b/app/bootstrap.ts new file mode 100644 index 0000000..b3303f3 --- /dev/null +++ b/app/bootstrap.ts @@ -0,0 +1,9 @@ +import {provide} from 'angular2/core'; +import {bootstrap} from 'angular2/platform/browser'; +import {ROUTER_PROVIDERS, LocationStrategy, HashLocationStrategy} from 'angular2/router'; +import {App} from './components/app/app'; + +bootstrap(App, [ + ROUTER_PROVIDERS, + provide(LocationStrategy, { useClass: HashLocationStrategy }) +]); diff --git a/app/components/app/app.html b/app/components/app/app.html new file mode 100644 index 0000000..a8a1969 --- /dev/null +++ b/app/components/app/app.html @@ -0,0 +1,6 @@ +<router-outlet></router-outlet> +<footer>PEV is made by + <a href="http://tatiyants.com/">Alex Tatiyants</a> + <a href="https://twitter.com/AlexTatiyants"><i class="fa fa-twitter"></i></a> + <a href="https://github.com/AlexTatiyants"><i class="fa fa-github"></i></a> +</footer> diff --git a/app/components/app/app.ts b/app/components/app/app.ts new file mode 100644 index 0000000..f9c83e0 --- /dev/null +++ b/app/components/app/app.ts @@ -0,0 +1,22 @@ +import {Component, ViewEncapsulation} from 'angular2/core'; +import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router'; + +import {PlanView} from '../plan-view/plan-view'; +import {PlanList} from '../plan-list/plan-list'; +import {PlanNew} from '../plan-new/plan-new'; + +@Component({ + selector: 'app', + templateUrl: './components/app/app.html', + encapsulation: ViewEncapsulation.None, + directives: [ROUTER_DIRECTIVES] +}) + +@RouteConfig([ + { path: '/', redirectTo: ['/PlanList'] }, + { path: '/plans', component: PlanList, name: 'PlanList' }, + { path: '/plans/new', component: PlanNew, name: 'PlanNew' }, + { path: '/plans/:id', component: PlanView, name: 'PlanView' } +]) + +export class App { } diff --git a/app/components/plan-list/plan-list.html b/app/components/plan-list/plan-list.html new file mode 100644 index 0000000..a2f1a9d --- /dev/null +++ b/app/components/plan-list/plan-list.html @@ -0,0 +1,38 @@ +<nav> + <div class="nav-container"> + <a class="btn btn-primary btn-lg pull-right" [routerLink]="['/PlanNew']">create</a> + <a [routerLink]="['PlanList']">plans</a> + </div> +</nav> + +<div class="page"> + <div class="hero-container" *ngIf="plans.length === 0"> + Welcome to PEV! Please <a [routerLink]="['/PlanNew']">submit</a> a plan for visualization + </div> + + <table class="table"> + <tr *ngFor="#plan of plans"> + <td><a [routerLink]="['/PlanView', {id: plan.id}]">{{plan.name}}</a></td> + <td>created on {{plan.createdOn | momentDate }}</td> + <td class="align-right"><button class="btn btn-danger" (click)="requestDelete()"> + <i class="fa fa-trash"></i>delete</button> + <!-- this is a hack that should be converted to a proper dialog once that is available in angular 2--> + <div *ngIf="openDialog"> + <div class="modal-backdrop"></div> + + <div class="modal"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-body">You're about to delete this plan. Are you sure?</div> + <div class="modal-footer"> + <button class="btn btn-primary" (click)="deletePlan(plan)">Yes</button> + <button class="btn btn-default" (click)="cancelDelete()">No</button> + </div> + </div> + </div> + </div> + </div> + </td> + </tr> + </table> +</div> diff --git a/app/components/plan-list/plan-list.ts b/app/components/plan-list/plan-list.ts new file mode 100644 index 0000000..888e2e2 --- /dev/null +++ b/app/components/plan-list/plan-list.ts @@ -0,0 +1,47 @@ +import {Component, OnInit} from 'angular2/core'; +import {ROUTER_DIRECTIVES} from 'angular2/router'; + +import {IPlan} from '../../interfaces/iplan'; +import {PlanService} from '../../services/plan-service'; +import {PlanNew} from '../plan-new/plan-new'; + +import {MomentDatePipe} from '../../pipes'; + +@Component({ + selector: 'plan-list', + templateUrl: './components/plan-list/plan-list.html', + providers: [PlanService], + directives: [ROUTER_DIRECTIVES, PlanNew], + pipes: [MomentDatePipe] +}) +export class PlanList { + plans: Array<IPlan>; + newPlanName: string; + newPlanContent: any; + newPlanId: string; + openDialog: boolean = false; + + constructor(private _planService: PlanService) { } + + ngOnInit() { + this.plans = this._planService.getPlans(); + } + + requestDelete() { + this.openDialog = true; + } + + deletePlan(plan) { + this.openDialog = false; + this._planService.deletePlan(plan); + this.plans = this._planService.getPlans(); + } + + cancelDelete() { + this.openDialog = false; + } + + deleteAllPlans() { + this._planService.deleteAllPlans(); + } +} diff --git a/app/components/plan-new/plan-new.html b/app/components/plan-new/plan-new.html new file mode 100644 index 0000000..f9babb6 --- /dev/null +++ b/app/components/plan-new/plan-new.html @@ -0,0 +1,18 @@ +<nav> + <div class="nav-container"> + <a [routerLink]="['PlanList']">plans</a> + <span class="text-muted"> | </span> + create plan + </div> +</nav> + +<div class="page"> + <span class="text-muted">For best results, use EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS, FORMAT JSON)</span> + <div> + <input placeholder="name (optional)" class="input-box input-box-main" type="text" [(ngModel)]="newPlanName"> + <button class="btn btn-primary btn-lg pull-right" (click)="submitPlan()">submit</button> + </div> + + <textarea placeholder="paste execution plan" class="input-box input-box-lg" [(ngModel)]="newPlanContent"></textarea> + <textarea placeholder="paste corresponding SQL query" class="input-box input-box-lg" [(ngModel)]="newPlanQuery"></textarea> +</div> diff --git a/app/components/plan-new/plan-new.ts b/app/components/plan-new/plan-new.ts new file mode 100644 index 0000000..4a748ea --- /dev/null +++ b/app/components/plan-new/plan-new.ts @@ -0,0 +1,26 @@ +import {Component, OnInit} from 'angular2/core'; +import {Router, ROUTER_DIRECTIVES} from 'angular2/router'; +import {IPlan} from '../../interfaces/iplan'; + +import {PlanService} from '../../services/plan-service'; + +@Component({ + selector: 'plan-new', + templateUrl: './components/plan-new/plan-new.html', + providers: [PlanService], + directives: [ROUTER_DIRECTIVES] +}) +export class PlanNew { + planIds: string[]; + newPlanName: string; + newPlanContent: string; + newPlanQuery: string; + newPlan: IPlan; + + constructor( private _router: Router, private _planService: PlanService) { } + + submitPlan() { + this.newPlan = this._planService.createPlan(this.newPlanName, this.newPlanContent, this.newPlanQuery); + this._router.navigate( ['PlanView', { id: this.newPlan.id }] ); + } +} diff --git a/app/components/plan-node/plan-node.html b/app/components/plan-node/plan-node.html new file mode 100644 index 0000000..49380a2 --- /dev/null +++ b/app/components/plan-node/plan-node.html @@ -0,0 +1,50 @@ +<div class="plan-node"> + <header (click)="showDetails = !showDetails"> + <h4>{{node['Node Type'] | uppercase}}</h4> + <span class="node-duration">{{duration}}<span class="text-muted">{{durationUnit}} | </span> + <strong>{{executionTimePercent}}</strong><span class="text-muted">%</span> + </span> + </header> + + <div class="relation-name" *ngIf="node['Relation Name']"><span class="text-muted">on </span> + <span *ngIf="node['Schema']">{{node['Schema']}}.</span>{{node['Relation Name']}} + <span *ngIf="node['Alias']"> ({{node['Alias']}})</span> + </div> + + <div class="relation-name" *ngIf="node['Group Key']"><span class="text-muted">by</span> {{node['Group Key']}}</div> + <div class="relation-name" *ngIf="node['Sort Key']"><span class="text-muted">by</span> {{node['Sort Key']}}</div> + <div class="relation-name" *ngIf="node['Join Type']">{{node['Join Type']}} <span class="text-muted">join</span></div> + <div class="relation-name" *ngIf="node['Index Name']"><span class="text-muted">using</span> {{node['Index Name']}}</div> + + <div class="tags" *ngIf="viewOptions.showTags && tags.length > 0"> + <span *ngFor="#tag of tags">{{tag}}</span> + </div> + + <div *ngIf="currentHighlightType !== highlightTypes.NONE"> + <div class="node-bar-container" [style.width]="(MAX_WIDTH+3)+'px'"> + <span class="node-bar" [style.width]="width+'px'" [style.backgroundColor]="backgroundColor"></span> + </div> + <span class="node-bar-label"> + <span class="text-muted">{{viewOptions.highlightType}}:</span> {{highlightValue | number:'.0-2'}} + </span> + </div> + + <div class="planner-estimate" *ngIf="viewOptions.showPlannerEstimate"> + <span *ngIf="plannerRowEstimateDirection === estimateDirections.over"><strong>over</strong> estimated rows</span> + <span *ngIf="plannerRowEstimateDirection === estimateDirections.under"><strong>under</strong> estimated rows</span> + <span> by <strong>{{plannerRowEstimateValue}}</strong>x</span> + </div> + + <table *ngIf="showDetails" class="table prop-list"> + <tr *ngFor="#prop of props"> + <td width="40%">{{prop.key}}</td> + <td>{{prop.value}}</td> + <tr> + </table> +</div> + +<ul *ngIf="node.Plans"> + <li *ngFor="#subNode of node.Plans"> + <plan-node [node]="subNode" [viewOptions]="viewOptions" [planStats]="planStats"></plan-node> + </li> +</ul> diff --git a/app/components/plan-node/plan-node.ts b/app/components/plan-node/plan-node.ts new file mode 100644 index 0000000..3562ea6 --- /dev/null +++ b/app/components/plan-node/plan-node.ts @@ -0,0 +1,176 @@ +import {Component, OnInit} from 'angular2/core'; +import {HighlightType, EstimateDirection} from '../../enums'; +import {PlanService} from '../../services/plan-service'; +/// <reference path="lodash.d.ts" /> + +@Component({ + selector: 'plan-node', + inputs: ['node', 'planStats', 'viewOptions'], + templateUrl: './components/plan-node/plan-node.html', + directives: [PlanNode], + providers: [PlanService] +}) + +export class PlanNode { + // consts + MAX_WIDTH: number = 220; + MIN_ESTIMATE_MISS: number = 100; + COSTLY_TAG: string = 'costliest'; + SLOW_TAG: string = 'slowest'; + LARGE_TAG: string = 'largest'; + ESTIMATE_TAG: string = 'bad estimate'; + + // inputs + node: any; + planStats: any; + viewOptions: any; + + // calculated properties + duration: string; + durationUnit: string; + executionTimePercent: number; + backgroundColor: string; + highlightValue: number; + width: number; + props: Array<any>; + tags: Array<string>; + plannerRowEstimateValue: number; + plannerRowEstimateDirection: EstimateDirection; + currentHighlightType: string; + + // expose enum to view + estimateDirections = EstimateDirection; + highlightTypes = HighlightType; + + constructor(private _planService: PlanService) { } + + ngOnInit() { + this.currentHighlightType = this.viewOptions.highlightType; + this.calculateBar(); + this.calculateProps(); + this.calculateDuration(); + this.calculateTags(); + + this.plannerRowEstimateDirection = this.node[this._planService.PLANNER_ESIMATE_DIRECTION]; + this.plannerRowEstimateValue = _.round(this.node[this._planService.PLANNER_ESTIMATE_FACTOR]); + } + + ngDoCheck() { + // console.log("check", this.currentHighlightType, this.viewOptions.highlightType); + if (this.currentHighlightType !== this.viewOptions.highlightType) { + this.currentHighlightType = this.viewOptions.highlightType; + this.calculateBar(); + } + } + + calculateBar() { + switch (this.currentHighlightType) { + case HighlightType.DURATION: + this.highlightValue = (this.node[this._planService.ACTUAL_DURATION_PROP]); + this.width = Math.round((this.highlightValue / this.planStats.maxDuration) * this.MAX_WIDTH); + break; + case HighlightType.ROWS: + this.highlightValue = (this.node[this._planService.ACTUAL_ROWS_PROP]); + this.width = Math.round((this.highlightValue / this.planStats.maxRows) * this.MAX_WIDTH); + break; + case HighlightType.COST: + this.highlightValue = (this.node[this._planService.ACTUAL_COST_PROP]); + this.width = Math.round((this.highlightValue / this.planStats.maxCost) * this.MAX_WIDTH); + break; + } + + if (this.width < 1) { this.width = 1 } + this.backgroundColor = this.numberToColorHsl(1 - this.width / this.MAX_WIDTH); + } + + calculateDuration() { + var dur: number = _.round(this.node[this._planService.ACTUAL_DURATION_PROP]); + // convert duration into approriate units + if (dur < 1) { + this.duration = "<1"; + this.durationUnit = 'ms'; + } else if (dur > 1 && dur < 1000) { + this.duration = dur.toString(); + this.durationUnit = 'ms'; + } else { + this.duration = _.round(dur / 1000, 2).toString(); + this.durationUnit = 'mins'; + } + this.executionTimePercent = (_.round((dur / this.planStats.executionTime) * 100)); + } + + // create an array of node propeties so that they can be displayed in the view + calculateProps() { + this.props = _.chain(this.node) + .omit('Plans') + .map((value, key) => { + return { key: key, value: value }; + }) + .value(); + } + + calculateTags() { + this.tags = []; + if (this.node[this._planService.SLOWEST_NODE_PROP]) { + this.tags.push(this.SLOW_TAG); + } + if (this.node[this._planService.COSTLIEST_NODE_PROP]) { + this.tags.push(this.COSTLY_TAG); + } + if (this.node[this._planService.LARGEST_NODE_PROP]) { + this.tags.push(this.LARGE_TAG); + } + if (this.node[this._planService.PLANNER_ESTIMATE_FACTOR] >= this.MIN_ESTIMATE_MISS) { + this.tags.push(this.ESTIMATE_TAG); + } + } + + /** + * http://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion + * + * Converts an HSL color value to RGB. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns r, g, and b in the set [0, 255]. + * + * @param Number h The hue + * @param Number s The saturation + * @param Number l The lightness + * @return Array The RGB representation + */ + hslToRgb(h, s, l) { + var r, g, b; + + if (s == 0) { + r = g = b = l; // achromatic + } else { + function hue2rgb(p, q, t) { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p + (q - p) * 6 * t; + if (t < 1 / 2) return q; + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; + return p; + } + + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = hue2rgb(p, q, h + 1 / 3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1 / 3); + } + + return [Math.floor(r * 255), Math.floor(g * 255), Math.floor(b * 255)]; + } + + // convert a number to a color using hsl + numberToColorHsl(i) { + // as the function expects a value between 0 and 1, and red = 0° and green = 120° + // we convert the input to the appropriate hue value + var hue = i * 100 * 1.2 / 360; + // we convert hsl to rgb (saturation 100%, lightness 50%) + var rgb = this.hslToRgb(hue, .9, .4); + // we format to css value and return + return 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')'; + } +} diff --git a/app/components/plan-view/plan-view.html b/app/components/plan-view/plan-view.html new file mode 100644 index 0000000..ab9b7dc --- /dev/null +++ b/app/components/plan-view/plan-view.html @@ -0,0 +1,72 @@ +<div class="menu" [class.menu-hidden]="hideMenu"> + <header> + <i class="fa fa-cogs menu-toggle" (click)="hideMenu = !hideMenu"></i> + <h3>display options</h3> + </header> + + <ul> + <li> + <input id="showPlanStats" type="checkbox" [(ngModel)]="viewOptions.showPlanStats"> + <label class="clickable" for="showPlanStats"> show plan stats</label> + </li> + + <li> + <input id="showPlannerEstimate" type="checkbox" [(ngModel)]="viewOptions.showPlannerEstimate"> + <label class="clickable" for="showPlannerEstimate"> show planner estimate</label> + </li> + + <li> + <input id="showTags" type="checkbox" [(ngModel)]="viewOptions.showTags"> + <label class="clickable" for="showTags"> show analysis tags</label> + </li> + + <li> + <label>graph metric: </label> + <select [(ngModel)]="viewOptions.highlightType"> + <option value="{{highlightTypes.NONE}}">{{highlightTypes.NONE}}</option> + <option value="{{highlightTypes.DURATION}}">{{highlightTypes.DURATION}}</option> + <option value="{{highlightTypes.ROWS}}">{{highlightTypes.ROWS}}</option> + <option value="{{highlightTypes.COST}}">{{highlightTypes.COST}}</option> + </select> + </li> + </ul> +</div> + +<nav> + <div class="nav-container"> + <a [routerLink]="['PlanList']">plans</a><span class="text-muted"> / </span>{{plan.name}} + </div> +</nav> + +<div class="page page-stretch"> + <div *ngIf="viewOptions.showPlanStats" class="plan-stats"> + <div> + <span class="stat-value">{{executionTime}}</span> + <span class="stat-label">execution time ({{executionTimeUnit}})</span> + </div> + <div *ngIf="planStats.planningTime"> + <span class="stat-value">{{planStats.planningTime | number:'.0-2'}}</span> + <span class="stat-label">planning time (ms)</span> + </div> + <div *ngIf="planStats.maxDuration"> + <span class="stat-value">{{planStats.maxDuration | number:'.0-2'}}</span> + <span class="stat-label">slowest node (ms)</span> + </div> + <div *ngIf="planStats.maxRows"> + <span class="stat-value">{{planStats.maxRows | number:'.0-2'}}</span> + <span class="stat-label">largest node (rows)</span> + </div> + <div *ngIf="planStats.maxCost"> + <span class="stat-value">{{planStats.maxCost | number:'.0-2'}}</span> + <span class="stat-label">costliest node</span> + </div> + </div> + + <div class="plan"> + <ul> + <li> + <plan-node [node]="rootContainer.Plan" [planStats]="planStats" [viewOptions]="viewOptions"></plan-node> + </li> + </ul> + </div> +</div> diff --git a/app/components/plan-view/plan-view.ts b/app/components/plan-view/plan-view.ts new file mode 100644 index 0000000..ab4e6a3 --- /dev/null +++ b/app/components/plan-view/plan-view.ts @@ -0,0 +1,96 @@ +import {Component, OnInit} from 'angular2/core'; +import {RouteParams} from 'angular2/router'; +import {ROUTER_DIRECTIVES} from 'angular2/router'; + +import {IPlan} from '../../interfaces/iplan'; +import {PlanService} from '../../services/plan-service'; +import {HighlightType} from '../../enums'; +import {PlanNode} from '../plan-node/plan-node'; + +@Component({ + selector: 'plan-view', + templateUrl: './components/plan-view/plan-view.html', + directives: [ROUTER_DIRECTIVES, PlanNode], + providers: [PlanService] +}) +export class PlanView { + id: string; + plan: IPlan; + rootContainer: any; + executionTime: string; + executionTimeUnit: string; + hideMenu: boolean = true; + + planStats: any = { + executionTime: 0, + maxRows: 0, + maxCost: 0, + maxDuration: 0 + }; + + viewOptions: any = { + showPlanStats: true, + showHighlightBar: true, + showPlannerEstimate: false, + showTags: true, + highlightType: HighlightType.NONE + }; + + showPlannerEstimate: boolean = true; + showMenu: boolean = false; + + highlightTypes = HighlightType; // exposing the enum to the view + + constructor(private _planService: PlanService, routeParams: RouteParams) { + this.id = routeParams.get('id'); + } + + getPlan() { + if (!this.id) { + return; + } + + this.plan = this._planService.getPlan(this.id); + this.rootContainer = this.plan.content; + + var executionTime: number = this.rootContainer['Execution Time'] || this.rootContainer['Total Runtime']; + [this.executionTime, this.executionTimeUnit] = this.calculateDuration(executionTime); + + this.planStats = { + executionTime: executionTime, + planningTime: this.rootContainer['Planning Time'], + maxRows: this.rootContainer[this._planService.MAXIMUM_ROWS_PROP], + maxCost: this.rootContainer[this._planService.MAXIMUM_COSTS_PROP], + maxDuration: this.rootContainer[this._planService.MAXIMUM_DURATION_PROP] + } + } + + ngOnInit() { + this.getPlan(); + } + + toggleHighlight(type: HighlightType) { + this.viewOptions.highlightType = type; + } + + analyzePlan() { + this._planService.analyzePlan(this.plan); + } + + calculateDuration(originalValue: number) { + var duration: string = ''; + var unit: string = ''; + + if (originalValue < 1) { + duration = "<1"; + unit = 'ms'; + } else if (originalValue > 1 && originalValue < 1000) { + duration = originalValue.toString(); + unit = 'ms'; + } else { + duration = _.round(originalValue / 1000, 2).toString(); + unit = 'mins'; + } + return [duration, unit]; + } +} diff --git a/app/enums.ts b/app/enums.ts new file mode 100644 index 0000000..d7784d8 --- /dev/null +++ b/app/enums.ts @@ -0,0 +1,11 @@ +export class HighlightType { + static NONE: string = "none"; + static DURATION: string = "duration"; + static ROWS: string = "rows"; + static COST: string = "cost"; +} + +export enum EstimateDirection { + over, + under +} diff --git a/app/index.html b/app/index.html new file mode 100644 index 0000000..a43262e --- /dev/null +++ b/app/index.html @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <title><%= APP_TITLE %></title> + <meta name="description" content=""> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <!-- inject:css --> + <!-- endinject --> +</head> +<body> + + <app>Loading...</app> + + <!-- shims:js --> + <!-- endinject --> + + <script>System.config(<%= JSON.stringify(SYSTEM_CONFIG) %>)</script> + + <!-- libs:js --> + <!-- endinject --> + + <script> + System.import('bootstrap'); + </script> + + <!-- inject:js --> + <!-- endinject --> + +</body> +</html> diff --git a/app/interfaces/iplan.ts b/app/interfaces/iplan.ts new file mode 100644 index 0000000..bd08478 --- /dev/null +++ b/app/interfaces/iplan.ts @@ -0,0 +1,7 @@ +export interface IPlan { + id: string; + name: string; + content: any; + query: string; + createdOn: Date; +} diff --git a/app/pipes.ts b/app/pipes.ts new file mode 100644 index 0000000..d9f7ab5 --- /dev/null +++ b/app/pipes.ts @@ -0,0 +1,10 @@ +import {Pipe} from 'angular2/core'; +/// <reference path="moment.d.ts" /> + +@Pipe({name: 'momentDate'}) + +export class MomentDatePipe { + transform(value:string, args:string[]) : any { + return moment(value).format('LLLL'); + } +} diff --git a/app/sample-plans/plan1.json b/app/sample-plans/plan1.json new file mode 100644 index 0000000..3be6615 --- /dev/null +++ b/app/sample-plans/plan1.json @@ -0,0 +1,334 @@ +[ + { + "Plan": { + "Node Type": "Limit", + "Startup Cost": 60970.08, + "Total Cost": 60970.11, + "Plan Rows": 10, + "Plan Width": 468, + "Actual Startup Time": 1941.751, + "Actual Total Time": 1941.780, + "Actual Rows": 10, + "Actual Loops": 1, + "Output": ["a.id", "(COALESCE(a.display_name, a.alert_name))", "a.external_alert_id", "a.venue_code", "altt.code", "altt.name", "altst.name", "a.stop_type", "a.deploy_mode", "a.estimated_cost", "(sum(s.total_alerts))", "(sum(s.total_followed))", "(sum(s.total_overridden))", "(sum(s.total_ignored))", "(sum(s.total_not_seen))", "(sum(s.total_unknown))", "(percenttotal((sum(s.total_followed)), (sum(s.total_alerts))))", "(percenttotal((sum(s.total_overridden)), (sum(s.total_alerts))))", "(percenttotal((sum(s.total_ignored)), (sum(s.total_alerts))))", "(percenttotal((sum(s.total_not_seen)), (sum(s.total_alerts))))", "(percenttotal((sum(s.total_unknown)), (sum(s.total_alerts))))", "(((sum(s.total_alerts)) * a.estimated_cost))"], + "Shared Hit Blocks": 260587, + "Shared Read Blocks": 0, + "Shared Dirtied Blocks": 0, + "Shared Written Blocks": 0, + "Local Hit Blocks": 0, + "Local Read Blocks": 0, + "Local Dirtied Blocks": 0, + "Local Written Blocks": 0, + "Temp Read Blocks": 0, + "Temp Written Blocks": 0, + "I/O Read Time": 0.000, + "I/O Write Time": 0.000, + "Plans": [ + { + "Node Type": "Sort", + "Parent Relationship": "Outer", + "Startup Cost": 60970.08, + "Total Cost": 60977.40, + "Plan Rows": 2927, + "Plan Width": 468, + "Actual Startup Time": 1941.747, + "Actual Total Time": 1941.757, + "Actual Rows": 10, + "Actual Loops": 1, + "Output": ["a.id", "(COALESCE(a.display_name, a.alert_name))", "a.external_alert_id", "a.venue_code", "altt.code", "altt.name", "altst.name", "a.stop_type", "a.deploy_mode", "a.estimated_cost", "(sum(s.total_alerts))", "(sum(s.total_followed))", "(sum(s.total_overridden))", "(sum(s.total_ignored))", "(sum(s.total_not_seen))", "(sum(s.total_unknown))", "(percenttotal((sum(s.total_followed)), (sum(s.total_alerts))))", "(percenttotal((sum(s.total_overridden)), (sum(s.total_alerts))))", "(percenttotal((sum(s.total_ignored)), (sum(s.total_alerts))))", "(percenttotal((sum(s.total_not_seen)), (sum(s.total_alerts))))", "(percenttotal((sum(s.total_unknown)), (sum(s.total_alerts))))", "(((sum(s.total_alerts)) * a.estimated_cost))"], + "Sort Key": ["(sum(s.total_alerts))"], + "Sort Method": "top-N heapsort", + "Sort Space Used": 27, + "Sort Space Type": "Memory", + "Shared Hit Blocks": 260587, + "Shared Read Blocks": 0, + "Shared Dirtied Blocks": 0, + "Shared Written Blocks": 0, + "Local Hit Blocks": 0, + "Local Read Blocks": 0, + "Local Dirtied Blocks": 0, + "Local Written Blocks": 0, + "Temp Read Blocks": 0, + "Temp Written Blocks": 0, + "I/O Read Time": 0.000, + "I/O Write Time": 0.000, + "Plans": [ + { + "Node Type": "Nested Loop", + "Parent Relationship": "Outer", + "Join Type": "Left", + "Startup Cost": 37552.36, + "Total Cost": 60906.83, + "Plan Rows": 2927, + "Plan Width": 468, + "Actual Startup Time": 522.250, + "Actual Total Time": 1865.979, + "Actual Rows": 32352, + "Actual Loops": 1, + "Output": ["a.id", "COALESCE(a.display_name, a.alert_name)", "a.external_alert_id", "a.venue_code", "altt.code", "altt.name", "altst.name", "a.stop_type", "a.deploy_mode", "a.estimated_cost", "(sum(s.total_alerts))", "(sum(s.total_followed))", "(sum(s.total_overridden))", "(sum(s.total_ignored))", "(sum(s.total_not_seen))", "(sum(s.total_unknown))", "percenttotal((sum(s.total_followed)), (sum(s.total_alerts)))", "percenttotal((sum(s.total_overridden)), (sum(s.total_alerts)))", "percenttotal((sum(s.total_ignored)), (sum(s.total_alerts)))", "percenttotal((sum(s.total_not_seen)), (sum(s.total_alerts)))", "percenttotal((sum(s.total_unknown)), (sum(s.total_alerts)))", "((sum(s.total_alerts)) * a.estimated_cost)"], + "Shared Hit Blocks": 260587, + "Shared Read Blocks": 0, + "Shared Dirtied Blocks": 0, + "Shared Written Blocks": 0, + "Local Hit Blocks": 0, + "Local Read Blocks": 0, + "Local Dirtied Blocks": 0, + "Local Written Blocks": 0, + "Temp Read Blocks": 0, + "Temp Written Blocks": 0, + "I/O Read Time": 0.000, + "I/O Write Time": 0.000, + "Plans": [ + { + "Node Type": "Nested Loop", + "Parent Relationship": "Outer", + "Join Type": "Left", + "Startup Cost": 37552.22, + "Total Cost": 56750.41, + "Plan Rows": 2927, + "Plan Width": 461, + "Actual Startup Time": 522.141, + "Actual Total Time": 1161.187, + "Actual Rows": 32352, + "Actual Loops": 1, + "Output": ["(sum(s.total_alerts))", "(sum(s.total_followed))", "(sum(s.total_overridden))", "(sum(s.total_ignored))", "(sum(s.total_not_seen))", "(sum(s.total_unknown))", "a.id", "a.display_name", "a.alert_name", "a.external_alert_id", "a.venue_code", "a.stop_type", "a.deploy_mode", "a.estimated_cost", "a.subtype_id", "altt.code", "altt.name"], + "Shared Hit Blocks": 197115, + "Shared Read Blocks": 0, + "Shared Dirtied Blocks": 0, + "Shared Written Blocks": 0, + "Local Hit Blocks": 0, + "Local Read Blocks": 0, + "Local Dirtied Blocks": 0, + "Local Written Blocks": 0, + "Temp Read Blocks": 0, + "Temp Written Blocks": 0, + "I/O Read Time": 0.000, + "I/O Write Time": 0.000, + "Plans": [ + { + "Node Type": "Nested Loop", + "Parent Relationship": "Outer", + "Join Type": "Inner", + "Startup Cost": 37552.07, + "Total Cost": 56230.56, + "Plan Rows": 2927, + "Plan Width": 405, + "Actual Startup Time": 522.131, + "Actual Total Time": 918.895, + "Actual Rows": 32352, + "Actual Loops": 1, + "Output": ["(sum(s.total_alerts))", "(sum(s.total_followed))", "(sum(s.total_overridden))", "(sum(s.total_ignored))", "(sum(s.total_not_seen))", "(sum(s.total_unknown))", "a.id", "a.display_name", "a.alert_name", "a.external_alert_id", "a.venue_code", "a.stop_type", "a.deploy_mode", "a.estimated_cost", "a.type_id", "a.subtype_id"], + "Shared Hit Blocks": 132411, + "Shared Read Blocks": 0, + "Shared Dirtied Blocks": 0, + "Shared Written Blocks": 0, + "Local Hit Blocks": 0, + "Local Read Blocks": 0, + "Local Dirtied Blocks": 0, + "Local Written Blocks": 0, + "Temp Read Blocks": 0, + "Temp Written Blocks": 0, + "I/O Read Time": 0.000, + "I/O Write Time": 0.000, + "Plans": [ + { + "Node Type": "Aggregate", + "Strategy": "Hashed", + "Parent Relationship": "Outer", + "Startup Cost": 37551.64, + "Total Cost": 37624.82, + "Plan Rows": 2927, + "Plan Width": 56, + "Actual Startup Time": 522.107, + "Actual Total Time": 587.536, + "Actual Rows": 32352, + "Actual Loops": 1, + "Output": ["s.alert_id", "sum(s.total_alerts)", "sum(s.total_followed)", "sum(s.total_overridden)", "sum(s.total_ignored)", "sum(s.total_not_seen)", "sum(s.total_unknown)"], + "Group Key": ["s.alert_id"], + "Shared Hit Blocks": 2784, + "Shared Read Blocks": 0, + "Shared Dirtied Blocks": 0, + "Shared Written Blocks": 0, + "Local Hit Blocks": 0, + "Local Read Blocks": 0, + "Local Dirtied Blocks": 0, + "Local Written Blocks": 0, + "Temp Read Blocks": 0, + "Temp Written Blocks": 0, + "I/O Read Time": 0.000, + "I/O Write Time": 0.000, + "Plans": [ + { + "Node Type": "Bitmap Heap Scan", + "Parent Relationship": "Outer", + "Relation Name": "alert_daily_summaries", + "Schema": "analytics", + "Alias": "s", + "Startup Cost": 3265.35, + "Total Cost": 35524.50, + "Plan Rows": 115837, + "Plan Width": 56, + "Actual Startup Time": 10.745, + "Actual Total Time": 165.318, + "Actual Rows": 140451, + "Actual Loops": 1, + "Output": ["s.id", "s.org_id", "s.alert_id", "s.alert_day", "s.total_alerts", "s.total_followed", "s.total_overridden", "s.total_ignored", "s.total_not_seen", "s.total_unknown", "s.override_comments"], + "Recheck Cond": "((s.org_id = 2) AND (s.alert_day >= '2015-10-01 00:00:00'::timestamp without time zone) AND (s.alert_day <= '2015-12-01 00:00:00'::timestamp without time zone))", + "Rows Removed by Index Recheck": 0, + "Exact Heap Blocks": 2243, + "Lossy Heap Blocks": 0, + "Shared Hit Blocks": 2784, + "Shared Read Blocks": 0, + "Shared Dirtied Blocks": 0, + "Shared Written Blocks": 0, + "Local Hit Blocks": 0, + "Local Read Blocks": 0, + "Local Dirtied Blocks": 0, + "Local Written Blocks": 0, + "Temp Read Blocks": 0, + "Temp Written Blocks": 0, + "I/O Read Time": 0.000, + "I/O Write Time": 0.000, + "Plans": [ + { + "Node Type": "Bitmap Index Scan", + "Parent Relationship": "Outer", + "Index Name": "alert_daily_summaries_org_id_alert_day_idx", + "Startup Cost": 0.00, + "Total Cost": 3236.39, + "Plan Rows": 115837, + "Plan Width": 0, + "Actual Startup Time": 10.445, + "Actual Total Time": 10.445, + "Actual Rows": 140451, + "Actual Loops": 1, + "Index Cond": "((s.org_id = 2) AND (s.alert_day >= '2015-10-01 00:00:00'::timestamp without time zone) AND (s.alert_day <= '2015-12-01 00:00:00'::timestamp without time zone))", + "Shared Hit Blocks": 541, + "Shared Read Blocks": 0, + "Shared Dirtied Blocks": 0, + "Shared Written Blocks": 0, + "Local Hit Blocks": 0, + "Local Read Blocks": 0, + "Local Dirtied Blocks": 0, + "Local Written Blocks": 0, + "Temp Read Blocks": 0, + "Temp Written Blocks": 0, + "I/O Read Time": 0.000, + "I/O Write Time": 0.000 + } + ] + } + ] + }, + { + "Node Type": "Index Scan", + "Parent Relationship": "Inner", + "Scan Direction": "Forward", + "Index Name": "alerts_pkey1", + "Relation Name": "alerts", + "Schema": "analytics", + "Alias": "a", + "Startup Cost": 0.42, + "Total Cost": 6.34, + "Plan Rows": 1, + "Plan Width": 213, + "Actual Startup Time": 0.004, + "Actual Total Time": 0.005, + "Actual Rows": 1, + "Actual Loops": 32352, + "Output": ["a.id", "a.org_id", "a.external_alert_id", "a.alert_name", "a.display_name", "a.estimated_cost", "a.description", "a.source", "a.venue_code", "a.action_expected", "a.cancel_expected", "a.responsible_provider_type", "a.status", "a.version", "a.created_by", "a.created_date", "a.modified_by", "a.modified_date", "a.tracking_id", "a.record_date", "a.released_date", "a.released", "a.comments", "a.default_lockout_hours", "a.deploy_mode", "a.stop_type", "a.importance_level", "a.type_id", "a.subtype_id"], + "Index Cond": "(a.id = s.alert_id)", + "Rows Removed by Index Recheck": 0, + "Shared Hit Blocks": 129627, + "Shared Read Blocks": 0, + "Shared Dirtied Blocks": 0, + "Shared Written Blocks": 0, + "Local Hit Blocks": 0, + "Local Read Blocks": 0, + "Local Dirtied Blocks": 0, + "Local Written Blocks": 0, + "Temp Read Blocks": 0, + "Temp Written Blocks": 0, + "I/O Read Time": 0.000, + "I/O Write Time": 0.000 + } + ] + }, + { + "Node Type": "Index Scan", + "Parent Relationship": "Inner", + "Scan Direction": "Forward", + "Index Name": "alert_types_id_org_id_key", + "Relation Name": "alert_types", + "Schema": "analytics", + "Alias": "altt", + "Startup Cost": 0.15, + "Total Cost": 0.17, + "Plan Rows": 1, + "Plan Width": 72, + "Actual Startup Time": 0.002, + "Actual Total Time": 0.003, + "Actual Rows": 1, + "Actual Loops": 32352, + "Output": ["altt.id", "altt.version", "altt.code", "altt.name", "altt.org_id"], + "Index Cond": "(a.type_id = altt.id)", + "Rows Removed by Index Recheck": 0, + "Shared Hit Blocks": 64704, + "Shared Read Blocks": 0, + "Shared Dirtied Blocks": 0, + "Shared Written Blocks": 0, + "Local Hit Blocks": 0, + "Local Read Blocks": 0, + "Local Dirtied Blocks": 0, + "Local Written Blocks": 0, + "Temp Read Blocks": 0, + "Temp Written Blocks": 0, + "I/O Read Time": 0.000, + "I/O Write Time": 0.000 + } + ] + }, + { + "Node Type": "Index Scan", + "Parent Relationship": "Inner", + "Scan Direction": "Forward", + "Index Name": "alert_subtypes_id_org_id_key", + "Relation Name": "alert_subtypes", + "Schema": "analytics", + "Alias": "altst", + "Startup Cost": 0.14, + "Total Cost": 0.16, + "Plan Rows": 1, + "Plan Width": 23, + "Actual Startup Time": 0.002, + "Actual Total Time": 0.003, + "Actual Rows": 1, + "Actual Loops": 32352, + "Output": ["altst.id", "altst.version", "altst.code", "altst.name", "altst.org_id"], + "Index Cond": "(a.subtype_id = altst.id)", + "Rows Removed by Index Recheck": 0, + "Shared Hit Blocks": 63472, + "Shared Read Blocks": 0, + "Shared Dirtied Blocks": 0, + "Shared Written Blocks": 0, + "Local Hit Blocks": 0, + "Local Read Blocks": 0, + "Local Dirtied Blocks": 0, + "Local Written Blocks": 0, + "Temp Read Blocks": 0, + "Temp Written Blocks": 0, + "I/O Read Time": 0.000, + "I/O Write Time": 0.000 + } + ] + } + ] + } + ] + }, + "Planning Time": 0.507, + "Triggers": [ + ], + "Execution Time": 1953.684 + } +] diff --git a/app/services/plan-service.ts b/app/services/plan-service.ts new file mode 100644 index 0000000..5d7dc3c --- /dev/null +++ b/app/services/plan-service.ts @@ -0,0 +1,166 @@ +import {IPlan} from '../interfaces/iplan'; +import {HighlightType, EstimateDirection} from '../enums'; +/// <reference path="moment.d.ts" /> +/// <reference path="lodash.d.ts" /> + +export class PlanService { + // plan property keys + NODE_TYPE_PROP: string = 'Node Type'; + ACTUAL_ROWS_PROP: string = 'Actual Rows'; + PLAN_ROWS_PROP: string = 'Plan Rows'; + ACTUAL_TOTAL_TIME_PROP: string = 'Actual Total Time'; + ACTUAL_LOOPS_PROP: string = 'Actual Loops'; + TOTAL_COST_PROP: string = 'Total Cost'; + PLANS_PROP: string = 'Plans'; + + + // computed by pev + COMPUTED_TAGS_PROP: string = "*Tags"; + + COSTLIEST_NODE_PROP: string = "*Costiest Node (by cost)"; + LARGEST_NODE_PROP: string = "*Largest Node (by rows)"; + SLOWEST_NODE_PROP: string = "*Slowest Node (by duration)"; + + MAXIMUM_COSTS_PROP: string = '*Most Expensive Node (cost)'; + MAXIMUM_ROWS_PROP: string = '*Largest Node (rows)'; + MAXIMUM_DURATION_PROP: string = '*Slowest Node (time)'; + ACTUAL_DURATION_PROP: string = '*Actual Duration'; + ACTUAL_COST_PROP: string = '*Actual Cost'; + PLANNER_ESTIMATE_FACTOR: string = '*Planner Row Estimate Factor'; + PLANNER_ESIMATE_DIRECTION: string = '*Planner Row Estimate Direction'; + + ARRAY_INDEX_KEY: string = 'arrayIndex'; + + private _maxRows: number = 0; + private _maxCost: number = 0; + private _maxDuration: number = 0; + + getPlans(): Array<IPlan> { + var plans: Array<IPlan> = []; + + for (var i in localStorage) { + plans.push(JSON.parse(localStorage[i])); + } + + return plans; + } + + getPlan(id: string): IPlan { + return JSON.parse(localStorage.getItem(id)); + } + + createPlan(planName: string, planContent: string, planQuery): IPlan { + var plan: IPlan = { + id: 'plan_' + new Date().getTime().toString(), + name: planName || 'plan created on ' + moment().format('LLL'), + createdOn: new Date(), + content: JSON.parse(planContent)[0], + query: planQuery + }; + + this.analyzePlan(plan); + return plan; + } + + analyzePlan(plan: IPlan) { + this.processNode(plan.content.Plan); + plan.content[this.MAXIMUM_ROWS_PROP] = this._maxRows; + plan.content[this.MAXIMUM_COSTS_PROP] = this._maxCost; + plan.content[this.MAXIMUM_DURATION_PROP] = this._maxDuration; + + this.findOutlierNodes(plan.content.Plan); + + localStorage.setItem(plan.id, JSON.stringify(plan)); + } + + deletePlan(plan: IPlan) { + localStorage.removeItem(plan.id); + } + + deleteAllPlans() { + localStorage.clear(); + } + + // recursively walk down the plan to compute various metrics + processNode(node) { + this.calculatePlannerEstimate(node); + this.calculateActuals(node); + + _.each(node, (value, key) => { + this.calculateMaximums(node, key, value); + + if (key === this.PLANS_PROP) { + _.each(value, (value) => { + this.processNode(value); + }) + } + }); + } + + calculateMaximums(node, key, value) { + if (key === this.ACTUAL_ROWS_PROP && this._maxRows < value) { + this._maxRows = value; + } + if (key === this.ACTUAL_COST_PROP && this._maxCost < value) { + this._maxCost = value; + } + + if (key === this.ACTUAL_DURATION_PROP && this._maxDuration < value) { + this._maxDuration = value; + } + } + + findOutlierNodes(node) { + node[this.SLOWEST_NODE_PROP] = false; + node[this.LARGEST_NODE_PROP] = false; + node[this.COSTLIEST_NODE_PROP] = false; + + if (node[this.ACTUAL_COST_PROP] === this._maxCost) { + node[this.COSTLIEST_NODE_PROP] = true; + } + if (node[this.ACTUAL_ROWS_PROP] === this._maxRows) { + node[this.LARGEST_NODE_PROP] = true; + } + if (node[this.ACTUAL_DURATION_PROP] === this._maxDuration) { + node[this.SLOWEST_NODE_PROP] = true; + } + + _.each(node, (value, key) => { + if (key === this.PLANS_PROP) { + _.each(value, (value) => { + this.findOutlierNodes(value); + }) + } + }); + } + + // actual duration and actual cost are calculated by subtracting child values from the total + calculateActuals(node) { + node[this.ACTUAL_DURATION_PROP] = node[this.ACTUAL_TOTAL_TIME_PROP]; + node[this.ACTUAL_COST_PROP] = node[this.TOTAL_COST_PROP]; + + _.each(node.Plans, subPlan => { + node[this.ACTUAL_DURATION_PROP] = node[this.ACTUAL_DURATION_PROP] - subPlan[this.ACTUAL_TOTAL_TIME_PROP]; + node[this.ACTUAL_COST_PROP] = node[this.ACTUAL_COST_PROP] - subPlan[this.TOTAL_COST_PROP]; + }); + + if (node[this.ACTUAL_COST_PROP] < 0) { + node[this.ACTUAL_COST_PROP] = 0; + } + + // since time is reported for an invidual loop, actual duration must be adjusted by number of loops + node[this.ACTUAL_DURATION_PROP] = node[this.ACTUAL_DURATION_PROP] * node[this.ACTUAL_LOOPS_PROP]; + } + + // figure out order of magnitude by which the planner mis-estimated how many rows would be + // invloved in this node + calculatePlannerEstimate(node) { + node[this.PLANNER_ESTIMATE_FACTOR] = node[this.ACTUAL_ROWS_PROP] / node[this.PLAN_ROWS_PROP]; + node[this.PLANNER_ESIMATE_DIRECTION] = EstimateDirection.under; + + if (node[this.PLANNER_ESTIMATE_FACTOR] < 1) { + node[this.PLANNER_ESIMATE_DIRECTION] = EstimateDirection.over; + node[this.PLANNER_ESTIMATE_FACTOR] = node[this.PLAN_ROWS_PROP] / node[this.ACTUAL_ROWS_PROP]; + } + } +} |