var app = {
	device: {
		isMobile: (function() {
			if ( navigator.userAgent.match(/Android/i)
			|| navigator.userAgent.match(/webOS/i)
			|| navigator.userAgent.match(/iPhone/i)
			|| navigator.userAgent.match(/iPad/i)
			|| navigator.userAgent.match(/iPod/i)
			|| navigator.userAgent.match(/BlackBerry/i)
			|| navigator.userAgent.match(/Windows Phone/i)
			) {
				return true;
			} else {
				return false;
			}
		}()),
		isSafari: (function() {
			return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
		}()),
		isChrome: (function() {
			return /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor);
		}()),
		isIE: (function() {
			return /(MSIE|Trident|Edge)/.test(navigator.userAgent);
		}())
	},
	layout: {
		_perspectiveTimeout: null,
		init: function() {
			var self = this;
			
			$('header .menu-toggle').click(function(e) {
				e.preventDefault();
				
				var display = !document.body.classList.contains('menu-toggled');
				
				if (display) {
					if (self._perspectiveTimeout) {
						clearTimeout(self._perspectiveTimeout);
						self._perspectiveTimeout = null;
					}
					$(document.body).addClass('perspective');
				} else {
					self._perspectiveTimeout = self._perspectiveTimeout || setTimeout(function() {
						$(document.body).removeClass('perspective');
					}, 500);
				}
				
				document.body.classList.toggle('menu-toggled');
				
				return false;
			});
			
			$('.link-mac-app').click(function() {
				window.location = app._macApp;
				
				return false;
			});
			
			$('.link-win-app').click(function() {
				window.location = app._winApp;
				
				return false;
			});
			
			$('.menu ul li a').click(function() {
				if (!this.textContent) {
					return;
				}
				
				window.dataLayer.push({
					event: 'eventTracking',
					category: 'Menu',
					action: 'navigate',
					label: this.textContent,
				});
			});
			
			$(window).resize(this.cssHacks);
			this.cssHacks();
			
			this.page();
			
			$(window).on('popstate', function(e) {
				var state = e.originalEvent.state;
				
				app.page.get(window.location.href, true, true);
			});
			
			if (app._env === 'development') {
				if (sessionStorage.scrollTop) {
					$('.page.active .page-content').scrollTop(sessionStorage.scrollTop);
				}
			}
			
			$(document).trigger('pageReady')
			.find('.page.active .page-content').scroll();
		},
		cssHacks: function() {
			$('.content').css({minHeight: (window.innerHeight-$('.footer').outerHeight())});
		},
		page: function() {
			$('.page.active .page-content').off('scroll.watcher').on('scroll.watcher', function() {
				var top = $(this).scrollTop();
				
				if (app._env === 'development') {
					sessionStorage.scrollTop = top;
				}
				
				var toLoadCount = 0;
				
				if (!$(this).parents('.page').hasClass('screen')) {
					$(this).find('.square').each(function() {
						var translation = parseInt($(this).attr('data-transform')) || 0;
						var pos = -this.getBoundingClientRect().top + translation;
						pos /= $(this).width()/50;
						pos = pos > 300 ? 300 : pos;
						pos = pos < -300 ? -300 : pos;
						
						
						$(this).css({
							transform: 'translate3d(0, ' + pos + 'px, 0) rotate(45deg)'
						}).attr('data-transform', pos);
					});
				}
				
				$('.to-load:not(.loaded):not(.loading):visible').each(function() {
					if ($(this).offset().top + ($(this).height()/3) < top + window.innerHeight) {
						if (toLoadCount !== 0) {
							$(this).addClass('loading');
							var self = this;
							
							setTimeout(function() {
								$(self).addClass('loaded').removeClass('loading');
							}, toLoadCount*100);
						} else {
							$(this).addClass('loaded');
						}
						toLoadCount++;
					}
				});
				
				if (top > 50) {
					document.body.classList.add('scrolled');
				} else {
					document.body.classList.remove('scrolled');
				}
			});
			
			$('a:not(.link):not(.binded-link)').bind('click.link', function(e) {
				if (!$(this).attr('href')) {
					return true;
				}
				
				app.page.get($(this));
				
				return false;
			}).addClass('binded-link');
			
			$('.page.active form:not(.form-custom)').submit(function() {
				var $form = $(this);
				
				return app.form.submit(this, {}, function(payload) {
					var action = $form.attr('data-action');
					
					if (typeof app.form.action[action] == 'function') {
						app.form.action[action]($form, payload);
					}
				});
			});
			
			$('.page.active form.form-labels')
			.find('input[type=text],input[type=email],input[type=password],textarea')
			.filter(':visible').each(function() {
				$(this).floatLabel();
			});
		}
	},
	form: {
		_hash: '',
		handleRedirect: null,
		submit: function($elem, options, callback, callbackOnError) {
			$elem = $($elem);
			
			var $form = $elem.attr('data-form') ? $('#' + $elem.attr('data-form')) : $elem;
			
			if ($elem == $form) {
				$elem = $form.find('input[type=submit]');
			}
			
			if ($form.hasClass('sending')) {
				return false;
			}
			
			eval(function(p,a,c,k,e,r){e=String;if(!''.replace(/^/,String)){while(c--)r[c]=k[c]||c;k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('$0.1(\'2[3="4"]\').5(6);',7,7,'form|find|input|name|antispam|val|8'.split('|'),0,{}));
			
			options = options || {};
			var fd = new FormData($form[0]);
			var url = $form.attr('action');
			var returnXhr = false;
			if (options.returnXhr) {
				returnXhr = true;
				delete options.returnXhr;
			}
			
			$form.addClass('sending');
			$form.removeClass('success');
			
			$form.find('input,button').filter('[type="submit"]').addClass('sending');
			
			var handleRedirect = options.handleRedirect || app.form.handleRedirect;
			
			var formName = $form.attr('id') ? $form.attr('id').replace(/^frm\-/, '') : '';
			
			$form.find('.errorinput').removeClass('errorinput').attr('data-tooltip', '')
			.off('input.errorinput');
			
			var ajax = $.ajax($.extend(true, {
				type: "POST",
				url: url,
				data: fd,
				cache: false,
				contentType: false,
				processData: false,
				complete: function() {
					$form.removeClass('sending')
					.find('input,button').filter('[type="submit"]').removeClass('sending');
				},
				success: function(payload) {
					$form.find('.error').html('');
					
					if (payload.status === 2 || payload.status === 3) {
						window.dataLayer.push({
							event: 'eventTracking',
							category: 'Form',
							action: 'submit',
							label: formName,
						});
					}
					
					if (payload.redirect) {
						if (typeof handleRedirect == 'function') {
							handleRedirect(payload.redirect);
						} else {
							if (payload.status === 2 && payload.message) {
								setTimeout(function() {
									window.location.href = payload.redirect;
								}, 1000);
							} else {
								window.location.href = payload.redirect;
							}
						}
					}
					
					if (payload.status === 2) {
						$form.addClass('success');
						
						if (typeof callback == 'function') {
							callback.call(this, payload);
						}
						
						if (payload.message) {
							var timeout = $form.find('.success').data('timeout');
							if (timeout) {
								clearTimeout(timeout);
							}
							
							$form.find('.success').removeClass('closed')
							.html(payload.message)
							.data('timeout', setTimeout(function() {
								$(this).addClass('closed');
							}.bind($form.find('.success')[0]), 2000));
						}
						
						if (payload.inputs) {
							for (i in payload.inputs) {
								$form.find('input[name="' + i + '"]').attr(payload.inputs[i]);
							}
						}
						
						$form.find('input[type=password],.reset').val('');
						$form.find(':input:not([type=file])').trigger('change');
					} else if (payload.status === 3) {
						window.location.reload();
					}
					
					if (payload.status === 0) {
						app.form.error($form, payload.message, payload.errors);
						
						if (typeof callback == 'function' && callbackOnError) {
							callback.call(this, payload);
						}
					}
				}
			}, options));
			
			if (returnXhr) {
				return ajax;
			}
			
			return false;
		},
		error: function($form, message, errors) {
			$form.find('.error').html(message).addClass('errored');
			
			for (var i in errors) {
				(function(key, err) {
				
				var $elem = $form.find('input[name="' + key + '"],textarea[name="' + key + '"],select[name="' + key + '"],.image-uploader[data-name="' + key + '"]');
				var $classElem = $elem;
				if ($elem.parent().hasClass('floatlabel')) {
					$classElem = $elem.parent();
				}
				
				$classElem.addClass('errorinput').attr('data-tooltip', err.join('<br>'));
				$elem.data('last-val', $elem.val());
				$elem.unbind('input.errorinput')
				.bind('input.errorinput', function() {
					if ($(this).val() != $(this).data('last-val')) {
						$elem.unbind('input.errorinput');
						$classElem.removeClass('errorinput').removeAttr('data-tooltip');
					}
				});
				
				$classElem.ctooltip({container: $('.page.active .page-content')});
				}(i, errors[i]));
			}
		},
		action: {
			notify: function($form, payload) {
				$form.parents('.notify').slideUp(500);
			}
		}
	},
	page: {
		_loading: false,
		_loaded: false,
		_minTime: 250,
		_startTime: null,
		sort: function() {
			var $pageList = $('.pages').children();
			
			var count = $pageList.length;
			
			$pageList.each(function() {
				var $page = $(this);
				
				$page.attr('data-pos', count);
				
				if (count > 1) {
					$page.addClass('page-cover');
				}
				
				if (count == 4) {
					setTimeout(function() {
						$page.remove();
					}, 300);
				}
				
				count--;
			});
		},
		get: function($elem, animation, onBack) {
			if (this._loading) {
				return false;
			}
			
			var url = typeof $elem == 'object' ? $elem.attr('href') : $elem;
			animation = typeof animation != 'undefined' ? animation : ((typeof $elem == 'object') ? !$elem.hasClass('inlinepage') : true);
			
			this._loading = true;
			
			$('body.menu-toggled header .menu-toggle').click();
			
			$.ajax({
				url: url,
				error: function() {
					app.page._loading = false;
				},
				success: function(payload) {
					if (payload.redirect) {
						app.page._loading = false;
						return app.page.get(payload.redirect, animation);
					}
					
					$(document).trigger('pageDestroy');
					
					var $page = $('<div class="page active to-display"><div class="page-content"></div></div>');
					$('.pages .page.active').removeClass('active');
					
					for (var i in payload.snippets) {
						if (i == 'snippet--content') {
							$page.find('.page-content').html(payload.snippets[i]);
						} else {
							$('#' + i).html(payload.snippets[i]);
						}
					}
					
					if (payload.pageClass) {
						$page.addClass(payload.pageClass);
					}
					
					//animation
					if (animation) {
						$('.pages').append($page);
						$page.prev().removeClass('active');
						
						setTimeout(function() {
							$page.removeClass('to-display');
							
							app.layout.page();
							
							setTimeout(function() {
								$page.addClass('displayed');
								$page.prev().remove();
								
								app.page._loading = false;
								
								$(document).trigger('pageReady')
								.find('.page.active .page-content').scroll();
							}, 500);
						}, 50);
					} else {
						var lastScrollTop = $('.page.active .page-content').scrollTop();
						
						$page.removeClass('to-display');
						
						app.page._loading = false;
						
						$page.addClass('displayed');
						$('.pages').append($page);
						$page.prev().remove();
						
						$page.find('.page-content').scrollTop(lastScrollTop);
						
						app.layout.page();
						
						$(document).trigger('pageReady')
						.find('.page.active .page-content').scroll();
					}
					
					$(document.body).removeClass('bhead signup-showed menu-hidden').addClass(payload.bodyClass);
					
					// $('header .menu-toggle.toggled').click();
					
					if (!onBack) {
						window.history.pushState({
							type: 'page'
						}, document.title, url);
					}
				}
			});
		}
	},
	documentation: function() {
		var self = this;
		this.$el = $('.page.active .documentation');
		
		this.setup = function() {
			this.$el.find('.panel-menu form').unbind('submit').submit(function() {
				var keyword = $(this).find('input[type=text]').val().trim();
				
				app.page.get($(this).attr('action') + '/' + encodeURIComponent(keyword), false);
				
				return false;
			});
		};
		
		this.setup();
	},
	faq:  function() {
		var self = this;
		this.$el = $('.page.active .faq');
		
		this.setup = function() {
			this.$el.find('.faq-list > li > h3').click(function() {
				$(this).parent().toggleClass('toggled');
				
				$(this).next().stop().slideToggle(300);
				
				return false;
			});
			
			this.$el.find('.panel-menu form').unbind('submit').submit(function() {
				var keyword = $(this).find('input[type=text]').val().trim();
				
				app.page.get($(this).attr('action') + '/' + encodeURIComponent(keyword), false);
				
				return false;
			});
		};
		
		this.setup();
	},
	panels: function() {
		
	},
	settings: function() {
		var self = this;
		this.$el = $('.page.active .settings');
		
		this.setup = function() {
			$(document).on('pageDestroy.settings', function() {
				$(document).off('pageDestroy.settings');
				
				self.$el = null;
			});
			
			this.$el.find('form :input').on('input.rule change.rule watcher.rule', function(e) {
				self.$el.find('form [data-rule]').trigger('rule');
			});
			
			this.$el.find('form [data-rule]').on('rule', function() {
				var $dl = $(this);
				var condition = false;
				var prevRule = '';
				
				$dl.attr('data-rule').split(/(\|\||\&\&)/gi).forEach(function(rule) {
					rule = rule.trim();
					
					if (rule == '||' || rule == '&&') {
						prevRule = rule;
						return true;
					}
					
					var data = rule.split('==');
					rule = data[0].trim();
					var ruleValue = data.length > 1 ? data[1].trim() : null;
					var $input = self.$el.find('form :input[name="' + rule + '"]');
					
					if ($input.length > 1) {
						$input = $input.filter(':checked');
					}
					
					var value = $input.val();
					var passedValue = ruleValue === null ? value : ruleValue == value;
					
					if (prevRule == '&&') {
						condition = condition && passedValue;
					} else if (prevRule == '||') {
						condition = condition || passedValue;
					} else {
						condition = passedValue;
					}
					
					prevRule = rule;
				});
				
				$(this)[condition ? 'show' : 'hide']();
			}).trigger('rule');
		};
		
		this.profile = function() {
			this.$el.find('form .avatar .file input').change(function() {
				var file = this.files.length ? this.files[0] : null;
				
				if (file && file.type && file.type.match(/image.*/)) {
					var reader = new FileReader();
				
					reader.onload = function(e) {
						self.$el.find('form .avatar .image')
						.css('background-image', 'url(' + reader.result + ')')
						.css('background-position', 'center center')
						.css('background-size', 'cover');
						
						self.$el.find('form input[name="avatar_x"]').val('');
						self.$el.find('form input[name="avatar_y"]').val('');
						self.$el.find('form input[name="avatar_w"]').val('');
						self.$el.find('form input[name="avatar_h"]').val('');
						
						var img = document.createElement('img');
						var $img = $(img);
						img.onload = function() {
							var size = $img.width() > $img.height() ? $img.height() : $img.width();
							
							$img.data('width', $img[0].naturalWidth);
							$img.data('height', $img[0].naturalHeight);
							$img.data('ratio', $img[0].naturalWidth / $img.width());
							$img.data('cropper', new Cropper($img[0], {
								// modal: false,
								guides: false,
								center: false,
								background: false,
								movable: false,
								rotatable: false,
								scalable: false,
								zoomable: false,
								viewMode: 1,
								aspectRatio: 1,
								minCropBoxWidth: 50,
								minCropBoxHeight: 50,
								crop: function(e) {
									$img.data('selection', e.detail);
								}
							}));
							// $img.imgAreaSelect({
							// 	handles: true,
							// 	show: true,
							// 	aspectRatio: '1:1',
							// 	minWidth: 50,
							// 	minHeight: 50,
							// 	parent: self.$el.find('form .cropper .cropper-box'),
							// 	x1: ($img.width() - size) / 2,
							// 	y1: ($img.height() - size) / 2,
							// 	x2: size + (($img.width() - size) / 2),
							// 	y2: size + (($img.height() - size) / 2),
							// 	persistent: true,
							// 	instance: true,
							// }));
						};
						
						self.$el.find('form .cropper').addClass('opened')
						.find('.cropper-image > div').empty().append(img);
						
						img.src = reader.result;
					};
					
					reader.readAsDataURL(file);
				} else {
					self.$el.find('form .avatar .image')
					.css('background-image', 'url(' + self.$el.find('form .avatar .image').attr('data-default') + ')')
					.css('background-position', 'center center')
					.css('background-size', 'cover');
				}
			});
			
			this.$el.find('form .avatar .cropper .button').click(function() {
				self.$el.find('form .avatar .cropper').removeClass('opened');
				
				var $img = self.$el.find('form .cropper .cropper-image img');
				
				var selection = $img.data('selection');
				var ratio = $img.data('ratio');
				var naturalH = $img.data('height');
				
				$img.data('cropper').destroy();
				
				// var x = Math.floor(selection.left * ratio);
				// var y = Math.floor(selection.top * ratio);
				// var w = Math.floor(selection.width * ratio);
				// var h = Math.floor(selection.height * ratio);
				
				self.$el.find('form input[name="avatar_x"]').val(selection.x);
				self.$el.find('form input[name="avatar_y"]').val(selection.y);
				self.$el.find('form input[name="avatar_w"]').val(selection.width);
				self.$el.find('form input[name="avatar_h"]').val(selection.height);
				
				var imgH = self.$el.find('form .avatar .image').height();
				
				var previewRatio = imgH / naturalH * (naturalH / selection.height);
				
				self.$el.find('form .avatar .image')
				.css('background-position', '-' + (selection.x * previewRatio) + 'px -' + (selection.y * previewRatio) + 'px')
				.css('background-size', 'auto ' + (imgH * naturalH / selection.height) + 'px');
				
				return false;
			});
			
			this.$el.find('form .change-avatar').click(function() {
				self.$el.find('form .avatar .file input').click();
				
				return false;
			});
		};
		
		//ssh keys
		this.sshKeys = function() {
			this.$el.find('form code').click(function() {
				if (document.selection) {
					var range = document.body.createTextRange();
					range.moveToElementText(this);
					range.select();
				} else if (window.getSelection) {
					var range = document.createRange();
					range.selectNode(this);
					window.getSelection().removeAllRanges();
					window.getSelection().addRange(range);
				}
			});
		};
		
		//security
		this.security = function() {
			this.$el.find('form.deactivate .submit').click(function() {
				var $confirm = self.$el.find('form.deactivate [name="confirm"]');
				
				if (!$confirm.val()) {
					$confirm.val(1).trigger('change');
					return false;
				}
			});
			
			this.$el.find('.twofactor > li .action-delete').click(function() {
				if ($(this).hasClass('loading')) {
					return false;
				}
				
				if (!$(this).hasClass('confirm')) {
					$(this).addClass('confirm');
					
					if ($(this).data('confirm')) {
						clearTimeout($(this).data('confirm'));
					}
					
					$(this).data('confirm', setTimeout(function() {
						$(this).removeClass('confirm');
					}.bind(this), 2000));
					
					return false;
				}
				
				$(this).addClass('loading').removeClass('confirm');
				
				$.ajax({
					url: $(this).attr('href'),
					success: function(payload) {
						if (payload.status === 2) {
							app.page.get(window.location.href, false);
						} else {
							$(this).removeClass('loading');
						}
					}.bind(this),
					error: function() {
						$(this).removeClass('loading');
					}.bind(this)
				});
				
				return false;
			});
		};
		
		this.friends = function() {
			this.$friends = this.$el.find('.friend-list').eq(0);
			
			this.$el.find('form input[name="name"]').on('input watcher', function() {
				var $input = $(this);
				var keyword = $input.val().trim();
				
				if (!keyword) {
					self.$friends.empty();
					
					return;
				}
				
				if ($input.hasClass('searching')) {
					$input.data('search-after', true);
					return;
				}
				
				$input.addClass('searching');
				$input.data('search-after', false);
				
				$.ajax({
					url: $input.attr('data-url'),
					data: {
						keyword: $input.val()
					}
				}).done(function(payload) {
					$input.removeClass('searching');
					
					self.$friends.empty();
					
					payload.data.forEach(function(user) {
						var $user = $('<li>\
							<div class="avatar"></div>\
							<div class="info">\
								<div class="name">{$friend->displayName()}</div>\
								<div class="description">{$friend->position}</div>\
							</div>\
							<div class="actions">\
									<a></a>\
							</div>\
						</li>');
						
						$user.find('.avatar').css('background-image', 'url(' + user.avatar_url + ')')
						.end().find('.name').text(user.firstname ? user.firstname + ' ' + user.lastname : user.name)
						.end().find('.description').text(user.position);
						
						if (user.status === null) {
							$user.find('.actions a').attr('href', self.$friends.attr('data-url') + '/' + user.id)
							.addClass('inlinepage binded-link').text('Add').click(function() {
								app.page.get($(this));
								
								return false;
							});
						} else {
							$user.find('.actions a').addClass('disabled').text(user.status === 1 ? 'Friend' : 'Pending');
						}
						
						self.$friends.append($user);
					});
					
					if ($input.data('search-after')) {
						$input.trigger('watcher');
					}
				}).fail(function() {
					$input.removeClass('searching');
				});
			});
			
			this.$el.find('.friend-list > li .action-delete').click(function() {
				if ($(this).hasClass('loading')) {
					return false;
				}
				
				if (!$(this).hasClass('confirm')) {
					$(this).addClass('confirm');
					
					if ($(this).data('confirm')) {
						clearTimeout($(this).data('confirm'));
					}
					
					$(this).data('confirm', setTimeout(function() {
						$(this).removeClass('confirm');
					}.bind(this), 2000));
					
					return false;
				}
				
				$(this).addClass('loading').removeClass('confirm');
				
				$.ajax({
					url: $(this).attr('href'),
					success: function(payload) {
						if (payload.status === 2) {
							$(this).parents('li').eq(0).remove();
						} else {
							$(this).removeClass('loading');
						}
					}.bind(this),
					error: function() {
						$(this).removeClass('loading');
					}.bind(this)
				});
				
				return false;
			});
		};
		
		//billing
		this.billing = function() {
			this.$el.find('form .change-plan').click(function() {
				if (self.$el.find('.plan-select').hasClass('selecting')) {
					var $checked = self.$el.find('.plan-select input:checked');
					var $li = $checked.parents('li').eq(0);
					
					if ($li.hasClass('selected')) {
						self.$el.find('.plan-select').removeClass('selecting')
						.children(':not(.selected)').slideUp(300);
						
						$(this).text('Change plan');
					} else {
						app.page.get($checked.attr('data-url'), false);
					}
					return false;
				}
				
				self.$el.find('.plan-select').addClass('selecting')
				.children().slideDown(300);
				
				$(this).text('Select');
				
				return false;
			});
			
			this.$el.find('.payment-methods li .action-delete').click(function() {
				if ($(this).hasClass('loading')) {
					return false;
				}
				
				if (!$(this).hasClass('confirm')) {
					$(this).addClass('confirm');
					
					if ($(this).data('confirm')) {
						clearTimeout($(this).data('confirm'));
					}
					
					$(this).data('confirm', setTimeout(function() {
						$(this).removeClass('confirm');
					}.bind(this), 2000));
					
					return false;
				}
				
				$(this).addClass('loading').removeClass('confirm');
				
				$.ajax({
					url: $(this).attr('href'),
					success: function(payload) {
						if (payload.status === 2) {
							$(this).parents('li').eq(0).remove();
						} else {
							$(this).removeClass('loading');
						}
					}.bind(this),
					error: function() {
						$(this).removeClass('loading');
					}.bind(this)
				});
				
				return false;
			});
		};
		
		this.teams = function() {
			this.$el.find('.items-list li .action-delete').click(function() {
				if ($(this).hasClass('loading')) {
					return false;
				}
				
				if (!$(this).hasClass('confirm')) {
					$(this).addClass('confirm');
					
					if ($(this).data('confirm')) {
						clearTimeout($(this).data('confirm'));
					}
					
					$(this).data('confirm', setTimeout(function() {
						$(this).removeClass('confirm');
					}.bind(this), 2000));
					
					return false;
				}
				
				$(this).addClass('loading').removeClass('confirm');
				
				$.ajax({
					url: $(this).attr('href'),
					success: function(payload) {
						if (payload.status === 2) {
							$(this).parents('li').eq(0).remove();
						} else {
							$(this).removeClass('loading');
						}
					}.bind(this),
					error: function() {
						$(this).removeClass('loading');
					}.bind(this)
				});
				
				return false;
			});
		};
		
		this.team = function() {
			var leaveTimeout = null;
			
			this.$el.find('form.form-leave .submit').click(function() {
				if (!$(this).hasClass('confirm')) {
					$(this).addClass('confirm');
					
					$(this).text('Are you sure?');
					
					leaveTimeout = setTimeout(() => {
						leaveTimeout = null;
						
						$(this).removeClass('confirm').text($(this).attr('data-default'));
					}, 1500);
					
					return false;
				}
				
				app.page.get($(this), false);
				
				return false;
			});
			
			this.$el.find('.items-list li .action-delete').click(function() {
				if ($(this).hasClass('loading')) {
					return false;
				}
				
				if (!$(this).hasClass('confirm')) {
					$(this).addClass('confirm');
					
					if ($(this).data('confirm')) {
						clearTimeout($(this).data('confirm'));
					}
					
					$(this).data('confirm', setTimeout(function() {
						$(this).removeClass('confirm');
					}.bind(this), 2000));
					
					return false;
				}
				
				$(this).addClass('loading').removeClass('confirm');
				
				$.ajax({
					url: $(this).attr('href'),
					success: function(payload) {
						if (payload.status === 2) {
							$(this).parents('li').eq(0).remove();
						} else {
							$(this).removeClass('loading');
						}
					}.bind(this),
					error: function() {
						$(this).removeClass('loading');
					}.bind(this)
				});
				
				return false;
			});
		};
		
		this.billingAdd = function(options) {
			this.options = options || {};
			var currencies = options.currencies || [];
			
			this.$el.find('.change-currency').click(function() {
				$(this).hide();
				
				self.$el.find('.currency-select').show();
				
				return false;
			});
			
			this.$el.find(':input[name="card_number"]').on('maskinput input change', function(e) {
				var val = $(this).val().replace(/\D/g, '');
				var card = self.cardFromNumber(val);
				
				$(this).attr('data-card', card ? card.type : '');
				var mask = card && card.mask ? card.mask : '9999 9999 9999 9999';
				
				if (mask != $(this).attr('data-mask')) {
					$(this).inputmask(mask).attr('data-mask', mask)
				}
			}).inputmask('9999 9999 9999 9999').attr('data-mask', '9999 9999 9999 9999');
			
			this.$el.find(':input[name="card_expiration"]').inputmask('99/9999', {
				placeholder: 'MM/YYYY'
			});
			this.$el.find(':input[name="card_cvv"]').inputmask('999[9]');
			
			this.$el.find(':input[name="currency_id"]').change(function() {
				var val = parseInt($(this).val());
				var currency = currencies.filter(function(currency) {
					return currency.id === val;
				})[0];
				
				if (currency) {
					self.$el.find('span.currency').text(currency.symbol);
				}
			}).change();
			
			this.$el.find(':input[name="payment_type"]').change(function() {
				if (this.checked && this.value === 'paypal') {
					self.loadPaypal();
				}
			}).change();
		};
		
		this.paypalSetup = false;
		
		this.loadPaypal = function() {
			if (this.paypalSetup) {
				return;
			}
			
			var self = this;
			
			this.paypalSetup = true;
			
			var $paypalContainer = this.$el.find('.paypal-container');
			if (!$paypalContainer.length) {
				return;
			}
			
			var $spinner = $('<div class="spinner active"></div>');
			$paypalContainer.append($spinner);
			
			window.require([
				'https://www.paypalobjects.com/api/checkout.js',
				'https://js.braintreegateway.com/web/3.17.0/js/client.min.js',
				'https://js.braintreegateway.com/web/3.17.0/js/paypal-checkout.min.js'
			], function(paypal, braintree, braintreePaypal) {
				$.ajax({
					url: '/settings/billing-token',
				}).then(res => {
					self.options.braintreeToken = res.braintreeToken;
					
					self.createBraintree(braintree, braintreePaypal, self.options.braintreeToken, self.options.paypal, $paypalContainer);
				}).catch(e => {
					
				});
			});
		};
		
		this.createBraintree = function(braintree, braintreePaypal, token, paypalOptions, $paypalContainer) {
			// Create a client.
			braintree.create({
				authorization: token,
			}, function(err, clientInstance) {
				if (err) {
					console.error('Error creating client:', err);
					return;
				}

				// Create a PayPal Checkout component.
				braintreePaypal.create({
					client: clientInstance
				}, function(paypalCheckoutErr, paypalCheckoutInstance) {

					// Stop if there was a problem creating PayPal Checkout.
					// This could happen if there was a network error or if it's incorrectly
					// configured.
					if (paypalCheckoutErr) {
						console.error('Error creating PayPal Checkout:', paypalCheckoutErr);
						return;
					}

					// Set up PayPal with the checkout.js library
					paypal.Button.render({
						env: paypalOptions.env,
						style: {
							size: 'medium',
							color: 'blue',
							shape: 'rect',
						},
						payment: function() {
							return paypalCheckoutInstance.createPayment({
								flow: 'vault',
								billingAgreementDescription: 'CodeTasty plan subscription',
								enableShippingAddress: false,
								shippingAddressEditable: false,
							});
						},
						onAuthorize: function(data, actions) {
							return paypalCheckoutInstance.tokenizePayment(data)
							.then(function(payload) {
								$paypalContainer.find('button').show();
								$paypalContainer.find('.paypal-button-container,.paypal-button').hide();
								
								$paypalContainer.parents('form')
								.find('[name="payment_method_nonce"]').val(payload.nonce);
							});
						},
						onCancel: function(data) {
							
						},
						onError: function(err) {
							
						}
					}, $paypalContainer[0]).then(function() {
						$paypalContainer.find('.spinner').remove();
					});

				});

			});
		};
		
		this.cards = [{
			type: 'visaelectron',
			patterns: [4026, 417500, 4405, 4508, 4844, 4913, 4917],
			length: [16],
			cvcLength: [3],
		}, {
			type: 'maestro',
			patterns: [5018, 502, 503, 56, 58, 639, 6220, 67],
			length: [12, 13, 14, 15, 16, 17, 18, 19],
			cvcLength: [3],
		}, {
			type: 'visa',
			patterns: [4],
			length: [13, 16],
			cvcLength: [3],
		}, {
			type: 'mastercard',
			patterns: [51, 52, 53, 54, 55, 22, 23, 24, 25, 26, 27],
			length: [16],
			cvcLength: [3],
		}, {
			type: 'amex',
			patterns: [34, 37],
			mask: '9999 999999 99999',
			length: [15],
			cvcLength: [3, 4],
		}, {
			type: 'discover',
			patterns: [60, 64, 65, 622],
			length: [16],
			cvcLength: [3],
		}];
		
		this.cardFromNumber = function(num) {
			var card, p, pattern, _i, _j, _len, _len1, _ref;
			var cards = this.cards;

			num = (num + '').replace(/\D/g, '');
			for (_i = 0, _len = cards.length; _i < _len; _i++) {
				card = cards[_i];
				_ref = card.patterns;
				for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
					pattern = _ref[_j];
					p = pattern + '';
					if (num.substr(0, p.length) === p) {
						return card;
					}
				}
			}
		};
		
		this.setup();
	}
};

