<commit_before>'use strict';

function repo_drawlogic(){
    canvas_buffer.save();
    canvas_buffer.translate(
      canvas_properties['width-half'],
      canvas_properties['height-half']
    );

    // Draw corridor over background.
    canvas_setproperties({
      'properties': {
        'fillStyle': '#000',
      },
    });
    canvas_buffer.fillRect(
      -canvas_properties['width-half'],
      -half_corridor_height,
      canvas_properties['width'],
      core_storage_data['corridor-height']
    );

    // Draw player body.
    canvas_setproperties({
      'properties': {
        'fillStyle': core_storage_data['color-positive'],
      },
    });
    canvas_buffer.fillRect(
      0,
      -entity_entities['player']['y'] - 25,
      25,
      50
    );

    // Draw jetpack.
    canvas_setproperties({
      'properties': {
        'fillStyle': '#aaa',
      },
    });
    canvas_buffer.fillRect(
      -25,
      -entity_entities['player']['y'] - 15,
      25,
      20
    );

    // Draw activated jetpack fire.
    if(core_mode === 1
      && core_keys[core_storage_data['jump']]['state']){
        canvas_setproperties({
          'properties': {
            'fillStyle': '#f00',
          },
        });
        canvas_buffer.fillRect(
          -22,
          -entity_entities['player']['y'] + 5,
          18,
          10
        );
    }

    // Draw obstacles.
    entity_group_modify({
      'groups': [
        'obstacle',
      ],
      'todo': function(entity){
          canvas_setproperties({
            'properties': {
              'fillStyle': '#555',
            },
          });
          canvas_buffer.fillRect(
            entity_entities[entity]['x'],
            entity_entities[entity]['y'],
            entity_entities[entity]['width'] * 2,
            entity_entities[entity]['height'] * 2
          );
          canvas_setproperties({
            'properties': {
              'fillStyle': '#fff',
            },
          });
          canvas_buffer.fillText(
            entity_entities[entity]['counter'],
            entity_entities[entity]['x'],
            entity_entities[entity]['y']
          );
      },
    });

    // Draw smoke trails behind the player.
    canvas_setproperties({
      'properties': {
        'fillStyle': '#777',
      },
    });
    entity_group_modify({
      'groups': [
        'smoke',
      ],
      'todo': function(entity){
          canvas_buffer.fillRect(
            entity_entities[entity]['x'],
            -entity_entities[entity]['y'],
            10,
            10
          );
      },
    });

    canvas_buffer.restore();

    // If game is over, display game over messages.
    if(core_mode === 0){
        canvas_setproperties({
          'properties': {
            'fillStyle': '#f00',
          },
        });
        canvas_buffer.fillText(
          'You crashed... ☹',
          0,
          125
        );
    }
}

function repo_logic(){
    if(core_mode === 0){
        return;
    }

    // Check if player is outside of game boundaries.
    if(entity_entities['player']['y'] + 25 > half_corridor_height
      || entity_entities['player']['y'] - 25 < -half_corridor_height){
        core_mode = 0;
        return;
    }

    frame_counter += 1;

    // If new obstacle should be added this frame, add one.
    if(frame_counter % frames_per_obstacle === 0){
        const obstacle_width = core_random_integer({
          'max': 15,
        }) + 20;
        entity_create({
          'id': 'obstacle-' + obstacle_counter,
          'properties': {
            'counter': obstacle_counter++,
            'height': core_random_integer({
              'max': 15,
            }) + 20,
            'width': obstacle_width,
            'x': canvas_properties['width-half'] + obstacle_width,
            'y': core_random_integer({
              'max': core_storage_data['corridor-height'],
            }) - half_corridor_height,
          },
          'types': [
            'obstacle',
          ],
        });
    }

    // If obstacle-increase frames reached, increase obstacle frequency.
    if(core_storage_data['obstacle-frequency'] > 0
      && frames_per_obstacle > 1
      && frame_counter % core_storage_data['obstacle-increase'] === 0){
        frames_per_obstacle -= 1;
    }

    // If the player has activated jetpack, increase y speed and add smoke...
    if(core_keys[core_storage_data['jump']]['state']){
        entity_entities['player']['speed'] += core_storage_data['jetpack-power'];
        entity_create({
          'properties': {
            'y': entity_entities['player']['y'] - 10,
          },
          'types': [
            'smoke',
          ],
        });

    // ...else apply gravity.
    }else{
        entity_entities['player']['speed'] -= core_storage_data['gravity'];
    }

    entity_entities['player']['y'] += entity_entities['player']['speed'];

    entity_group_modify({
      'groups': [
        'obstacle',
      ],
      'todo': function(entity){
          // Move obstacles left at speed.
          entity_entities[entity]['x'] -= core_storage_data['speed'];

          // Check for player collision with obstacle.
          if(entity_entities[entity]['x'] > -entity_entities[entity]['width'] * 2
            && entity_entities[entity]['x'] < entity_entities[entity]['width']
            && entity_entities[entity]['y'] > -entity_entities['player']['y'] - 25 - entity_entities[entity]['height'] * 2
            && entity_entities[entity]['y'] < -entity_entities['player']['y'] + 25){
              core_mode = 0;
          }

          // Delete obstacles that are past left side of screen.
          if(entity_entities[entity]['x'] < -canvas_properties['width-half'] - 70){
              entity_remove({
                'entities': [
                  entity,
                ],
              });
          }
      },
    });

    // Delete smoke trails past left side of screen.
    entity_group_modify({
      'groups': [
        'smoke',
      ],
      'todo': function(entity){
          entity_entities[entity]['x'] -= core_storage_data['speed'];

          if(entity_entities[entity]['x'] < -canvas_properties['width-half']){
              entity_remove({
                'entities': [
                  entity,
                ],
              });
          }
      },
    });

    core_ui_update({
      'ids': {
        'score': frame_counter,
      },
    });
}

function repo_escape(){
    if(!entity_entities['player']
      && !core_menu_open){
        core_repo_reset();
    }
}

function repo_init(){
    core_repo_init({
      'events': {
        'start': {
          'onclick': core_repo_reset,
        },
      },
      'globals': {
        'frame_counter': 0,
        'frames_per_obstacle': 0,
        'half_corridor_height': 0,
        'obstacle_counter': 0,
        'smoke': [],
      },
      'info': '<select id=level><option value=0>Cave Corridor</option></select><input id=start type=button value="Start New Flight">',
      'menu': true,
      'reset': canvas_setmode,
      'storage': {
        'corridor-height': 500,
        'gravity': 1,
        'jetpack-power': 2,
        'level': 0,
        'obstacle-frequency': 23,
        'obstacle-increase': 115,
        'speed': 10,
      },
      'storage-menu': '

<input id=corridor-height>Corridor Height'
        + '
<input id=gravity>Gravity'
        + '
<input id=jetpack-power>Jetpack Power'
        + '
<input id=speed>Jetpack Speed'
        + '
<input id=obstacle-frequency>Obstacle Frequency'
        + '
<input id=obstacle-increase>Obstacle Increase
',
      'title': 'Jetpack-2D.htm',
      'ui': 'Score: ',
    });
    entity_set({
      'type': 'obstacle',
    });
    entity_set({
      'properties': {
        'x': -20,
      },
      'type': 'smoke',
    });
    entity_set({
      'properties': {
        'speed': 0,
      },
      'type': 'player',
    });
    canvas_init();

    canvas_properties['clearColor'] = '#333';
}
<commit_msg>added number type to settings inputs, removed unnecessary comments<commit_after>'use strict';

function repo_drawlogic(){
    canvas_buffer.save();
    canvas_buffer.translate(
      canvas_properties['width-half'],
      canvas_properties['height-half']
    );

    canvas_setproperties({
      'properties': {
        'fillStyle': '#000',
      },
    });
    canvas_buffer.fillRect(
      -canvas_properties['width-half'],
      -half_corridor_height,
      canvas_properties['width'],
      core_storage_data['corridor-height']
    );

    canvas_setproperties({
      'properties': {
        'fillStyle': core_storage_data['color-positive'],
      },
    });
    canvas_buffer.fillRect(
      0,
      -entity_entities['player']['y'] - 25,
      25,
      50
    );

    canvas_setproperties({
      'properties': {
        'fillStyle': '#aaa',
      },
    });
    canvas_buffer.fillRect(
      -25,
      -entity_entities['player']['y'] - 15,
      25,
      20
    );

    if(core_mode === 1
      && core_keys[core_storage_data['jump']]['state']){
        canvas_setproperties({
          'properties': {
            'fillStyle': '#f00',
          },
        });
        canvas_buffer.fillRect(
          -22,
          -entity_entities['player']['y'] + 5,
          18,
          10
        );
    }

    entity_group_modify({
      'groups': [
        'obstacle',
      ],
      'todo': function(entity){
          canvas_setproperties({
            'properties': {
              'fillStyle': '#555',
            },
          });
          canvas_buffer.fillRect(
            entity_entities[entity]['x'],
            entity_entities[entity]['y'],
            entity_entities[entity]['width'] * 2,
            entity_entities[entity]['height'] * 2
          );
          canvas_setproperties({
            'properties': {
              'fillStyle': '#fff',
            },
          });
          canvas_buffer.fillText(
            entity_entities[entity]['counter'],
            entity_entities[entity]['x'],
            entity_entities[entity]['y']
          );
      },
    });

    canvas_setproperties({
      'properties': {
        'fillStyle': '#777',
      },
    });
    entity_group_modify({
      'groups': [
        'smoke',
      ],
      'todo': function(entity){
          canvas_buffer.fillRect(
            entity_entities[entity]['x'],
            -entity_entities[entity]['y'],
            10,
            10
          );
      },
    });

    canvas_buffer.restore();

    if(core_mode === 0){
        canvas_setproperties({
          'properties': {
            'fillStyle': '#f00',
          },
        });
        canvas_buffer.fillText(
          'You crashed... ☹',
          0,
          125
        );
    }
}

function repo_logic(){
    if(core_mode === 0){
        return;
    }

    if(entity_entities['player']['y'] + 25 > half_corridor_height
      || entity_entities['player']['y'] - 25 < -half_corridor_height){
        core_mode = 0;
        return;
    }

    frame_counter += 1;

    if(frame_counter % frames_per_obstacle === 0){
        const obstacle_width = core_random_integer({
          'max': 15,
        }) + 20;
        entity_create({
          'id': 'obstacle-' + obstacle_counter,
          'properties': {
            'counter': obstacle_counter++,
            'height': core_random_integer({
              'max': 15,
            }) + 20,
            'width': obstacle_width,
            'x': canvas_properties['width-half'] + obstacle_width,
            'y': core_random_integer({
              'max': core_storage_data['corridor-height'],
            }) - half_corridor_height,
          },
          'types': [
            'obstacle',
          ],
        });
    }

    if(core_storage_data['obstacle-frequency'] > 0
      && frames_per_obstacle > 1
      && frame_counter % core_storage_data['obstacle-increase'] === 0){
        frames_per_obstacle -= 1;
    }

    if(core_keys[core_storage_data['jump']]['state']){
        entity_entities['player']['speed'] += core_storage_data['jetpack-power'];
        entity_create({
          'properties': {
            'y': entity_entities['player']['y'] - 10,
          },
          'types': [
            'smoke',
          ],
        });

    }else{
        entity_entities['player']['speed'] -= core_storage_data['gravity'];
    }

    entity_entities['player']['y'] += entity_entities['player']['speed'];

    entity_group_modify({
      'groups': [
        'obstacle',
      ],
      'todo': function(entity){
          entity_entities[entity]['x'] -= core_storage_data['speed'];

          if(entity_entities[entity]['x'] > -entity_entities[entity]['width'] * 2
            && entity_entities[entity]['x'] < entity_entities[entity]['width']
            && entity_entities[entity]['y'] > -entity_entities['player']['y'] - 25 - entity_entities[entity]['height'] * 2
            && entity_entities[entity]['y'] < -entity_entities['player']['y'] + 25){
              core_mode = 0;
          }

          if(entity_entities[entity]['x'] < -canvas_properties['width-half'] - 70){
              entity_remove({
                'entities': [
                  entity,
                ],
              });
          }
      },
    });

    entity_group_modify({
      'groups': [
        'smoke',
      ],
      'todo': function(entity){
          entity_entities[entity]['x'] -= core_storage_data['speed'];

          if(entity_entities[entity]['x'] < -canvas_properties['width-half']){
              entity_remove({
                'entities': [
                  entity,
                ],
              });
          }
      },
    });

    core_ui_update({
      'ids': {
        'score': frame_counter,
      },
    });
}

