<commit_before>'use strict';

(function() {
	const $btnEdit = $('#btnEdit'),
	$contentContainer = $('#contentContainer'),
	$contentViewport = $('#contentContainer').find('#contentViewport'),
	$inputContainer = $('#inputContainer'),
	$articleTitle = $('#inputContainer').find('#article-title'),
	$imageUrl = $('#inputContainer').find('#imageUrl'),
	$txtContent = $('#inputContainer').find('#txtContent'),
	$txtContentFeat = $('#inputContainer').find('#txtContentFeat'),
	$featured = $('#inputContainer').find('#featured'),
	$btnSave = $('#inputContainer').find('#btnSave'),
	$btnCancel = $('#inputContainer').find('#btnCancel'),
	$formMsg = $('#inputContainer').find('#formMsg');

	//For Test data
	const $testDiv = $contentContainer.find('.testDiv'),
	$networkStatus =  $contentContainer.find('#networkStatus'),
	$btnTestData = $contentContainer.find('#btnTestData');

	const illegal = ['style', 'html', 'body', 'script'];

	//Evaluate for performance, maybe use regex?
	const serverPort = 3000;
	const serverUrl = `${location.protocol}//${location.hostname}:${serverPort}`;
	const url = window.location.href;
	const queryIndex = url.indexOf('?') + 1;
	let articleId = url.substring(queryIndex);

	let illegalItem,
	errorMsg,
	isNewArticle = 1;

	/*
		=========================
			ERROR CODES
		=========================
		 0: no error
		 1: Empty main content textbox
		 2: Illegal html tags found
		 3: General network error
		 4: No Article ID
		 5: Featured checkbox checked without actual featured content
		 6: Article already exists
		 7: Underscore in Article ID
	*/

	function getArticleByTitle() {
		console.log(`Retrieved article : [${articleId}]`);
		$.ajax({
			type: 'GET',
			url: `${serverUrl}/${articleId}`,
			success: function(data) {
				if (data) {
					$contentViewport.html(convertToHtml(data.content));
					$articleTitle.val(data.title.replace(/_/g, ' '));
					$txtContentFeat.val(data.contentFeat);
					$featured.val(data.featured);
					$imageUrl.val(data.imageUrl);

					if (data.featured) {
						$featured.prop('checked', true);
					}
				}

				evalContentViewport();
			},
			error: function(err) {
				errorMsg = JSON.stringify(err);
		    	processFormError(3, errorMsg);
			}
		});
	}

	function checkArticleByTitle(formTitle, article) {
		//check if title already exists
		$.ajax({
			type: 'GET',
			url: `${serverUrl}/${article.title}`,
			success: function(data) {

				if (isNewArticle) {
					if (data) {
						errorMsg = `Sorry, an article for <a target="_blank" href="${url}?${article.title}"><em>${formTitle}</em></a> already exists.`;
		    			processFormError(6, errorMsg);
					} else {
						article.featuredDate = 0;
						ajaxSaveArticle(article);
					}
				} else {
					ajaxUpdateArticle(article);
				}
			},
			error: function(err) {
				errorMsg = JSON.stringify(err);
		    	processFormError(3, errorMsg);
			}
		});
	}

	//show form to save a new article if no article is present
	function evalContentViewport() {
		if (!$contentViewport.html()) {
			hideElements([$contentViewport]);
			showElements([$btnTestData, $inputContainer, $btnSave]);
			isNewArticle = 1;
		} else {
			hideElements([$btnTestData, $inputContainer]);
			showElements([$contentViewport]);
			isNewArticle = 0;
		}
	}

	function processForm(o) {
		const illegalPrefix = '<';
	  	let content = $txtContent.val();

	  	errorMsg = '';

	  	//Numbers, letters and whitespace allowed.
	  	let regex = /^[a-z0-9\s]*$/i;

		for (let i=0; i<illegal.length; i++) {
		    illegalItem = illegal[i];

		    //Error cases
		    if (!content.trim()) {
		    	errorMsg = 'Content is empty.';
		    	processFormError(1, errorMsg);
		     	break;
		    } else if (content.indexOf(illegalPrefix + illegalItem) > -1) {
		    	errorMsg = `<${illegalItem}> tags are not allowed.`;
		    	processFormError(2, errorMsg);
				break;
		    } else if (!$articleTitle.val().trim()) {
		    	errorMsg = 'Article ID is required.';
		    	processFormError(4, errorMsg);
				break;
		    } else if ($featured.is(':checked') && !$txtContentFeat.val().trim()) {
		    	errorMsg = 'Featured Content must be added if you want to feature this article';
		    	processFormError(5, errorMsg);
				break;
		    } else if ($articleTitle.val().match(regex) == null){
		    	errorMsg = 'Only letters and numbers are allowed in the Article ID';
		    	processFormError(7, errorMsg);
				break;
		    }
		}

		if (!errorMsg) {
		  	if (!networkAvailable) {
				processhtml(content, convertToHtml);
			} else {
				saveArticle();
			}
		}
	}

	function saveArticle() {
		let article = {
			title: $articleTitle.val().replace(/\s/g, '_'),
			content: $txtContent.val(),
			contentFeat: $txtContentFeat.val(),
			featured: $featured.is(':checked'),
			imageUrl: $imageUrl.val()
		};

		checkArticleByTitle($articleTitle.val(), article);

	}

	function removeStatusMsg() {
		$formMsg.html('').removeClass();
	}

	function processFormError(errcode, msg) {
		removeStatusMsg();
		$formMsg.addClass('callout alert');
		// $formMsg.html(`Err ${errcode}: ${msg}`);
		$formMsg.html(msg);
	}

	function ajaxSaveArticle(article) {
		$.ajax({
			type: 'POST',
			url: `${serverUrl}/saveArticle`,
			data: article,
			success: function(data) {
				processhtml(data.content, convertToHtml);
				// Override edit state of our page the article can be updated without having to reload the page.
				articleId = data.title;
				isNewArticle = 0;
				console.log(`ADDED article : [${data.title}]`);
			},
			error: function(err) {
				errorMsg = JSON.stringify(err);
		    	processFormError(3, errorMsg);
			}
		});
	}

	function ajaxUpdateArticle(article) {
		$.ajax({
				type: 'PUT',
				url: `${serverUrl}/updateArticle/${articleId}`,
				data: article,
				success: function(data) {
					hideElements([$btnTestData, $inputContainer]);
					showElements([$contentViewport]);

					processhtml(data.content, convertToHtml);
					console.log(`UPDATED article : [${data.title}]`);
				},
				error: function(err) {
					errorMsg = JSON.stringify(err);
		    		processFormError(3, errorMsg);
				}
			});
	}

	function processhtml(html, callback) {
		//Apply form content
		hideElements([$btnTestData, $inputContainer]);
		showElements([$contentViewport]);

		$contentViewport.html(callback(html));
	}

	//Convert What-You-See to html format
	function convertToHtml(html) {
		html = html.replace(/\n<image\>\n/g, '
');
		html = html.replace(/\n\<\/image\>\n/g, '
');
		html = html.replace(/\<img src=\"/g, '<img src="img/wiki-img/');
		html = html.replace(/\n/g, '
');
		return html;
	}

	//Convert html format to What-You-See
	function convertToWYS(content) {
		content = content.replace(/\
/g, '\n');
		content = content.replace(/\
/g, '\n<image>\n');
		content = content.replace(/\<\/div\>/g, '\n</image>\n');
		content = content.replace(/\<img src=\"img\/wiki-img\//g, ' 1) {
			for (var i=0; i<arr.length; i++) {
				arr[i].hide();
			}
		} else {
			arr[0].hide();
		}
	}

	function showElements(arr) {
		if (arr.length > 1) {
			for (var i=0; i<arr.length; i++) {
				arr[i].show();
			}
		} else {
			arr[0].show();
		}
	}

	/* =============================
		EVENT LISTENERS
	 ============================= */
	//Add tab capability to textarea
	$("textarea").on('keydown', function(e) {
	    if(e.keyCode === 9) { // tab was pressed
	        // get caret position/selection
	        var start = this.selectionStart,
	        end = this.selectionEnd;

	        var $this = $(this),
	        value = $this.val();

	        // set textarea value to: text before caret + tab + text after caret
	        $this.val(value.substring(0, start)
	                    + "\t"
	                    + value.substring(end));

	        // put caret at right position again (add one for the tab)
	        this.selectionStart = this.selectionEnd = start + 1;

	        // prevent the focus lose
	        e.preventDefault();
	    }
	});

	//Enable edit mode
	$btnEdit.on('click', () => {
		removeStatusMsg();

		let content = $contentViewport.html();

		// hideElements([$contentViewport, $btnSave]);
		hideElements([$contentViewport]);
		showElements([$btnTestData, $inputContainer]);

		if (!$contentViewport.html()) {
			//Assuming a new article
			// showElements([$btnSave]);
			$txtContent.val('');
			$articleTitle.val('');
			$imageUrl.val('');
			$txtContent.val('');
			$txtContentFeat.val('');
			$featured.prop('checked', false);

			isNewArticle = 1;
		} else {
			//Assuming updating an existing article
			$articleTitle.prop('disabled', true);
			isNewArticle = 0;
		}
		$txtContent.val(convertToWYS(content));
	});

	//Cancel edit mode
	$btnCancel.on('click', () => {
		removeStatusMsg();

		hideElements([$btnTestData, $inputContainer]);
		showElements([$contentViewport]);
	});

	//Input test data
	$btnTestData.on('click', () => {
		$articleTitle.val('Arthur Sifton');
		$imageUrl.val('Arthur_Lewis_Watkins_Sifton.jpg');

		let clientContent = new XMLHttpRequest();
		clientContent.open('GET', './testArticle.html');
		clientContent.onreadystatechange = function() {
		  $txtContent.val(clientContent.responseText);
		}
		clientContent.send();

		let clientContentFeat = new XMLHttpRequest();
		clientContentFeat.open('GET', './testFeature.html');
		clientContentFeat.onreadystatechange = function() {
		  $txtContentFeat.val(clientContentFeat.responseText);
		}
		clientContentFeat.send();
	});

	//Save Article
	$btnSave.on('click', processForm);

	function init() {
		if (networkAvailable) {
			$networkStatus.addClass('networkStatusOK');
			$networkStatus.html('*ONLINE MODE*');

			//If we have a query string, attempt to find the related article
			if (queryIndex) {
				getArticleByTitle();
			}

		} else {
			// ***FOR OFFLINE MODE ONLY***
				$articleTitle.val('Arthur Sifton');
				$imageUrl.val('Arthur_Lewis_Watkins_Sifton.jpg');
				$featured.prop('checked', true);

				let clientContent = new XMLHttpRequest();
				clientContent.open('GET', './testArticle.html');
				clientContent.onreadystatechange = function() {

					$contentViewport.html(convertToHtml(clientContent.responseText));
					evalContentViewport();
				}
				clientContent.send();

				let clientContentFeat = new XMLHttpRequest();
				clientContentFeat.open('GET', './testFeature.html');
				clientContentFeat.onreadystatechange = function() {
					$txtContentFeat.val(clientContentFeat.responseText);
				}
				clientContentFeat.send();
			// ***FOR OFFLINE MODE ONLY***

			$networkStatus.addClass('networkStatusNOK');
			$networkStatus.html('*OFFLINE MODE*');
		}

		//Evaluate whether to show edit form or not
		// evalContentViewport();

		//Prevent initial flash of the entire input form before js has a chance to evaluate
		$inputContainer.removeClass('hide');
	}

	/*
		Init
	*/
	// Are we network ready?
	setTimeout(init, 500);

}());

<commit_msg>formatting<commit_after>'use strict';

(function() {
	const $btnEdit = $('#btnEdit'),
	$contentContainer = $('#contentContainer'),
	$contentViewport = $('#contentContainer').find('#contentViewport'),
	$inputContainer = $('#inputContainer'),
	$articleTitle = $('#inputContainer').find('#article-title'),
	$imageUrl = $('#inputContainer').find('#imageUrl'),
	$txtContent = $('#inputContainer').find('#txtContent'),
	$txtContentFeat = $('#inputContainer').find('#txtContentFeat'),
	$featured = $('#inputContainer').find('#featured'),
	$btnSave = $('#inputContainer').find('#btnSave'),
	$btnCancel = $('#inputContainer').find('#btnCancel'),
	$formMsg = $('#inputContainer').find('#formMsg');

	//For Test data
	const $testDiv = $contentContainer.find('.testDiv'),
	$networkStatus =  $contentContainer.find('#networkStatus'),
	$btnTestData = $contentContainer.find('#btnTestData');

	const illegal = ['style', 'html', 'body', 'script'];

	//Evaluate for performance, maybe use regex?
	const serverPort = 3000;
	const serverUrl = `${location.protocol}//${location.hostname}:${serverPort}`;
	const url = window.location.href;
	const queryIndex = url.indexOf('?') + 1;
	let articleId = url.substring(queryIndex);

	let illegalItem,
	errorMsg,
	isNewArticle = 1;

	/*
		=========================
			ERROR CODES
		=========================
		 0: no error
		 1: Empty main content textbox
		 2: Illegal html tags found
		 3: General network error
		 4: No Article ID
		 5: Featured checkbox checked without actual featured content
		 6: Article already exists
		 7: Underscore in Article ID
	*/

	function getArticleByTitle() {
		console.log(`Retrieved article : [${articleId}]`);
		$.ajax({
			type: 'GET',
			url: `${serverUrl}/${articleId}`,
			success: function(data) {
				if (data) {
					$contentViewport.html(convertToHtml(data.content));
					$articleTitle.val(data.title.replace(/_/g, ' '));
					$txtContentFeat.val(data.contentFeat);
					$featured.val(data.featured);
					$imageUrl.val(data.imageUrl);

					if (data.featured) {
						$featured.prop('checked', true);
					}
				}

				evalContentViewport();
			},
			error: function(err) {
				errorMsg = JSON.stringify(err);
		    	processFormError(3, errorMsg);
			}
		});
	}

	function checkArticleByTitle(formTitle, article) {
		//check if title already exists
		$.ajax({
			type: 'GET',
			url: `${serverUrl}/${article.title}`,
			success: function(data) {

				if (isNewArticle) {
					if (data) {
						errorMsg = `Sorry, an article for <a target="_blank" href="${url}?${article.title}"><em>${formTitle}</em></a> already exists.`;
		    			processFormError(6, errorMsg);
					} else {
						article.featuredDate = 0;
						ajaxSaveArticle(article);
					}
				} else {
					ajaxUpdateArticle(article);
				}
			},
			error: function(err) {
				errorMsg = JSON.stringify(err);
		    	processFormError(3, errorMsg);
			}
		});
	}

	//show form to save a new article if no article is present
	function evalContentViewport() {
		if (!$contentViewport.html()) {
			hideElements([$contentViewport]);
			showElements([$btnTestData, $inputContainer, $btnSave]);
			isNewArticle = 1;
		} else {
			hideElements([$btnTestData, $inputContainer]);
			showElements([$contentViewport]);
			isNewArticle = 0;
		}
	}

	function processForm(o) {
		const illegalPrefix = '<';
	  	let content = $txtContent.val();

	  	errorMsg = '';

	  	//Numbers, letters and whitespace allowed.
	  	let regex = /^[a-z0-9\s]*$/i;

		for (let i=0; i<illegal.length; i++) {
		    illegalItem = illegal[i];

		    //Error cases
		    if (!content.trim()) {
		    	errorMsg = 'Content is empty.';
		    	processFormError(1, errorMsg);
		     	break;
		    } else if (content.indexOf(illegalPrefix + illegalItem) > -1) {
		    	errorMsg = `<${illegalItem}> tags are not allowed.`;
		    	processFormError(2, errorMsg);
				break;
		    } else if (!$articleTitle.val().trim()) {
		    	errorMsg = 'Article ID is required.';
		    	processFormError(4, errorMsg);
				break;
		    } else if ($featured.is(':checked') && !$txtContentFeat.val().trim()) {
		    	errorMsg = 'Featured Content must be added if you want to feature this article';
		    	processFormError(5, errorMsg);
				break;
		    } else if ($articleTitle.val().match(regex) == null){
		    	errorMsg = 'Only letters and numbers are allowed in the Article ID';
		    	processFormError(7, errorMsg);
				break;
		    }
		}

		if (!errorMsg) {
		  	if (!networkAvailable) {
				processhtml(content, convertToHtml);
			} else {
				saveArticle();
			}
		}
	}

	function saveArticle() {
		let article = {
			title: $articleTitle.val().replace(/\s/g, '_'),
			content: $txtContent.val(),
			contentFeat: $txtContentFeat.val(),
			featured: $featured.is(':checked'),
			imageUrl: $imageUrl.val()
		};

		checkArticleByTitle($articleTitle.val(), article);
	}

	function removeStatusMsg() {
		$formMsg.html('').removeClass();
	}

	function processFormError(errcode, msg) {
		removeStatusMsg();
		$formMsg.addClass('callout alert');
		// $formMsg.html(`Err ${errcode}: ${msg}`);
		$formMsg.html(msg);
	}

	function ajaxSaveArticle(article) {
		$.ajax({
			type: 'POST',
			url: `${serverUrl}/saveArticle`,
			data: article,
			success: function(data) {
				processhtml(data.content, convertToHtml);
				// Override edit state of our page the article can be updated without having to reload the page.
				articleId = data.title;
				isNewArticle = 0;
				console.log(`ADDED article : [${data.title}]`);
			},
			error: function(err) {
				errorMsg = JSON.stringify(err);
		    	processFormError(3, errorMsg);
			}
		});
	}

	function ajaxUpdateArticle(article) {
		$.ajax({
				type: 'PUT',
				url: `${serverUrl}/updateArticle/${articleId}`,
				data: article,
				success: function(data) {
					hideElements([$btnTestData, $inputContainer]);
					showElements([$contentViewport]);

					processhtml(data.content, convertToHtml);
					console.log(`UPDATED article : [${data.title}]`);
				},
				error: function(err) {
					errorMsg = JSON.stringify(err);
		    		processFormError(3, errorMsg);
				}
			});
	}

	function processhtml(html, callback) {
		//Apply form content
		hideElements([$btnTestData, $inputContainer]);
		showElements([$contentViewport]);

		$contentViewport.html(callback(html));
	}

	//Convert What-You-See to html format
	function convertToHtml(html) {
		html = html.replace(/\n<image\>\n/g, '
');
		html = html.replace(/\n\<\/image\>\n/g, '
');
		html = html.replace(/\<img src=\"/g, '<img src="img/wiki-img/');
		html = html.replace(/\n/g, '
');
		return html;
	}

	//Convert html format to What-You-See
	function convertToWYS(content) {
		content = content.replace(/\
/g, '\n');
		content = content.replace(/\
/g, '\n<image>\n');
		content = content.replace(/\<\/div\>/g, '\n</image>\n');
		content = content.replace(/\<img src=\"img\/wiki-img\//g, ' 1) {
			for (var i=0; i<arr.length; i++) {
				arr[i].hide();
			}
		} else {
			arr[0].hide();
		}
	}

	function showElements(arr) {
		if (arr.length > 1) {
			for (var i=0; i<arr.length; i++) {
				arr[i].show();
			}
		} else {
			arr[0].show();
		}
	}

	/* =============================
		EVENT LISTENERS
	 ============================= */
	//Add tab capability to textarea
	$("textarea").on('keydown', function(e) {
	    if(e.keyCode === 9) { // tab was pressed
	        // get caret position/selection
	        var start = this.selectionStart,
	        end = this.selectionEnd;

	        var $this = $(this),
	        value = $this.val();

	        // set textarea value to: text before caret + tab + text after caret
	        $this.val(value.substring(0, start)
	                    + "\t"
	                    + value.substring(end));

	        // put caret at right position again (add one for the tab)
	        this.selectionStart = this.selectionEnd = start + 1;

	        // prevent the focus lose
	        e.preventDefault();
	    }
	});

	//Enable edit mode
	$btnEdit.on('click', () => {
		removeStatusMsg();

		let content = $contentViewport.html();

		// hideElements([$contentViewport, $btnSave]);
		hideElements([$contentViewport]);
		showElements([$btnTestData, $inputContainer]);

		if (!$contentViewport.html()) {
			//Assuming a new article
			// showElements([$btnSave]);
			$txtContent.val('');
			$articleTitle.val('');
			$imageUrl.val('');
			$txtContent.val('');
			$txtContentFeat.val('');
			$featured.prop('checked', false);

			isNewArticle = 1;
		} else {
			//Assuming updating an existing article
			$articleTitle.prop('disabled', true);
			isNewArticle = 0;
		}
		$txtContent.val(convertToWYS(content));
	});

	//Cancel edit mode
	$btnCancel.on('click', () => {
		removeStatusMsg();

		hideElements([$btnTestData, $inputContainer]);
		showElements([$contentViewport]);
	});

	//Input test data
	$btnTestData.on('click', () => {
		$articleTitle.val('Arthur Sifton');
		$imageUrl.val('Arthur_Lewis_Watkins_Sifton.jpg');

		let clientContent = new XMLHttpRequest();
		clientContent.open('GET', './testArticle.html');
		clientContent.onreadystatechange = function() {
		  $txtContent.val(clientContent.responseText);
		}
		clientContent.send();

		let clientContentFeat = new XMLHttpRequest();
		clientContentFeat.open('GET', './testFeature.html');
		clientContentFeat.onreadystatechange = function() {
		  $txtContentFeat.val(clientContentFeat.responseText);
		}
		clientContentFeat.send();
	});

	//Save Article
	$btnSave.on('click', processForm);

	function init() {
		if (networkAvailable) {
			$networkStatus.addClass('networkStatusOK');
			$networkStatus.html('*ONLINE MODE*');

			//If we have a query string, attempt to find the related article
			if (queryIndex) {
				getArticleByTitle();
			}

		} else {
			// ***FOR OFFLINE MODE ONLY***
				$articleTitle.val('Arthur Sifton');
				$imageUrl.val('Arthur_Lewis_Watkins_Sifton.jpg');
				$featured.prop('checked', true);

				let clientContent = new XMLHttpRequest();
				clientContent.open('GET', './testArticle.html');
				clientContent.onreadystatechange = function() {

					$contentViewport.html(convertToHtml(clientContent.responseText));
					evalContentViewport();
				}
				clientContent.send();

				let clientContentFeat = new XMLHttpRequest();
				clientContentFeat.open('GET', './testFeature.html');
				clientContentFeat.onreadystatechange = function() {
					$txtContentFeat.val(clientContentFeat.responseText);
				}
				clientContentFeat.send();
			// ***FOR OFFLINE MODE ONLY***

			$networkStatus.addClass('networkStatusNOK');
			$networkStatus.html('*OFFLINE MODE*');
		}

		//Evaluate whether to show edit form or not
		// evalContentViewport();

		//Prevent initial flash of the entire input form before js has a chance to evaluate
		$inputContainer.removeClass('hide');
	}

	/*
		Init
	*/
	// Are we network ready?
	setTimeout(init, 500);
}());

<|endoftext|>


<commit_before>var EmbarkJS = {
  onReady: __embarkContext.execWhenReady
};

EmbarkJS.isNewWeb3 = function() {
  var _web3 = new Web3();
  if (typeof(_web3.version) === "string") {
    return true;
  }
  return parseInt(_web3.version.api.split('.')[0], 10) >= 1;
};

EmbarkJS.Contract = function(options) {
    var self = this;
    var i, abiElement;
    var ContractClass;

    this.abi = options.abi;
    this.address = options.address;
    this.code = '0x' + options.code;
    //this.web3 = options.web3 || web3;
    this.web3 = options.web3 || window.web3;

    if (EmbarkJS.isNewWeb3()) {
      // TODO:
      // add default **from** address
      // add gasPrice
      ContractClass = new this.web3.eth.Contract(this.abi, this.address);
      ContractClass.setProvider(this.web3.currentProvider);
      ContractClass.options.data = this.code;
      ContractClass.abi = ContractClass.options.abi;
      ContractClass.address = this.address;

      let originalMethods = Object.keys(ContractClass);
      let methods = [];

      ContractClass._jsonInterface.forEach((abi) => {
        if (originalMethods.indexOf(abi.name) >= 0) {
          console.log(abi.name + " is a reserved word and cannot be used as a contract method, property or event");
          return;
        }
        methods.push(abi.name);

        if (!abi.inputs) {
          return;
        }

        let numExpectedInputs = abi.inputs.length;

        if (abi.type === 'function' && abi.constant) {
          ContractClass[abi.name] = function() {
            let options = {}, cb = null, args = Array.from(arguments || []).slice(0, numExpectedInputs);
            if (typeof (arguments[numExpectedInputs]) === 'function') {
              cb = arguments[numExpectedInputs];
            } else if (typeof (arguments[numExpectedInputs]) === 'object') {
              options = arguments[numExpectedInputs];
              cb = arguments[numExpectedInputs + 1];
            }

            let ref = ContractClass.methods[abi.name];
            let call = ref.apply(ref, ...arguments).call;
            return call.apply(call, []);
          };
        } else if (abi.type === 'function') {
          ContractClass[abi.name] = function() {
            let options = {}, cb = null, args = Array.from(arguments || []).slice(0, numExpectedInputs);
            if (typeof (arguments[numExpectedInputs]) === 'function') {
              cb = arguments[numExpectedInputs];
            } else if (typeof (arguments[numExpectedInputs]) === 'object') {
              options = arguments[numExpectedInputs];
              cb = arguments[numExpectedInputs + 1];
            }

            let ref = ContractClass.methods[abi.name];
            let send = ref.apply(ref, args).send;
            return send.apply(send, [options, cb]);
          };
        } else if (abi.type === 'event') {
          ContractClass[abi.name] = function(options, cb) {
            let ref = ContractClass.events[abi.name];
            return ref.apply(ref, [options, cb]);
          }
        }
      });

      return ContractClass;
    } else {
      ContractClass = this.web3.eth.contract(this.abi);

      this.eventList = [];

      if (this.abi) {
        for (i = 0; i < this.abi.length; i++) {
          abiElement = this.abi[i];
          if (abiElement.type === 'event') {
            this.eventList.push(abiElement.name);
          }
        }
      }

      var messageEvents = function() {
        this.cb = function() {};
      };

      messageEvents.prototype.then = function(cb) {
        this.cb = cb;
      };

      messageEvents.prototype.error = function(err) {
        return err;
      };

      this._originalContractObject = ContractClass.at(this.address);
      this._methods = Object.getOwnPropertyNames(this._originalContractObject).filter(function(p) {
        // TODO: check for forbidden properties
        if (self.eventList.indexOf(p) >= 0) {

          self[p] = function() {
            var promise = new messageEvents();
            var args = Array.prototype.slice.call(arguments);
            args.push(function(err, result) {
              if (err) {
                promise.error(err);
              } else {
                promise.cb(result);
              }
            });

            self._originalContractObject[p].apply(self._originalContractObject[p], args);
            return promise;
          };
          return true;
        } else if (typeof self._originalContractObject[p] === 'function') {
          self[p] = function(_args) {
            var args = Array.prototype.slice.call(arguments);
            var fn = self._originalContractObject[p];
            var props = self.abi.find((x) => x.name == p);

            var promise = new Promise(function(resolve, reject) {
              args.push(function(err, transaction) {
                promise.tx = transaction;
                if (err) {
                  return reject(err);
                }

                var getConfirmation = function() {
                  self.web3.eth.getTransactionReceipt(transaction, function(err, receipt) {
                    if (err) {
                      return reject(err);
                    }

                    if (receipt !== null) {
                      return resolve(receipt);
                    }

                    setTimeout(getConfirmation, 1000);
                  });
                };

                if (typeof(transaction) !== "string" || props.constant) {
                  resolve(transaction);
                } else {
                  getConfirmation();
                }
              });

              fn.apply(fn, args);
            });

            return promise;
          };
          return true;
        }
        return false;
      });
    }
};

EmbarkJS.Contract.prototype.deploy = function(args, _options) {
    var self = this;
    var contractParams;
    var options = _options || {};

    contractParams = args || [];

    contractParams.push({
        from: this.web3.eth.accounts[0],
        data: this.code,
        gas: options.gas || 800000
    });

    var contractObject = this.web3.eth.contract(this.abi);

    var promise = new Promise(function(resolve, reject) {
        contractParams.push(function(err, transaction) {
            if (err) {
                reject(err);
            } else if (transaction.address !== undefined) {
                resolve(new EmbarkJS.Contract({
                    abi: self.abi,
                    code: self.code,
                    address: transaction.address
                }));
            }
        });

        // returns promise
        // deploys contract
        // wraps it around EmbarkJS.Contract
        contractObject["new"].apply(contractObject, contractParams);
    });

    return promise;
};

EmbarkJS.Contract.prototype.new = EmbarkJS.Contract.prototype.deploy;

EmbarkJS.Contract.prototype.at = function(address) {
  return new EmbarkJS.Contract({ abi: this.abi, code: this.code, address: address });
};

EmbarkJS.Contract.prototype.send = function(value, unit, _options) {
  var options, wei;
  if (typeof unit === 'object') {
    options = unit;
    wei = value;
  } else {
    options = _options || {};
    wei = this.web3.toWei(value, unit);
  }

  options.to = this.address;
  options.value = wei;

  this.web3.eth.sendTransaction(options);
};

EmbarkJS.Storage = {};

EmbarkJS.Storage.Providers = {};

EmbarkJS.Storage.saveText = function(text) {
  if (!this.currentStorage) {
    throw new Error('Storage provider not set; e.g EmbarkJS.Storage.setProvider("ipfs")');
  }
  return this.currentStorage.saveText(text);
};

EmbarkJS.Storage.get = function(hash) {
  if (!this.currentStorage) {
    throw new Error('Storage provider not set; e.g EmbarkJS.Storage.setProvider("ipfs")');
  }
  return this.currentStorage.get(hash);
};

EmbarkJS.Storage.uploadFile = function(inputSelector) {
  if (!this.currentStorage) {
    throw new Error('Storage provider not set; e.g EmbarkJS.Storage.setProvider("ipfs")');
  }
  return this.currentStorage.uploadFile(inputSelector);
};

EmbarkJS.Storage.getUrl = function(hash) {
  if (!this.currentStorage) {
    throw new Error('Storage provider not set; e.g EmbarkJS.Storage.setProvider("ipfs")');
  }
  return this.currentStorage.getUrl(hash);
};

EmbarkJS.Storage.registerProvider = function(providerName, obj) {
  EmbarkJS.Storage.Providers[providerName] = obj;
};

EmbarkJS.Storage.setProvider = function(provider, options) {
  let providerObj = this.Providers[provider];

  if (!providerObj) {
    throw new Error('Unknown storage provider');
  }

  this.currentStorage = providerObj;

  return providerObj.setProvider(options);
};

EmbarkJS.Storage.isAvailable = function(){
  if (!this.currentStorage) {
    throw new Error('Storage provider not set; e.g EmbarkJS.Storage.setProvider("ipfs")');
  }
  return this.currentStorage.isAvailable();
};

EmbarkJS.Messages = {};

EmbarkJS.Messages.Providers = {};

EmbarkJS.Messages.registerProvider = function(providerName, obj) {
  EmbarkJS.Messages.Providers[providerName] = obj;
};

EmbarkJS.Messages.setProvider = function(provider, options) {
  let providerObj = this.Providers[provider];

  if (!providerObj) {
    throw new Error('Unknown messages provider');
  }

  this.currentMessages = providerObj;

  return providerObj.setProvider(options);
};

EmbarkJS.Messages.isAvailable = function(){
  return this.currentMessages.isAvailable();
};

EmbarkJS.Messages.sendMessage = function(options) {
  if (!this.currentMessages) {
    throw new Error('Messages provider not set; e.g EmbarkJS.Messages.setProvider("whisper")');
  }
  return this.currentMessages.sendMessage(options);
};

EmbarkJS.Messages.listenTo = function(options, callback) {
  if (!this.currentMessages) {
    throw new Error('Messages provider not set; e.g EmbarkJS.Messages.setProvider("whisper")');
  }
  return this.currentMessages.listenTo(options, callback);
};

EmbarkJS.Names = {};

EmbarkJS.Names.Providers = {};

EmbarkJS.Names.registerProvider = function(providerName, obj) {
  EmbarkJS.Names.Providers[providerName] = obj;
}

EmbarkJS.Names.setProvider = function(provider, options) {
  let providerObj = this.Providers[provider];

  if (!providerObj) {
    throw new Error('Unknown name system provider');
  }

  this.currentNameSystems = providerObj;

  return providerObj.setProvider(options);
};

// resolve resolves a name into an identifier of some kind
EmbarkJS.Names.resolve = function(name) {
  if (!this.currentNameSystems) {
    throw new Error('Name system provider not set; e.g EmbarkJS.Names.setProvider("ens")');
  }
  return this.currentNameSystems.resolve(name);
}

// the reverse of resolve, resolves using an identifier to get to a name
EmbarkJS.Names.lookup = function(identifier) {
  if (!this.currentNameSystems) {
    throw new Error('Name system provider not set; e.g EmbarkJS.Names.setProvider("ens")');
  }
  return this.currentNameSystems.lookup(identifier);
}

// To Implement

/*
// register a name
EmbarkJS.Names.register = function(name, options) {

}
*/

EmbarkJS.Utils = {
  fromAscii: function(str) {
    var _web3 = new Web3();
    return _web3.utils ? _web3.utils.fromAscii(str) : _web3.fromAscii(str);
  },
  toAscii: function(str) {
    var _web3 = new Web3();
    return _web3.utils.toAscii(str);
  }
};

export default EmbarkJS;
<commit_msg>clean up, improve setting the web3 object<commit_after>var EmbarkJS = {
  onReady: __embarkContext.execWhenReady
};

EmbarkJS.isNewWeb3 = function() {
  var _web3 = new Web3();
  if (typeof(_web3.version) === "string") {
    return true;
  }
  return parseInt(_web3.version.api.split('.')[0], 10) >= 1;
};

EmbarkJS.Contract = function(options) {
    var self = this;
    var i, abiElement;
    var ContractClass;

    this.abi = options.abi;
    this.address = options.address;
    this.code = '0x' + options.code;
    //this.web3 = options.web3 || web3;
    this.web3 = options.web3;
    if (!this.web3 && typeof ('web3') !== 'undefined') {
      this.web3 = web3;
    } else {
      this.web3 = window.web3;
    }

    if (EmbarkJS.isNewWeb3()) {
      ContractClass = new this.web3.eth.Contract(this.abi, this.address);
      ContractClass.setProvider(this.web3.currentProvider);
      ContractClass.options.data = this.code;
      ContractClass.options.from = this.from;
      ContractClass.abi = ContractClass.options.abi;
      ContractClass.address = this.address;

      let originalMethods = Object.keys(ContractClass);

      ContractClass._jsonInterface.forEach((abi) => {
        if (originalMethods.indexOf(abi.name) >= 0) {
          console.log(abi.name + " is a reserved word and cannot be used as a contract method, property or event");
          return;
        }

        if (!abi.inputs) {
          return;
        }

        let numExpectedInputs = abi.inputs.length;

        if (abi.type === 'function' && abi.constant) {
          ContractClass[abi.name] = function() {
            let options = {}, cb = null, args = Array.from(arguments || []).slice(0, numExpectedInputs);
            if (typeof (arguments[numExpectedInputs]) === 'function') {
              cb = arguments[numExpectedInputs];
            } else if (typeof (arguments[numExpectedInputs]) === 'object') {
              options = arguments[numExpectedInputs];
              cb = arguments[numExpectedInputs + 1];
            }

            let ref = ContractClass.methods[abi.name];
            let call = ref.apply(ref, ...arguments).call;
            return call.apply(call, []);
          };
        } else if (abi.type === 'function') {
          ContractClass[abi.name] = function() {
            let options = {}, cb = null, args = Array.from(arguments || []).slice(0, numExpectedInputs);
            if (typeof (arguments[numExpectedInputs]) === 'function') {
              cb = arguments[numExpectedInputs];
            } else if (typeof (arguments[numExpectedInputs]) === 'object') {
              options = arguments[numExpectedInputs];
              cb = arguments[numExpectedInputs + 1];
            }

            let ref = ContractClass.methods[abi.name];
            let send = ref.apply(ref, args).send;
            return send.apply(send, [options, cb]);
          };
        } else if (abi.type === 'event') {
          ContractClass[abi.name] = function(options, cb) {
            let ref = ContractClass.events[abi.name];
            return ref.apply(ref, [options, cb]);
          }
        }
      });

      return ContractClass;
    } else {
      ContractClass = this.web3.eth.contract(this.abi);

      this.eventList = [];

      if (this.abi) {
        for (i = 0; i < this.abi.length; i++) {
          abiElement = this.abi[i];
          if (abiElement.type === 'event') {
            this.eventList.push(abiElement.name);
          }
        }
      }

      var messageEvents = function() {
        this.cb = function() {};
      };

      messageEvents.prototype.then = function(cb) {
        this.cb = cb;
      };

      messageEvents.prototype.error = function(err) {
        return err;
      };

      this._originalContractObject = ContractClass.at(this.address);
      this._methods = Object.getOwnPropertyNames(this._originalContractObject).filter(function(p) {
        // TODO: check for forbidden properties
        if (self.eventList.indexOf(p) >= 0) {

          self[p] = function() {
            var promise = new messageEvents();
            var args = Array.prototype.slice.call(arguments);
            args.push(function(err, result) {
              if (err) {
                promise.error(err);
              } else {
                promise.cb(result);
              }
            });

            self._originalContractObject[p].apply(self._originalContractObject[p], args);
            return promise;
          };
          return true;
        } else if (typeof self._originalContractObject[p] === 'function') {
          self[p] = function(_args) {
            var args = Array.prototype.slice.call(arguments);
            var fn = self._originalContractObject[p];
            var props = self.abi.find((x) => x.name == p);

            var promise = new Promise(function(resolve, reject) {
              args.push(function(err, transaction) {
                promise.tx = transaction;
                if (err) {
                  return reject(err);
                }

                var getConfirmation = function() {
                  self.web3.eth.getTransactionReceipt(transaction, function(err, receipt) {
                    if (err) {
                      return reject(err);
                    }

                    if (receipt !== null) {
                      return resolve(receipt);
                    }

                    setTimeout(getConfirmation, 1000);
                  });
                };

                if (typeof(transaction) !== "string" || props.constant) {
                  resolve(transaction);
                } else {
                  getConfirmation();
                }
              });

              fn.apply(fn, args);
            });

            return promise;
          };
          return true;
        }
        return false;
      });
    }
};

EmbarkJS.Contract.prototype.deploy = function(args, _options) {
    var self = this;
    var contractParams;
    var options = _options || {};

    contractParams = args || [];

    contractParams.push({
        from: this.web3.eth.accounts[0],
        data: this.code,
        gas: options.gas || 800000
    });

    var contractObject = this.web3.eth.contract(this.abi);

    var promise = new Promise(function(resolve, reject) {
        contractParams.push(function(err, transaction) {
            if (err) {
                reject(err);
            } else if (transaction.address !== undefined) {
                resolve(new EmbarkJS.Contract({
                    abi: self.abi,
                    code: self.code,
                    address: transaction.address
                }));
            }
        });

        // returns promise
        // deploys contract
        // wraps it around EmbarkJS.Contract
        contractObject["new"].apply(contractObject, contractParams);
    });

    return promise;
};

EmbarkJS.Contract.prototype.new = EmbarkJS.Contract.prototype.deploy;

EmbarkJS.Contract.prototype.at = function(address) {
  return new EmbarkJS.Contract({ abi: this.abi, code: this.code, address: address });
};

EmbarkJS.Contract.prototype.send = function(value, unit, _options) {
  var options, wei;
  if (typeof unit === 'object') {
    options = unit;
    wei = value;
  } else {
    options = _options || {};
    wei = this.web3.toWei(value, unit);
  }

  options.to = this.address;
  options.value = wei;

  this.web3.eth.sendTransaction(options);
};

EmbarkJS.Storage = {};

EmbarkJS.Storage.Providers = {};

EmbarkJS.Storage.saveText = function(text) {
  if (!this.currentStorage) {
    throw new Error('Storage provider not set; e.g EmbarkJS.Storage.setProvider("ipfs")');
  }
  return this.currentStorage.saveText(text);
};

EmbarkJS.Storage.get = function(hash) {
  if (!this.currentStorage) {
    throw new Error('Storage provider not set; e.g EmbarkJS.Storage.setProvider("ipfs")');
  }
  return this.currentStorage.get(hash);
};

EmbarkJS.Storage.uploadFile = function(inputSelector) {
  if (!this.currentStorage) {
    throw new Error('Storage provider not set; e.g EmbarkJS.Storage.setProvider("ipfs")');
  }
  return this.currentStorage.uploadFile(inputSelector);
};

EmbarkJS.Storage.getUrl = function(hash) {
  if (!this.currentStorage) {
    throw new Error('Storage provider not set; e.g EmbarkJS.Storage.setProvider("ipfs")');
  }
  return this.currentStorage.getUrl(hash);
};

EmbarkJS.Storage.registerProvider = function(providerName, obj) {
  EmbarkJS.Storage.Providers[providerName] = obj;
};

EmbarkJS.Storage.setProvider = function(provider, options) {
  let providerObj = this.Providers[provider];

  if (!providerObj) {
    throw new Error('Unknown storage provider');
  }

  this.currentStorage = providerObj;

  return providerObj.setProvider(options);
};

EmbarkJS.Storage.isAvailable = function(){
  if (!this.currentStorage) {
    throw new Error('Storage provider not set; e.g EmbarkJS.Storage.setProvider("ipfs")');
  }
  return this.currentStorage.isAvailable();
};

EmbarkJS.Messages = {};

EmbarkJS.Messages.Providers = {};

EmbarkJS.Messages.registerProvider = function(providerName, obj) {
  EmbarkJS.Messages.Providers[providerName] = obj;
};

EmbarkJS.Messages.setProvider = function(provider, options) {
  let providerObj = this.Providers[provider];

  if (!providerObj) {
    throw new Error('Unknown messages provider');
  }

  this.currentMessages = providerObj;

  return providerObj.setProvider(options);
};

EmbarkJS.Messages.isAvailable = function(){
  return this.currentMessages.isAvailable();
};

EmbarkJS.Messages.sendMessage = function(options) {
  if (!this.currentMessages) {
    throw new Error('Messages provider not set; e.g EmbarkJS.Messages.setProvider("whisper")');
  }
  return this.currentMessages.sendMessage(options);
};

EmbarkJS.Messages.listenTo = function(options, callback) {
  if (!this.currentMessages) {
    throw new Error('Messages provider not set; e.g EmbarkJS.Messages.setProvider("whisper")');
  }
  return this.currentMessages.listenTo(options, callback);
};

EmbarkJS.Names = {};

EmbarkJS.Names.Providers = {};

EmbarkJS.Names.registerProvider = function(providerName, obj) {
  EmbarkJS.Names.Providers[providerName] = obj;
}

EmbarkJS.Names.setProvider = function(provider, options) {
  let providerObj = this.Providers[provider];

  if (!providerObj) {
    throw new Error('Unknown name system provider');
  }

  this.currentNameSystems = providerObj;

  return providerObj.setProvider(options);
};

// resolve resolves a name into an identifier of some kind
EmbarkJS.Names.resolve = function(name) {
  if (!this.currentNameSystems) {
    throw new Error('Name system provider not set; e.g EmbarkJS.Names.setProvider("ens")');
  }
  return this.currentNameSystems.resolve(name);
}

// the reverse of resolve, resolves using an identifier to get to a name
EmbarkJS.Names.lookup = function(identifier) {
  if (!this.currentNameSystems) {
    throw new Error('Name system provider not set; e.g EmbarkJS.Names.setProvider("ens")');
  }
  return this.currentNameSystems.lookup(identifier);
}

// To Implement

/*
// register a name
EmbarkJS.Names.register = function(name, options) {

}
*/

EmbarkJS.Utils = {
  fromAscii: function(str) {
    var _web3 = new Web3();
    return _web3.utils ? _web3.utils.fromAscii(str) : _web3.fromAscii(str);
  },
  toAscii: function(str) {
    var _web3 = new Web3();
    return _web3.utils.toAscii(str);
  }
};

export default EmbarkJS;
<|endoftext|>


<commit_before>/* Engine.js
 * This file provides the game loop functionality (update entities and render),
 * draws the initial game board on the screen, and then calls the update and
 * render methods on your player and enemy objects (defined in your app.js).
 *
 * A game engine works by drawing the entire game screen over and over, kind of
 * like a flipbook you may have created as a kid. When your player moves across
 * the screen, it may look like just that image/character is moving or being
 * drawn but that is not the case. What's really happening is the entire "scene"
 * is being drawn over and over, presenting the illusion of animation.
 *
 * This engine is available globally via the Engine variable and it also makes
 * the canvas' context (ctx) object globally available to make writing app.js
 * a little simpler to work with.
 */

var Engine = (function(global) {
    /* Predefine the variables we'll be using within this scope,
     * create the canvas element, grab the 2D context for that canvas
     * set the canvas elements height/width and add it to the DOM.
     */
    var doc = global.document,
        win = global.window,
        canvas = doc.createElement('canvas'),
        ctx = canvas.getContext('2d'),
        time = 0,
        time2 = 540,
        lastTime;

    canvas.width = 800;
    canvas.height = 600;
    canvas.style.border = "1px solid";
    canvas.setAttribute('id', 'canvas');
    doc.body.appendChild(canvas);

    /* This function serves as the kickoff point for the game loop itself
     * and handles properly calling the update and render methods.
     */
    function main() {
        /* Get our time delta information which is required if your game
         * requires smooth animation. Because everyone's computer processes
         * instructions at different speeds we need a constant value that
         * would be the same for everyone (regardless of how fast their
         * computer is) - hurray time!
         */
        var now = Date.now(),
            dt = (now - lastTime) / 1000.0;

        /* Call our update/render functions, pass along the time delta to
         * our update function since it may be used for smooth animation.
         */
        update(dt);
        render();

        /* Set our lastTime variable which is used to determine the time delta
         * for the next time this function is called.
         */
        lastTime = now;

        /* Use the browser's requestAnimationFrame function to call this
         * function again as soon as the browser is able to draw another frame.
         */
        win.requestAnimationFrame(main);
    }

    /* This function does some initial setup that should only occur once,
     * particularly setting the lastTime variable that is required for the
     * game loop.
     */
    function init() {
        reset();
        lastTime = Date.now();
        main();
    }

    /* This function is called by main (our game loop) and itself calls all
     * of the functions which may need to update entity's data. Based on how
     * you implement your collision detection (when two entities occupy the
     * same space, for instance when your character should die), you may find
     * the need to add an additional function call here. For now, we've left
     * it commented out - you may or may not want to implement this
     * functionality this way (you could just implement collision detection
     * on the entities themselves within your app.js file).
     */
    function update(dt) {
        updateEntities(dt);
        // checkCollisions();
    }

    /* This is called by the update function  and loops through all of the
     * objects within your allEnemies array as defined in app.js and calls
     * their update() methods. It will then call the update function for your
     * player object. These update methods should focus purely on updating
     * the data/properties related to  the object. Do your drawing in your
     * render methods.
     */
    function updateEntities(dt) {
        // allEnemies.forEach(function(enemy) {
        //     enemy.update(dt);
        // });
        player.update();
        rocks.forEach(function(rock){
            rock.update(dt);
        });
    }

    /* This function initially draws the "game level", it will then call
     * the renderEntities function. Remember, this function is called every
     * game tick (or loop of the game engine) because that's how games work -
     * they are flipbooks creating the illusion of animation but in reality
     * they are just drawing the entire screen over and over.
     */
    function render() {
        // Draw background
        ctx.drawImage(Resources.get(SPACEBG), 0, 0);

        // time element paces the movement of the background
        // moving background math ported from my python version of asteroids
        // http://www.codeskulptor.org/#user39_tlhzYVXuHl_17.py on line 299
        time+=0.5; //increase the tick
        time2+=0.5; // second timer for second round of debris because the image isn't large enough
        // wtime and wtime2 are used to simulate a scrolling down effect as time and time2 tick on
        // we modulo divide with twice the debris width to loop it so we have a changing dy
        wtime = time % 900 ;
        wtime2 = time2 % 960;

        // drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
        // dWidth and dHeight are to specify the scaled image resolution (can't run without it)
        ctx.drawImage(Resources.get(DEBRIS), 0, 0, 640, 480, 30, wtime - 380, 640, 480);
        ctx.drawImage(Resources.get(DEBRIS), 0, 0, 640, 480, 30, wtime2 - 400, 640, 480);

        //drawImageRot(ROCK, 250, 250, 101, 84, 360);
        // Draw every gameobj like asteroids
        renderEntities();

    }
    setInterval(rock_maker, 1200); // put outside of render because render spawns all rocks at once..

    /* This function is called by the render function and is called on each game
     * tick. It's purpose is to then call the render functions you have defined
     * on your enemy and player entities within app.js
     */
    function renderEntities() {
        /* Loop through all of the objects within the allEnemies array and call
         * the render function you have defined.
         */
        rocks.forEach(function(rock) {
            rock.render();
        });
        player.render();

    }

    /* This function does nothing but it could have been a good place to
     * handle game reset states - maybe a new game menu or a game over screen
     * those sorts of things. It's only called once by the init() method.
     */
    function reset() {
        // game state changes SHOULD GO HERE...
        // Something like the below? Bind reset onto a button to activate onclick
        // SCORE = 0;
        // LIVES = 3;
        // STARTED = false;
        // GAMEOVER = false;
    }

    /* Go ahead and load all of the images we know we're going to need to
     * draw our game level. Then set init as the callback method, so that when
     * all of these images are properly loaded our game will start.
     */
    Resources.load([
        'images/space-bg.jpg',
        'images/space-oj.jpg',
        'images/redship.png',
        'images/rock1.png',
        'images/debris.png'
        // 'images/stone-block.png',
        // 'images/water-block.png',
        // 'images/grass-block.png',
        // 'images/enemy-bug.png',
        // 'images/char-boy.png'
    ]);
    Resources.onReady(init);

    /* Assign the canvas' context object to the global variable (the window
     * object when run in a browser) so that developer's can use it more easily
     * from within their app.js files.
     */
    global.ctx = ctx;
})(this);<commit_msg>feat: changed bg to black<commit_after>/* Engine.js
 * This file provides the game loop functionality (update entities and render),
 * draws the initial game board on the screen, and then calls the update and
 * render methods on your player and enemy objects (defined in your app.js).
 *
 * A game engine works by drawing the entire game screen over and over, kind of
 * like a flipbook you may have created as a kid. When your player moves across
 * the screen, it may look like just that image/character is moving or being
 * drawn but that is not the case. What's really happening is the entire "scene"
 * is being drawn over and over, presenting the illusion of animation.
 *
 * This engine is available globally via the Engine variable and it also makes
 * the canvas' context (ctx) object globally available to make writing app.js
 * a little simpler to work with.
 */

var Engine = (function(global) {
    /* Predefine the variables we'll be using within this scope,
     * create the canvas element, grab the 2D context for that canvas
     * set the canvas elements height/width and add it to the DOM.
     */
    var doc = global.document,
        win = global.window,
        canvas = doc.createElement('canvas'),
        ctx = canvas.getContext('2d'),
        time = 0,
        time2 = 540,
        lastTime;

    document.body.style.backgroundColor = "black";
    canvas.width = 800;
    canvas.height = 600;
    canvas.style.border = "1px solid";
    canvas.setAttribute('id', 'canvas');
    doc.body.appendChild(canvas);

    /* This function serves as the kickoff point for the game loop itself
     * and handles properly calling the update and render methods.
     */
    function main() {
        /* Get our time delta information which is required if your game
         * requires smooth animation. Because everyone's computer processes
         * instructions at different speeds we need a constant value that
         * would be the same for everyone (regardless of how fast their
         * computer is) - hurray time!
         */
        var now = Date.now(),
            dt = (now - lastTime) / 1000.0;

        /* Call our update/render functions, pass along the time delta to
         * our update function since it may be used for smooth animation.
         */
        update(dt);
        render();

        /* Set our lastTime variable which is used to determine the time delta
         * for the next time this function is called.
         */
        lastTime = now;

        /* Use the browser's requestAnimationFrame function to call this
         * function again as soon as the browser is able to draw another frame.
         */
        win.requestAnimationFrame(main);
    }

    /* This function does some initial setup that should only occur once,
     * particularly setting the lastTime variable that is required for the
     * game loop.
     */
    function init() {
        reset();
        lastTime = Date.now();
        main();
    }

    /* This function is called by main (our game loop) and itself calls all
     * of the functions which may need to update entity's data. Based on how
     * you implement your collision detection (when two entities occupy the
     * same space, for instance when your character should die), you may find
     * the need to add an additional function call here. For now, we've left
     * it commented out - you may or may not want to implement this
     * functionality this way (you could just implement collision detection
     * on the entities themselves within your app.js file).
     */
    function update(dt) {
        updateEntities(dt);
        // checkCollisions();
    }

    /* This is called by the update function  and loops through all of the
     * objects within your allEnemies array as defined in app.js and calls
     * their update() methods. It will then call the update function for your
     * player object. These update methods should focus purely on updating
     * the data/properties related to  the object. Do your drawing in your
     * render methods.
     */
    function updateEntities(dt) {
        // allEnemies.forEach(function(enemy) {
        //     enemy.update(dt);
        // });
        player.update();
        rocks.forEach(function(rock){
            rock.update(dt);
        });
    }

    /* This function initially draws the "game level", it will then call
     * the renderEntities function. Remember, this function is called every
     * game tick (or loop of the game engine) because that's how games work -
     * they are flipbooks creating the illusion of animation but in reality
     * they are just drawing the entire screen over and over.
     */
    function render() {
        // Draw background
        ctx.drawImage(Resources.get(SPACEBG), 0, 0);

        // time element paces the movement of the background
        // moving background math ported from my python version of asteroids
        // http://www.codeskulptor.org/#user39_tlhzYVXuHl_17.py on line 299
        time+=0.5; //increase the tick
        time2+=0.5; // second timer for second round of debris because the image isn't large enough
        // wtime and wtime2 are used to simulate a scrolling down effect as time and time2 tick on
        // we modulo divide with twice the debris width to loop it so we have a changing dy
        wtime = time % 900 ;
        wtime2 = time2 % 960;

        // drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
        // dWidth and dHeight are to specify the scaled image resolution (can't run without it)
        ctx.drawImage(Resources.get(DEBRIS), 0, 0, 640, 480, 30, wtime - 380, 640, 480);
        ctx.drawImage(Resources.get(DEBRIS), 0, 0, 640, 480, 30, wtime2 - 400, 640, 480);

        //drawImageRot(ROCK, 250, 250, 101, 84, 360);
        // Draw every gameobj like asteroids
        renderEntities();
    }
    setInterval(rock_maker, 1200); // put outside of render because render spawns all rocks at once..

    /* This function is called by the render function and is called on each game
     * tick. It's purpose is to then call the render functions you have defined
     * on your enemy and player entities within app.js
     */
    function renderEntities() {
        /* Loop through all of the objects within the allEnemies array and call
         * the render function you have defined.
         */
        rocks.forEach(function(rock) {
            rock.render();
        });
        player.render();

    }

    /* This function does nothing but it could have been a good place to
     * handle game reset states - maybe a new game menu or a game over screen
     * those sorts of things. It's only called once by the init() method.
     */
    function reset() {
        // game state changes SHOULD GO HERE...
        // Something like the below? Bind reset onto a button to activate onclick
        // SCORE = 0;
        // LIVES = 3;
        // STARTED = false;
        // GAMEOVER = false;
    }

    /* Go ahead and load all of the images we know we're going to need to
     * draw our game level. Then set init as the callback method, so that when
     * all of these images are properly loaded our game will start.
     */
    Resources.load([
        'images/space-bg.jpg',
        'images/space-oj.jpg',
        'images/redship.png',
        'images/rock1.png',
        'images/debris.png'
        // 'images/stone-block.png',
        // 'images/water-block.png',
        // 'images/grass-block.png',
        // 'images/enemy-bug.png',
        // 'images/char-boy.png'
    ]);
    Resources.onReady(init);

    /* Assign the canvas' context object to the global variable (the window
     * object when run in a browser) so that developer's can use it more easily
     * from within their app.js files.
     */
    global.ctx = ctx;
})(this);<|endoftext|>


<commit_before>//Problem: There is no input search feature to quickly find a student
//Solution: Add JS to dynamically add a search input field to find all matching students

/* Global Variables --------------------------------*/
var $student = $('.student-details');

/* Main Functions ----------------------------------*/

function appendSearchDiv() {
    //Include search input to look for particular student
    //Add it dynamically to index.html using the format:
    var search =  '
';
    search += '<input placeholder="search for...">';
    search += '<button>Search</button>';
    search += '
';
    $('.page-header').append(search);
}

//Search button click returns all results that match name or emails which include matching name
function searchButtonClicked() {
    //get text value from input
    $('.student-search button').on('click', function(){
        // console.log('search button clicked');
        searchNames();
    });

    //function call to search studentNames & studentEmails for matching name
}

function searchNames(){
    var $input = $('.student-search');
    var inputValue = $input[0].firstChild.value;
    var arr = [];
    // console.log(inputValue);

    //Iterate thru DOM to collect all the students
    for (var idx=0; idx < $student.length; idx++){
        arr.push($student[idx].childNodes[1].innerText);
        if ($student[idx].childNodes[1].innerText.includes(inputValue)) {
            console.log('Found a match for ' + inputValue + ': ' + $student[idx].childNodes[1].innerText );
        }
    }
}

function searchEmails() {
    var studentEmails = [];

}

function noMatchesMessage() {
    //If no matches, then a message in the HTML tells user there are no matches
}

$(document).ready(function(){
    //functions to append content filter elements & functionality to the DOM
    appendSearchDiv();
    searchButtonClicked();
});
<commit_msg>Function to display matching student names working, just needs to display multiple matching results to the DOM.<commit_after>//Problem: There is no input search feature to quickly find a student
//Solution: Add JS to dynamically add a search input field to find all matching students

/* Global Variables --------------------------------*/
var $studentDetails = $('.student-details');
var $student = $('.student-item');

/* Main Functions ----------------------------------*/

function appendSearchDiv() {
    //Include search input to look for particular student
    //Add it dynamically to index.html using the format:
    var search =  '
';
    search += '<input placeholder="search for...">';
    search += '<button>Search</button>';
    search += '
';
    $('.page-header').append(search);
}

//Search button click returns all results that match name or emails which include matching name
function searchButtonClicked() {
    //get text value from input
    $('.student-search button').on('click', function(){
        searchNames();
    });

    //function call to search studentNames & studentEmails for matching name
}

function searchNames(){
    var $input = $('.student-search');
    var inputValue = $input[0].firstChild.value;
    // var arr = [];

    //Iterate thru DOM to collect all the students
    for (var idx=0; idx < $studentDetails.length; idx++){
        if ($studentDetails[idx].innerText.includes(inputValue)) {
            console.log('Found a match for ' + inputValue + ': ' + $student[idx].childNodes[1].innerText );
            // arr.push($student[idx].childNodes[1].innerText);

            // hides all the students
            $student.slice(0, $student.length).css('display', 'none');
            //shows only matching students
            $student.slice(idx, idx+1).css('display', 'list-item');
        } else {
            //call function to display msg 'Name not found.'
            //console.log('Name not found.');
        }
    }
    //if (value): $studentDetails[idx].childNodes[1].innerText.includes(inputValue)
}

function searchEmails() {
    var studentEmails = [];

}

function noMatchesMessage() {
    //If no matches, then a message in the HTML tells user there are no matches
}

$(document).ready(function(){
    //functions to append content filter elements & functionality to the DOM
    appendSearchDiv();
    searchButtonClicked();
});
<|endoftext|>


<commit_before>/**
 * Variables.
 */

var // Dictionary of MediaStreamRenderers.
	// - key: MediaStreamRenderer id.
	// - value: MediaStreamRenderer.
	mediaStreamRenderers = {},
	// Dictionary of MediaStreams.
	// - key: MediaStream blobId.
	// - value: MediaStream.
	mediaStreams = {},
	/**
	 * Dependencies.
	 */
	debug = require('debug')('iosrtc'),
	exec = require('cordova/exec'),
	domready = require('domready'),
	getUserMedia = require('./getUserMedia'),
	enumerateDevices = require('./enumerateDevices'),
	RTCPeerConnection = require('./RTCPeerConnection'),
	RTCSessionDescription = require('./RTCSessionDescription'),
	RTCIceCandidate = require('./RTCIceCandidate'),
	MediaDevices = require('./MediaDevices'),
	MediaStream = require('./MediaStream'),
	MediaStreamTrack = require('./MediaStreamTrack'),
	videoElementsHandler = require('./videoElementsHandler');

/**
 * Expose the iosrtc object.
 */
module.exports = {
	// Expose WebRTC classes and functions.
	getUserMedia: getUserMedia,
	enumerateDevices: enumerateDevices,
	getMediaDevices: enumerateDevices, // TMP
	RTCPeerConnection: RTCPeerConnection,
	RTCSessionDescription: RTCSessionDescription,
	RTCIceCandidate: RTCIceCandidate,
	MediaDevices: MediaDevices,
	MediaStream: MediaStream,
	MediaStreamTrack: MediaStreamTrack,

	// Expose a function to refresh current videos rendering a MediaStream.
	refreshVideos: videoElementsHandler.refreshVideos,

	// Expose a function to handle a video not yet inserted in the DOM.
	observeVideo: videoElementsHandler.observeVideo,

	// Select audio output (earpiece or speaker).
	selectAudioOutput: selectAudioOutput,

	// turnOnSpeaker with options
	turnOnSpeaker: turnOnSpeaker,

	// Checking permision (audio and camera)
	requestPermission: requestPermission,

	// Expose a function to initAudioDevices if needed, sets the audio session active
	initAudioDevices: initAudioDevices,

	// Expose a function to pollute window and naigator namespaces.
	registerGlobals: registerGlobals,

	// Expose the debug module.
	debug: require('debug'),

	// Debug function to see what happens internally.
	dump: dump,

	// Debug Stores to see what happens internally.
	mediaStreamRenderers: mediaStreamRenderers,
	mediaStreams: mediaStreams
};

domready(function () {
	// Let the MediaStream class and the videoElementsHandler share same MediaStreams container.
	MediaStream.setMediaStreams(mediaStreams);
	videoElementsHandler(mediaStreams, mediaStreamRenderers);

	// refreshVideos on device orientation change to resize peers video
	// while local video will resize du orientation change
	window.addEventListener('resize', function () {
		videoElementsHandler.refreshVideos();
	});
});

function selectAudioOutput(output) {
	debug('selectAudioOutput() | [output:"%s"]', output);

	switch (output) {
		case 'earpiece':
			exec(null, null, 'iosrtcPlugin', 'selectAudioOutputEarpiece', []);
			break;
		case 'speaker':
			exec(null, null, 'iosrtcPlugin', 'selectAudioOutputSpeaker', []);
			break;
		default:
			throw new Error('output must be "earpiece" or "speaker"');
	}
}

function turnOnSpeaker(isTurnOn) {
	debug('turnOnSpeaker() | [isTurnOn:"%s"]', isTurnOn);

	exec(null, null, 'iosrtcPlugin', 'RTCTurnOnSpeaker', [isTurnOn]);
}

function requestPermission(needMic, needCamera, callback) {
	debug('requestPermission() | [needMic:"%s", needCamera:"%s"]', needMic, needCamera);

	function ok() {
		callback(true);
	}

	function error() {
		callback(false);
	}
	exec(ok, error, 'iosrtcPlugin', 'RTCRequestPermission', [needMic, needCamera]);
}

function initAudioDevices() {
	debug('initAudioDevices()');

	exec(null, null, 'iosrtcPlugin', 'initAudioDevices', []);
}

function callbackifyMethod(originalMethod) {
	return function () {
		var success,
			failure,
			originalArgs = Array.prototype.slice.call(arguments);

		var callbackArgs = [];
		originalArgs.forEach(function (arg) {
			if (typeof arg === 'function') {
				if (!success) {
					success = arg;
				} else {
					failure = arg;
				}
			} else {
				callbackArgs.push(arg);
			}
		});

		var promiseResult = originalMethod.apply(this, callbackArgs);

		// Only apply then if callback success available
		if (typeof success === 'function') {
			promiseResult = promiseResult.then(success);
		}

		// Only apply catch if callback failure available
		if (typeof failure === 'function') {
			promiseResult = promiseResult.catch(failure);
		}

		return promiseResult;
	};
}

function callbackifyPrototype(proto, method) {
	var originalMethod = proto[method];
	proto[method] = callbackifyMethod(originalMethod);
}

function restoreCallbacksSupport() {
	debug('restoreCallbacksSupport()');
	getUserMedia = callbackifyMethod(getUserMedia);
	enumerateDevices = callbackifyMethod(enumerateDevices);
	callbackifyPrototype(RTCPeerConnection.prototype, 'createAnswer');
	callbackifyPrototype(RTCPeerConnection.prototype, 'createOffer');
	callbackifyPrototype(RTCPeerConnection.prototype, 'setRemoteDescription');
	callbackifyPrototype(RTCPeerConnection.prototype, 'setLocalDescription');
	callbackifyPrototype(RTCPeerConnection.prototype, 'addIceCandidate');
	callbackifyPrototype(RTCPeerConnection.prototype, 'getStats');
}

function registerGlobals(doNotRestoreCallbacksSupport) {
	debug('registerGlobals()');

	if (!global.navigator) {
		global.navigator = {};
	}

	if (!navigator.mediaDevices) {
		navigator.mediaDevices = new MediaDevices();
	}

	// Restore Callback support
	if (!doNotRestoreCallbacksSupport) {
		restoreCallbacksSupport();
	}

	navigator.getUserMedia = getUserMedia;
	navigator.webkitGetUserMedia = getUserMedia;
	navigator.mediaDevices.getUserMedia = getUserMedia;
	navigator.mediaDevices.enumerateDevices = enumerateDevices;

	window.RTCPeerConnection = RTCPeerConnection;
	window.webkitRTCPeerConnection = RTCPeerConnection;
	window.RTCSessionDescription = RTCSessionDescription;
	window.RTCIceCandidate = RTCIceCandidate;
	window.MediaStream = MediaStream;
	window.webkitMediaStream = MediaStream;
	window.MediaStreamTrack = MediaStreamTrack;

	// Apply CanvasRenderingContext2D.drawImage monkey patch
	var drawImage = CanvasRenderingContext2D.prototype.drawImage;
	CanvasRenderingContext2D.prototype.drawImage = function (arg) {
		var args = Array.prototype.slice.call(arguments);
		var context = this;
		if (arg instanceof HTMLVideoElement && arg.render) {
			arg.render.save(function (data) {
				var img = new window.Image();
				img.addEventListener('load', function () {
					args.splice(0, 1, img);
					drawImage.apply(context, args);
				});
				img.setAttribute('src', 'data:image/jpg;base64,' + data);
			});
		} else {
			return drawImage.apply(context, args);
		}
	};
}

function dump() {
	exec(null, null, 'iosrtcPlugin', 'dump', []);
}
<commit_msg>force early GC on Image loaded for Video to Canvas shim by retting src to null<commit_after>/**
 * Variables.
 */

var // Dictionary of MediaStreamRenderers.
	// - key: MediaStreamRenderer id.
	// - value: MediaStreamRenderer.
	mediaStreamRenderers = {},
	// Dictionary of MediaStreams.
	// - key: MediaStream blobId.
	// - value: MediaStream.
	mediaStreams = {},
	/**
	 * Dependencies.
	 */
	debug = require('debug')('iosrtc'),
	exec = require('cordova/exec'),
	domready = require('domready'),
	getUserMedia = require('./getUserMedia'),
	enumerateDevices = require('./enumerateDevices'),
	RTCPeerConnection = require('./RTCPeerConnection'),
	RTCSessionDescription = require('./RTCSessionDescription'),
	RTCIceCandidate = require('./RTCIceCandidate'),
	MediaDevices = require('./MediaDevices'),
	MediaStream = require('./MediaStream'),
	MediaStreamTrack = require('./MediaStreamTrack'),
	videoElementsHandler = require('./videoElementsHandler');

/**
 * Expose the iosrtc object.
 */
module.exports = {
	// Expose WebRTC classes and functions.
	getUserMedia: getUserMedia,
	enumerateDevices: enumerateDevices,
	getMediaDevices: enumerateDevices, // TMP
	RTCPeerConnection: RTCPeerConnection,
	RTCSessionDescription: RTCSessionDescription,
	RTCIceCandidate: RTCIceCandidate,
	MediaDevices: MediaDevices,
	MediaStream: MediaStream,
	MediaStreamTrack: MediaStreamTrack,

	// Expose a function to refresh current videos rendering a MediaStream.
	refreshVideos: videoElementsHandler.refreshVideos,

	// Expose a function to handle a video not yet inserted in the DOM.
	observeVideo: videoElementsHandler.observeVideo,

	// Select audio output (earpiece or speaker).
	selectAudioOutput: selectAudioOutput,

	// turnOnSpeaker with options
	turnOnSpeaker: turnOnSpeaker,

	// Checking permision (audio and camera)
	requestPermission: requestPermission,

	// Expose a function to initAudioDevices if needed, sets the audio session active
	initAudioDevices: initAudioDevices,

	// Expose a function to pollute window and naigator namespaces.
	registerGlobals: registerGlobals,

	// Expose the debug module.
	debug: require('debug'),

	// Debug function to see what happens internally.
	dump: dump,

	// Debug Stores to see what happens internally.
	mediaStreamRenderers: mediaStreamRenderers,
	mediaStreams: mediaStreams
};

domready(function () {
	// Let the MediaStream class and the videoElementsHandler share same MediaStreams container.
	MediaStream.setMediaStreams(mediaStreams);
	videoElementsHandler(mediaStreams, mediaStreamRenderers);

	// refreshVideos on device orientation change to resize peers video
	// while local video will resize du orientation change
	window.addEventListener('resize', function () {
		videoElementsHandler.refreshVideos();
	});
});

function selectAudioOutput(output) {
	debug('selectAudioOutput() | [output:"%s"]', output);

	switch (output) {
		case 'earpiece':
			exec(null, null, 'iosrtcPlugin', 'selectAudioOutputEarpiece', []);
			break;
		case 'speaker':
			exec(null, null, 'iosrtcPlugin', 'selectAudioOutputSpeaker', []);
			break;
		default:
			throw new Error('output must be "earpiece" or "speaker"');
	}
}

function turnOnSpeaker(isTurnOn) {
	debug('turnOnSpeaker() | [isTurnOn:"%s"]', isTurnOn);

	exec(null, null, 'iosrtcPlugin', 'RTCTurnOnSpeaker', [isTurnOn]);
}

function requestPermission(needMic, needCamera, callback) {
	debug('requestPermission() | [needMic:"%s", needCamera:"%s"]', needMic, needCamera);

	function ok() {
		callback(true);
	}

	function error() {
		callback(false);
	}
	exec(ok, error, 'iosrtcPlugin', 'RTCRequestPermission', [needMic, needCamera]);
}

function initAudioDevices() {
	debug('initAudioDevices()');

	exec(null, null, 'iosrtcPlugin', 'initAudioDevices', []);
}

function callbackifyMethod(originalMethod) {
	return function () {
		var success,
			failure,
			originalArgs = Array.prototype.slice.call(arguments);

		var callbackArgs = [];
		originalArgs.forEach(function (arg) {
			if (typeof arg === 'function') {
				if (!success) {
					success = arg;
				} else {
					failure = arg;
				}
			} else {
				callbackArgs.push(arg);
			}
		});

		var promiseResult = originalMethod.apply(this, callbackArgs);

		// Only apply then if callback success available
		if (typeof success === 'function') {
			promiseResult = promiseResult.then(success);
		}

		// Only apply catch if callback failure available
		if (typeof failure === 'function') {
			promiseResult = promiseResult.catch(failure);
		}

		return promiseResult;
	};
}

function callbackifyPrototype(proto, method) {
	var originalMethod = proto[method];
	proto[method] = callbackifyMethod(originalMethod);
}

function restoreCallbacksSupport() {
	debug('restoreCallbacksSupport()');
	getUserMedia = callbackifyMethod(getUserMedia);
	enumerateDevices = callbackifyMethod(enumerateDevices);
	callbackifyPrototype(RTCPeerConnection.prototype, 'createAnswer');
	callbackifyPrototype(RTCPeerConnection.prototype, 'createOffer');
	callbackifyPrototype(RTCPeerConnection.prototype, 'setRemoteDescription');
	callbackifyPrototype(RTCPeerConnection.prototype, 'setLocalDescription');
	callbackifyPrototype(RTCPeerConnection.prototype, 'addIceCandidate');
	callbackifyPrototype(RTCPeerConnection.prototype, 'getStats');
}

function registerGlobals(doNotRestoreCallbacksSupport) {
	debug('registerGlobals()');

	if (!global.navigator) {
		global.navigator = {};
	}

	if (!navigator.mediaDevices) {
		navigator.mediaDevices = new MediaDevices();
	}

	// Restore Callback support
	if (!doNotRestoreCallbacksSupport) {
		restoreCallbacksSupport();
	}

	navigator.getUserMedia = getUserMedia;
	navigator.webkitGetUserMedia = getUserMedia;
	navigator.mediaDevices.getUserMedia = getUserMedia;
	navigator.mediaDevices.enumerateDevices = enumerateDevices;

	window.RTCPeerConnection = RTCPeerConnection;
	window.webkitRTCPeerConnection = RTCPeerConnection;
	window.RTCSessionDescription = RTCSessionDescription;
	window.RTCIceCandidate = RTCIceCandidate;
	window.MediaStream = MediaStream;
	window.webkitMediaStream = MediaStream;
	window.MediaStreamTrack = MediaStreamTrack;

	// Apply CanvasRenderingContext2D.drawImage monkey patch
	var drawImage = CanvasRenderingContext2D.prototype.drawImage;
	CanvasRenderingContext2D.prototype.drawImage = function (arg) {
		var args = Array.prototype.slice.call(arguments);
		var context = this;
		if (arg instanceof HTMLVideoElement && arg.render) {
			arg.render.save(function (data) {
				var img = new window.Image();
				img.addEventListener('load', function () {
					args.splice(0, 1, img);
					drawImage.apply(context, args);
					img.src = null;
				});
				img.setAttribute('src', 'data:image/jpg;base64,' + data);
			});
		} else {
			return drawImage.apply(context, args);
		}
	};
}

function dump() {
	exec(null, null, 'iosrtcPlugin', 'dump', []);
}
<|endoftext|>


<commit_before>/**
 * Variables.
 */

var // Dictionary of MediaStreamRenderers.
	// - key: MediaStreamRenderer id.
	// - value: MediaStreamRenderer.
	mediaStreamRenderers = {},
	// Dictionary of MediaStreams.
	// - key: MediaStream blobId.
	// - value: MediaStream.
	mediaStreams = {},
	/**
	 * Dependencies.
	 */
	debug = require('debug')('iosrtc'),
	exec = require('cordova/exec'),
	domready = require('domready'),
	getUserMedia = require('./getUserMedia'),
	enumerateDevices = require('./enumerateDevices'),
	RTCPeerConnection = require('./RTCPeerConnection'),
	RTCSessionDescription = require('./RTCSessionDescription'),
	RTCIceCandidate = require('./RTCIceCandidate'),
	MediaDevices = require('./MediaDevices'),
	MediaStream = require('./MediaStream'),
	MediaStreamTrack = require('./MediaStreamTrack'),
	videoElementsHandler = require('./videoElementsHandler');

/**
 * Expose the iosrtc object.
 */
module.exports = {
	// Expose WebRTC classes and functions.
	getUserMedia: getUserMedia,
	enumerateDevices: enumerateDevices,
	getMediaDevices: enumerateDevices, // TMP
	RTCPeerConnection: RTCPeerConnection,
	RTCSessionDescription: RTCSessionDescription,
	RTCIceCandidate: RTCIceCandidate,
	MediaDevices: MediaDevices,
	MediaStream: MediaStream,
	MediaStreamTrack: MediaStreamTrack,

	// Expose a function to refresh current videos rendering a MediaStream.
	refreshVideos: videoElementsHandler.refreshVideos,

	// Expose a function to handle a video not yet inserted in the DOM.
	observeVideo: videoElementsHandler.observeVideo,

	// Select audio output (earpiece or speaker).
	selectAudioOutput: selectAudioOutput,

	// turnOnSpeaker with options
	turnOnSpeaker: turnOnSpeaker,

	// Checking permision (audio and camera)
	requestPermission: requestPermission,

	// Expose a function to initAudioDevices if needed, sets the audio session active
	initAudioDevices: initAudioDevices,

	// Expose a function to pollute window and naigator namespaces.
	registerGlobals: registerGlobals,

	// Expose the debug module.
	debug: require('debug'),

	// Debug function to see what happens internally.
	dump: dump,

	// Debug Stores to see what happens internally.
	mediaStreamRenderers: mediaStreamRenderers,
	mediaStreams: mediaStreams
};

domready(function () {
	// Let the MediaStream class and the videoElementsHandler share same MediaStreams container.
	MediaStream.setMediaStreams(mediaStreams);
	videoElementsHandler(mediaStreams, mediaStreamRenderers);

	// refreshVideos on device orientation change to resize peers video
	// while local video will resize du orientation change
	window.addEventListener('resize', function () {
		videoElementsHandler.refreshVideos();
	});
});

function selectAudioOutput(output) {
	debug('selectAudioOutput() | [output:"%s"]', output);

	switch (output) {
		case 'earpiece':
			exec(null, null, 'iosrtcPlugin', 'selectAudioOutputEarpiece', []);
			break;
		case 'speaker':
			exec(null, null, 'iosrtcPlugin', 'selectAudioOutputSpeaker', []);
			break;
		default:
			throw new Error('output must be "earpiece" or "speaker"');
	}
}

function turnOnSpeaker(isTurnOn) {
	debug('turnOnSpeaker() | [isTurnOn:"%s"]', isTurnOn);

	exec(null, null, 'iosrtcPlugin', 'RTCTurnOnSpeaker', [isTurnOn]);
}

function requestPermission(needMic, needCamera, callback) {
	debug('requestPermission() | [needMic:"%s", needCamera:"%s"]', needMic, needCamera);

	function ok() {
		callback(true);
	}

	function error() {
		callback(false);
	}
	exec(ok, error, 'iosrtcPlugin', 'RTCRequestPermission', [needMic, needCamera]);
}

function initAudioDevices() {
	debug('initAudioDevices()');

	exec(null, null, 'iosrtcPlugin', 'initAudioDevices', []);
}

function callbackifyMethod(originalMethod) {
	return function () {
		var success,
			failure,
			originalArgs = Array.prototype.slice.call(arguments);

		var callbackArgs = [];
		originalArgs.forEach(function (arg) {
			if (typeof arg === 'function') {
				if (!success) {
					success = arg;
				} else {
					failure = arg;
				}
			} else {
				callbackArgs.push(arg);
			}
		});

		var promiseResult = originalMethod.apply(this, callbackArgs);

		// Only apply then if callback success available
		if (typeof success === 'function') {
			promiseResult = promiseResult.then(success);
		}

		// Only apply catch if callback failure available
		if (typeof failure === 'function') {
			promiseResult = promiseResult.catch(failure);
		}

		return promiseResult;
	};
}

function callbackifyPrototype(proto, method) {
	var originalMethod = proto[method];
	proto[method] = callbackifyMethod(originalMethod);
}

function restoreCallbacksSupport() {
	debug('restoreCallbacksSupport()');
	getUserMedia = callbackifyMethod(getUserMedia);
	enumerateDevices = callbackifyMethod(enumerateDevices);
	callbackifyPrototype(RTCPeerConnection.prototype, 'createAnswer');
	callbackifyPrototype(RTCPeerConnection.prototype, 'createOffer');
	callbackifyPrototype(RTCPeerConnection.prototype, 'setRemoteDescription');
	callbackifyPrototype(RTCPeerConnection.prototype, 'setLocalDescription');
	callbackifyPrototype(RTCPeerConnection.prototype, 'addIceCandidate');
	callbackifyPrototype(RTCPeerConnection.prototype, 'getStats');
}

function registerGlobals(doNotRestoreCallbacksSupport) {
	debug('registerGlobals()');

	if (!global.navigator) {
		global.navigator = {};
	}

	// Restore Callback support
	if (!doNotRestoreCallbacksSupport) {
		restoreCallbacksSupport();
	}

	navigator.getUserMedia = getUserMedia;
	navigator.webkitGetUserMedia = getUserMedia;

	// Prevent WebRTC-adapter to overide navigator.mediaDevices after shim is applied since ios 14.3
	if (!(navigator.mediaDevices instanceof MediaDevices)) {
		Object.defineProperty(
			navigator,
			'mediaDevices',
			{
				value: new MediaDevices(),
				writable: false
			},
			{
				enumerable: false,
				configurable: false,
				writable: false,
				value: 'static'
			}
		);
	}

	window.RTCPeerConnection = RTCPeerConnection;
	window.webkitRTCPeerConnection = RTCPeerConnection;
	window.RTCSessionDescription = RTCSessionDescription;
	window.RTCIceCandidate = RTCIceCandidate;
	window.MediaStream = MediaStream;
	window.webkitMediaStream = MediaStream;
	window.MediaStreamTrack = MediaStreamTrack;

	// Apply CanvasRenderingContext2D.drawImage monkey patch
	var drawImage = CanvasRenderingContext2D.prototype.drawImage;
	CanvasRenderingContext2D.prototype.drawImage = (function () {
		// Methods to address the memory leaks problems in Safari
		let temporaryImage, imageElement;
		const BASE64_MARKER = ';base64,';
		const objectURL = window.URL || window.webkitURL;

		function convertDataURIToBlob(dataURI) {
			// Validate input data
			if (!dataURI) {
				return;
			}

			// Convert image (in base64) to binary data
			const base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
			const base64 = dataURI.substring(base64Index);
			const raw = window.atob(base64);
			const rawLength = raw.length;
			let array = new Uint8Array(new ArrayBuffer(rawLength));

			for (let i = 0; i < rawLength; i++) {
				array[i] = raw.charCodeAt(i);
			}

			// Create and return a new blob object using binary data
			return new Blob([array], { type: 'image/jpeg' });
		}

		return function (arg) {
			var args = Array.prototype.slice.call(arguments);
			var context = this;
			if (arg instanceof HTMLVideoElement && arg.render) {
				arg.render.save(function (base64Image) {
					// Destroy old image
					if (temporaryImage) {
						objectURL.revokeObjectURL(temporaryImage);
					}

					// Create a new image from binary data
					var imageDataBlob = convertDataURIToBlob(base64Image);

					// Create a new object URL object
					imageElement = imageElement || new Image();
					temporaryImage = objectURL.createObjectURL(imageDataBlob);

					imageElement.addEventListener('load', function () {
						args.splice(0, 1, imageElement);
						drawImage.apply(context, args);
					});

					// Set the new image
					imageElement.src = temporaryImage;
				});
			} else {
				return drawImage.apply(context, args);
			}
		};
	})();
}

function dump() {
	exec(null, null, 'iosrtcPlugin', 'dump', []);
}
<commit_msg>fix CanvasRenderingContext2D.prototype.drawImage<commit_after>/**
 * Variables.
 */

var // Dictionary of MediaStreamRenderers.
	// - key: MediaStreamRenderer id.
	// - value: MediaStreamRenderer.
	mediaStreamRenderers = {},
	// Dictionary of MediaStreams.
	// - key: MediaStream blobId.
	// - value: MediaStream.
	mediaStreams = {},
	/**
	 * Dependencies.
	 */
	debug = require('debug')('iosrtc'),
	exec = require('cordova/exec'),
	domready = require('domready'),
	getUserMedia = require('./getUserMedia'),
	enumerateDevices = require('./enumerateDevices'),
	RTCPeerConnection = require('./RTCPeerConnection'),
	RTCSessionDescription = require('./RTCSessionDescription'),
	RTCIceCandidate = require('./RTCIceCandidate'),
	MediaDevices = require('./MediaDevices'),
	MediaStream = require('./MediaStream'),
	MediaStreamTrack = require('./MediaStreamTrack'),
	videoElementsHandler = require('./videoElementsHandler');

/**
 * Expose the iosrtc object.
 */
module.exports = {
	// Expose WebRTC classes and functions.
	getUserMedia: getUserMedia,
	enumerateDevices: enumerateDevices,
	getMediaDevices: enumerateDevices, // TMP
	RTCPeerConnection: RTCPeerConnection,
	RTCSessionDescription: RTCSessionDescription,
	RTCIceCandidate: RTCIceCandidate,
	MediaDevices: MediaDevices,
	MediaStream: MediaStream,
	MediaStreamTrack: MediaStreamTrack,

	// Expose a function to refresh current videos rendering a MediaStream.
	refreshVideos: videoElementsHandler.refreshVideos,

	// Expose a function to handle a video not yet inserted in the DOM.
	observeVideo: videoElementsHandler.observeVideo,

	// Select audio output (earpiece or speaker).
	selectAudioOutput: selectAudioOutput,

	// turnOnSpeaker with options
	turnOnSpeaker: turnOnSpeaker,

	// Checking permision (audio and camera)
	requestPermission: requestPermission,

	// Expose a function to initAudioDevices if needed, sets the audio session active
	initAudioDevices: initAudioDevices,

	// Expose a function to pollute window and naigator namespaces.
	registerGlobals: registerGlobals,

	// Expose the debug module.
	debug: require('debug'),

	// Debug function to see what happens internally.
	dump: dump,

	// Debug Stores to see what happens internally.
	mediaStreamRenderers: mediaStreamRenderers,
	mediaStreams: mediaStreams
};

domready(function () {
	// Let the MediaStream class and the videoElementsHandler share same MediaStreams container.
	MediaStream.setMediaStreams(mediaStreams);
	videoElementsHandler(mediaStreams, mediaStreamRenderers);

	// refreshVideos on device orientation change to resize peers video
	// while local video will resize du orientation change
	window.addEventListener('resize', function () {
		videoElementsHandler.refreshVideos();
	});
});

function selectAudioOutput(output) {
	debug('selectAudioOutput() | [output:"%s"]', output);

	switch (output) {
		case 'earpiece':
			exec(null, null, 'iosrtcPlugin', 'selectAudioOutputEarpiece', []);
			break;
		case 'speaker':
			exec(null, null, 'iosrtcPlugin', 'selectAudioOutputSpeaker', []);
			break;
		default:
			throw new Error('output must be "earpiece" or "speaker"');
	}
}

function turnOnSpeaker(isTurnOn) {
	debug('turnOnSpeaker() | [isTurnOn:"%s"]', isTurnOn);

	exec(null, null, 'iosrtcPlugin', 'RTCTurnOnSpeaker', [isTurnOn]);
}

function requestPermission(needMic, needCamera, callback) {
	debug('requestPermission() | [needMic:"%s", needCamera:"%s"]', needMic, needCamera);

	function ok() {
		callback(true);
	}

	function error() {
		callback(false);
	}
	exec(ok, error, 'iosrtcPlugin', 'RTCRequestPermission', [needMic, needCamera]);
}

function initAudioDevices() {
	debug('initAudioDevices()');

	exec(null, null, 'iosrtcPlugin', 'initAudioDevices', []);
}

function callbackifyMethod(originalMethod) {
	return function () {
		var success,
			failure,
			originalArgs = Array.prototype.slice.call(arguments);

		var callbackArgs = [];
		originalArgs.forEach(function (arg) {
			if (typeof arg === 'function') {
				if (!success) {
					success = arg;
				} else {
					failure = arg;
				}
			} else {
				callbackArgs.push(arg);
			}
		});

		var promiseResult = originalMethod.apply(this, callbackArgs);

		// Only apply then if callback success available
		if (typeof success === 'function') {
			promiseResult = promiseResult.then(success);
		}

		// Only apply catch if callback failure available
		if (typeof failure === 'function') {
			promiseResult = promiseResult.catch(failure);
		}

		return promiseResult;
	};
}

function callbackifyPrototype(proto, method) {
	var originalMethod = proto[method];
	proto[method] = callbackifyMethod(originalMethod);
}

function restoreCallbacksSupport() {
	debug('restoreCallbacksSupport()');
	getUserMedia = callbackifyMethod(getUserMedia);
	enumerateDevices = callbackifyMethod(enumerateDevices);
	callbackifyPrototype(RTCPeerConnection.prototype, 'createAnswer');
	callbackifyPrototype(RTCPeerConnection.prototype, 'createOffer');
	callbackifyPrototype(RTCPeerConnection.prototype, 'setRemoteDescription');
	callbackifyPrototype(RTCPeerConnection.prototype, 'setLocalDescription');
	callbackifyPrototype(RTCPeerConnection.prototype, 'addIceCandidate');
	callbackifyPrototype(RTCPeerConnection.prototype, 'getStats');
}

function registerGlobals(doNotRestoreCallbacksSupport) {
	debug('registerGlobals()');

	if (!global.navigator) {
		global.navigator = {};
	}

	// Restore Callback support
	if (!doNotRestoreCallbacksSupport) {
		restoreCallbacksSupport();
	}

	navigator.getUserMedia = getUserMedia;
	navigator.webkitGetUserMedia = getUserMedia;

	// Prevent WebRTC-adapter to overide navigator.mediaDevices after shim is applied since ios 14.3
	if (!(navigator.mediaDevices instanceof MediaDevices)) {
		Object.defineProperty(
			navigator,
			'mediaDevices',
			{
				value: new MediaDevices(),
				writable: false
			},
			{
				enumerable: false,
				configurable: false,
				writable: false,
				value: 'static'
			}
		);
	}

	window.RTCPeerConnection = RTCPeerConnection;
	window.webkitRTCPeerConnection = RTCPeerConnection;
	window.RTCSessionDescription = RTCSessionDescription;
	window.RTCIceCandidate = RTCIceCandidate;
	window.MediaStream = MediaStream;
	window.webkitMediaStream = MediaStream;
	window.MediaStreamTrack = MediaStreamTrack;

	// Apply CanvasRenderingContext2D.drawImage monkey patch
	var drawImage = CanvasRenderingContext2D.prototype.drawImage;
	CanvasRenderingContext2D.prototype.drawImage = (function () {
		// Methods to address the memory leaks problems in Safari
		let temporaryImage, imageElement;
		const BASE64_MARKER = ';base64,';
		const objectURL = window.URL || window.webkitURL;

		function convertDataURIToBlob(dataURI) {
			// Validate input data
			if (!dataURI) {
				return;
			}

			// Convert image (in base64) to binary data
			const base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
			const base64 = dataURI.substring(base64Index);
			const raw = window.atob(base64);
			const rawLength = raw.length;
			let array = new Uint8Array(new ArrayBuffer(rawLength));

			for (let i = 0; i < rawLength; i++) {
				array[i] = raw.charCodeAt(i);
			}

			// Create and return a new blob object using binary data
			return new Blob([array], { type: 'image/jpeg' });
		}

		return function (arg) {
			const context = this;
			let args = Array.prototype.slice.call(arguments);
			if (arg instanceof HTMLVideoElement && arg.render) {
				arg.render.save(function (base64Image) {
					// Destroy old image
					if (temporaryImage) {
						objectURL.revokeObjectURL(temporaryImage);
					}

					// Create a new image from binary data
					const imageDataBlob = convertDataURIToBlob('data:image/jpg;base64,' + base64Image);

					// Create a new object URL object
					imageElement = imageElement || new Image();
					temporaryImage = objectURL.createObjectURL(imageDataBlob);

					imageElement.addEventListener('load', function () {
						args.splice(0, 1, imageElement);
						drawImage.apply(context, args);
					});

					// Set the new image
					imageElement.src = temporaryImage;
				});
			} else {
				return drawImage.apply(context, args);
			}
		};
	})();
}

function dump() {
	exec(null, null, 'iosrtcPlugin', 'dump', []);
}
<|endoftext|>


<commit_before>// a key map of allowed keys
var allowedKeys = {
  37: 'left',
  38: 'up',
  39: 'right',
  40: 'down',
  65: 'a',
  66: 'b'
};

// Konami Code sequence
var konamiCode = ['up', 'up', 'down', 'down', 'left', 'right', 'left', 'right', 'b', 'a'];

// a variable to remember the 'position' the user has reached so far.
var konamiCodePosition = 0;

// add keydown event listener
document.addEventListener('keydown', function(e) {
  // get the value of the key code from the key map
  var key = allowedKeys[e.keyCode];
  // get the value of the required key from the konami code
  var requiredKey = konamiCode[konamiCodePosition];

  // compare the key with the required key
  if (key == requiredKey) {

    // move to the next key in the konami code sequence
    konamiCodePosition++;

    // if the last key is reached, activate cheats
    if (konamiCodePosition == konamiCode.length) {
      activateCheats();
      konamiCodePosition = 0;
    }
  } else {
    konamiCodePosition = 0;
  }
});

// update this to what I want it to be.
function activateCheats() {
  document.body.style.backgroundImage = "url('img/about/Thank-You.jpg')";

  var audio = new Audio('audio/Here Comes The Sun.mp3');
  audio.play();

  alert("cheats activated");
}
 Run code snippetReturn to post
<commit_msg>fixed konami code<commit_after>// a key map of allowed keys
var allowedKeys = {
  37: 'left',
  38: 'up',
  39: 'right',
  40: 'down',
  65: 'a',
  66: 'b'
};

// Konami Code sequence
var konamiCode = ['up', 'up', 'down', 'down', 'left', 'right', 'left', 'right', 'b', 'a'];

// a variable to remember the 'position' the user has reached so far.
var konamiCodePosition = 0;

// add keydown event listener
document.addEventListener('keydown', function(e) {
  // get the value of the key code from the key map
  var key = allowedKeys[e.keyCode];
  // get the value of the required key from the konami code
  var requiredKey = konamiCode[konamiCodePosition];

  // compare the key with the required key
  if (key == requiredKey) {

    // move to the next key in the konami code sequence
    konamiCodePosition++;

    // if the last key is reached, activate cheats
    if (konamiCodePosition == konamiCode.length) {
      activateCheats();
      konamiCodePosition = 0;
    }
  } else {
    konamiCodePosition = 0;
  }
});

// update this to what I want it to be.
function activateCheats() {
  document.body.style.backgroundImage = "url('img/eagles.jpg')";

  var audio = new Audio('audio/FlyEaglesFly.mp3');
  audio.play();

  alert("cheats activated");
}
 Run code snippetReturn to post
<|endoftext|>