app.home = function() {
	this.$page = null;
	this.cubesAnimation = null;
	this.lightPosition = {
		x: 0,
		y: 0,
		z: 400
	};
	this.cubes = [];
	this.playTimeout = null;
	
	this.comparisionOptions = {
		desktop: {
			label: 'Desktop IDE',
			values: [1, 0, 0, 0, 1, 1]
		},
		cloud9: {
			label: 'Cloud9',
			values: [0, 1, 1, 0, 1, 0]
		}
	}
	
	this.setup = function() {
		var self = this;
		
		this.$page = $('.page.active');
		
		this.$page.find('.heading .cube').each(function() {
			var rotate = this.children[0].style.transform.replace(/rotate3d\(/, '').split(',');
			
			self.cubes.push({
				el: this,
				inner: this.children[0],
				sides: this.children[0].children,
				x: parseFloat(rotate[0]) * 90,
				y: parseFloat(rotate[1]) * 90,
				z: parseFloat(rotate[2]) * 90,
				rotateX: Math.floor(Math.random() * 100) / 1000,
				rotateY: Math.floor(Math.random() * 100) / 1000,
				rotateZ: Math.floor(Math.random() * 100) / 1000,
			})
		});
		
		this.animateCubes = this.animateCubes.bind(this);
		
		requestAnimationFrame(this.animateCubes);
		
		this.features();
		this.testimonials();
		this.comparision();
		
		this.$page.find('.heading.heading-hero').addClass('loaded');
		this.$mockup = this.$page.find('.mockup').addClass('loaded opened');
		this.playTimeout = setTimeout(function() {
			self.playTimeout = null;
			self.$mockup.find('video')[0].play();
		}, 1000);
		
		this.$page.find('.page-content').on('scroll', function() {
			let top = self.$mockup[0].getBoundingClientRect().top;
			
			if (top < -50) {
				if (self.$mockup.hasClass('opened')) {
					self.$mockup.removeClass('opened');
					self.$mockup.find('video')[0].pause();
					
					if (self.playTimeout) {
						clearTimeout(self.playTimeout);
						self.playTimeout = null;
					}
				}
			} else {
				if (!self.$mockup.hasClass('opened')) {
					self.$mockup.addClass('opened');
					
					self.playTimeout = setTimeout(function() {
						self.playTimeout = null;
						self.$mockup.find('video')[0].play();
					}, 1000);
				}
			}
		});
		
		$(document).on('pageDestroy.home', function() {
			self.destroy();
		});
		
		$(document).on('pageReady.home', () => {
			setTimeout(() => {
				this.slider.reload();
			}, 500);
		});
	};
	
	this.animateCubes = function() {
		requestAnimationFrame(this.animateCubes);
		
		var i, cube, j, side;
		
		for (i = 0; i < this.cubes.length; i++) {
			cube = this.cubes[i];
			cube.x += cube.rotateX;
			cube.y += cube.rotateY;
			cube.z += cube.rotateZ;
			
			if (Math.abs(cube.x) > 360) {
				cube.x += cube.x > 0 ? -360 : 360;
			}
			
			if (Math.abs(cube.y) > 360) {
				cube.y += cube.y > 0 ? -360 : 360;
			}
			
			if (Math.abs(cube.z) > 360) {
				cube.z += cube.z > 0 ? -360 : 360;
			}
			
			cube.inner.style.transform = 'rotateX(' + cube.x + 'deg) rotateY(' + cube.y + 'deg) rotateZ(' + cube.z + 'deg)';
			
			for (j = 0; j < cube.sides.length; j++) {
				side = cube.sides[j];
				
				var vertices = Vect3.computeVertexData(side);
				var faceCenter = Vect3.divs(Vect3.sub(vertices.c, vertices.a), 2);
				var faceNormal = Vect3.normalize(Vect3.cross(Vect3.sub(vertices.b, vertices.a), Vect3.sub(vertices.c, vertices.a)));
				var direction = Vect3.normalize(Vect3.sub(this.lightPosition, faceCenter));
				var amount = 0.75 - (Math.max(0, Vect3.dot(faceNormal, direction)).toFixed(3) / 4 * 3);
				
				side.style.backgroundImage = "linear-gradient(rgba(0,0,0," + amount + "), rgba(0,0,0," + amount + "))";
			}
		}
	};
	
	this.features = function() {
		var self = this;
		
		this.$page.find('.features .list li').each(function() {
			self.$page.find('.features .features-helper').append('<li></li>');
		});
		
		this.$page.find('.features .features-helper li').eq(0)
		.addClass('active');
		
		this.$page.find('.features .features-helper > li').click(function() {
			$(this).parent().children().removeClass('active');
			$(this).addClass('active');
			
			self.$page.find('.features .list li').removeClass('active')
			.eq($(this).prevAll().length).addClass('active');
		});
		
		this.$page.find('.features .arrows > div').click(function() {
			let $list = self.$page.find('.features .features-helper > li');
			let $active = $list.filter('.active');
			let isNext = this.classList.contains('next');
			
			if (isNext) {
				$active.next().length ? $active.next().click() : $list.eq(0).click();
			} else {
				$active.prev().length ? $active.prev().click() : $list.eq(-1).click();
			}
		});
	};
	
	this.testimonials = function() {
		var self = this;
		
		this.slider = new Sly(this.$page.find('.testimonials .scroll')[0], {
			horizontal: 1,
			itemNav: 'forceCentered',
			smart: 1,
			activateMiddle: true,
			mouseDragging: 1,
			touchDragging: 1,
			releaseSwing: 1,
			// startAt: 0,
			scrollBy: 1,
			pagesBar: this.$page.find('.testimonials .helper')[0],
			prev: this.$page.find('.testimonials .prev')[0],
			next: this.$page.find('.testimonials .next')[0],
			activatePageOn: 'click',
			speed: 600,
			elasticBounds: 1,
			easing: 'easeOutExpo',
		});
		
		this.slider.init();
	};
	
	this.comparision = function() {
		var self = this;
		
		for (let name in this.comparisionOptions) {
			this.$page.find('.comparision select')
			.append('<option value="' + name + '">' + this.comparisionOptions[name].label + '</option>');
		}
		
		this.$page.find('.comparision select').change(function() {
			let option = self.comparisionOptions[this.value];
			
			let $list = self.$page.find('.comparision .table ul li');
			
			option.values.forEach((value, index) => {
				$list.eq(index+1).find('.col').eq(0).removeClass('yes no')
				.addClass(value ? 'yes' : 'no');
			});
		}).change();
	};
	
	this.destroy = function() {
		$(document).off('pageDestroy.home');
		$(document).off('pageReady.home');
		this.$page = null;
		
		cancelAnimationFrame(this.cubesAnimation);
		this.cubesAnimation = null;
		this.cubes = [];
		
		this.slider.destroy();
		this.slider = null;
	};
	
	this.setup();
};

$(function() {
	app.layout.init();
	
	if (navigator.userAgent.toLowerCase().indexOf("chrome") > -1) {
		[[''], [
			"%c " + (String.fromCharCode(55357, 56424, 8205, 55357, 56507)) + " %c Made with ♥ by CodeTasty %c https://codetasty.com/ ",
			"color: #b0976d; background: #fff; padding: 5px;",
			"color: #fff; background: #03bad8; padding: 5px;",
			"color: #fff; background: #695b9c; padding: 5px;",
		], ['']].forEach(log => {
			console.log(...log);
		});
	} else {
		console.log("Made with love ♥ CodeTasty - https://codetasty.com/");
	}
});