function repo_escape(){
    if(!entity_entities['player']
      && !core_menu_open){
        core_repo_reset();
    }
}

function repo_init(){
    core_repo_init({
      'events': {
        'start': {
          'onclick': core_repo_reset,
        },
      },
      'globals': {
        'frame_counter': 0,
        'frames_per_obstacle': 0,
        'half_corridor_height': 0,
        'obstacle_counter': 0,
        'smoke': [],
      },
      'info': '<select id=level><option value=0>Cave Corridor</option></select><input id=start type=button value="Start New Flight">',
      'menu': true,
      'reset': canvas_setmode,
      'storage': {
        'corridor-height': 500,
        'gravity': 1,
        'jetpack-power': 2,
        'level': 0,
        'obstacle-frequency': 23,
        'obstacle-increase': 115,
        'speed': 10,
      },
      'storage-menu': '

<input id=corridor-height min=1 type=number>Corridor Height'
        + '
<input id=gravity type=number>Gravity'
        + '
<input id=jetpack-power type=number>Jetpack Power'
        + '
<input id=speed type=number>Jetpack Speed'
        + '
<input id=obstacle-frequency min=1 type=number>Obstacle Frequency'
        + '
<input id=obstacle-increase min=1 type=number>Obstacle Increase
',
      'title': 'Jetpack-2D.htm',
      'ui': 'Score: ',
    });
    entity_set({
      'type': 'obstacle',
    });
    entity_set({
      'properties': {
        'x': -20,
      },
      'type': 'smoke',
    });
    entity_set({
      'properties': {
        'speed': 0,
      },
      'type': 'player',
    });
    canvas_init();

    canvas_properties['clearColor'] = '#333';
}
<|endoftext|>


<commit_before>// import * from './scripts/example';

// import './styles/style.css';
// import './styles/style.sass';
import 'normalize.css';
import './styles/style.scss';

import webfont from 'webfontloader';
import Analytics from 'analytics'
import googleAnalytics from '@analytics/google-analytics'
import 'focus-visible';

/* ---------- Webfont (asyncronously load fonts) ---------- */

webfont.load({
	google: {
		families: ['Montserrat:400,400i,600,700,800,800i&display=swap']
	}
});

/* ---------- Google Analytics ---------- */

const analytics = Analytics({
  app: 'hackupc-landing',
  plugins: [
    googleAnalytics({
			trackingId: 'UA-69542332-1',
			anonymizeIp: true,
    })
  ]
})

document.querySelectorAll('[data-ga-apply-button]').forEach((elem) => {
	elem.addEventListener('click', (event) => {
		const data = event.target.dataset;

		analytics.track('applyed', {
			buttonLocation: data.location,
		});
	});
})

document.querySelectorAll('[data-ga-nav-item]').forEach((elem) => {
	elem.addEventListener('click', (event) => {
		analytics.track('navbar-clicked', {
			buttonLocation: event.target.href,
		});
	});
})

// window.dataLayer = window.dataLayer || [];
// function gtag(){
// 	dataLayer.push(arguments);
// }
// gtag('js', new Date());
// gtag('config', 'UA-69542332-1');

/* ---------- Lax.js ---------- */
// import lax from 'lax.js'

// window.onload = function() {
// 	lax.setup() // init

// 	const updateLax = () => {
// 		lax.update(window.scrollY)
// 		window.requestAnimationFrame(updateLax)
// 	}

// 	window.requestAnimationFrame(updateLax)
// }

/* ---------- Real vh ---------- */
// https://css-tricks.com/the-trick-to-viewport-units-on-mobile/

// We listen to the resize event
// window.addEventListener('resize', () => {
//   // We execute the same script as before
//   let vh = window.innerHeight * 0.01;
//   document.documentElement.style.setProperty('--vh', `${vh}px`);
// });

/* ---------- Update hero perspective ---------- */
const heroElem = document.getElementsByClassName('hero-3d-space')[0];
const applyElem = document.getElementsByClassName('apply-button')[0];
let mouseX = 0.5;
let mouseY = 0.5;

let alpha = 0.5;
let beta = 0.5;
let gamma = 0.5;

let alphaOrig = 0.5;
let betaOrig = 0.5;
let gammaOrig = 0.5;

let perspectiveX = window.innerWidth/2;
let perspectiveY = window.innerHeight * 0.125;

window.addEventListener('scroll', updateHeroPerspective, {passive: true});
window.addEventListener('mousemove', updateHeroPerspective);
window.addEventListener('resize', updateHeroPerspective);
updateHeroPerspective();
let heroWaitingRefresh = false;

// iOS 13+ device orientation requestPermission
if (window.DeviceOrientationEvent && typeof window.DeviceOrientationEvent.requestPermission === 'function') {
	heroElem.addEventListener('click', (event) => {
		if(event.currentTarget !== applyElem){
			window.DeviceOrientationEvent.requestPermission()
			.then(permissionState => {
				if (permissionState === 'granted') {
					window.addEventListener('deviceorientation', updateHeroPerspective, false);
				}
			}).catch(console.error);
		}
	});
} else {
	window.addEventListener('deviceorientation', updateHeroPerspective, false);
}

document.addEventListener('visibilitychange', () => {
	alphaOrig = 0.5;
	betaOrig  = 0.5;
	gammaOrig = 0.5;
});

function updateHeroPerspective(event) {
	if(window.pageYOffset <= window.innerHeight && !heroWaitingRefresh) {
		if(event){
			// alpha [0,360]  -->[0,1]
			// beta  [-180,180]-->[0,1]
			// gamma [-90,90] -->[0,1]

			let newMouseX = mod(event.clientX/window.innerWidth);
			let newMouseY = mod(event.clientY/window.innerHeight);
			let newAlpha  = mod(event.alpha/360 + 0.5);
			let newBeta   = mod((event.beta + 180)/360 - 0.125);
			let newGamma  = mod((event.gamma + 90)/180);

			mouseX = smooth(newMouseX, mouseX);
			mouseY = smooth(newMouseY, mouseY);
			alpha  = smooth(newAlpha,  alpha);
			beta   = smooth(newBeta,   beta);
			gamma  = smooth(newGamma,  gamma);

			if(!isNaN(newAlpha) && alphaOrig === 0.5){ alpha = newAlpha; alphaOrig = newAlpha; }
			if(!isNaN(newBeta ) && betaOrig  === 0.5){ beta  = newBeta;  betaOrig  = newBeta;  }
			if(!isNaN(newGamma) && gammaOrig === 0.5){ gamma = newGamma; gammaOrig = newGamma; }
		}

		heroWaitingRefresh = true;
		window.requestAnimationFrame(() => {
			perspectiveX = 0
			+ window.innerWidth/2
			+ 250 * magnet((mod(alpha - alphaOrig + 0.5) - 0.5) * 2)
			+ 250 * magnet((mod(gamma - gammaOrig + 0.5) - 0.5) * 2)
			+ -window.innerWidth/40 * magnet((mouseX - 0.5) * 2)

			let height = Math.min(900, window.innerHeight);
			perspectiveY = 0
			+ window.pageYOffset
			+ height * 0.125
			+ 500 * magnet((mod(beta - betaOrig + 0.5) - 0.5) * 2)
			+ -height/40 * magnet((mouseY - 0.6667) * 2)

			heroElem.style.perspectiveOrigin = `${perspectiveX}px ${perspectiveY}px`;
			heroWaitingRefresh = false;
		});
	}
}

function mod(n,m=1){
	return ((n % m) + m) % m;
}
function magnet(x=0.5) {
	return Math.sin(Math.PI/2*x);
}

function smooth(final, initial=0) {
	if(isNaN(final)) return initial;

	let dif = final - initial;
	let s = dif >= 0 ? +1 : -1;
	return (initial + s * dif**2);
}
// function smooth(final, initial=0) {
// 	let dif = final - initial;
// 	if(dif < 0.01 && dif > -0.01) return initial;
// 	else return (initial + dif);
// }
// function smooth(final, initial=0) {
// 	let dif = final - initial;
// 	dif = Math.min(dif, 0.1)
// 	dif = Math.max(dif, -0.1)
// 	return (initial + dif);
// }
// function smooth(final, initial=0) {
//   return (initial + final)/2;
// }
// function smooth(final, initial=0) {
//   return final;
// }
/* ---------- Animations ---------- */

// Animation Lamp
const lampOnElem = document.getElementById('lamp-on');
let lampIsOn = 1;
lampOnElem.addEventListener('mousedown', event => {
	lampIsOn = !lampIsOn;
	lampOnElem.style.opacity = lampIsOn + 0;
});

// Animation countdown
const countdownNumElem = {
	day:    document.querySelector('.countdown__cell[data-unit="day"] .countdown__number'),
	hour:   document.querySelector('.countdown__cell[data-unit="hour"] .countdown__number'),
	minute: document.querySelector('.countdown__cell[data-unit="minute"] .countdown__number'),
	second: document.querySelector('.countdown__cell[data-unit="second"] .countdown__number'),
}
const countdownPluralElem = {
	day:    document.querySelector('.countdown__cell[data-unit="day"] .countdown__label-plural'),
	hour:   document.querySelector('.countdown__cell[data-unit="hour"] .countdown__label-plural'),
	minute: document.querySelector('.countdown__cell[data-unit="minute"] .countdown__label-plural'),
	second: document.querySelector('.countdown__cell[data-unit="second"] .countdown__label-plural'),
}

const countdownDate = new Date(2020,9,11,19,0,0); // Notice: January is 0 and December 11
let secondsLeft = Math.floor((countdownDate - new Date()) / 1000);

const countdownInterval = setInterval(updateCountdown, 1000);
updateCountdown();

function updateCountdown() {
	if(secondsLeft > 0){

		secondsLeft -= 1;

		countdownNumElem.day.textContent    = Math.floor(secondsLeft / 60 / 60 / 24);
		countdownNumElem.hour.textContent   = Math.floor(secondsLeft / 60 / 60) % 24;
		countdownNumElem.minute.textContent = Math.floor(secondsLeft / 60) % 60;
		countdownNumElem.second.textContent = Math.floor(secondsLeft) % 60;

		countdownPluralElem.day.style.display    = countdownNumElem.day.textContent === '1' ? 'none' : 'inline-block';
		countdownPluralElem.hour.style.display   = countdownNumElem.hour.textContent === '1' ? 'none' : 'inline-block';
		countdownPluralElem.minute.style.display = countdownNumElem.minute.textContent === '1' ? 'none' : 'inline-block';
		countdownPluralElem.second.style.display = countdownNumElem.second.textContent === '1' ? 'none' : 'inline-block';

	}else{
		clearInterval(countdownInterval);
	}
}

// Animation rocket

const rocketElem = document.querySelector('.object--rocket');
let rocketOn = 1;
rocketElem.addEventListener('click', event => {
	if(rocketElem.classList.contains('stop-animation')){
		rocketElem.classList.remove('stop-animation');
		setTimeout(() => {
			rocketElem.classList.add('stop-animation');
		}, (4+3+1+1) * 1000);
	}
});

// Animation duck

const duckElem = document.getElementsByClassName('object--rubber-duck')[0];
const duckSilhouetteElem = document.getElementsByClassName('wanted__duck-silhouette--missing')[0];
const duckSignElem = document.getElementsByClassName('wanted__sign')[0];
const duckListElem = document.getElementsByClassName('wanted__list')[0];
duckElem.addEventListener('click', (event) => {
	duckElem.classList.add('duck-cliked');
	duckElem.style.pointerEvents = 'none';
	setTimeout(() => {
		duckSilhouetteElem.classList.remove('wanted__duck-silhouette--missing')
		duckSilhouetteElem.classList.add('wanted__duck-silhouette--found')
		duckListElem.style.pointerEvents = 'none';
		setTimeout(() => {
			duckSignElem.textContent = 'FOUND';
		}, 200);
	}, 1000);
});

// Plot animation

const plotLinesSteps = 5;
const plotWidth = 200;
const plotHandle = Math.floor(plotWidth/plotLinesSteps/3);

const plotLines = [
	document.getElementsByClassName('plot__plot-line--1')[0],
	document.getElementsByClassName('plot__plot-line--2')[0],
	document.getElementsByClassName('plot__plot-line--3')[0],
	document.getElementsByClassName('plot__plot-line--4')[0],
];
const barContents = [
	document.getElementsByClassName('plot__bar-content--1')[0],
	document.getElementsByClassName('plot__bar-content--2')[0],
	document.getElementsByClassName('plot__bar-content--3')[0],
	document.getElementsByClassName('plot__bar-content--4')[0],
];

for (const i in plotLines) {
	animatePlotLine(i);
}

function animatePlotLine(i){
	plotLines[i].style.d = `path("${generatePattern()}")`;
	barContents[i].style.transform = `scaleY(${Math.random()})`;

	setTimeout(() => {
		animatePlotLine(i);
	}, Math.random()*5000+5500);
}

function generatePattern(){
	// If you want to understand whow the curve is build read this article:
	// https://css-tricks.com/svg-path-syntax-illustrated-guide/

	let pattern = `M${plotWidth},${Math.floor(Math.random()*100.99)}`;

	for (let i = plotLinesSteps-1; i >= 0 ; i--) {
		let x = Math.floor(plotWidth/plotLinesSteps*i);
		let y = Math.floor(Math.random()*100.99);

		pattern += ` S${x+plotHandle},${y} ${x},${y}`;
	}
	return pattern;
}

// FAQ

const faqQuestionTitleElems = document.querySelectorAll('.faq__question-title');

for (const faqQuestionTitleElem of faqQuestionTitleElems) {
	faqQuestionTitleElem.addEventListener('click', function(event) {
		const faqQuestionElem = this.closest('.faq__question');
		const faqAnswerElem = faqQuestionElem.querySelector('.faq__question-answer');
		// const faqLinksElems = faqQuestionElem.querySelectorAll('a');

    if (faqQuestionTitleElem.getAttribute('aria-expanded') === 'true') {
			faqQuestionElem.classList.remove('faq__question--expanded');
			faqQuestionTitleElem.setAttribute('aria-expanded', 'false');
			faqAnswerElem.setAttribute('aria-hidden', 'true');
			faqAnswerElem.style.maxHeight = null;
    } else {
			faqQuestionElem.classList.add('faq__question--expanded');
			faqAnswerElem.setAttribute('aria-hidden', 'false');
			faqQuestionTitleElem.setAttribute('aria-expanded', 'true');
			faqAnswerElem.style.maxHeight = `${faqAnswerElem.scrollHeight}px`;
    }
	});
}
<commit_msg>Use default GA attributes<commit_after>// import * from './scripts/example';

// import './styles/style.css';
// import './styles/style.sass';
import 'normalize.css';
import './styles/style.scss';

import webfont from 'webfontloader';
import Analytics from 'analytics'
import googleAnalytics from '@analytics/google-analytics'
import 'focus-visible';

/* ---------- Webfont (asyncronously load fonts) ---------- */

webfont.load({
	google: {
		families: ['Montserrat:400,400i,600,700,800,800i&display=swap']
	}
});

/* ---------- Google Analytics ---------- */

const analytics = Analytics({
  app: 'hackupc-landing',
  plugins: [
    googleAnalytics({
			trackingId: 'UA-69542332-1',
			anonymizeIp: true,
    })
  ]
})

document.querySelectorAll('[data-ga-apply-button]').forEach((elem) => {
	elem.addEventListener('click', (event) => {
		const data = event.target.dataset;

		analytics.track('applyed', {
			category: 'Apply',
			label: 'Apply button clicked',
			value: data.location,
		});
	});
})

document.querySelectorAll('[data-ga-nav-item]').forEach((elem) => {
	elem.addEventListener('click', (event) => {
		analytics.track('navbar-clicked', {
			category: 'Navigation',
			label: 'Navbar link clicked',
			value: event.target.href,
		});
	});
})

// window.dataLayer = window.dataLayer || [];
// function gtag(){
// 	dataLayer.push(arguments);
// }
// gtag('js', new Date());
// gtag('config', 'UA-69542332-1');

/* ---------- Lax.js ---------- */
// import lax from 'lax.js'

// window.onload = function() {
// 	lax.setup() // init

// 	const updateLax = () => {
// 		lax.update(window.scrollY)
// 		window.requestAnimationFrame(updateLax)
// 	}

// 	window.requestAnimationFrame(updateLax)
// }

/* ---------- Real vh ---------- */
// https://css-tricks.com/the-trick-to-viewport-units-on-mobile/

// We listen to the resize event
// window.addEventListener('resize', () => {
//   // We execute the same script as before
//   let vh = window.innerHeight * 0.01;
//   document.documentElement.style.setProperty('--vh', `${vh}px`);
// });

/* ---------- Update hero perspective ---------- */
const heroElem = document.getElementsByClassName('hero-3d-space')[0];
const applyElem = document.getElementsByClassName('apply-button')[0];
let mouseX = 0.5;
let mouseY = 0.5;

let alpha = 0.5;
let beta = 0.5;
let gamma = 0.5;

let alphaOrig = 0.5;
let betaOrig = 0.5;
let gammaOrig = 0.5;

let perspectiveX = window.innerWidth/2;
let perspectiveY = window.innerHeight * 0.125;

window.addEventListener('scroll', updateHeroPerspective, {passive: true});
window.addEventListener('mousemove', updateHeroPerspective);
window.addEventListener('resize', updateHeroPerspective);
updateHeroPerspective();
let heroWaitingRefresh = false;

// iOS 13+ device orientation requestPermission
if (window.DeviceOrientationEvent && typeof window.DeviceOrientationEvent.requestPermission === 'function') {
	heroElem.addEventListener('click', (event) => {
		if(event.currentTarget !== applyElem){
			window.DeviceOrientationEvent.requestPermission()
			.then(permissionState => {
				if (permissionState === 'granted') {
					window.addEventListener('deviceorientation', updateHeroPerspective, false);
				}
			}).catch(console.error);
		}
	});
} else {
	window.addEventListener('deviceorientation', updateHeroPerspective, false);
}

document.addEventListener('visibilitychange', () => {
	alphaOrig = 0.5;
	betaOrig  = 0.5;
	gammaOrig = 0.5;
});

function updateHeroPerspective(event) {
	if(window.pageYOffset <= window.innerHeight && !heroWaitingRefresh) {
		if(event){
			// alpha [0,360]  -->[0,1]
			// beta  [-180,180]-->[0,1]
			// gamma [-90,90] -->[0,1]

			let newMouseX = mod(event.clientX/window.innerWidth);
			let newMouseY = mod(event.clientY/window.innerHeight);
			let newAlpha  = mod(event.alpha/360 + 0.5);
			let newBeta   = mod((event.beta + 180)/360 - 0.125);
			let newGamma  = mod((event.gamma + 90)/180);

			mouseX = smooth(newMouseX, mouseX);
			mouseY = smooth(newMouseY, mouseY);
			alpha  = smooth(newAlpha,  alpha);
			beta   = smooth(newBeta,   beta);
			gamma  = smooth(newGamma,  gamma);

			if(!isNaN(newAlpha) && alphaOrig === 0.5){ alpha = newAlpha; alphaOrig = newAlpha; }
			if(!isNaN(newBeta ) && betaOrig  === 0.5){ beta  = newBeta;  betaOrig  = newBeta;  }
			if(!isNaN(newGamma) && gammaOrig === 0.5){ gamma = newGamma; gammaOrig = newGamma; }
		}

		heroWaitingRefresh = true;
		window.requestAnimationFrame(() => {
			perspectiveX = 0
			+ window.innerWidth/2
			+ 250 * magnet((mod(alpha - alphaOrig + 0.5) - 0.5) * 2)
			+ 250 * magnet((mod(gamma - gammaOrig + 0.5) - 0.5) * 2)
			+ -window.innerWidth/40 * magnet((mouseX - 0.5) * 2)

			let height = Math.min(900, window.innerHeight);
			perspectiveY = 0
			+ window.pageYOffset
			+ height * 0.125
			+ 500 * magnet((mod(beta - betaOrig + 0.5) - 0.5) * 2)
			+ -height/40 * magnet((mouseY - 0.6667) * 2)

			heroElem.style.perspectiveOrigin = `${perspectiveX}px ${perspectiveY}px`;
			heroWaitingRefresh = false;
		});
	}
}

function mod(n,m=1){
	return ((n % m) + m) % m;
}
function magnet(x=0.5) {
	return Math.sin(Math.PI/2*x);
}

function smooth(final, initial=0) {
	if(isNaN(final)) return initial;

	let dif = final - initial;
	let s = dif >= 0 ? +1 : -1;
	return (initial + s * dif**2);
}
// function smooth(final, initial=0) {
// 	let dif = final - initial;
// 	if(dif < 0.01 && dif > -0.01) return initial;
// 	else return (initial + dif);
// }
// function smooth(final, initial=0) {
// 	let dif = final - initial;
// 	dif = Math.min(dif, 0.1)
// 	dif = Math.max(dif, -0.1)
// 	return (initial + dif);
// }
// function smooth(final, initial=0) {
//   return (initial + final)/2;
// }
// function smooth(final, initial=0) {
//   return final;
// }
/* ---------- Animations ---------- */

// Animation Lamp
const lampOnElem = document.getElementById('lamp-on');
let lampIsOn = 1;
lampOnElem.addEventListener('mousedown', event => {
	lampIsOn = !lampIsOn;
	lampOnElem.style.opacity = lampIsOn + 0;
});

// Animation countdown
const countdownNumElem = {
	day:    document.querySelector('.countdown__cell[data-unit="day"] .countdown__number'),
	hour:   document.querySelector('.countdown__cell[data-unit="hour"] .countdown__number'),
	minute: document.querySelector('.countdown__cell[data-unit="minute"] .countdown__number'),
	second: document.querySelector('.countdown__cell[data-unit="second"] .countdown__number'),
}
const countdownPluralElem = {
	day:    document.querySelector('.countdown__cell[data-unit="day"] .countdown__label-plural'),
	hour:   document.querySelector('.countdown__cell[data-unit="hour"] .countdown__label-plural'),
	minute: document.querySelector('.countdown__cell[data-unit="minute"] .countdown__label-plural'),
	second: document.querySelector('.countdown__cell[data-unit="second"] .countdown__label-plural'),
}

const countdownDate = new Date(2020,9,11,19,0,0); // Notice: January is 0 and December 11
let secondsLeft = Math.floor((countdownDate - new Date()) / 1000);

const countdownInterval = setInterval(updateCountdown, 1000);
updateCountdown();

function updateCountdown() {
	if(secondsLeft > 0){

		secondsLeft -= 1;

		countdownNumElem.day.textContent    = Math.floor(secondsLeft / 60 / 60 / 24);
		countdownNumElem.hour.textContent   = Math.floor(secondsLeft / 60 / 60) % 24;
		countdownNumElem.minute.textContent = Math.floor(secondsLeft / 60) % 60;
		countdownNumElem.second.textContent = Math.floor(secondsLeft) % 60;

		countdownPluralElem.day.style.display    = countdownNumElem.day.textContent === '1' ? 'none' : 'inline-block';
		countdownPluralElem.hour.style.display   = countdownNumElem.hour.textContent === '1' ? 'none' : 'inline-block';
		countdownPluralElem.minute.style.display = countdownNumElem.minute.textContent === '1' ? 'none' : 'inline-block';
		countdownPluralElem.second.style.display = countdownNumElem.second.textContent === '1' ? 'none' : 'inline-block';

	}else{
		clearInterval(countdownInterval);
	}
}

// Animation rocket

const rocketElem = document.querySelector('.object--rocket');
let rocketOn = 1;
rocketElem.addEventListener('click', event => {
	if(rocketElem.classList.contains('stop-animation')){
		rocketElem.classList.remove('stop-animation');
		setTimeout(() => {
			rocketElem.classList.add('stop-animation');
		}, (4+3+1+1) * 1000);
	}
});

// Animation duck

const duckElem = document.getElementsByClassName('object--rubber-duck')[0];
const duckSilhouetteElem = document.getElementsByClassName('wanted__duck-silhouette--missing')[0];
const duckSignElem = document.getElementsByClassName('wanted__sign')[0];
const duckListElem = document.getElementsByClassName('wanted__list')[0];
duckElem.addEventListener('click', (event) => {
	duckElem.classList.add('duck-cliked');
	duckElem.style.pointerEvents = 'none';
	setTimeout(() => {
		duckSilhouetteElem.classList.remove('wanted__duck-silhouette--missing')
		duckSilhouetteElem.classList.add('wanted__duck-silhouette--found')
		duckListElem.style.pointerEvents = 'none';
		setTimeout(() => {
			duckSignElem.textContent = 'FOUND';
		}, 200);
	}, 1000);
});

// Plot animation

const plotLinesSteps = 5;
const plotWidth = 200;
const plotHandle = Math.floor(plotWidth/plotLinesSteps/3);

const plotLines = [
	document.getElementsByClassName('plot__plot-line--1')[0],
	document.getElementsByClassName('plot__plot-line--2')[0],
	document.getElementsByClassName('plot__plot-line--3')[0],
	document.getElementsByClassName('plot__plot-line--4')[0],
];
const barContents = [
	document.getElementsByClassName('plot__bar-content--1')[0],
	document.getElementsByClassName('plot__bar-content--2')[0],
	document.getElementsByClassName('plot__bar-content--3')[0],
	document.getElementsByClassName('plot__bar-content--4')[0],
];

for (const i in plotLines) {
	animatePlotLine(i);
}

function animatePlotLine(i){
	plotLines[i].style.d = `path("${generatePattern()}")`;
	barContents[i].style.transform = `scaleY(${Math.random()})`;

	setTimeout(() => {
		animatePlotLine(i);
	}, Math.random()*5000+5500);
}

function generatePattern(){
	// If you want to understand whow the curve is build read this article:
	// https://css-tricks.com/svg-path-syntax-illustrated-guide/

	let pattern = `M${plotWidth},${Math.floor(Math.random()*100.99)}`;

	for (let i = plotLinesSteps-1; i >= 0 ; i--) {
		let x = Math.floor(plotWidth/plotLinesSteps*i);
		let y = Math.floor(Math.random()*100.99);

		pattern += ` S${x+plotHandle},${y} ${x},${y}`;
	}
	return pattern;
}

// FAQ

const faqQuestionTitleElems = document.querySelectorAll('.faq__question-title');

for (const faqQuestionTitleElem of faqQuestionTitleElems) {
	faqQuestionTitleElem.addEventListener('click', function(event) {
		const faqQuestionElem = this.closest('.faq__question');
		const faqAnswerElem = faqQuestionElem.querySelector('.faq__question-answer');
		// const faqLinksElems = faqQuestionElem.querySelectorAll('a');

    if (faqQuestionTitleElem.getAttribute('aria-expanded') === 'true') {
			faqQuestionElem.classList.remove('faq__question--expanded');
			faqQuestionTitleElem.setAttribute('aria-expanded', 'false');
			faqAnswerElem.setAttribute('aria-hidden', 'true');
			faqAnswerElem.style.maxHeight = null;
    } else {
			faqQuestionElem.classList.add('faq__question--expanded');
			faqAnswerElem.setAttribute('aria-hidden', 'false');
			faqQuestionTitleElem.setAttribute('aria-expanded', 'true');
			faqAnswerElem.style.maxHeight = `${faqAnswerElem.scrollHeight}px`;
    }
	});
}
<|endoftext|>


<commit_before>import rokka, { authenticate, resetClient } from '../rokka'
import { get as getCookie, set as setCookie, del as delCookie } from '../utils/cookie'

const SESSION_COOKIE_KEY = 'rka_session'

const session = getCookie(SESSION_COOKIE_KEY)

if (session && session.auth) {
  const { auth } = session
  login(auth.organization, auth.apiKey)
}

const defaultState = {
  showSidebar: false,
  stackClone: {},
  auth: null,
  images: [],
  stacks: {},
  operations: {},
  stackOptions: null,
  alert: null
}

let internalState = defaultState

let listener = null

/**
 * Update state and notify listener.
 *
 * @param {*} partialState
 */
function updateState (partialState) {
  internalState = Object.assign({}, internalState, partialState)
  if (!listener && process.env.NODE_ENV !== 'production') {
    console.warn('No listener added to state updates.')
    return
  }
  listener(internalState)
}

/**
 * Show or hide sidebar.
 */
export function toggleSidebar () {
  updateState({ showSidebar: !internalState.showSidebar })
}

/**
 * Delete a Image
 *
 * @param {string} hash
 *
 * @return {Promise}
 */
export function deleteImage (hash) {
  return rokka.sourceimages.delete(internalState.auth.organization, hash)
    .then(() => {
      clearImages()
    })
}

/**
 * Update Images state
 */
export function updateUploadedImages (images) {
  updateState({ images: images })
}

export function clearImages () {
  updateState({ images: [] })
}

/**
 * Login sets the API key to the rokka API client.
 *
 * @param {string}   organization
 * @param {string}   apiKey
 * @param {Function} successCb    Success callback
 *
 * @returns {Promise}
 */
export function login (organization, apiKey, successCb) {
  authenticate(apiKey)

  return rokka.organizations.get(organization)
    .then(() => {
      // remove alert in case there was auth failed before.
      removeAlert()

      const done = () => {
        updateState({ auth: { organization, apiKey } })
        setCookie(SESSION_COOKIE_KEY, { auth: { organization, apiKey } })
        listOperations()
        getDefaultStackOptions()
      }

      if (!successCb) {
        return done()
      }

      successCb(done)
    })
    .catch((err) => {
      console.error(err)

      setCookie(SESSION_COOKIE_KEY, {}) // clear session on error

      if (err.statusCode === 403 || err.statusCode === 404) {
        updateState({ auth: null })
        setAlert('error', 'Authentication failed')

        return
      }
      setAlert('error', 'Error getting organizations', 10000)
    })
}

/**
 * Logout clears the store and removes the API key from rokka API client.
 * Additionally it also removes the cookie.
 */
export function logout () {
  resetClient()
  delCookie(SESSION_COOKIE_KEY)
  updateState(defaultState)
}

/**
 * List stacks of an organization and populate the global state with the result.
 *
 * @param {number} limit
 *
 * @returns {Promise}
 */
export function listStacks (limit = 999) {
  const { currentOffset = 0, items = {} } = internalState.stacks

  return rokka.stacks.list(internalState.auth.organization, limit, currentOffset)
    .then(({ body }) => {
      updateState({
        stacks: {
          currentOffset: currentOffset + limit,
          total: body.total,
          items: [...items, ...body.items]
        }
      })
    })
    .catch((err) => {
      console.error(err)
      if (err.statusCode === 403) {
        updateState({ auth: null })
        setAlert('error', 'Authentication failed')
        return
      }
      setAlert('error', 'Error when fetching stacks', 10000)
    })
}

/**
 * Resets the internal state with stacks and fetches them again.
 *
 * TODO: Slightly ugly that we have to manually override the internalState.stacks.
 *
 * @returns {Promise}
 */
export function refreshStacks () {
  internalState.stacks = {}
  return listStacks()
}

/**
 * List operations and populate the global state with the result.
 */
export function listOperations () {
  rokka.operations.list()
    .then(({ body }) => {
      updateState({
        operations: body
      })
    })
    .catch((err) => {
      console.error(err)
      if (err.statusCode === 403) {
        updateState({ auth: null })
        setAlert('error', 'Authentication failed')
        return
      }
      setAlert('error', 'Error when fetching operations', 10000)
    })
}

/**
 * Fetch default stack options and populate the global state with the result.
 */
export function getDefaultStackOptions () {
  rokka.stackoptions.get()
    .then(({ body }) => {
      updateState({
        stackOptions: body.properties
      })
    })
    .catch(err => {
      console.error(err)
      setAlert('error', 'Error fetching default stack options', 10000)
    })
}

/**
 * Create a new stack
 *
 * @param {string}      name
 * @param {Array}       operations
 * @param {Object|null} options
 *
 * @return {Promise}
 */
export function createStack (name, operations, options) {
  return rokka.stacks.create(internalState.auth.organization, name, operations, options)
}

/**
 * Delete a stack
 *
 * @param {string} name
 *
 * @return {Promise}
 */
export function deleteStack (name) {
  return rokka.stacks.delete(internalState.auth.organization, name)
    .then(() => {
      refreshStacks()
    })
}

/**
 * Set global alert
 *
 * @param {string} type           error|pending|success
 * @param {string} message
 * @param {number} [timeout=null] Timeout in ms
 */
export function setAlert (type, message, timeout = null) {
  updateState({
    alert: {
      type,
      message
    }
  })

  if (timeout) {
    setTimeout(() => {
      removeAlert()
    }, timeout)
  }
}

/**
 * Remove global alert
 */
export function removeAlert () {
  updateState({ alert: null })
}

/**
 * Subscribe to state updates
 *
 * @param {function} cb Listener
 *
 * @returns {function} Unsubscribe function
 */
export function subscribe (cb) {
  listener = cb
  return () => {
    listener = null
  }
}

/**
 * Clone stack
 *
 * @param {string} name
 * @param {object} operations
 */
export function cloneStack (name, operations, options) {
  updateState({
    stackClone: {
      name: name,
      operations: operations,
      options: options
    }
  })
}

/**
 * Reset stack clone state
 *
 */
export function resetStackClone () {
  updateState({
    stackClone: {}
  })
}

// export state as readonly
const state = Object.assign({}, internalState)
export default state
<commit_msg>Rokka-167 Sort Stacks Alphabetically (#23)<commit_after>import rokka, { authenticate, resetClient } from '../rokka'
import { get as getCookie, set as setCookie, del as delCookie } from '../utils/cookie'

const SESSION_COOKIE_KEY = 'rka_session'

const session = getCookie(SESSION_COOKIE_KEY)

if (session && session.auth) {
  const { auth } = session
  login(auth.organization, auth.apiKey)
}

const defaultState = {
  showSidebar: false,
  stackClone: {},
  auth: null,
  images: [],
  stacks: {},
  operations: {},
  stackOptions: null,
  alert: null
}

let internalState = defaultState

let listener = null

/**
 * Update state and notify listener.
 *
 * @param {*} partialState
 */
function updateState (partialState) {
  internalState = Object.assign({}, internalState, partialState)
  if (!listener && process.env.NODE_ENV !== 'production') {
    console.warn('No listener added to state updates.')
    return
  }
  listener(internalState)
}

/**
 * Show or hide sidebar.
 */
export function toggleSidebar () {
  updateState({ showSidebar: !internalState.showSidebar })
}

/**
 * Delete a Image
 *
 * @param {string} hash
 *
 * @return {Promise}
 */
export function deleteImage (hash) {
  return rokka.sourceimages.delete(internalState.auth.organization, hash)
    .then(() => {
      clearImages()
    })
}

/**
 * Update Images state
 */
export function updateUploadedImages (images) {
  updateState({ images: images })
}

export function clearImages () {
  updateState({ images: [] })
}

/**
 * Login sets the API key to the rokka API client.
 *
 * @param {string}   organization
 * @param {string}   apiKey
 * @param {Function} successCb    Success callback
 *
 * @returns {Promise}
 */
export function login (organization, apiKey, successCb) {
  authenticate(apiKey)

  return rokka.organizations.get(organization)
    .then(() => {
      // remove alert in case there was auth failed before.
      removeAlert()

      const done = () => {
        updateState({ auth: { organization, apiKey } })
        setCookie(SESSION_COOKIE_KEY, { auth: { organization, apiKey } })
        listOperations()
        getDefaultStackOptions()
      }

      if (!successCb) {
        return done()
      }

      successCb(done)
    })
    .catch((err) => {
      console.error(err)

      setCookie(SESSION_COOKIE_KEY, {}) // clear session on error

      if (err.statusCode === 403 || err.statusCode === 404) {
        updateState({ auth: null })
        setAlert('error', 'Authentication failed')

        return
      }
      setAlert('error', 'Error getting organizations', 10000)
    })
}

/**
 * Logout clears the store and removes the API key from rokka API client.
 * Additionally it also removes the cookie.
 */
export function logout () {
  resetClient()
  delCookie(SESSION_COOKIE_KEY)
  updateState(defaultState)
}

/**
 * List stacks of an organization and populate the global state with the result.
 *
 * @param {number} limit
 *
 * @returns {Promise}
 */
export function listStacks (limit = 999) {
  const { currentOffset = 0, items = {} } = internalState.stacks

  return rokka.stacks.list(internalState.auth.organization, limit, currentOffset)
    .then(({ body }) => {
      sortAlphabetically(body.items)
      updateState({
        stacks: {
          currentOffset: currentOffset + limit,
          total: body.total,
          items: [...items, ...body.items]
        }
      })
    })
    .catch((err) => {
      console.error(err)
      if (err.statusCode === 403) {
        updateState({ auth: null })
        setAlert('error', 'Authentication failed')
        return
      }
      setAlert('error', 'Error when fetching stacks', 10000)
    })
}

/**
 * Resets the internal state with stacks and fetches them again.
 *
 * TODO: Slightly ugly that we have to manually override the internalState.stacks.
 *
 * @returns {Promise}
 */
export function refreshStacks () {
  internalState.stacks = {}
  return listStacks()
}

/**
 * Sorts Alphabetically
 *
 * @param {array} items
 *
 * @returns {array}
 */
function sortAlphabetically (items) {
  return items.sort((a, b) => {
    if (a.name < b.name) { return -1 }
    if (a.name > b.name) { return 1 }
    return 0
  })
}

/**
 * List operations and populate the global state with the result.
 */
export function listOperations () {
  rokka.operations.list()
    .then(({ body }) => {
      updateState({
        operations: body
      })
    })
    .catch((err) => {
      console.error(err)
      if (err.statusCode === 403) {
        updateState({ auth: null })
        setAlert('error', 'Authentication failed')
        return
      }
      setAlert('error', 'Error when fetching operations', 10000)
    })
}

/**
 * Fetch default stack options and populate the global state with the result.
 */
export function getDefaultStackOptions () {
  rokka.stackoptions.get()
    .then(({ body }) => {
      updateState({
        stackOptions: body.properties
      })
    })
    .catch(err => {
      console.error(err)
      setAlert('error', 'Error fetching default stack options', 10000)
    })
}

/**
 * Create a new stack
 *
 * @param {string}      name
 * @param {Array}       operations
 * @param {Object|null} options
 *
 * @return {Promise}
 */
export function createStack (name, operations, options) {
  return rokka.stacks.create(internalState.auth.organization, name, operations, options)
}

/**
 * Delete a stack
 *
 * @param {string} name
 *
 * @return {Promise}
 */
export function deleteStack (name) {
  return rokka.stacks.delete(internalState.auth.organization, name)
    .then(() => {
      refreshStacks()
    })
}

/**
 * Set global alert
 *
 * @param {string} type           error|pending|success
 * @param {string} message
 * @param {number} [timeout=null] Timeout in ms
 */
export function setAlert (type, message, timeout = null) {
  updateState({
    alert: {
      type,
      message
    }
  })

  if (timeout) {
    setTimeout(() => {
      removeAlert()
    }, timeout)
  }
}

/**
 * Remove global alert
 */
export function removeAlert () {
  updateState({ alert: null })
}

/**
 * Subscribe to state updates
 *
 * @param {function} cb Listener
 *
 * @returns {function} Unsubscribe function
 */
export function subscribe (cb) {
  listener = cb
  return () => {
    listener = null
  }
}

/**
 * Clone stack
 *
 * @param {string} name
 * @param {object} operations
 */
export function cloneStack (name, operations, options) {
  updateState({
    stackClone: {
      name: name,
      operations: operations,
      options: options
    }
  })
}

/**
 * Reset stack clone state
 *
 */
export function resetStackClone () {
  updateState({
    stackClone: {}
  })
}

// export state as readonly
const state = Object.assign({}, internalState)
export default state
<|endoftext|>


<commit_before>const {assoc, filter, mapObjIndexed, map, values, flatten, pipe} = require("ramda")
const addFilenameToLinks = require("./add-filename-to-links")
const getFileContents = require("./get-file-contents")
const pickHtmlFiles = require("./pick-html-files")
const shouldCheckLink = require("./should-check-link")
const handleLinks = require("./handle-links")
const normalizeFiles = require("./normalize-files")
const isLinkBroken = require("./is-link-broken")
const extractLinks = require("./extract-links")
const path = require("path")

function fileExists(files, filename) {
  // Remove leading slash before checking to match the Metalsmith files format
  if (filename.charAt(0) === "/") {
    filename = filename.slice(1)
  }

  // True if it exists in the files object
  if (filename in files) {
    return true
  }

  // Fallback for Windows paths
  const winPath = filename.split("/").join(path.sep)
  return winPath in files
}

module.exports = (options) => {

  if (options == null) { options = {} }
  if (options === true) { options = {} } // Allow CLI to specify true
  if (options.warn == null) { options.warn = false }
  if (options.checkLinks == null) { options.checkLinks = true }
  if (options.checkImages == null) { options.checkImages = true }
  if (options.allowRegex == null) { options.allowRegex = null }
  if (options.allowAnchors == null) { options.allowAnchors = true }
  if (options.baseURL == null) { options.baseURL = null }

  return (files) => {
    // const normalized = normalizeFiles(files)
    const normalized = files

    pipe(
      pickHtmlFiles,
      map(getFileContents),
      map(extractLinks),
      mapObjIndexed(addFilenameToLinks),
      values,
      flatten,
      filter(shouldCheckLink(options)),
      map(addBrokenStatus(files, fileExists, options)),
      handleLinks(options)
    )(normalized)
  }
}

function addBrokenStatus(files, fileExists, options) {
  return (link) => {
    const broken = isLinkBroken({
      files,
      fileExists,
      link,
      options,
    })

    return assoc("broken", broken, link)
  }
}
<commit_msg>Added new option to check for broken hash fragment<commit_after>const {assoc, filter, mapObjIndexed, map, values, flatten, pipe} = require("ramda")
const addFilenameToLinks = require("./add-filename-to-links")
const getFileContents = require("./get-file-contents")
const pickHtmlFiles = require("./pick-html-files")
const shouldCheckLink = require("./should-check-link")
const handleLinks = require("./handle-links")
const normalizeFiles = require("./normalize-files")
const isLinkBroken = require("./is-link-broken")
const extractLinks = require("./extract-links")
const path = require("path")

function fileExists(files, filename) {
  // Remove leading slash before checking to match the Metalsmith files format
  if (filename.charAt(0) === "/") {
    filename = filename.slice(1)
  }

  // True if it exists in the files object
  if (filename in files) {
    return true
  }

  // Fallback for Windows paths
  const winPath = filename.split("/").join(path.sep)
  return winPath in files
}

module.exports = (options) => {

  if (options == null) { options = {} }
  if (options === true) { options = {} } // Allow CLI to specify true
  if (options.warn == null) { options.warn = false }
  if (options.checkLinks == null) { options.checkLinks = true }
  if (options.checkImages == null) { options.checkImages = true }
  if (options.checkAnchors == null) {options.checkAnchors = false }
  if (options.allowRegex == null) { options.allowRegex = null }
  if (options.allowAnchors == null) { options.allowAnchors = true }
  if (options.baseURL == null) { options.baseURL = null }

  return (files) => {
    // const normalized = normalizeFiles(files)
    const normalized = files

    pipe(
      pickHtmlFiles,
      map(getFileContents),
      map(extractLinks),
      mapObjIndexed(addFilenameToLinks),
      values,
      flatten,
      filter(shouldCheckLink(options)),
      map(addBrokenStatus(files, fileExists, options)),
      handleLinks(options)
    )(normalized)
  }
}

function addBrokenStatus(files, fileExists, options) {
  return (link) => {
    const broken = isLinkBroken({
      files,
      fileExists,
      link,
      options,
    })

    return assoc("broken", broken, link)
  }
}
<|endoftext|>


<commit_before>import { getRandomArbitrary } from "utils";
import { Wall, SpritePlayer, SpriteEnemy, SpriteBullet, BoomerangSprite } from "SpriteConstants";
import {
  CameraVelocity,
  FlashColor,
  FlashDuration,
  ShakeIntensity,
  ShakeDuration,
  SpriteWidth,
  SpriteHeight,
  EnemyWidth,
  EnemyHeight,
  Border,
  CharacterWitdh,
  CharacterHeight
  } from "Constants";

import Player from "objects/Character";
import Boomerang from "objects/Boomerang";
import Room from "objects/Room";
import EnemyGroup from "objects/EnemyGroup";

const needCamera = false;

const MinDivision = 1;
const MaxDivision = 5;

const Division = getRandomArbitrary(MinDivision, MaxDivision);

const MaxBorder = 60;
const MinBorder = 30;

const SizeMaze = getRandomArbitrary(MinBorder, MaxBorder);
// assuming SpriteWidth = SpriteHeight
const Bounds = 2 * Border + SizeMaze * SpriteWidth;

class Game extends Phaser.State {

  create() {
    this.game.stage.backgroundColor = 0x000000;
    this.game.world.setBounds(0, 0, Bounds, Bounds);
    this.room = new Room(this.game);
    this.game.add.existing(this.room);
    this.room.createRandomSquare(Border,Border,SizeMaze, Division);

    this.hero = new Player(this.game, 100, 100);
    this.game.add.existing(this.hero);
    this.getInitialPosition(this.hero, CharacterWitdh, CharacterHeight);

    //this.boomerang = new Boomerang(this.game, this.hero.position.x, this.hero.position.y);
    ///this.game.add.existing(this.boomerang);

    this.enemies = new EnemyGroup(this.game);

    if(needCamera) {
      this.cursors = this.game.input.keyboard.createCursorKeys();
    }
    this.camera.follow(this.hero);
  }

  getInitialPosition(sprite, spriteWidth, spriteHeight) {
    let maxAttempt = 0;
    let hasBlock = false;
    do {
      const x = getRandomArbitrary(2 * Border, this.game.world.bounds.width - spriteWidth - 2 * Border);
      const y = getRandomArbitrary(2 * Border, this.game.world.bounds.height - spriteHeight - 2 * Border);
      sprite.position.setTo(x,y);
      maxAttempt = maxAttempt + 1;
      hasBlock = this.game.physics.arcade.collide(sprite, this.room);
    } while(maxAttempt < 10 && hasBlock);
  }

  update() {
    this.game.physics.arcade.overlap(this.hero, this.enemies, this.damage, null, this);
    this.game.physics.arcade.overlap(this.hero.bullets(), this.enemies, this.kill, null, this);
    this.game.physics.arcade.overlap(this.enemies, this.room, this.pushBlock, null, this);

    this.game.physics.arcade.collide(this.enemies);
    this.game.physics.arcade.collide(this.hero.bullets(), this.room, this.killBullet);
    //this.game.physics.arcade.collide(this.enemies, this.boomerang, this.killByBoomerang, null, this);
    this.game.physics.arcade.collide(this.hero, this.room);
    //this.game.physics.arcade.overlap(this.hero, this.boomerang, this.launchBoomerang, null, this);
    this.enemies.follow(this.hero.body.position);

    if(this.hero.isDeath()) {
      this.lost();
    }

     if(this.hero.isOutSideTheLevel(this.game) || !this.enemies.hasEnemies()) {
        this.won();
     }
  }

  kill(bullet, enemy) {
    this.enemies.remove(enemy);
    bullet.kill();
  }

  killBullet(bullet) {
    bullet.kill();
  }

  killByBoomerang(_, enemy) {
    this.enemies.remove(enemy);
  }

  damage() {
    this.hero.damage();
    this.camera.flash(FlashColor, FlashDuration);
  }

  pushBlock(enemy, block) {
    this.game.camera.shake(ShakeIntensity, ShakeDuration);
    const enemyLeft = enemy.body.position.x;
    const enemyRight = enemy.body.position.x + EnemyWidth;
    const enemyTop = enemy.body.position.y - EnemyHeight;
    const enemyBottom = enemy.body.position.y;

    const blockLeft = block.body.position.x;
    const blockRight = block.body.position.x + SpriteWidth;
    const blockTop = block.body.position.y - SpriteHeight;
    const blockBottom = block.body.position.y;

    const bigValue = 1000;
    let left = bigValue
    let right = bigValue;
    let up = bigValue;
    let down = bigValue;

    if( enemyLeft < blockLeft &&
        blockLeft < enemyRight &&
        enemyRight < blockRight
      ) {
      left = enemyRight - blockLeft;
    }

    if( blockLeft < enemyLeft &&
        enemyLeft < blockRight &&
        blockRight < enemyRight
     ) {
      right = blockRight - enemyLeft;
    }

    if( enemyTop < blockTop &&
        blockTop < enemyBottom &&
        enemyBottom < blockBottom
      ) {
      up = enemyBottom - blockTop;
    }

    if( blockTop < enemyTop &&
        enemyTop < blockBottom &&
        blockBottom < enemyBottom
    ) {
      down = blockBottom - enemyTop;
    }

    if(left < right && left < up  &&  left < down ) {
       block.body.position.x += 1;
    } else if( right < left && right < up  &&  right < down ) {
      block.body.position.x -= 1;
    } else if( up < down && up < left && up < right) {
      block.body.position.y += 1;
    } else if (down < up && down < left && down < right) {
      block.body.position.y -= 1;
    }

  }

  launchBoomerang() {
    this.camera.follow(this.boomerang);
    let tween = this.game.add.tween(this.boomerang).to( { y: 200 }, 2000, Phaser.Easing.Linear.None, true);
    tween.onComplete.add((boomerang, tween) => {
       this.camera.follow(this.hero);
       this.boomerang.kill();
    });
  }

  lost() {
    this.hero.kill();
    setTimeout(() => {
      this.game.goToLose()
    }, 500);
  }

  won() {
    this.game.goToWin();
  }

  preload() {
    this.game.load.image(Wall, "res/1.png");
    this.game.load.image(SpritePlayer, "res/player.png");
    this.game.load.image(SpriteEnemy, "res/enemy.png");
    this.game.load.image(SpriteBullet, "res/bullet.png");
    this.game.load.image(BoomerangSprite, "res/boomerang.png");
  }

  render() {
    this.game.debug.spriteInfo(this.hero, 32, 32);
    //this.game.debug.text(Bounds, 2, 14, "#ff0000");
    //this.game.debug.spriteInfo(this.hero, 32, 32);
  }

  moveCamera() {
    if(needCamera) {
      if (this.cursors.up.isDown)
      {
        this.game.camera.y -= CameraVelocity;
      }
      else if (this.cursors.down.isDown)
      {
        this.game.camera.y += CameraVelocity;
      }

      if (this.cursors.left.isDown)
      {
        this.game.camera.x -= CameraVelocity;
      }
      else if (this.cursors.right.isDown)
      {
        this.game.camera.x += CameraVelocity;
      }
    }
  }

}

export default Game;
<commit_msg>improve boomering but still in progress<commit_after>import { getRandomArbitrary } from "utils";
import { Wall, SpritePlayer, SpriteEnemy, SpriteBullet, BoomerangSprite } from "SpriteConstants";
import {
  CameraVelocity,
  FlashColor,
  FlashDuration,
  ShakeIntensity,
  ShakeDuration,
  SpriteWidth,
  SpriteHeight,
  EnemyWidth,
  EnemyHeight,
  Border,
  CharacterWitdh,
  CharacterHeight
  } from "Constants";

import Player from "objects/Character";
import Boomerang from "objects/Boomerang";
import Room from "objects/Room";
import EnemyGroup from "objects/EnemyGroup";

const needCamera = false;

const MinDivision = 1;
const MaxDivision = 5;

const Division = getRandomArbitrary(MinDivision, MaxDivision);

const MaxBorder = 60;
const MinBorder = 30;

const SizeMaze = getRandomArbitrary(MinBorder, MaxBorder);
// assuming SpriteWidth = SpriteHeight
const Bounds = 2 * Border + SizeMaze * SpriteWidth;

class Game extends Phaser.State {

  create() {
    this.game.stage.backgroundColor = 0x000000;
    this.game.world.setBounds(0, 0, Bounds, Bounds);
    this.room = new Room(this.game);
    this.game.add.existing(this.room);
    this.room.createRandomSquare(Border,Border,SizeMaze, Division);

    this.hero = new Player(this.game, 100, 100);
    this.game.add.existing(this.hero);
    this.getInitialPosition(this.hero, CharacterWitdh, CharacterHeight);

    //this.boomerang = new Boomerang(this.game, this.hero.position.x, this.hero.position.y);
    //this.game.add.existing(this.boomerang);

    this.enemies = new EnemyGroup(this.game);

    if(needCamera) {
      this.cursors = this.game.input.keyboard.createCursorKeys();
    }
    this.camera.follow(this.hero);
  }

  getInitialPosition(sprite, spriteWidth, spriteHeight) {
    let maxAttempt = 0;
    let hasBlock = false;
    do {
      const x = getRandomArbitrary(2 * Border, this.game.world.bounds.width - spriteWidth - 2 * Border);
      const y = getRandomArbitrary(2 * Border, this.game.world.bounds.height - spriteHeight - 2 * Border);
      sprite.position.setTo(x,y);
      maxAttempt = maxAttempt + 1;
      hasBlock = this.game.physics.arcade.collide(sprite, this.room);
    } while(maxAttempt < 10 && hasBlock);
  }

  update() {
    this.game.physics.arcade.overlap(this.hero, this.enemies, this.damage, null, this);
    this.game.physics.arcade.overlap(this.hero.bullets(), this.enemies, this.kill, null, this);
    this.game.physics.arcade.overlap(this.enemies, this.room, this.pushBlock, null, this);

    this.game.physics.arcade.collide(this.enemies);
    this.game.physics.arcade.collide(this.hero.bullets(), this.room, this.killBullet);
    //this.game.physics.arcade.collide(this.enemies, this.boomerang, this.killByBoomerang, null, this);
    this.game.physics.arcade.collide(this.hero, this.room);
    //this.game.physics.arcade.overlap(this.hero, this.boomerang, this.launchBoomerang, null, this);
    this.enemies.follow(this.hero.body.position);

    if(this.hero.isDeath()) {
      this.lost();
    }

     if(this.hero.isOutSideTheLevel(this.game) || !this.enemies.hasEnemies()) {
        this.won();
     }
  }

  kill(bullet, enemy) {
    this.enemies.remove(enemy);
    bullet.kill();
  }

  killBullet(bullet) {
    bullet.kill();
  }

  killByBoomerang(_, enemy) {
    this.enemies.remove(enemy);
  }

  damage() {
    this.hero.damage();
    this.camera.flash(FlashColor, FlashDuration);
  }

  pushBlock(enemy, block) {
    this.game.camera.shake(ShakeIntensity, ShakeDuration);
    const enemyLeft = enemy.body.position.x;
    const enemyRight = enemy.body.position.x + EnemyWidth;
    const enemyTop = enemy.body.position.y - EnemyHeight;
    const enemyBottom = enemy.body.position.y;

    const blockLeft = block.body.position.x;
    const blockRight = block.body.position.x + SpriteWidth;
    const blockTop = block.body.position.y - SpriteHeight;
    const blockBottom = block.body.position.y;

    const bigValue = 1000;
    let left = bigValue
    let right = bigValue;
    let up = bigValue;
    let down = bigValue;

    if( enemyLeft < blockLeft &&
        blockLeft < enemyRight &&
        enemyRight < blockRight
      ) {
      left = enemyRight - blockLeft;
    }

    if( blockLeft < enemyLeft &&
        enemyLeft < blockRight &&
        blockRight < enemyRight
     ) {
      right = blockRight - enemyLeft;
    }

    if( enemyTop < blockTop &&
        blockTop < enemyBottom &&
        enemyBottom < blockBottom
      ) {
      up = enemyBottom - blockTop;
    }

    if( blockTop < enemyTop &&
        enemyTop < blockBottom &&
        blockBottom < enemyBottom
    ) {
      down = blockBottom - enemyTop;
    }

    if(left < right && left < up  &&  left < down ) {
       block.body.position.x += 1;
    } else if( right < left && right < up  &&  right < down ) {
      block.body.position.x -= 1;
    } else if( up < down && up < left && up < right) {
      block.body.position.y += 1;
    } else if (down < up && down < left && down < right) {
      block.body.position.y -= 1;
    }

  }

  launchBoomerang() {
    this.camera.follow(this.boomerang);
    const y = this.boomerang.position.y;
    let tweenA = this.game.add.tween(this.boomerang).to( { y: 200 }, 2000, Phaser.Easing.Linear.None, true,0,0,true);
    tweenA.onComplete.add((boomerang, tween) => {
       this.boomerang.kill();
       tweenA.stop()
       this.camera.follow(this.hero);
    });
  }

  lost() {
    this.hero.kill();
    setTimeout(() => {
      this.game.goToLose()
    }, 500);
  }

  won() {
    this.game.goToWin();
  }

  preload() {
    this.game.load.image(Wall, "res/1.png");
    this.game.load.image(SpritePlayer, "res/player.png");
    this.game.load.image(SpriteEnemy, "res/enemy.png");
    this.game.load.image(SpriteBullet, "res/bullet.png");
    this.game.load.image(BoomerangSprite, "res/boomerang.png");
  }

  render() {
    this.game.debug.spriteInfo(this.hero, 32, 32);
    //this.game.debug.text(Bounds, 2, 14, "#ff0000");
    //this.game.debug.spriteInfo(this.hero, 32, 32);
  }

  moveCamera() {
    if(needCamera) {
      if (this.cursors.up.isDown)
      {
        this.game.camera.y -= CameraVelocity;
      }
      else if (this.cursors.down.isDown)
      {
        this.game.camera.y += CameraVelocity;
      }

      if (this.cursors.left.isDown)
      {
        this.game.camera.x -= CameraVelocity;
      }
      else if (this.cursors.right.isDown)
      {
        this.game.camera.x += CameraVelocity;
      }
    }
  }

}

export default Game;
<|endoftext|>


<commit_before>'use strict';

const chalk = require('chalk');
const table = require('text-table');
const gps   = require('wifi-location');
const geo   = require('node-geocoder')('google', 'http');
const pkg   = require('../package');
const uber  = require('uber-api')(pkg.uber);
const yay   = chalk.dim.bgGreen.bold;
const nay   = chalk.white.bgRed.bold;

export default class Surge {
  constructor() {
    this.estimates = [];
    this.getCoords(this.handleCoords.bind(this));
  }

  isNonEmptyObject(obj) {
    return Object.getOwnPropertyNames(obj || {}).length !== 0
  }

  flatten(arr) {
    return arr.reduce((i, chunk) => {
      return i.concat(chunk);
    });
  }

  handleCoords(err, data) {
    if (err) throw (err);
    let { lat, lng } = data;
    this.getDetailsFromLatLng(this.handleDetails.bind(this), lat, lng);
    this.getPriceEstimateFromLatLng(this.handlePriceEstimate.bind(this), lat, lng);
  }

  handlePriceEstimate(err, estimates) {
    if (err) throw (err);
    this.parseEstimates(estimates);
  }

  handleDetails(err, details) {
    if (err) throw (err);
    this.parseDetails(this.flatten(details));
  }

  parseEstimates(estimates) {
    console.log(table(estimates));
  }

  parseDetails(details) {
    console.log('');
    console.log('Location:  Nearby', chalk.dim.blue(details.streetName));
    console.log('');
  }

  getDetailsFromLatLng(cb, lat, lng) {
    geo.reverse({ lat: lat, lon: lng }, ((err, res) => {
      if (err) cb(err);
      cb(null, res);
    }));
  }

  getPriceEstimateFromLatLng(cb, lat, lng) {
    uber.getPriceEstimate({ sLat: lat, sLng: lng, eLat: lat, eLng: lng }, (err, resp) => {
      if (err) return cb(err);
      this.estimates = resp.prices.map((type) => {
        let good = yay(' ✔ GOOD ');
        let bad  = nay(' $ SURGE', chalk.white.bgRed(type.surge_multiplier + 'x '));
        return [
          type.localized_display_name,             // UberX, UberT, etc.
          type.surge_multiplier === 1 ? good : bad // Surge Pricing?
        ];
      });
      cb(null, this.estimates);
    });
  }

  getCoords(cb) {
    gps.getTowers((err, towers) => {
      if (err) return cb(err);
      gps.getLocation(towers, (err, location) => {
        if (err) return cb(err);
        if (!this.isNonEmptyObject(location)) return cb(Error(chalk.dim.red('Briefly unable to locate you. Try again.')));
        let { latitude, longitude } = location;
        let coords = { lat: latitude, lng: longitude };
        cb(null, coords);
      });
    });
  }
}
<commit_msg>suddenly not in the mood for semicolons<commit_after>'use strict'

const chalk = require('chalk')
const table = require('text-table')
const gps   = require('wifi-location')
const geo   = require('node-geocoder')('google', 'http')
const pkg   = require('../package')
const uber  = require('uber-api')(pkg.uber)
const yay   = chalk.dim.bgGreen.bold
const nay   = chalk.white.bgRed.bold

export default class Surge {
  constructor() {
    this.estimates = []
    this.getCoords(this.handleCoords.bind(this))
  }

  isNonEmptyObject(obj) {
    return Object.getOwnPropertyNames(obj || {}).length !== 0
  }

  flatten(arr) {
    return arr.reduce((i, chunk) => {
      return i.concat(chunk)
    })
  }

  handleCoords(err, data) {
    if (err) throw (err)
    let { lat, lng } = data
    this.getDetailsFromLatLng(this.handleDetails.bind(this), lat, lng)
    this.getPriceEstimateFromLatLng(this.handlePriceEstimate.bind(this), lat, lng)
  }

  handlePriceEstimate(err, estimates) {
    if (err) throw (err)
    this.parseEstimates(estimates)
  }

  handleDetails(err, details) {
    if (err) throw (err)
    this.parseDetails(this.flatten(details))
  }

  parseEstimates(estimates) {
    console.log(table(estimates))
  }

  parseDetails(details) {
    console.log('')
    console.log('Location:  Nearby', chalk.dim.blue(details.streetName))
    console.log('')
  }

  getDetailsFromLatLng(cb, lat, lng) {
    geo.reverse({ lat: lat, lon: lng }, ((err, res) => {
      if (err) cb(err)
      cb(null, res)
    }))
  }

  getPriceEstimateFromLatLng(cb, lat, lng) {
    uber.getPriceEstimate({ sLat: lat, sLng: lng, eLat: lat, eLng: lng }, (err, resp) => {
      if (err) return cb(err)
      this.estimates = resp.prices.map((type) => {
        let good = yay(' ✔ GOOD ')
        let bad  = nay(' $ SURGE', chalk.white.bgRed(type.surge_multiplier + 'x '))
        return [
          type.localized_display_name,             // UberX, UberT, etc.
          type.surge_multiplier === 1 ? good : bad // Surge Pricing?
        ]
      })
      cb(null, this.estimates)
    })
  }

  getCoords(cb) {
    gps.getTowers((err, towers) => {
      if (err) return cb(err)
      gps.getLocation(towers, (err, location) => {
        if (err) return cb(err)
        if (!this.isNonEmptyObject(location)) return cb(Error(chalk.dim.red('Briefly unable to locate you. Try again.')))
        let { latitude, longitude } = location
        let coords = { lat: latitude, lng: longitude }
        cb(null, coords)
      })
    })
  }
}
<|endoftext|>


<commit_before>class Main extends Phaser.State {
	constructor() {
		super();
		this.groundFront;
		this.player;
		this.jumpButton;
		this.doubleJump = 1;
		this.jumpTimer = 0;
		this.timer = 0;
		this.total = 0;
		this.totalScore = 0;
		this.tractor;
		this.weed;
		this.kernel;
		this.ammo;
		this.fireRate = 100;
		this.nextFire = 0;
	}

	create() {
		// Score and coinCounter reinitialize to zero upon restarting
		this.enemiesPassed = 0;
		this.coinCounter = 0;
		this.totalScore = 0;

		//Enable Arcade Physics
		this.game.physics.startSystem(Phaser.Physics.ARCADE);
		this.game.physics.arcade.gravity.y = 2000;

		//Set the games background colour
		this.game.stage.backgroundColor = '#c8f2fb';
		// this.sky = this.game.add.sprite(0,0,'sky');
		// this.sky.scale.setTo(5,5);

		this.mountainsBack = this.game.add.tileSprite(0,
			this.game.height - this.game.cache.getImage('mountains-back').height,
			this.game.width,
			this.game.cache.getImage('mountains-back').height,
			'mountains-back'
		);

		this.hillsMid1 = this.game.add.tileSprite(0,
			this.game.height - this.game.cache.getImage('hills-mid1').height,
			this.game.width,
			this.game.cache.getImage('hills-mid1').height,
			'hills-mid1'
		);

		this.fenceMid2 = this.game.add.tileSprite(0,
			this.game.height - this.game.cache.getImage('fence-mid2').height,
			this.game.width,
			this.game.cache.getImage('fence-mid2').height,
			'fence-mid2'
		);

		this.groundFront = this.game.add.tileSprite(0,
			this.game.height - this.game.cache.getImage('ground-front').height,
			this.game.width,
			this.game.cache.getImage('ground-front').height,
			'ground-front'
		);

		this.enemyScore = this.game.add.text(20, 20, "0", { font: "30px Arial", fill: "#fffff"});
		this.coinScore = this.game.add.text(60, 20, "0", { font: "30px Arial", fill: "#fffff"});
		this.sumScore = this.game.add.text(100, 20, "0", { font: "30px Arial", fill: "#fffff"});

		this.player = this.game.add.sprite(500, 1000, 'cornman');
		// this.player.scale.setTo(3, 3);

		this.player.animations.add('left', [0, 1, 2, 3], 10, true);
		this.player.animations.add('right', [0, 1, 2, 3], 10, true);

		this.game.physics.arcade.enable([this.player, this.groundFront]);
		this.player.body.collideWorldBounds = true;
		this.player.body.gravity.y = -50;
		// this.player.body.maxVelocity.y = 1000;

		this.groundFront.body.collideWorldBounds = true;
		this.groundFront.body.immovable = true;
		this.groundFront.body.allowGravity = false;

		this.obstacles = this.game.add.group();
		this.coinBag = this.game.add.group();

		this.stopButton = this.game.add.button(this.game.width - 90, 15, 'stop-game', this.stopGame, this);

		// Create Button Controller
			// Jump Button
		this.buttonJump = this.add.button(-(this.world.width*0.5), 0, 'blank', null, this);
		this.buttonJump.scale.setTo(20, 20)
		this.buttonJump.onInputDown.add(this.jumpPressed, this);

			// Fire Button & Keyboard Press
		this.fireButton = this.add.button((this.game.world.width*0.5), 0, 'blank', null, this);
		this.fireButton.scale.setTo(20, 20)
		this.fireButton.onInputDown.add(this.goShootPressed, this);
<<<<<<< HEAD
		this.fire = this.input.keyboard.addKey(Phaser.KeyCode.SPACEBAR);
		this.fire.onDown.add(this.goShootPressed, this);

		// Create Firing Object group
		this.ammo = this.game.add.group();
		this.ammo.enableBody = true;
		this.ammo.physicsBodyType = Phaser.Physics.ARCADE;
		this.ammo.createMultiple(10, 'bullet', 0, false);
		this.ammo.setAll('checkWorldBounds', true);
		this.ammo.setAll('outOfBoundsKill', true);
		this.ammo.setAll('anchor.x', - 2);
    this.ammo.setAll('anchor.y', - 1);

		//  An popcorn pool
    this.popcorn = this.game.add.group();
    this.popcorn.createMultiple(100, 'taco');
    this.popcorn.forEach(this.setupPopcorn, this);
=======
		this.fireButton.onInputUp.add(this.goShootReleased, this);

	}
>>>>>>> master

	addCoins() {
		// Generate Obstacles
		this.coin = this.game.add.sprite( 2800, 800, 'coin');
		this.game.physics.arcade.enable(this.coin);
		this.coin.body.allowGravity = false;

		this.game.add.tween(this.coin).to({
			x: this.coin.x - 55000 }, 110000, Phaser.Easing.Linear.None, true);

		this.coinBag.add(this.coin);
		this.total++;
		this.timer = this.game.time.now + 6000;
		this.coin.checkWorldBounds = true;
		this.coin.outofBoundsKill = true;
	}

		setupPopcorn(obstacle){
			obstacle.animations.add('taco');
		}

		// Touch Enabled jumping function
		jumpPressed(){
			if((this.game.time.now > this.jumpTimer) && this.doubleJump <= 2) {
				this.player.body.velocity.y = -1250;
				this.player.body.velocity.x = 2;
				this.jumpTimer = this.game.time.now + 200;
				this.doubleJump += 1;
			}
		}

		goShootPressed(){
			if(this.game.time.now > this.nextFire && this.ammo.countDead() > 0) {
				this.nextFire = this.game.time.now + this.fireRate;
				this.kernel = this.ammo.getFirstDead(false);
				this.kernel.physicsBodyType = Phaser.Physics.ARACADE;
				this.kernel.bulletSpeed = 600
				this.kernel.bulletAngleOffset = 90;
				this.kernel.reset(this.player.x + 10, this.player.y + 10);
				this.kernel.body.velocity.x = 1600;
				this.kernel.body.allowGravity = false;
			}
		}

	addCows() {
		// Generate Obstacles
		this.cow = this.game.add.sprite( 2800, 1290, 'cow');
		// Gives each cow a point to grant when player passes successfully
		this.cow.grantPoint = true;
		this.game.physics.arcade.enable(this.cow);
		this.cow.animations.add('walk')
		this.cow.animations.play('walk', 3, true);

		this.game.add.tween(this.cow).to({
			x: this.cow.x - 55000 }, 110000, Phaser.Easing.Linear.None, true);

		this.obstacles.add(this.cow);
		this.total++;
		this.timer = this.game.time.now + 6000;
		this.cow.checkWorldBounds = true;
		this.cow.outofBoundsKill = true;
	}

	addTractors() {

		// Generate Obstacles
		this.tractor = this.game.add.sprite( 2800, 1225, 'tractor', );
		// Gives each tractor a point to grant when player passes successfully
		this.tractor.grantPoint = true;
		this.game.physics.arcade.enable(this.tractor);
		this.tractor.animations.add('walk')
		this.tractor.animations.play('walk', 200, true);

		this.game.add.tween(this.tractor).to({
			x: this.tractor.x - 70000 }, 110000, Phaser.Easing.Linear.None, true);

		this.obstacles.add(this.tractor);
		this.total++;
		this.timer = this.game.time.now + 4000;
		this.tractor.checkWorldBounds = true;
		this.tractor.outofBoundsKill = true;
	}

	addWeeds() {
		this.weed = this.game.add.sprite( 3500 ,1000, 'weed', );
		// Gives each weed a point to grant when player passes successfully
		this.weed.grantPoint = true;
		this.game.physics.arcade.enable(this.weed);

		this.weed.animations.add('waddle')
		this.weed.animations.play('waddle', 1000, true);
		this.weed.animations.getAnimation('waddle').delay = 500

		this.game.add.tween(this.weed).to({
			x: this.weed.x - 300000 }, 110000, Phaser.Easing.Linear.None, true);

		this.obstacles.add(this.weed);
		this.total++;
		this.timer = this.game.time.now + 9000;
		this.weed.checkWorldBounds = true;
		this.weed.outofBoundsKill = true;
	}

	endGame() {
		this.game.state.start('Stats');
	}

	destroyWeed(kernel, obstacle){
		this.kernel.kill();
		this.weed.kill();
		// Create Popcorn Effect
		this.poppin = this.popcorn.getFirstExists(false);
		this.poppin.reset(this.weed.x, this.weed.y);
		this.poppin.play('taco', 100, false, true)
	}

	destroyTractor(kernel, obstacle){
		this.kernel.kill();
		this.tractor.kill();
		this.poppin = this.popcorn.getFirstExists(false);
		this.poppin.reset(this.tractor.x, this.tractor.y);
		this.poppin.play('taco', 100, false, true)
	}

	destroyCow(kernel, obstacle){
		this.kernel.kill();
		this.cow.kill();
		this.poppin = this.popcorn.getFirstExists(false);
		this.poppin.reset(this.cow.x, this.cow.y);
		this.poppin.play('taco', 100, false, true)
	}

	update() {
		this.player.animations.play('right');
		this.game.physics.arcade.collide(this.player, this.groundFront);
		this.game.physics.arcade.collide(this.weed, this.groundFront);
		this.game.physics.arcade.collide(this.tractor, this.groundFront);
		this.game.physics.arcade.collide(this.cow, this.groundFront);
		this.game.physics.arcade.collide(this.coin, this.groundFront);

		this.mountainsBack.tilePosition.x -= 0.10;
		this.hillsMid1.tilePosition.x -= 0.3;
		this.fenceMid2.tilePosition.x -= 3.0;
		this.groundFront.tilePosition.x -= 6.0;

		if(this.player.body.touching.down){
			this.doubleJump = 1;
		}

		// Generate Obstacles
		if (this.total < 1000 && this.game.time.now > this.timer){
			this.addTractors();
			this.addWeeds();
			this.addCows();
			this.addCoins();
		}

		// Functionality to count passing enemies ONCE
		if (this.weed.grantPoint && (this.weed.x < this.player.x)){
			this.enemiesPassed++;
			this.weed.grantPoint = false;
			this.enemyScore.text = this.enemiesPassed;
			this.totalScore = (this.enemiesPassed + this.coinCounter);
			this.sumScore.text = this.totalScore;
		}

		if (this.cow.grantPoint && (this.cow.x < this.player.x)){
			this.enemiesPassed++;
			this.cow.grantPoint = false;
			this.enemyScore.text = this.enemiesPassed;
			this.totalScore = (this.enemiesPassed + this.coinCounter);
			this.sumScore.text = this.totalScore;
		}

		if (this.tractor.grantPoint && (this.tractor.x < this.player.x)){
			this.enemiesPassed++;
			this.tractor.grantPoint = false;
			this.enemyScore.text = this.enemiesPassed;
			this.totalScore = (this.enemiesPassed + this.coinCounter);
			this.sumScore.text = this.totalScore;
		}

		// Collision to collect Corn Coins
		this.game.physics.arcade.overlap(
			this.player, this.coinBag, this.countCoin, null, this);

		// Collision to End Game between Player & Obstacles
		this.game.physics.arcade.overlap(
			this.player, this.obstacles, this.endGame, null, this);

		this.game.physics.arcade.overlap(
			this.ammo, this.weed, this.destroyWeed, null, this);

		this.game.physics.arcade.overlap(
			this.ammo, this.cow, this.destroyCow, null, this);

		this.game.physics.arcade.overlap(
			this.ammo, this.tractor, this.destroyTractor, null, this);

		countCoin() {
			this.coinCounter++;
			this.totalScore = (this.enemiesPassed + this.coinCounter);
			this.coin.kill();
			this.coinScore.text = this.coinCounter;
			this.sumScore.text = this.totalScore;
		}

}

export default Main;
<commit_msg>clean code<commit_after>class Main extends Phaser.State {
	constructor() {
		super();
		this.groundFront;
		this.player;
		this.jumpButton;
		this.doubleJump = 1;
		this.jumpTimer = 0;
		this.timer = 0;
		this.total = 0;
		this.totalScore = 0;
		this.tractor;
		this.weed;
		this.kernel;
		this.ammo;
		this.fireRate = 100;
		this.nextFire = 0;
	}

	create() {
		// Score and coinCounter reinitialize to zero upon restarting
		this.enemiesPassed = 0;
		this.coinCounter = 0;
		this.totalScore = 0;

		//Enable Arcade Physics
		this.game.physics.startSystem(Phaser.Physics.ARCADE);
		this.game.physics.arcade.gravity.y = 2000;

		//Set the games background colour
		this.game.stage.backgroundColor = '#c8f2fb';
		// this.sky = this.game.add.sprite(0,0,'sky');
		// this.sky.scale.setTo(5,5);

		this.mountainsBack = this.game.add.tileSprite(0,
			this.game.height - this.game.cache.getImage('mountains-back').height,
			this.game.width,
			this.game.cache.getImage('mountains-back').height,
			'mountains-back'
		);

		this.hillsMid1 = this.game.add.tileSprite(0,
			this.game.height - this.game.cache.getImage('hills-mid1').height,
			this.game.width,
			this.game.cache.getImage('hills-mid1').height,
			'hills-mid1'
		);

		this.fenceMid2 = this.game.add.tileSprite(0,
			this.game.height - this.game.cache.getImage('fence-mid2').height,
			this.game.width,
			this.game.cache.getImage('fence-mid2').height,
			'fence-mid2'
		);

		this.groundFront = this.game.add.tileSprite(0,
			this.game.height - this.game.cache.getImage('ground-front').height,
			this.game.width,
			this.game.cache.getImage('ground-front').height,
			'ground-front'
		);

		this.enemyScore = this.game.add.text(20, 20, "0", { font: "30px Arial", fill: "#fffff"});
		this.coinScore = this.game.add.text(60, 20, "0", { font: "30px Arial", fill: "#fffff"});
		this.sumScore = this.game.add.text(100, 20, "0", { font: "30px Arial", fill: "#fffff"});

		this.player = this.game.add.sprite(500, 1000, 'cornman');
		// this.player.scale.setTo(3, 3);

		this.player.animations.add('left', [0, 1, 2, 3], 10, true);
		this.player.animations.add('right', [0, 1, 2, 3], 10, true);

		this.game.physics.arcade.enable([this.player, this.groundFront]);
		this.player.body.collideWorldBounds = true;
		this.player.body.gravity.y = -50;
		// this.player.body.maxVelocity.y = 1000;

		this.groundFront.body.collideWorldBounds = true;
		this.groundFront.body.immovable = true;
		this.groundFront.body.allowGravity = false;

		this.obstacles = this.game.add.group();
		this.coinBag = this.game.add.group();

		this.stopButton = this.game.add.button(this.game.width - 90, 15, 'stop-game', this.stopGame, this);

		// Create Button Controller
			// Jump Button
		this.buttonJump = this.add.button(-(this.world.width*0.5), 0, 'blank', null, this);
		this.buttonJump.scale.setTo(20, 20)
		this.buttonJump.onInputDown.add(this.jumpPressed, this);

			// Fire Button & Keyboard Press
		this.fireButton = this.add.button((this.game.world.width*0.5), 0, 'blank', null, this);
		this.fireButton.scale.setTo(20, 20)
		this.fireButton.onInputDown.add(this.goShootPressed, this);
		this.fire = this.input.keyboard.addKey(Phaser.KeyCode.SPACEBAR);
		this.fire.onDown.add(this.goShootPressed, this);

		// Create Firing Object group
		this.ammo = this.game.add.group();
		this.ammo.enableBody = true;
		this.ammo.physicsBodyType = Phaser.Physics.ARCADE;
		this.ammo.createMultiple(10, 'bullet', 0, false);
		this.ammo.setAll('checkWorldBounds', true);
		this.ammo.setAll('outOfBoundsKill', true);
		this.ammo.setAll('anchor.x', - 2);
    this.ammo.setAll('anchor.y', - 1);

		//  An popcorn pool
    this.popcorn = this.game.add.group();
    this.popcorn.createMultiple(100, 'taco');
    this.popcorn.forEach(this.setupPopcorn, this);

	}

	addCoins() {
		// Generate Obstacles
		this.coin = this.game.add.sprite( 2800, 800, 'coin');
		this.game.physics.arcade.enable(this.coin);
		this.coin.body.allowGravity = false;

		this.game.add.tween(this.coin).to({
			x: this.coin.x - 55000 }, 110000, Phaser.Easing.Linear.None, true);

		this.coinBag.add(this.coin);
		this.total++;
		this.timer = this.game.time.now + 6000;
		this.coin.checkWorldBounds = true;
		this.coin.outofBoundsKill = true;
	}

	setupPopcorn(obstacle){
		obstacle.animations.add('taco');
	}

		// Touch Enabled jumping function
	jumpPressed(){
		if((this.game.time.now > this.jumpTimer) && this.doubleJump <= 2) {
			this.player.body.velocity.y = -1250;
			this.player.body.velocity.x = 2;
			this.jumpTimer = this.game.time.now + 200;
			this.doubleJump += 1;
		}
	}

	goShootPressed(){
		if(this.game.time.now > this.nextFire && this.ammo.countDead() > 0) {
			this.nextFire = this.game.time.now + this.fireRate;
			this.kernel = this.ammo.getFirstDead(false);
			this.kernel.physicsBodyType = Phaser.Physics.ARACADE;
			this.kernel.bulletSpeed = 600
			this.kernel.bulletAngleOffset = 90;
			this.kernel.reset(this.player.x + 10, this.player.y + 10);
			this.kernel.body.velocity.x = 1600;
			this.kernel.body.allowGravity = false;
		}
	}

	addCows() {
		// Generate Obstacles
		this.cow = this.game.add.sprite( 2800, 1290, 'cow');
		// Gives each cow a point to grant when player passes successfully
		this.cow.grantPoint = true;
		this.game.physics.arcade.enable(this.cow);
		this.cow.animations.add('walk')
		this.cow.animations.play('walk', 3, true);

		this.game.add.tween(this.cow).to({
			x: this.cow.x - 55000 }, 110000, Phaser.Easing.Linear.None, true);

		this.obstacles.add(this.cow);
		this.total++;
		this.timer = this.game.time.now + 6000;
		this.cow.checkWorldBounds = true;
		this.cow.outofBoundsKill = true;
	}

	addTractors() {

		// Generate Obstacles
		this.tractor = this.game.add.sprite( 2800, 1225, 'tractor', );
		// Gives each tractor a point to grant when player passes successfully
		this.tractor.grantPoint = true;
		this.game.physics.arcade.enable(this.tractor);
		this.tractor.animations.add('walk')
		this.tractor.animations.play('walk', 200, true);

		this.game.add.tween(this.tractor).to({
			x: this.tractor.x - 70000 }, 110000, Phaser.Easing.Linear.None, true);

		this.obstacles.add(this.tractor);
		this.total++;
		this.timer = this.game.time.now + 4000;
		this.tractor.checkWorldBounds = true;
		this.tractor.outofBoundsKill = true;
	}

	addWeeds() {
		this.weed = this.game.add.sprite( 3500 ,1000, 'weed', );
		// Gives each weed a point to grant when player passes successfully
		this.weed.grantPoint = true;
		this.game.physics.arcade.enable(this.weed);

		this.weed.animations.add('waddle')
		this.weed.animations.play('waddle', 1000, true);
		this.weed.animations.getAnimation('waddle').delay = 500

		this.game.add.tween(this.weed).to({
			x: this.weed.x - 300000 }, 110000, Phaser.Easing.Linear.None, true);

		this.obstacles.add(this.weed);
		this.total++;
		this.timer = this.game.time.now + 9000;
		this.weed.checkWorldBounds = true;
		this.weed.outofBoundsKill = true;
	}

	endGame() {
		this.game.state.start('Stats');
	}

	destroyWeed(kernel, obstacle){
		this.kernel.kill();
		this.weed.kill();
		// Create Popcorn Effect
		this.poppin = this.popcorn.getFirstExists(false);
		this.poppin.reset(this.weed.x, this.weed.y);
		this.poppin.play('taco', 100, false, true)
	}

	destroyTractor(kernel, obstacle){
		this.kernel.kill();
		this.tractor.kill();
		this.poppin = this.popcorn.getFirstExists(false);
		this.poppin.reset(this.tractor.x, this.tractor.y);
		this.poppin.play('taco', 100, false, true)
	}

	destroyCow(kernel, obstacle){
		this.kernel.kill();
		this.cow.kill();
		this.poppin = this.popcorn.getFirstExists(false);
		this.poppin.reset(this.cow.x, this.cow.y);
		this.poppin.play('taco', 100, false, true)
	}

	update() {
		this.player.animations.play('right');
		this.game.physics.arcade.collide(this.player, this.groundFront);
		this.game.physics.arcade.collide(this.weed, this.groundFront);
		this.game.physics.arcade.collide(this.tractor, this.groundFront);
		this.game.physics.arcade.collide(this.cow, this.groundFront);
		this.game.physics.arcade.collide(this.coin, this.groundFront);

		this.mountainsBack.tilePosition.x -= 0.10;
		this.hillsMid1.tilePosition.x -= 0.3;
		this.fenceMid2.tilePosition.x -= 3.0;
		this.groundFront.tilePosition.x -= 6.0;

		if(this.player.body.touching.down){
			this.doubleJump = 1;
		}

		// Generate Obstacles
		if (this.total < 1000 && this.game.time.now > this.timer){
			this.addTractors();
			this.addWeeds();
			this.addCows();
			this.addCoins();
		}

		// Functionality to count passing enemies ONCE
		if (this.weed.grantPoint && (this.weed.x < this.player.x)){
			this.enemiesPassed++;
			this.weed.grantPoint = false;
			this.enemyScore.text = this.enemiesPassed;
			this.totalScore = (this.enemiesPassed + this.coinCounter);
			this.sumScore.text = this.totalScore;
		}

		if (this.cow.grantPoint && (this.cow.x < this.player.x)){
			this.enemiesPassed++;
			this.cow.grantPoint = false;
			this.enemyScore.text = this.enemiesPassed;
			this.totalScore = (this.enemiesPassed + this.coinCounter);
			this.sumScore.text = this.totalScore;
		}

		if (this.tractor.grantPoint && (this.tractor.x < this.player.x)){
			this.enemiesPassed++;
			this.tractor.grantPoint = false;
			this.enemyScore.text = this.enemiesPassed;
			this.totalScore = (this.enemiesPassed + this.coinCounter);
			this.sumScore.text = this.totalScore;
		}

		// Collision to collect Corn Coins
		this.game.physics.arcade.overlap(
			this.player, this.coinBag, this.countCoin, null, this);

		// Collision to End Game between Player & Obstacles
		this.game.physics.arcade.overlap(
			this.player, this.obstacles, this.endGame, null, this);

		this.game.physics.arcade.overlap(
			this.ammo, this.weed, this.destroyWeed, null, this);

		this.game.physics.arcade.overlap(
			this.ammo, this.cow, this.destroyCow, null, this);

		this.game.physics.arcade.overlap(
			this.ammo, this.tractor, this.destroyTractor, null, this);

	}

	countCoin() {
		this.coinCounter++;
		this.totalScore = (this.enemiesPassed + this.coinCounter);
		this.coin.kill();
		this.coinScore.text = this.coinCounter;
		this.sumScore.text = this.totalScore;
	}
}

export default Main;
<|endoftext|>


<commit_before><commit_msg>playAnimation() (base)<commit_after><|endoftext|>