<commit_before>mw.kalturaPluginWrapper(function() {

	mw.PluginManager.add( 'tvpapiAnalytics', mw.KBasePlugin.extend({

		defaultConfig: {
			mediaHitInterval: 30
		},

		isPlaying: false,
		concurrentFlag: false,
		fileId: null,
		didFirstPlay: false,
		mediaHitInterval: null,

		setup: function() {
			this.bindEvents();
			this.bindContinueToTime();
		},

		bindEvents: function() {
			var _this = this;

			this.bind('playerReady', function(){
				_this.didFirstPlay = false;
				_this.fileId = _this.getPlayer().getSource() ? _this.getPlayer().getSource().assetid : null;
			});

			this.bind('firstPlay', function(){
				_this.didFirstPlay = true;
				_this.sendMediaMark('first_play');
			});

			this.bind('onplay', function(){
				_this.isPlaying = true;
				_this.startMediaHitInterval();
				_this.sendMediaMark('play');
			});

			this.bind('onpause', function(){
				_this.isPlaying = false;
				// During player start up, the player trigger "onpause" events
				// We use didFirstPlay flag to ignore them
				if( _this.didFirstPlay ) {
					_this.sendMediaMark('pause');
				}
			});

			this.bind('onEndedDone', function(){
				_this.isPlaying = false;
				_this.sendMediaMark('finish');
			});

			this.bind('widgetLoaded', function(){
				_this.sendMediaMark('load');
			});

			this.bind('SourceChange', function(){
				if(!_this.didFirstPlay) return;
				_this.sendMediaMark('bitrate_change');
			});
		},

		bindContinueToTime: function() {
			this.bind('tvpapiContinueToTime', $.proxy(function(e, seekTime){
				this.playFromContinue = true;
				this.continueTime = seekTime;
			},this));
			this.bind('seeked', $.proxy(function(){
				this.playFromContinue = false;
			},this));
		},

		startMediaHitInterval: function() {
			var _this = this;
			this.clearMediaHitInterval();
			this.mediaHitInterval = setInterval(function(){
				if( _this.isPlaying ) {
					_this.sendMediaHit();
				}
			}, this.getConfig('mediaHitInterval') * 1000 );
		},

		clearMediaHitInterval: function() {
			clearInterval(this.mediaHitInterval);
			this.mediaHitInterval = null;
		},

		sendMediaMark: function( action ) {
			var params = this.getBaseParams();
			params['Action'] = action;
			this.sendPostRequest('MediaMark', params);
		},

		sendMediaHit: function() {
			// Do not send media hit in the following conditions: concurrent limit, current time not updated (might be error)
			if(this.concurrentFlag || this.getPlayer().getPlayerElementTime() === 0 ){
				return;
			}
			this.sendPostRequest('MediaHit', this.getBaseParams());
		},

		getProxyData: function( key ) {
			return this.getPlayer().getKalturaConfig('proxyData', key);
		},

		getCurrentTime: function() {
			var currentTime;
			if( this.playFromContinue ) {
				currentTime = this.continueTime;
			} else {
				currentTime = Math.round(this.getPlayer().getPlayerElementTime());
			}
			return currentTime;
		},

		getBaseParams: function() {
			return {
				"initObj": this.getProxyData('initObj'),
				"mediaType": 0,
				"iMediaID": this.getProxyData('MediaID'),
				"iFileID": this.fileId,
				"iLocation": this.getCurrentTime()
			};
		},

		sendPostRequest: function( service, params ) {
			// Do not send requests during ad playback
			if( !this.getPlayer().isInSequence() ) {
				this.getPlayer().triggerHelper(service, [service, params]);

				this.log('sendPostRequest: request: ' + service, params);
				var _this = this;
				$.ajax({
					url: this.getPlayer().getFlashvars('TVPAPIBaseUrl') + service,
					data: JSON.stringify(params),
					crossDomain: true,
					type: 'POST',
					dataType: 'text',
					success: function (data) {
						_this.log('sendPostRequest: response for ' + service + ': ' + data);
						if (data == '"Concurrent"') {
							_this.concurrentFlag = true;
							_this.getPlayer().triggerHelper('tvpapiShowConcurrent');
						}
					},
					error: function (xhr, textStatus, errorThrown) {
						_this.log('sendPostRequest error', errorThrown);
					}
				});
			}
		}

	}));
});<commit_msg>FEC-3953 #comment Fix tvpapiAnalytics plugin wrapper<commit_after>(function (mw, $) {
	"use strict";

	mw.PluginManager.add( 'tvpapiAnalytics', mw.KBasePlugin.extend({

		defaultConfig: {
			mediaHitInterval: 30
		},

		isPlaying: false,
		concurrentFlag: false,
		fileId: null,
		didFirstPlay: false,
		mediaHitInterval: null,

		setup: function() {
			this.bindEvents();
			this.bindContinueToTime();
		},

		bindEvents: function() {
			var _this = this;

			this.bind('playerReady', function(){
				_this.didFirstPlay = false;
				_this.fileId = _this.getPlayer().getSource() ? _this.getPlayer().getSource().assetid : null;
			});

			this.bind('firstPlay', function(){
				_this.didFirstPlay = true;
				_this.sendMediaMark('first_play');
			});

			this.bind('onplay', function(){
				_this.isPlaying = true;
				_this.startMediaHitInterval();
				_this.sendMediaMark('play');
			});

			this.bind('onpause', function(){
				_this.isPlaying = false;
				// During player start up, the player trigger "onpause" events
				// We use didFirstPlay flag to ignore them
				if( _this.didFirstPlay ) {
					_this.sendMediaMark('pause');
				}
			});

			this.bind('onEndedDone', function(){
				_this.isPlaying = false;
				_this.sendMediaMark('finish');
			});

			this.bind('widgetLoaded', function(){
				_this.sendMediaMark('load');
			});

			this.bind('SourceChange', function(){
				if(!_this.didFirstPlay) return;
				_this.sendMediaMark('bitrate_change');
			});
		},

		bindContinueToTime: function() {
			this.bind('tvpapiContinueToTime', $.proxy(function(e, seekTime){
				this.playFromContinue = true;
				this.continueTime = seekTime;
			},this));
			this.bind('seeked', $.proxy(function(){
				this.playFromContinue = false;
			},this));
		},

		startMediaHitInterval: function() {
			var _this = this;
			this.clearMediaHitInterval();
			this.mediaHitInterval = setInterval(function(){
				if( _this.isPlaying ) {
					_this.sendMediaHit();
				}
			}, this.getConfig('mediaHitInterval') * 1000 );
		},

		clearMediaHitInterval: function() {
			clearInterval(this.mediaHitInterval);
			this.mediaHitInterval = null;
		},

		sendMediaMark: function( action ) {
			var params = this.getBaseParams();
			params['Action'] = action;
			this.sendPostRequest('MediaMark', params);
		},

		sendMediaHit: function() {
			// Do not send media hit in the following conditions: concurrent limit, current time not updated (might be error)
			if(this.concurrentFlag || this.getPlayer().getPlayerElementTime() === 0 ){
				return;
			}
			this.sendPostRequest('MediaHit', this.getBaseParams());
		},

		getProxyData: function( key ) {
			return this.getPlayer().getKalturaConfig('proxyData', key);
		},

		getCurrentTime: function() {
			var currentTime;
			if( this.playFromContinue ) {
				currentTime = this.continueTime;
			} else {
				currentTime = Math.round(this.getPlayer().getPlayerElementTime());
			}
			return currentTime;
		},

		getBaseParams: function() {
			return {
				"initObj": this.getProxyData('initObj'),
				"mediaType": 0,
				"iMediaID": this.getProxyData('MediaID'),
				"iFileID": this.fileId,
				"iLocation": this.getCurrentTime()
			};
		},

		sendPostRequest: function( service, params ) {
			// Do not send requests during ad playback
			if( !this.getPlayer().isInSequence() ) {
				this.getPlayer().triggerHelper(service, [service, params]);

				this.log('sendPostRequest: request: ' + service, params);
				var _this = this;
				$.ajax({
					url: this.getPlayer().getFlashvars('TVPAPIBaseUrl') + service,
					data: JSON.stringify(params),
					crossDomain: true,
					type: 'POST',
					dataType: 'text',
					success: function (data) {
						_this.log('sendPostRequest: response for ' + service + ': ' + data);
						if (data == '"Concurrent"') {
							_this.concurrentFlag = true;
							_this.getPlayer().triggerHelper('tvpapiShowConcurrent');
						}
					},
					error: function (xhr, textStatus, errorThrown) {
						_this.log('sendPostRequest error', errorThrown);
					}
				});
			}
		}

	}));
})(window.mw, window.jQuery);<|endoftext|>


<commit_before>import { isBrowser } from 'core';

const D = isBrowser ? window.document : {};
const scope = isBrowser ? window : global;

// Export globals for use in other modules
export const _$ = scope.WeeAlias || '$';
export const _doc = D;
export const _body = D.body;
export const _html = D.documentElement;
export const _slice = [].slice;
export const _win = scope;
export const U = undefined;<commit_msg>Correct import statement in core/variables<commit_after>import { isBrowser } from 'core/core';

const D = isBrowser ? window.document : {};
const scope = isBrowser ? window : global;

// Export globals for use in other modules
export const _$ = scope.WeeAlias || '$';
export const _doc = D;
export const _body = D.body;
export const _html = D.documentElement;
export const _slice = [].slice;
export const _win = scope;
export const U = undefined;<|endoftext|>


<commit_before>'use strict';

var API_KEY = window.GoogleSamples.Config.gcmAPIKey;
var GCM_ENDPOINT = 'https://android.googleapis.com/gcm/send';

var curlCommandDiv = document.querySelector('.js-curl-command');
var isPushEnabled = false;

// This method handles the removal of subscriptionId
// in Chrome 44 by concatenating the subscription Id
// to the subscription endpoint
function endpointWorkaround(pushSubscription) {
  console.log(pushSubscription);
  // Make sure we only mess with GCM
  if (pushSubscription.endpoint.indexOf('https://android.googleapis.com/gcm/send') !== 0) {
    return pushSubscription.endpoint;
  }

  var mergedEndpoint = pushSubscription.endpoint;
  // Chrome 42 + 43 will not have the subscriptionId attached
  // to the endpoint.
  if (pushSubscription.subscriptionId &&
    pushSubscription.endpoint.indexOf(pushSubscription.subscriptionId) === -1) {
    // Handle version 42 where you have separate subId and Endpoint
    mergedEndpoint = pushSubscription.endpoint + '/' +
      pushSubscription.subscriptionId;
  }
  return mergedEndpoint;
}

function sendSubscriptionToServer(subscription) {
  // TODO: Send the subscription.endpoint
  // to your server and save it to send a
  // push message at a later date
  //
  // For compatibly of Chrome 43, get the endpoint via
  // endpointWorkaround(subscription)
  console.log('TODO: Implement sendSubscriptionToServer()');

  var mergedEndpoint = endpointWorkaround(subscription);

  // This is just for demo purposes / an easy to test by
  // generating the appropriate cURL command
  // showCurlCommand(mergedEndpoint);
}

// NOTE: This code is only suitable for GCM endpoints,
// When another browser has a working version, alter
// this to send a PUSH request directly to the endpoint
function showCurlCommand(mergedEndpoint) {
  // The curl command to trigger a push message straight from GCM
  if (mergedEndpoint.indexOf(GCM_ENDPOINT) !== 0) {
    console.log('This browser isn\'t currently ' +
      'supported for this demo');
    return;
  }

  var endpointSections = mergedEndpoint.split('/');
  var subscriptionId = endpointSections[endpointSections.length - 1];

  var curlCommand = 'curl --header "Authorization: key=' + API_KEY +
    '" --header Content-Type:"application/json" ' + GCM_ENDPOINT +
    ' -d "{\\"registration_ids\\":[\\"' + subscriptionId + '\\"]}"';

  curlCommandDiv.textContent = curlCommand;
}

function unsubscribe() {
  var pushButton = document.querySelector('.js-push-button');
  pushButton.disabled = true;
  curlCommandDiv.textContent = '';

  navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
    // To unsubscribe from push messaging, you need get the
    // subcription object, which you can call unsubscribe() on.
    serviceWorkerRegistration.pushManager.getSubscription().then(
      function(pushSubscription) {
        // Check we have a subscription to unsubscribe
        if (!pushSubscription) {
          // No subscription object, so set the state
          // to allow the user to subscribe to push
          isPushEnabled = false;
          // pushButton.disabled = false;
          // pushButton.textContent = 'Enable Push Messages';
          return;
        }

        // TODO: Make a request to your server to remove
        // the users data from your data store so you
        // don't attempt to send them push messages anymore

        // We have a subcription, so call unsubscribe on it
        pushSubscription.unsubscribe().then(function(successful) {
          // pushButton.disabled = false;
          // pushButton.textContent = 'Enable Push Messages';
          isPushEnabled = false;
        }).catch(function(e) {
          // We failed to unsubscribe, this can lead to
          // an unusual state, so may be best to remove
          // the subscription id from your data store and
          // inform the user that you disabled push

          window.Demo.debug.log('Unsubscription error: ', e);
          // pushButton.disabled = false;
        });
      }).catch(function(e) {
        console.log('Error thrown while unsubscribing from ' +
          'push messaging.', e);
      });
  });
}

function subscribe() {
  // Disable the button so it can't be changed while
  // we process the permission request
  // var pushButton = document.querySelector('.js-push-button');
  // pushButton.disabled = true;

  navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
    serviceWorkerRegistration.pushManager.subscribe({userVisibleOnly: true})
      .then(function(subscription) {
        // The subscription was successful
        isPushEnabled = true;
        // pushButton.textContent = 'Disable Push Messages';
        // pushButton.disabled = false;

        // TODO: Send the subscription subscription.endpoint
        // to your server and save it to send a push message
        // at a later date
        return sendSubscriptionToServer(subscription);
      })
      .catch(function(e) {
        if (Notification.permission === 'denied') {
          // The user denied the notification permission which
          // means we failed to subscribe and the user will need
          // to manually change the notification permission to
          // subscribe to push messages
          console.log('Permission for Notifications was denied');
          // pushButton.disabled = true;
        } else {
          // A problem occurred with the subscription, this can
          // often be down to an issue or lack of the gcm_sender_id
          // and / or gcm_user_visible_only
          console.log('Unable to subscribe to push.', e);
          // pushButton.disabled = false;
          // pushButton.textContent = 'Enable Push Messages';
        }
      });
  });
}

// Once the service worker is registered set the initial state
function initialiseState() {
  console.log(ServiceWorkerRegistration.prototype);
  console.log(Notification.permission);
  // Are Notifications supported in the service worker?
  if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
    console.log('Notifications aren\'t supported.');
    return;
  }

  // Check the current Notification permission.
  // If its denied, it's a permanent block until the
  // user changes the permission
  if (Notification.permission === 'denied') {
    console.log('The user has blocked notifications.');
    return;
  }

  // Check if push messaging is supported
  if (!('PushManager' in window)) {
    console.log('Push messaging isn\'t supported.');
    return;
  }

  // We need the service worker registration to check for a subscription
  navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {

    console.log(serviceWorkerRegistration);
    // Do we already have a push message subscription?
    serviceWorkerRegistration.pushManager.getSubscription()
      .then(function(subscription) {
        // Enable any UI which subscribes / unsubscribes from
        // push messages.
        // var pushButton = document.querySelector('.js-push-button');
        // pushButton.disabled = false;

        if (!subscription) {
          // We aren’t subscribed to push, so set UI
          // to allow the user to enable push
          return;
        }

        // Keep your server in sync with the latest subscription
        sendSubscriptionToServer(subscription);

        // Set your UI to show they have subscribed for
        // push messages
        // pushButton.textContent = 'Disable Push Messages';
        isPushEnabled = true;
      })
      .catch(function(err) {
        console.log('Error during getSubscription()', err);
      });
  });
}

window.addEventListener('load', function() {
  // var pushButton = document.querySelector('.js-push-button');
  // pushButton.addEventListener('click', function() {
  //   if (isPushEnabled) {
  //     unsubscribe();
  //   } else {
  //     subscribe();
  //   }
  // });

  subscribe();

  // Check that service workers are supported, if so, progressively
  // enhance and add push messaging support, otherwise continue without it.
  console.log(navigator);
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('./service-worker.js')
    .then(initialiseState);
  } else {
    console.log('Service workers aren\'t supported in this browser.');
  }
});<commit_msg>update push code<commit_after>'use strict';

var API_KEY = window.GoogleSamples.Config.gcmAPIKey;
var GCM_ENDPOINT = 'https://android.googleapis.com/gcm/send';

var curlCommandDiv = document.querySelector('.js-curl-command');
var isPushEnabled = false;

// This method handles the removal of subscriptionId
// in Chrome 44 by concatenating the subscription Id
// to the subscription endpoint
function endpointWorkaround(pushSubscription) {
  console.log(pushSubscription);
  // Make sure we only mess with GCM
  if (pushSubscription.endpoint.indexOf('https://android.googleapis.com/gcm/send') !== 0) {
    return pushSubscription.endpoint;
  }

  var mergedEndpoint = pushSubscription.endpoint;
  // Chrome 42 + 43 will not have the subscriptionId attached
  // to the endpoint.
  if (pushSubscription.subscriptionId &&
    pushSubscription.endpoint.indexOf(pushSubscription.subscriptionId) === -1) {
    // Handle version 42 where you have separate subId and Endpoint
    mergedEndpoint = pushSubscription.endpoint + '/' +
      pushSubscription.subscriptionId;
  }
  return mergedEndpoint;
}

function sendSubscriptionToServer(subscription) {
  // TODO: Send the subscription.endpoint
  // to your server and save it to send a
  // push message at a later date
  //
  console.log('TODO: Implement sendSubscriptionToServer()');

  var endpoint = subscription.endpoint;

}

// NOTE: This code is only suitable for GCM endpoints,
// When another browser has a working version, alter
// this to send a PUSH request directly to the endpoint
function showCurlCommand(mergedEndpoint) {
  // The curl command to trigger a push message straight from GCM
  if (mergedEndpoint.indexOf(GCM_ENDPOINT) !== 0) {
    console.log('This browser isn\'t currently ' +
      'supported for this demo');
    return;
  }

  var endpointSections = mergedEndpoint.split('/');
  var subscriptionId = endpointSections[endpointSections.length - 1];

  var curlCommand = 'curl --header "Authorization: key=' + API_KEY +
    '" --header Content-Type:"application/json" ' + GCM_ENDPOINT +
    ' -d "{\\"registration_ids\\":[\\"' + subscriptionId + '\\"]}"';

  curlCommandDiv.textContent = curlCommand;
}

function unsubscribe() {
  var pushButton = document.querySelector('.js-push-button');
  pushButton.disabled = true;
  curlCommandDiv.textContent = '';

  navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
    // To unsubscribe from push messaging, you need get the
    // subcription object, which you can call unsubscribe() on.
    serviceWorkerRegistration.pushManager.getSubscription().then(
      function(pushSubscription) {
        // Check we have a subscription to unsubscribe
        if (!pushSubscription) {
          // No subscription object, so set the state
          // to allow the user to subscribe to push
          isPushEnabled = false;
          // pushButton.disabled = false;
          // pushButton.textContent = 'Enable Push Messages';
          return;
        }

        // TODO: Make a request to your server to remove
        // the users data from your data store so you
        // don't attempt to send them push messages anymore

        // We have a subcription, so call unsubscribe on it
        pushSubscription.unsubscribe().then(function(successful) {
          // pushButton.disabled = false;
          // pushButton.textContent = 'Enable Push Messages';
          isPushEnabled = false;
        }).catch(function(e) {
          // We failed to unsubscribe, this can lead to
          // an unusual state, so may be best to remove
          // the subscription id from your data store and
          // inform the user that you disabled push

          window.Demo.debug.log('Unsubscription error: ', e);
          // pushButton.disabled = false;
        });
      }).catch(function(e) {
        console.log('Error thrown while unsubscribing from ' +
          'push messaging.', e);
      });
  });
}

function subscribe() {
  // Disable the button so it can't be changed while
  // we process the permission request
  // var pushButton = document.querySelector('.js-push-button');
  // pushButton.disabled = true;

  navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
    serviceWorkerRegistration.pushManager.subscribe({userVisibleOnly: true})
      .then(function(subscription) {
        // The subscription was successful
        isPushEnabled = true;
        // pushButton.textContent = 'Disable Push Messages';
        // pushButton.disabled = false;

        // TODO: Send the subscription subscription.endpoint
        // to your server and save it to send a push message
        // at a later date
        return sendSubscriptionToServer(subscription);
      })
      .catch(function(e) {
        if (Notification.permission === 'denied') {
          // The user denied the notification permission which
          // means we failed to subscribe and the user will need
          // to manually change the notification permission to
          // subscribe to push messages
          console.log('Permission for Notifications was denied');
          // pushButton.disabled = true;
        } else {
          // A problem occurred with the subscription, this can
          // often be down to an issue or lack of the gcm_sender_id
          // and / or gcm_user_visible_only
          console.log('Unable to subscribe to push.', e);
          // pushButton.disabled = false;
          // pushButton.textContent = 'Enable Push Messages';
        }
      });
  });
}

// Once the service worker is registered set the initial state
function initialiseState() {
  console.log(ServiceWorkerRegistration.prototype);
  console.log(Notification.permission);
  // Are Notifications supported in the service worker?
  if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
    console.log('Notifications aren\'t supported.');
    return;
  }

  // Check the current Notification permission.
  // If its denied, it's a permanent block until the
  // user changes the permission
  if (Notification.permission === 'denied') {
    console.log('The user has blocked notifications.');
    return;
  }

  // Check if push messaging is supported
  if (!('PushManager' in window)) {
    console.log('Push messaging isn\'t supported.');
    return;
  }

  // We need the service worker registration to check for a subscription
  navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {

    console.log(serviceWorkerRegistration);
    // Do we already have a push message subscription?
    serviceWorkerRegistration.pushManager.getSubscription()
      .then(function(subscription) {
        // Enable any UI which subscribes / unsubscribes from
        // push messages.
        // var pushButton = document.querySelector('.js-push-button');
        // pushButton.disabled = false;

        if (!subscription) {
          // We aren’t subscribed to push, so set UI
          // to allow the user to enable push
          return;
        }

        // Keep your server in sync with the latest subscription
        sendSubscriptionToServer(subscription);

        // Set your UI to show they have subscribed for
        // push messages
        // pushButton.textContent = 'Disable Push Messages';
        isPushEnabled = true;
      })
      .catch(function(err) {
        console.log('Error during getSubscription()', err);
      });
  });
}

window.addEventListener('load', function() {
  // var pushButton = document.querySelector('.js-push-button');
  // pushButton.addEventListener('click', function() {
  //   if (isPushEnabled) {
  //     unsubscribe();
  //   } else {
  //     subscribe();
  //   }
  // });

  subscribe();

  // Check that service workers are supported, if so, progressively
  // enhance and add push messaging support, otherwise continue without it.
  console.log(navigator);
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('./service-worker.js')
    .then(initialiseState);
  } else {
    console.log('Service workers aren\'t supported in this browser.');
  }
});<|endoftext|>


<commit_before>/**
 * Blockly Demo: Turtle Graphics
 *
 * Copyright 2012 Google Inc.
 * http://blockly.googlecode.com/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Demonstration of Blockly: Turtle Graphics.
 * @author fraser@google.com (Neil Fraser)
 */
'use strict';

/**
 * Create a namespace for the application.
 */
var Turtle = {};

document.write(turtlepage.start({}, null,
    {MSG: MSG}));

Turtle.HEIGHT = 400;
Turtle.WIDTH = 400;

/**
 * PID of animation task currently executing.
 */
Turtle.pid = 0;

/**
 * Should the turtle be drawn?
 */
Turtle.visible = true;

/**
 * Initialize Blockly and the turtle.  Called on page load.
 */
Turtle.init = function() {
  // document.dir fails in Mozilla, use document.body.parentNode.dir instead.
  // https://bugzilla.mozilla.org/show_bug.cgi?id=151407
  var rtl = document.body.parentNode.dir == 'rtl';
  var toolbox = document.getElementById('toolbox');
  Blockly.inject(document.getElementById('blockly'),
      {path: '../../',
       rtl: rtl,
       toolbox: toolbox,
       trashcan: true});

  Blockly.JavaScript.INFINITE_LOOP_TRAP = '  Blockly.Apps.checkTimeout(%1);\n';

  // Add to reserved word list: API, local variables in execution evironment
  // (execute) and the infinite loop detection function.
  Blockly.JavaScript.addReservedWords('Turtle,code');

  window.addEventListener('beforeunload', function(e) {
    if (Blockly.mainWorkspace.getAllBlocks().length > 2) {
      e.returnValue = MSG.unloadWarning;  // Gecko.
      return MSG.unloadWarning;  // Webkit.
    }
    return null;
  });
  var blocklyDiv = document.getElementById('blockly');
  var onresize = function(e) {
    blocklyDiv.style.width = (window.innerWidth - blocklyDiv.offsetLeft - 18) +
        'px';
    blocklyDiv.style.height = (window.innerHeight - 22) + 'px';
  };
  window.addEventListener('resize', onresize);
  onresize();

  if (!('BlocklyStorage' in window)) {
    document.getElementById('linkButton').className = 'disabled';
  }

  // Initialize the slider.
  var sliderSvg = document.getElementById('slider');
  Turtle.speedSlider = new Slider(10, 35, 130, sliderSvg);

  // Add the starting block(s).
  // An href with #key trigers an AJAX call to retrieve saved blocks.
  if ('BlocklyStorage' in window && window.location.hash.length > 1) {
    BlocklyStorage.retrieveXml(window.location.hash.substring(1));
  } else {
    // Load the editor with starting blocks.
    var xml = '<xml>' +
        '  <block type="draw_move" x="70" y="70">' +
        '    <value name="VALUE">' +
        '      <block type="math_number">' +
        '        <title name="NUM">10</title>' +
        '      </block>' +
        '    </value>' +
        '  </block>' +
        '</xml>';
    xml = Blockly.Xml.textToDom(xml);
    Blockly.Xml.domToWorkspace(Blockly.mainWorkspace, xml);
  }

  Turtle.ctxDisplay = document.getElementById('display').getContext('2d');
  Turtle.ctxScratch = document.getElementById('scratch').getContext('2d');
  Turtle.reset();
};

window.addEventListener('load', Turtle.init);

/**
 * Reset the turtle to the start position, clear the display, and kill any
 * pending tasks.
 */
Turtle.reset = function() {
  // Starting location and heading of the turtle.
  Turtle.x = Turtle.HEIGHT / 2;
  Turtle.y = Turtle.WIDTH / 2;
  Turtle.heading = 0;
  Turtle.penDownValue = true;
  Turtle.visible = true;

  // Clear the display.
  Turtle.ctxScratch.canvas.width = Turtle.ctxScratch.canvas.width;
  Turtle.ctxScratch.strokeStyle = '#000000';
  Turtle.ctxScratch.lineWidth = 1;
  Turtle.ctxScratch.lineCap = 'round';
  Turtle.display();

  // Kill any task.
  if (Turtle.pid) {
    window.clearTimeout(Turtle.pid);
  }
  Turtle.pid = 0;
};

/**
 * Copy the scratch canvas to the display canvas. Add a turtle marker.
 */
Turtle.display = function() {
  Turtle.ctxDisplay.globalCompositeOperation = 'copy';
  Turtle.ctxDisplay.drawImage(Turtle.ctxScratch.canvas, 0, 0);
  Turtle.ctxDisplay.globalCompositeOperation = 'source-over';

  if (Turtle.visible) {
    // Draw the turtle body.
    var radius = Turtle.ctxScratch.lineWidth / 2 + 10;
    Turtle.ctxDisplay.beginPath();
    Turtle.ctxDisplay.arc(Turtle.x, Turtle.y, radius, 0, 2 * Math.PI, false);
    Turtle.ctxDisplay.lineWidth = 3;
    Turtle.ctxDisplay.strokeStyle = '#339933';
    Turtle.ctxDisplay.stroke();

    // Draw the turtle head.
    var WIDTH = 0.3;
    var HEAD_TIP = 10;
    var ARROW_TIP = 4;
    var BEND = 6;
    var radians = 2 * Math.PI * Turtle.heading / 360;
    var tipX = Turtle.x + (radius + HEAD_TIP) * Math.sin(radians);
    var tipY = Turtle.y - (radius + HEAD_TIP) * Math.cos(radians);
    radians -= WIDTH;
    var leftX = Turtle.x + (radius + ARROW_TIP) * Math.sin(radians);
    var leftY = Turtle.y - (radius + ARROW_TIP) * Math.cos(radians);
    radians += WIDTH / 2;
    var leftControlX = Turtle.x + (radius + BEND) * Math.sin(radians);
    var leftControlY = Turtle.y - (radius + BEND) * Math.cos(radians);
    radians += WIDTH;
    var rightControlX = Turtle.x + (radius + BEND) * Math.sin(radians);
    var rightControlY = Turtle.y - (radius + BEND) * Math.cos(radians);
    radians += WIDTH / 2;
    var rightX = Turtle.x + (radius + ARROW_TIP) * Math.sin(radians);
    var rightY = Turtle.y - (radius + ARROW_TIP) * Math.cos(radians);
    Turtle.ctxDisplay.beginPath();
    Turtle.ctxDisplay.fillStyle = '#339933';
    Turtle.ctxDisplay.moveTo(tipX, tipY);
    Turtle.ctxDisplay.lineTo(leftX, leftY);
    Turtle.ctxDisplay.bezierCurveTo(leftControlX, leftControlY,
        rightControlX, rightControlY, rightX, rightY);
    Turtle.ctxDisplay.closePath();
    Turtle.ctxDisplay.fill();
  }
};

/**
 * Click the run button.  Start the program.
 */
Turtle.runButtonClick = function() {
  document.getElementById('runButton').style.display = 'none';
  document.getElementById('resetButton').style.display = 'inline';
  document.getElementById('spinner').style.visibility = 'visible';
  Blockly.mainWorkspace.traceOn(true);
  Turtle.execute();
};

/**
 * Click the reset button.  Reset the Turtle.
 */
Turtle.resetButtonClick = function() {
  document.getElementById('runButton').style.display = 'inline';
  document.getElementById('resetButton').style.display = 'none';
  document.getElementById('spinner').style.visibility = 'hidden';
  Blockly.mainWorkspace.traceOn(false);
  Turtle.reset();
};

/**
 * Execute the user's code.  Heaven help us...
 */
Turtle.execute = function() {
  Blockly.Apps.log = [];
  Blockly.Apps.ticks = 1000000;

  var code = Blockly.Generator.workspaceToCode('JavaScript');
  try {
    eval(code);
  } catch (e) {
    // Null is thrown for infinite loop.
    // Otherwise, abnormal termination is a user error.
    if (e !== null) {
      alert(e);
    }
  }

  // Blockly.Apps.log now contains a transcript of all the user's actions.
  // Reset the graphic and animate the transcript.
  Turtle.reset();
  Turtle.pid = window.setTimeout(Turtle.animate, 100);
};

/**
 * Show the user's code in raw JavaScript.
 */
Turtle.showCode = function() {
  var code = Blockly.Generator.workspaceToCode('JavaScript');
  // Strip out serial numbers.
  code = code.replace(/(,\s*)?'\d+'\)/g, ')');
  alert(code);
};

/**
 * Iterate through the recorded path and animate the turtle's actions.
 */
Turtle.animate = function() {
  // All tasks should be complete now.  Clean up the PID list.
  Turtle.pid = 0;

  var tuple = Blockly.Apps.log.shift();
  if (!tuple) {
    document.getElementById('spinner').style.visibility = 'hidden';
    Blockly.mainWorkspace.highlightBlock(null);
    return;
  }
  Blockly.mainWorkspace.highlightBlock(tuple.pop());

  switch (tuple[0]) {
    case 'FD':  // Forward
      if (Turtle.penDownValue) {
        Turtle.ctxScratch.beginPath();
        Turtle.ctxScratch.moveTo(Turtle.x, Turtle.y);
      }
      var distance = tuple[1];
      if (distance) {
        Turtle.x += distance * Math.sin(2 * Math.PI * Turtle.heading / 360);
        Turtle.y -= distance * Math.cos(2 * Math.PI * Turtle.heading / 360);
        var bump = 0;
      } else {
        // WebKit (unlike Gecko) draws nothing for a zero-length line.
        var bump = 0.1;
      }
      if (Turtle.penDownValue) {
        Turtle.ctxScratch.lineTo(Turtle.x, Turtle.y + bump);
        Turtle.ctxScratch.stroke();
      }
      break;
    case 'RT':  // Right Turn
      Turtle.heading += tuple[1];
      Turtle.heading %= 360;
      if (Turtle.heading < 0) {
        Turtle.heading += 360;
      }
      break;
    case 'PU':  // Pen Up
      Turtle.penDownValue = false;
      break;
    case 'PD':  // Pen Down
      Turtle.penDownValue = true;
      break;
    case 'PW':  // Pen Width
      Turtle.ctxScratch.lineWidth = tuple[1];
      break;
    case 'PC':  // Pen Color
      Turtle.ctxScratch.strokeStyle = tuple[1];
      break;
    case 'HT':  // Hide Turtle
      Turtle.visible = false;
      break;
    case 'ST':  // Show Turtle
      Turtle.visible = true;
      break;
  }
  Turtle.display();

  // Scale the speed non-linearly, to give better precision at the fast end.
  var stepSpeed = 1000 * Math.pow(Turtle.speedSlider.getValue(), 2);
  Turtle.pid = window.setTimeout(Turtle.animate, stepSpeed);
};

// Turtle API.

Turtle.moveForward = function(distance, id) {
  Blockly.Apps.log.push(['FD', distance, id]);
};

Turtle.moveBackward = function(distance, id) {
  Blockly.Apps.log.push(['FD', -distance, id]);
};

Turtle.turnRight = function(angle, id) {
  Blockly.Apps.log.push(['RT', angle, id]);
};

Turtle.turnLeft = function(angle, id) {
  Blockly.Apps.log.push(['RT', -angle, id]);
};

Turtle.penUp = function(id) {
  Blockly.Apps.log.push(['PU', id]);
};

Turtle.penDown = function(id) {
  Blockly.Apps.log.push(['PD', id]);
};

Turtle.penWidth = function(width, id) {
  Blockly.Apps.log.push(['PW', Math.max(width, 0), id]);
};

Turtle.penColour = function(colour, id) {
  Blockly.Apps.log.push(['PC', colour, id]);
};

Turtle.hideTurtle = function(id) {
  Blockly.Apps.log.push(['HT', id]);
};

Turtle.showTurtle = function(id) {
  Blockly.Apps.log.push(['ST', id]);
};
<commit_msg>Add answers to Turtle levels (MOOC branch). Review URL: https://codereview.appspot.com/9097044<commit_after>/**
 * Blockly Demo: Turtle Graphics
 *
 * Copyright 2012 Google Inc.
 * http://blockly.googlecode.com/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Demonstration of Blockly: Turtle Graphics.
 * @author fraser@google.com (Neil Fraser)
 */
'use strict';

/**
 * Create a namespace for the application.
 */
var Turtle = {};

document.write(turtlepage.start({}, null,
    {MSG: MSG}));

Turtle.HEIGHT = 400;
Turtle.WIDTH = 400;

/**
 * PID of animation task currently executing.
 */
Turtle.pid = 0;

/**
 * Should the turtle be drawn?
 */
Turtle.visible = true;

/**
 * Initialize Blockly and the turtle.  Called on page load.
 */
Turtle.init = function() {
  // document.dir fails in Mozilla, use document.body.parentNode.dir instead.
  // https://bugzilla.mozilla.org/show_bug.cgi?id=151407
  var rtl = document.body.parentNode.dir == 'rtl';
  var toolbox = document.getElementById('toolbox');
  Blockly.inject(document.getElementById('blockly'),
      {path: '../../',
       rtl: rtl,
       toolbox: toolbox,
       trashcan: true});

  Blockly.JavaScript.INFINITE_LOOP_TRAP = '  Blockly.Apps.checkTimeout(%1);\n';

  // Add to reserved word list: API, local variables in execution evironment
  // (execute) and the infinite loop detection function.
  Blockly.JavaScript.addReservedWords('Turtle,code');

  window.addEventListener('beforeunload', function(e) {
    if (Blockly.mainWorkspace.getAllBlocks().length > 2) {
      e.returnValue = MSG.unloadWarning;  // Gecko.
      return MSG.unloadWarning;  // Webkit.
    }
    return null;
  });
  var blocklyDiv = document.getElementById('blockly');
  var onresize = function(e) {
    blocklyDiv.style.width = (window.innerWidth - blocklyDiv.offsetLeft - 18) +
        'px';
    blocklyDiv.style.height = (window.innerHeight - 22) + 'px';
  };
  window.addEventListener('resize', onresize);
  onresize();

  if (!('BlocklyStorage' in window)) {
    document.getElementById('linkButton').className = 'disabled';
  }

  // Initialize the slider.
  var sliderSvg = document.getElementById('slider');
  Turtle.speedSlider = new Slider(10, 35, 130, sliderSvg);

  // Add the starting block(s).
  // An href with #key trigers an AJAX call to retrieve saved blocks.
  if ('BlocklyStorage' in window && window.location.hash.length > 1) {
    BlocklyStorage.retrieveXml(window.location.hash.substring(1));
  } else {
    // Load the editor with starting blocks.
    var xml = '<xml>' +
        '  <block type="draw_move" x="70" y="70">' +
        '    <value name="VALUE">' +
        '      <block type="math_number">' +
        '        <title name="NUM">10</title>' +
        '      </block>' +
        '    </value>' +
        '  </block>' +
        '</xml>';
    xml = Blockly.Xml.textToDom(xml);
    Blockly.Xml.domToWorkspace(Blockly.mainWorkspace, xml);
  }

  Turtle.ctxDisplay = document.getElementById('display').getContext('2d');
  Turtle.ctxScratch = document.getElementById('scratch').getContext('2d');
  Turtle.reset();
};

window.addEventListener('load', Turtle.init);

/**
 * Reset the turtle to the start position, clear the display, and kill any
 * pending tasks.
 */
Turtle.reset = function() {
  // Starting location and heading of the turtle.
  Turtle.x = Turtle.HEIGHT / 2;
  Turtle.y = Turtle.WIDTH / 2;
  Turtle.heading = 0;
  Turtle.penDownValue = true;
  Turtle.visible = true;

  // Clear the display.
  Turtle.ctxScratch.canvas.width = Turtle.ctxScratch.canvas.width;
  Turtle.ctxScratch.strokeStyle = '#000000';
  Turtle.ctxScratch.lineWidth = 1;
  Turtle.ctxScratch.lineCap = 'round';
  Turtle.display();

  // Kill any task.
  if (Turtle.pid) {
    window.clearTimeout(Turtle.pid);
  }
  Turtle.pid = 0;
};

/**
 * Copy the scratch canvas to the display canvas. Add a turtle marker.
 */
Turtle.display = function() {
  Turtle.ctxDisplay.globalCompositeOperation = 'copy';
  Turtle.ctxDisplay.drawImage(Turtle.ctxScratch.canvas, 0, 0);
  Turtle.ctxDisplay.globalCompositeOperation = 'source-over';

  if (Turtle.visible) {
    // Draw the turtle body.
    var radius = Turtle.ctxScratch.lineWidth / 2 + 10;
    Turtle.ctxDisplay.beginPath();
    Turtle.ctxDisplay.arc(Turtle.x, Turtle.y, radius, 0, 2 * Math.PI, false);
    Turtle.ctxDisplay.lineWidth = 3;
    Turtle.ctxDisplay.strokeStyle = '#339933';
    Turtle.ctxDisplay.stroke();

    // Draw the turtle head.
    var WIDTH = 0.3;
    var HEAD_TIP = 10;
    var ARROW_TIP = 4;
    var BEND = 6;
    var radians = 2 * Math.PI * Turtle.heading / 360;
    var tipX = Turtle.x + (radius + HEAD_TIP) * Math.sin(radians);
    var tipY = Turtle.y - (radius + HEAD_TIP) * Math.cos(radians);
    radians -= WIDTH;
    var leftX = Turtle.x + (radius + ARROW_TIP) * Math.sin(radians);
    var leftY = Turtle.y - (radius + ARROW_TIP) * Math.cos(radians);
    radians += WIDTH / 2;
    var leftControlX = Turtle.x + (radius + BEND) * Math.sin(radians);
    var leftControlY = Turtle.y - (radius + BEND) * Math.cos(radians);
    radians += WIDTH;
    var rightControlX = Turtle.x + (radius + BEND) * Math.sin(radians);
    var rightControlY = Turtle.y - (radius + BEND) * Math.cos(radians);
    radians += WIDTH / 2;
    var rightX = Turtle.x + (radius + ARROW_TIP) * Math.sin(radians);
    var rightY = Turtle.y - (radius + ARROW_TIP) * Math.cos(radians);
    Turtle.ctxDisplay.beginPath();
    Turtle.ctxDisplay.fillStyle = '#339933';
    Turtle.ctxDisplay.moveTo(tipX, tipY);
    Turtle.ctxDisplay.lineTo(leftX, leftY);
    Turtle.ctxDisplay.bezierCurveTo(leftControlX, leftControlY,
        rightControlX, rightControlY, rightX, rightY);
    Turtle.ctxDisplay.closePath();
    Turtle.ctxDisplay.fill();
  }
};

/**
 * Click the run button.  Start the program.
 */
Turtle.runButtonClick = function() {
  document.getElementById('runButton').style.display = 'none';
  document.getElementById('resetButton').style.display = 'inline';
  document.getElementById('spinner').style.visibility = 'visible';
  Blockly.mainWorkspace.traceOn(true);
  Turtle.execute();
};

/**
 * Click the reset button.  Reset the Turtle.
 */
Turtle.resetButtonClick = function() {
  document.getElementById('runButton').style.display = 'inline';
  document.getElementById('resetButton').style.display = 'none';
  document.getElementById('spinner').style.visibility = 'hidden';
  Blockly.mainWorkspace.traceOn(false);
  Turtle.reset();
};

/**
 * Execute the user's code.  Heaven help us...
 */
Turtle.execute = function() {
  Blockly.Apps.log = [];
  Blockly.Apps.ticks = 1000000;

  var code = Blockly.Generator.workspaceToCode('JavaScript');
  try {
    eval(code);
  } catch (e) {
    // Null is thrown for infinite loop.
    // Otherwise, abnormal termination is a user error.
    if (e !== null) {
      alert(e);
    }
  }

  // Blockly.Apps.log now contains a transcript of all the user's actions.
  // Reset the graphic and animate the transcript.
  Turtle.reset();
  Turtle.pid = window.setTimeout(Turtle.animate, 100);
};

/**
 * Show the user's code in raw JavaScript.
 */
Turtle.showCode = function() {
  var code = Blockly.Generator.workspaceToCode('JavaScript');
  // Strip out serial numbers.
  code = code.replace(/(,\s*)?'\d+'\)/g, ')');
  alert(code);
};

/**
 * Iterate through the recorded path and animate the turtle's actions.
 */
Turtle.animate = function() {
  // All tasks should be complete now.  Clean up the PID list.
  Turtle.pid = 0;

  var tuple = Blockly.Apps.log.shift();
  if (!tuple) {
    document.getElementById('spinner').style.visibility = 'hidden';
    Blockly.mainWorkspace.highlightBlock(null);
    return;
  }
  var command = tuple.shift();
  var id = tuple.pop();
  Blockly.mainWorkspace.highlightBlock(id);
  Turtle.step(command, tuple);
  Turtle.display();

  // Scale the speed non-linearly, to give better precision at the fast end.
  var stepSpeed = 1000 * Math.pow(Turtle.speedSlider.getValue(), 2);
  Turtle.pid = window.setTimeout(Turtle.animate, stepSpeed);
};

/**
 * Execute one step.
 * @param {string} command Logo-style command (e.g. 'FD' or 'RT').
 * @param {!Array} values List of arguments for the cammand.
 */
Turtle.step = function(command, values) {
  switch (command) {
    case 'FD':  // Forward
      if (Turtle.penDownValue) {
        Turtle.ctxScratch.beginPath();
        Turtle.ctxScratch.moveTo(Turtle.x, Turtle.y);
      }
      var distance = values[0];
      if (distance) {
        Turtle.x += distance * Math.sin(2 * Math.PI * Turtle.heading / 360);
        Turtle.y -= distance * Math.cos(2 * Math.PI * Turtle.heading / 360);
        var bump = 0;
      } else {
        // WebKit (unlike Gecko) draws nothing for a zero-length line.
        var bump = 0.1;
      }
      if (Turtle.penDownValue) {
        Turtle.ctxScratch.lineTo(Turtle.x, Turtle.y + bump);
        Turtle.ctxScratch.stroke();
      }
      break;
    case 'RT':  // Right Turn
      Turtle.heading += values[0];
      Turtle.heading %= 360;
      if (Turtle.heading < 0) {
        Turtle.heading += 360;
      }
      break;
    case 'PU':  // Pen Up
      Turtle.penDownValue = false;
      break;
    case 'PD':  // Pen Down
      Turtle.penDownValue = true;
      break;
    case 'PW':  // Pen Width
      Turtle.ctxScratch.lineWidth = values[0];
      break;
    case 'PC':  // Pen Color
      Turtle.ctxScratch.strokeStyle = values[0];
      break;
    case 'HT':  // Hide Turtle
      Turtle.visible = false;
      break;
    case 'ST':  // Show Turtle
      Turtle.visible = true;
      break;
  }
};

// Turtle API.

Turtle.moveForward = function(distance, id) {
  Blockly.Apps.log.push(['FD', distance, id]);
};

Turtle.moveBackward = function(distance, id) {
  Blockly.Apps.log.push(['FD', -distance, id]);
};

Turtle.turnRight = function(angle, id) {
  Blockly.Apps.log.push(['RT', angle, id]);
};

Turtle.turnLeft = function(angle, id) {
  Blockly.Apps.log.push(['RT', -angle, id]);
};

Turtle.penUp = function(id) {
  Blockly.Apps.log.push(['PU', id]);
};

Turtle.penDown = function(id) {
  Blockly.Apps.log.push(['PD', id]);
};

Turtle.penWidth = function(width, id) {
  Blockly.Apps.log.push(['PW', Math.max(width, 0), id]);
};

Turtle.penColour = function(colour, id) {
  Blockly.Apps.log.push(['PC', colour, id]);
};

Turtle.hideTurtle = function(id) {
  Blockly.Apps.log.push(['HT', id]);
};

Turtle.showTurtle = function(id) {
  Blockly.Apps.log.push(['ST', id]);
};
<|endoftext|>


<commit_before>'use strict';

angular.module('copayApp.controllers').controller('CopayersController',
  function($scope, $rootScope, $location, backupService, walletFactory, controllerUtils) {

    $scope.backup = function() {
      var w = $rootScope.wallet;
      w.setBackupReady();
      backupService.download(w);
    };

    $scope.downloadBackup = function() {
      var w = $rootScope.wallet;
      backupService.download(w);
    }

    $scope.goToWallet = function() {
      controllerUtils.updateGlobalAddresses();
      $location.path('/receive');
    };

    $scope.deleteWallet = function() {
      var w = $rootScope.wallet;
      w.disconnect();
      walletFactory.delete(w.id, function() {
        controllerUtils.logout();
      });
    };

    // Cached list of copayers
    $scope.copayers = $rootScope.wallet.getRegisteredPeerIds();

    $scope.copayersList = function() {
      return $rootScope.wallet.getRegisteredPeerIds();
    }

    $scope.isBackupReady = function(copayer) {
      return $rootScope.wallet.publicKeyRing.isBackupReady(copayer.copayerId);
    }

  });
<commit_msg>Fixes: delete wallet on the intermediate screen<commit_after>'use strict';

angular.module('copayApp.controllers').controller('CopayersController',
  function($scope, $rootScope, $location, backupService, walletFactory, controllerUtils) {

    $scope.backup = function() {
      var w = $rootScope.wallet;
      w.setBackupReady();
      backupService.download(w);
    };

    $scope.downloadBackup = function() {
      var w = $rootScope.wallet;
      backupService.download(w);
    }

    $scope.goToWallet = function() {
      controllerUtils.updateGlobalAddresses();
      $location.path('/receive');
    };

    $scope.deleteWallet = function() {
      var w = $rootScope.wallet;
      walletFactory.delete(w.id, function() {
        controllerUtils.logout();
      });
    };

    // Cached list of copayers
    $scope.copayers = $rootScope.wallet.getRegisteredPeerIds();

    $scope.copayersList = function() {
      return $rootScope.wallet.getRegisteredPeerIds();
    }

    $scope.isBackupReady = function(copayer) {
      return $rootScope.wallet.publicKeyRing.isBackupReady(copayer.copayerId);
    }

  });
<|endoftext|>


<commit_before>const fastify = require("fastify")();
const handlers = require("./handlers");

fastify.register(require("point-of-view"), {
  engine: {
    ejs: require("handlebars")
  },
  templates: __dirname + "/views"
});

fastify.use((req, reply, next) => {
  reply.setHeader("Server", "Fastify");

  next();
});

fastify.get("/json", (req, reply) => {
  reply
    .header("Content-Type", "application/json")
    .code(200)
    .send({ message: "Hello, World!" });
});

fastify.get("/plaintext", (req, reply) => {
  reply
    .header("Content-Type", "text/plain")
    .code(200)
    .send("Hello, World!");
});

const database = process.env.DATABASE;

if (database) {
  const dbLayer = require(`./db/${database}`);
  const routerHandler = handlers(dbLayer);

  fastify.get("/db", routerHandler.singleQuery);
  fastify.get("/queries", routerHandler.multipleQueries);
  fastify.get("/fortunes", routerHandler.fortunes);
  fastify.get("/updates", routerHandler.updates);
}

fastify.listen(8080, "0.0.0.0", err => {
  if (err) {
    throw err;
  }

  console.log(
    `Worker started and listening on http://0.0.0.0:8080 ${new Date().toISOString()}`
  );
});
<commit_msg>Squashed commit of the following: (#5569)<commit_after>const fastify = require("fastify")();
const handlers = require("./handlers");

fastify.register(require("point-of-view"), {
  engine: {
    ejs: require("handlebars")
  },
  templates: __dirname + "/views"
});

fastify.addHook('onRequest', (request, reply, done) => {
  reply.setHeader("Server", "Fastify");
  done()
})

fastify.get("/json", {
  schema: {
    response: {
      200: {
        type: 'object',
        properties: {
          message: { type: 'string' }
        }
      }
    }
  }
}, (req, reply) => {
  reply
    .header("Content-Type", "application/json")
    .code(200)
    .send({ message: "Hello, World!" });
});

fastify.get("/plaintext", (req, reply) => {
  reply
    .header("Content-Type", "text/plain")
    .code(200)
    .send("Hello, World!");
});

const database = process.env.DATABASE;

if (database) {
  const dbLayer = require(`./db/${database}`);
  const routerHandler = handlers(dbLayer);

  const itemSchema = {
    type: 'object',
    properties: {
      id: { type: 'integer' },
      message: { type: 'string' },
      randomNumber: { type: 'integer' }
    }
  }

  if (database === 'postgres') {
    // postgres return lowercase columns
    itemSchema.properties.randomnumber = { type: 'integer' };
  }

  const singleQuerySchema = {
    schema: {
      response:{
        200: itemSchema
      }
    }
  }

  const multipleQueriesSchema = {
    schema: {
      response:{
        200: {
          type: 'array',
          items: itemSchema
        }
      }
    }
  }

  const updateSchema = {
    schema: {
      response:{
        200: {
          type: 'array',
          items: itemSchema
        }
      }
    }
  }

  fastify.get("/db", singleQuerySchema, routerHandler.singleQuery);
  fastify.get("/queries", multipleQueriesSchema, routerHandler.multipleQueries);
  fastify.get("/fortunes", routerHandler.fortunes);
  fastify.get("/updates", updateSchema, routerHandler.updates);
}

fastify.listen(8080, "0.0.0.0", err => {
  if (err) {
    throw err;
  }

  console.log(
    `Worker started and listening on http://0.0.0.0:8080 ${new Date().toISOString()}`
  );
});
<|endoftext|>


<commit_before>/*global ErizoGetUserMedia, L, document*/
/*
 * Class Stream represents a local or a remote Stream in the Room. It will handle the WebRTC stream
 * and identify the stream and where it should be drawn.
 */
var Erizo = Erizo || {};
Erizo.Stream = function (spec) {
    "use strict";
    var that = Erizo.EventDispatcher(spec),
        getFrame;

    that.stream = spec.stream;
    that.url = spec.url;
    that.recording = spec.recording;
    that.room = undefined;
    that.showing = false;
    that.local = false;
    that.video = spec.video;
    that.audio = spec.audio;
    that.screen = spec.screen;
    that.videoSize = spec.videoSize;
    that.extensionId = spec.extensionId;

    if (that.videoSize !== undefined && (!(that.videoSize instanceof Array) || that.videoSize.length != 4)) {
        throw Error("Invalid Video Size");
    }
    if (spec.local === undefined || spec.local === true) {
        that.local = true;
    }

    // Public functions

    that.getID = function () {
        return spec.streamID;
    };

    // Get attributes of this stream.
    that.getAttributes = function () {
        return spec.attributes;
    };

    // Changes the attributes of this stream in the room.
    that.setAttributes = function(attrs) {
        L.Logger.error("Failed to set attributes data. This Stream object has not been published.");
    };

    that.updateLocalAttributes = function(attrs) {
        spec.attributes = attrs;
    };

    // Indicates if the stream has audio activated
    that.hasAudio = function () {
        return spec.audio;
    };

    // Indicates if the stream has video activated
    that.hasVideo = function () {
        return spec.video;
    };

    // Indicates if the stream has data activated
    that.hasData = function () {
        return spec.data;
    };

    // Indicates if the stream has screen activated
    that.hasScreen = function () {
        return spec.screen;
    };

    // Sends data through this stream.
    that.sendData = function (msg) {
        L.Logger.error("Failed to send data. This Stream object has not that channel enabled.");
    };

    // Initializes the stream and tries to retrieve a stream from local video and audio
    // We need to call this method before we can publish it in the room.
    that.init = function () {
      try {
        if ((spec.audio || spec.video || spec.screen) && spec.url === undefined) {
          L.Logger.debug("Requested access to local media");
          var videoOpt = spec.video;
          if ((videoOpt == true || spec.screen == true) && that.videoSize !== undefined) {
            videoOpt = {mandatory: {minWidth: that.videoSize[0], minHeight: that.videoSize[1], maxWidth: that.videoSize[2], maxHeight: that.videoSize[3]}};
          } else if (spec.screen == true && videoOpt === undefined){
            videoOpt = true;
          }
          var opt = {video: videoOpt, audio: spec.audio, fake: spec.fake, screen: spec.screen, extensionId:that.extensionId};
          L.Logger.debug(opt);
          Erizo.GetUserMedia(opt, function (stream) {
            //navigator.webkitGetUserMedia("audio, video", function (stream) {

            L.Logger.info("User has granted access to local media.");
            that.stream = stream;

            var streamEvent = Erizo.StreamEvent({type: "access-accepted"});
            that.dispatchEvent(streamEvent);

          }, function (error) {
            L.Logger.error("Failed to get access to local media. Error code was " + error.code + ".");
            var streamEvent = Erizo.StreamEvent({type: "access-denied"});
            that.dispatchEvent(streamEvent);
          });
          } else {
            var streamEvent = Erizo.StreamEvent({type: "access-accepted"});
            that.dispatchEvent(streamEvent);
          }
          } catch (e) {
            L.Logger.error("Error accessing to local media", e);
          }
      };

     that.close = function () {
        if (that.local) {
            if (that.room !== undefined) {
                that.room.unpublish(that);
            }
            // Remove HTML element
            that.hide();
            if (that.stream !== undefined) {
                that.stream.getTracks().forEach(function (track) {
                    track.stop();
                });
            }
            that.stream = undefined;
        }
    };

    that.play = function (elementID, options) {
        options = options || {};
        that.elementID = elementID;
        if (that.hasVideo() || this.hasScreen()) {
            // Draw on HTML
            if (elementID !== undefined) {
                var player = new Erizo.VideoPlayer({id: that.getID(), stream: that, elementID: elementID, options: options});
                that.player = player;
                that.showing = true;
            }
        } else if (that.hasAudio) {
            var player = new Erizo.AudioPlayer({id: that.getID(), stream: that, elementID: elementID, options: options});
            that.player = player;
            that.showing = true;
        }
    };

    that.stop = function () {
        if (that.showing) {
            if (that.player !== undefined) {
                that.player.destroy();
                that.showing = false;
            }
        }
    };

    that.show = that.play;
    that.hide = that.stop;

    getFrame = function () {
        if (that.player !== undefined && that.stream !== undefined) {
            var video = that.player.video,

                style = document.defaultView.getComputedStyle(video),
                width = parseInt(style.getPropertyValue("width"), 10),
                height = parseInt(style.getPropertyValue("height"), 10),
                left = parseInt(style.getPropertyValue("left"), 10),
                top = parseInt(style.getPropertyValue("top"), 10),

                div = document.getElementById(that.elementID),
                divStyle = document.defaultView.getComputedStyle(div),
                divWidth = parseInt(divStyle.getPropertyValue("width"), 10),
                divHeight = parseInt(divStyle.getPropertyValue("height"), 10),

                canvas = document.createElement('canvas'),
                context;

            canvas.id = "testing";
            canvas.width = divWidth;
            canvas.height = divHeight;
            canvas.setAttribute('style', 'display: none');
            //document.body.appendChild(canvas);
            context = canvas.getContext('2d');

            context.drawImage(video, left, top, width, height);

            return canvas;
        } else {
            return null;
        }
    };

    that.getVideoFrameURL = function (format) {
        var canvas = getFrame();
        if (canvas !== null) {
            if (format) {
                return canvas.toDataURL(format);
            } else {
                return canvas.toDataURL();
            }
        } else {
            return null;
        }
    };

    that.getVideoFrame = function () {
        var canvas = getFrame();
        if (canvas !== null) {
            return canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height);
        } else {
            return null;
        }
    };

    that.updateConfiguration = function (config, callback) {
        if (config === undefined)
            return;
        if (that.pc){
            that.pc.updateSpec(config, callback);
        } else {
            return ("This stream has not been published, ignoring");
        }
    }

    return that;
};
<commit_msg>Firing access denied event when failing get user media<commit_after>/*global ErizoGetUserMedia, L, document*/
/*
 * Class Stream represents a local or a remote Stream in the Room. It will handle the WebRTC stream
 * and identify the stream and where it should be drawn.
 */
var Erizo = Erizo || {};
Erizo.Stream = function (spec) {
    "use strict";
    var that = Erizo.EventDispatcher(spec),
        getFrame;

    that.stream = spec.stream;
    that.url = spec.url;
    that.recording = spec.recording;
    that.room = undefined;
    that.showing = false;
    that.local = false;
    that.video = spec.video;
    that.audio = spec.audio;
    that.screen = spec.screen;
    that.videoSize = spec.videoSize;
    that.extensionId = spec.extensionId;

    if (that.videoSize !== undefined && (!(that.videoSize instanceof Array) || that.videoSize.length != 4)) {
        throw Error("Invalid Video Size");
    }
    if (spec.local === undefined || spec.local === true) {
        that.local = true;
    }

    // Public functions

    that.getID = function () {
        return spec.streamID;
    };

    // Get attributes of this stream.
    that.getAttributes = function () {
        return spec.attributes;
    };

    // Changes the attributes of this stream in the room.
    that.setAttributes = function(attrs) {
        L.Logger.error("Failed to set attributes data. This Stream object has not been published.");
    };

    that.updateLocalAttributes = function(attrs) {
        spec.attributes = attrs;
    };

    // Indicates if the stream has audio activated
    that.hasAudio = function () {
        return spec.audio;
    };

    // Indicates if the stream has video activated
    that.hasVideo = function () {
        return spec.video;
    };

    // Indicates if the stream has data activated
    that.hasData = function () {
        return spec.data;
    };

    // Indicates if the stream has screen activated
    that.hasScreen = function () {
        return spec.screen;
    };

    // Sends data through this stream.
    that.sendData = function (msg) {
        L.Logger.error("Failed to send data. This Stream object has not that channel enabled.");
    };

    // Initializes the stream and tries to retrieve a stream from local video and audio
    // We need to call this method before we can publish it in the room.
    that.init = function () {
      try {
        if ((spec.audio || spec.video || spec.screen) && spec.url === undefined) {
          L.Logger.debug("Requested access to local media");
          var videoOpt = spec.video;
          if ((videoOpt == true || spec.screen == true) && that.videoSize !== undefined) {
            videoOpt = {mandatory: {minWidth: that.videoSize[0], minHeight: that.videoSize[1], maxWidth: that.videoSize[2], maxHeight: that.videoSize[3]}};
          } else if (spec.screen == true && videoOpt === undefined){
            videoOpt = true;
          }
          var opt = {video: videoOpt, audio: spec.audio, fake: spec.fake, screen: spec.screen, extensionId:that.extensionId};
          L.Logger.debug(opt);
          Erizo.GetUserMedia(opt, function (stream) {
            //navigator.webkitGetUserMedia("audio, video", function (stream) {

            L.Logger.info("User has granted access to local media.");
            that.stream = stream;

            var streamEvent = Erizo.StreamEvent({type: "access-accepted"});
            that.dispatchEvent(streamEvent);

          }, function (error) {
            L.Logger.error("Failed to get access to local media. Error code was " + error.code + ".");
            var streamEvent = Erizo.StreamEvent({type: "access-denied"});
            that.dispatchEvent(streamEvent);
          });
          } else {
            var streamEvent = Erizo.StreamEvent({type: "access-accepted"});
            that.dispatchEvent(streamEvent);
          }
          } catch (e) {
            L.Logger.error("Failed to get access to local media. Error was " + e + ".");
            var streamEvent = Erizo.StreamEvent({type: "access-denied"});
            that.dispatchEvent(streamEvent);
          }
      };

     that.close = function () {
        if (that.local) {
            if (that.room !== undefined) {
                that.room.unpublish(that);
            }
            // Remove HTML element
            that.hide();
            if (that.stream !== undefined) {
                that.stream.getTracks().forEach(function (track) {
                    track.stop();
                });
            }
            that.stream = undefined;
        }
    };

    that.play = function (elementID, options) {
        options = options || {};
        that.elementID = elementID;
        if (that.hasVideo() || this.hasScreen()) {
            // Draw on HTML
            if (elementID !== undefined) {
                var player = new Erizo.VideoPlayer({id: that.getID(), stream: that, elementID: elementID, options: options});
                that.player = player;
                that.showing = true;
            }
        } else if (that.hasAudio) {
            var player = new Erizo.AudioPlayer({id: that.getID(), stream: that, elementID: elementID, options: options});
            that.player = player;
            that.showing = true;
        }
    };

    that.stop = function () {
        if (that.showing) {
            if (that.player !== undefined) {
                that.player.destroy();
                that.showing = false;
            }
        }
    };

    that.show = that.play;
    that.hide = that.stop;

    getFrame = function () {
        if (that.player !== undefined && that.stream !== undefined) {
            var video = that.player.video,

                style = document.defaultView.getComputedStyle(video),
                width = parseInt(style.getPropertyValue("width"), 10),
                height = parseInt(style.getPropertyValue("height"), 10),
                left = parseInt(style.getPropertyValue("left"), 10),
                top = parseInt(style.getPropertyValue("top"), 10),

                div = document.getElementById(that.elementID),
                divStyle = document.defaultView.getComputedStyle(div),
                divWidth = parseInt(divStyle.getPropertyValue("width"), 10),
                divHeight = parseInt(divStyle.getPropertyValue("height"), 10),

                canvas = document.createElement('canvas'),
                context;

            canvas.id = "testing";
            canvas.width = divWidth;
            canvas.height = divHeight;
            canvas.setAttribute('style', 'display: none');
            //document.body.appendChild(canvas);
            context = canvas.getContext('2d');

            context.drawImage(video, left, top, width, height);

            return canvas;
        } else {
            return null;
        }
    };

    that.getVideoFrameURL = function (format) {
        var canvas = getFrame();
        if (canvas !== null) {
            if (format) {
                return canvas.toDataURL(format);
            } else {
                return canvas.toDataURL();
            }
        } else {
            return null;
        }
    };

    that.getVideoFrame = function () {
        var canvas = getFrame();
        if (canvas !== null) {
            return canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height);
        } else {
            return null;
        }
    };

    that.updateConfiguration = function (config, callback) {
        if (config === undefined)
            return;
        if (that.pc){
            that.pc.updateSpec(config, callback);
        } else {
            return ("This stream has not been published, ignoring");
        }
    }

    return that;
};
<|endoftext|>


<commit_before>/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';

import MaterialPalette from 'react-native-material-palette';

export default class TestPalette extends Component {

  async componentDidMount() {
    const palette = await MaterialPalette.create(require('./assets/wroclaw.jpg'), {
      types: ['lightMuted', 'darkVibrant']
    });
    console.log(palette);
  }

  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to React Native!
        </Text>
        <Text style={styles.instructions}>
          To get started, edit index.android.js
        </Text>
        <Text style={styles.instructions}>
          Double tap R on your keyboard to reload,{'\n'}
          Shake or press menu button for dev menu
        </Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});

AppRegistry.registerComponent('TestPalette', () => TestPalette);
<commit_msg>example with static image and 3 color profiles<commit_after>/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, View, Image } from 'react-native';

import MaterialPalette from 'react-native-material-palette';

export default class TestPalette extends Component {
  state = {
    isLoading: true,
    palette: null,
  };

  async componentDidMount() {
    const palette = await MaterialPalette.create(
      require('./assets/wroclaw.jpg'), // eslint-disable-line global-require
      {
        types: ['lightMuted', 'darkVibrant', 'vibrant'],
      },
    );
    this.setState({
      palette,
      isLoading: false,
    });
  }

  render() {
    const { palette, isLoading } = this.state;
    return (
      <View style={styles.container}>
        {isLoading
          ? <Text>
              Generating palette asynchronously...
            </Text>
          : <View>
              <Image
                source={require('./assets/wroclaw.jpg')}
                style={styles.image}
              />
              {Object.keys(palette).map(profile => (
                <View
                  style={{
                    backgroundColor: palette[profile].color,
                    height: 50,
                  }}
                  key={profile}
                >
                  <Text style={{ color: palette[profile].bodyTextColor }}>
                    {profile.toUpperCase()}
                  </Text>
                </View>
              ))}
            </View>}
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    backgroundColor: '#F5FCFF',
  },
  image: {
    height: 200,
    width: null,
    resizeMode: 'cover',
  },
});

AppRegistry.registerComponent('TestPalette', () => TestPalette);
<|endoftext|>


<commit_before>// Copyright 2015-2021, University of Colorado Boulder

/**
 * Base type for ScreenViews that use a carousel to select a demo.
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */

import Property from '../../../axon/js/Property.js';
import ScreenView from '../../../joist/js/ScreenView.js';
import merge from '../../../phet-core/js/merge.js';
import PhetFont from '../../../scenery-phet/js/PhetFont.js';
import { Node } from '../../../scenery/js/imports.js';
import { Text } from '../../../scenery/js/imports.js';
import Tandem from '../../../tandem/js/Tandem.js';
import CarouselComboBox from '../CarouselComboBox.js';
import ComboBoxItem from '../ComboBoxItem.js';
import sun from '../sun.js';

// constants
const ITEM_FONT = new PhetFont( 14 );

/**
 * @typedef Demo - specification for a 'demo', the demonstration of some component or functionality
 * @property {string} label - label in the carousel
 * @property {function(layoutBounds:Bounds2): Node} createNode - creates the Node for the demo
 * @property {Node|null} node - the Node for the demo, created by DemosScreenView
 */

class DemosScreenView extends ScreenView {

  /**
   * @param {Demo[]} demos
   * @param {Object} [options]
   */
  constructor( demos, options ) {

    options = merge( {

      // {string|null} label field of the {Demo} to be selected initially, defaults to the first demo after sorting
      selectedDemoLabel: null,

      // {boolean} see https://github.com/phetsims/sun/issues/386
      // true = caches Nodes for all demos that have been selected
      // false = keeps only the Node for the selected demo in memory
      cacheDemos: false,

      tandem: Tandem.OPTIONAL
    }, options );

    super( options );

    const demosParent = new Node();
    const layoutBounds = this.layoutBounds;

    // Support PhET-iO API instrumentation and API tracking
    if ( Tandem.PHET_IO_ENABLED ) {
      options.cacheDemos = true;

      demos.forEach( demo => {
        demo.node = demo.createNode( layoutBounds, {
          tandem: options.tandem.createTandem( `demo${demo.label}` )
        } );
        demo.node.visible = false;
        demosParent.addChild( demo.node );
      } );
    }

    // All demos will be children of this node, to maintain rendering order with combo box list

    this.addChild( demosParent );

    // Sort the demos by label, so that they appear in the combo box in alphabetical order
    demos = _.sortBy( demos, demo => {
      return demo.label;
    } );

    // The initial demo that is selected
    let selectedDemo = demos[ 0 ];
    if ( options.selectedDemoLabel ) {
      selectedDemo = _.find( demos, demo => {
        return ( demo.label === options.selectedDemoLabel );
      } );
      if ( !selectedDemo ) {
        throw new Error( `demo not found: ${options.selectedDemoLabel}` );
      }
    }

    // {Property.<Demo>} the demo that is currently selected
    const selectedDemoProperty = new Property( selectedDemo );

    const selectADemoLabel = new Text( 'Select a Demo:', {
      font: new PhetFont( 16 )
    } );
    this.addChild( selectADemoLabel );

    // {ComboBoxItem[]}
    const items = _.map( demos, demo => new ComboBoxItem( new Text( demo.label, { font: ITEM_FONT } ), demo ) );

    const carouselComboBox = new CarouselComboBox( selectedDemoProperty, items, {
      tandem: options.tandem.createTandem( 'carouselComboBox' )
    } );
    this.addChild( carouselComboBox );

    // Layout, with button vertically centered on label.
    selectADemoLabel.left = this.layoutBounds.left + 20;
    carouselComboBox.left = selectADemoLabel.right + 10;
    carouselComboBox.top = this.layoutBounds.top + 20;
    selectADemoLabel.centerY = carouselComboBox.visibleBounds.centerY;

    // Make the selected demo visible
    selectedDemoProperty.link( ( demo, oldDemo ) => {

      // clean up the previously selected demo
      if ( oldDemo ) {
        if ( options.cacheDemos ) {

          // make the old demo invisible
          oldDemo.node.visible = false;
        }
        else {

          // delete the old demo
          demosParent.removeChild( oldDemo.node );
          oldDemo.node.dispose();
          oldDemo.node = null;
        }
      }

      if ( demo.node ) {

        // If the selected demo has an associated node, make it visible.
        demo.node.visible = true;
      }
      else {

        // If the selected demo doesn't doesn't have an associated node, create it.
        demo.node = demo.createNode( layoutBounds, {
          tandem: options.tandem.createTandem( `demo${demo.label}` )
        } );
        demosParent.addChild( demo.node );
      }
    } );
  }
}

sun.register( 'DemosScreenView', DemosScreenView );
export default DemosScreenView;<commit_msg>Convert to TypeScript, see https://github.com/phetsims/bamboo/issues/49<commit_after>// Copyright 2015-2021, University of Colorado Boulder

/**
 * Base type for ScreenViews that use a carousel to select a demo.
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */

import Property from '../../../axon/js/Property.js';
import ScreenView from '../../../joist/js/ScreenView.js';
import merge from '../../../phet-core/js/merge.js';
import PhetFont from '../../../scenery-phet/js/PhetFont.js';
import { Node } from '../../../scenery/js/imports.js';
import { Text } from '../../../scenery/js/imports.js';
import Tandem from '../../../tandem/js/Tandem.js';
import CarouselComboBox from '../CarouselComboBox.js';
import ComboBoxItem from '../ComboBoxItem.js';
import sun from '../sun.js';

// constants
const ITEM_FONT = new PhetFont( 14 );

/**
 * @typedef Demo - specification for a 'demo', the demonstration of some component or functionality
 * @property {string} label - label in the carousel
 * @property {function(layoutBounds:Bounds2): Node} createNode - creates the Node for the demo
 * @property {Node} [node] - the Node for the demo, created by DemosScreenView
 */

class DemosScreenView extends ScreenView {

  /**
   * @param {Demo[]} demos
   * @param {Object} [options]
   */
  constructor( demos, options ) {

    options = merge( {

      // {string|null} label field of the {Demo} to be selected initially, defaults to the first demo after sorting
      selectedDemoLabel: null,

      // {boolean} see https://github.com/phetsims/sun/issues/386
      // true = caches Nodes for all demos that have been selected
      // false = keeps only the Node for the selected demo in memory
      cacheDemos: false,

      tandem: Tandem.OPTIONAL
    }, options );

    super( options );

    const demosParent = new Node();
    const layoutBounds = this.layoutBounds;

    // Support PhET-iO API instrumentation and API tracking
    if ( Tandem.PHET_IO_ENABLED ) {
      options.cacheDemos = true;

      demos.forEach( demo => {
        demo.node = demo.createNode( layoutBounds, {
          tandem: options.tandem.createTandem( `demo${demo.label}` )
        } );
        demo.node.visible = false;
        demosParent.addChild( demo.node );
      } );
    }

    // All demos will be children of this node, to maintain rendering order with combo box list

    this.addChild( demosParent );

    // Sort the demos by label, so that they appear in the combo box in alphabetical order
    demos = _.sortBy( demos, demo => {
      return demo.label;
    } );

    // The initial demo that is selected
    let selectedDemo = demos[ 0 ];
    if ( options.selectedDemoLabel ) {
      selectedDemo = _.find( demos, demo => {
        return ( demo.label === options.selectedDemoLabel );
      } );
      if ( !selectedDemo ) {
        throw new Error( `demo not found: ${options.selectedDemoLabel}` );
      }
    }

    // {Property.<Demo>} the demo that is currently selected
    const selectedDemoProperty = new Property( selectedDemo );

    const selectADemoLabel = new Text( 'Select a Demo:', {
      font: new PhetFont( 16 )
    } );
    this.addChild( selectADemoLabel );

    // {ComboBoxItem[]}
    const items = _.map( demos, demo => new ComboBoxItem( new Text( demo.label, { font: ITEM_FONT } ), demo ) );

    const carouselComboBox = new CarouselComboBox( selectedDemoProperty, items, {
      tandem: options.tandem.createTandem( 'carouselComboBox' )
    } );
    this.addChild( carouselComboBox );

    // Layout, with button vertically centered on label.
    selectADemoLabel.left = this.layoutBounds.left + 20;
    carouselComboBox.left = selectADemoLabel.right + 10;
    carouselComboBox.top = this.layoutBounds.top + 20;
    selectADemoLabel.centerY = carouselComboBox.visibleBounds.centerY;

    // Make the selected demo visible
    selectedDemoProperty.link( ( demo, oldDemo ) => {

      // clean up the previously selected demo
      if ( oldDemo ) {
        if ( options.cacheDemos ) {

          // make the old demo invisible
          oldDemo.node.visible = false;
        }
        else {

          // delete the old demo
          demosParent.removeChild( oldDemo.node );
          oldDemo.node.dispose();
          oldDemo.node = null;
        }
      }

      if ( demo.node ) {

        // If the selected demo has an associated node, make it visible.
        demo.node.visible = true;
      }
      else {

        // If the selected demo doesn't doesn't have an associated node, create it.
        demo.node = demo.createNode( layoutBounds, {
          tandem: options.tandem.createTandem( `demo${demo.label}` )
        } );
        demosParent.addChild( demo.node );
      }
    } );
  }
}

sun.register( 'DemosScreenView', DemosScreenView );
export default DemosScreenView;<|endoftext|>


<commit_before>$(function () {
    if(!isSocial){
    var comments = {
            interval: 5 * 1000,
            commentsUrl: caramel.context + '/apis/comments?asset=' + $('#assetp-tabs').data('aid') + '&page=',
            pagingUrl: '/apis/comments/paging?page=',
            partial: '/themes/store/partials/comments.hbs'
        },
        paging = {
            current: 1,
            partial: '/themes/store/partials/pagination.hbs'
        };

    $('#tab-reviews').on('click', '.pagination a', function (e) {
        e.preventDefault();
        var page,
            thiz = $(this),
            str = thiz.text(),
            url = thiz.attr('href');
        if (url === '#') {
            return;
        }
        if (str.indexOf('Next') !== -1) {
            page = paging.current + 1;
        } else if (str.indexOf('Prev') !== -1) {
            page = paging.current - 1
        } else {
            page = parseInt(str, 10);
        }
        loadReviews(url, page);
    });

    var loadReviews = function (url, page) {
        var iframe, iframeHeight,
        	el = $('#tab-reviews').find('.content');
        comments.updated = new Date().getTime();
        async.parallel({
            comments: function (callback) {
                $.get(url, function (data) {
                    callback(null, data);
                }, 'json');
            },
            paging: function (callback) {
                caramel.post(comments.pagingUrl + page, {
                    asset: $('#assetp-tabs').data('aid')
                }, function (data) {
                    paging.current = data.current;
                    callback(null, data);
                }, 'json');
            }
        }, function (error, result) {
            if (error) {
                theme.loaded(el, '
Error while retrieving data.
')
            } else {
                async.parallel({
                    comments: function (callback) {
                        var i, comment,
                            comments = result.comments,
                            length = comments.length;
                        for(i = 0; i < length; i++) {
                            comment = comments[i];
                            comment.created.time = moment(comment.created.time).format('LL');
                        }
                        caramel.render('comments', {
                            user: store.user,
                            comments: comments
                        }, callback);
                    },
                    paging: function (callback) {
                        caramel.render('pagination', result.paging, callback);
                    }
                }, function (err, result) {
                    theme.loaded(el, result.comments);
                    el.append(result.paging);

                    iframe = $('#tab-reviews').find('iframe');
        			iframeHeight =  iframe.contents().height();
        			iframe.height(iframeHeight);
                });
            }
            $('#assetp-tabs').tab();
        });
        theme.loading(el);
    };

    $('#assetp-tabs').on('click', 'a[href="#tab-reviews"]',function (e) {
        var thiz = $(this),
            current = new Date().getTime();
        e.preventDefault();
        if (!comments.interval || (current - (comments.updated || 0) < comments.interval)) {
            thiz.tab('show');
            return;
        }
        loadReviews(comments.commentsUrl + paging.current, paging.current);
        thiz.tab('show');
    }).on('click', 'a[href="#tab-properties"]', function (e) {

        });

    $('#tab-review-box').find('.btn-primary').live('click', function (e) {
        if (!$("#form-review").valid()) return;
        caramel.post('/apis/comment', {
            asset: $('#assetp-tabs').data('aid'),
            content: $('#tab-review-box').find('.content').val()
        }, function (data) {
            loadReviews(comments.commentsUrl + paging.current, paging.current);
        }, 'json');
    });

	$('.text-review-box').live('keyup focus', function(e){
	if($('#comment-content').hasClass('user-review')) {
		$(".btn-review").removeClass("btn-primary");
		$(".btn-review").addClass("disabled");
		$('.text-review-box-charCount-msg').hide();
		$('.error-text').show();
		return false;
	}
	    var chars = this.value.length;
		$('.text-review-box-charCount-msg').show();
		var limit = 490;
                if (chars > limit) {
                    src.value = src.value.substr(0, limit);
                    chars = limit;
                }
				$("#charCount").html( limit - chars );
		return false;

    });

    /*    $('#btn-copy-gadget-code').click(function(){
     var script = $('#modal-add-gadget code').html().trim();
     localStorage['gadget-code'] = script;
     $(this).fadeOut("fast", function(){
     $(this).attr('id', 'btn-open-editor').text('Open Editor').fadeIn("fast", function(){
     $('.copy-status').html('Code copied to clipboard').delay(1000).fadeIn();
     });

     })

     })
     $('#btn-open-editor').live('click', function(){
     location.href = '/portal/dashboard.jag';
     })*/
    /*
     $(document).scroll(function(){
     var h = $(this).scrollTop();
     if(h>19){
     $('.asset-description-header').addClass('asset-description-header-scroll');
     } else {
     $('.asset-description-header').removeClass('asset-description-header-scroll');
     }
     })*/
    }
    $('#btn-add-gadget').click(function () {
	var elem = $(this);
	if(store.user){
	    isAssertTrue(elem.data('aid'),elem.data('type'));
		}else{
		   asset.process(elem.data('type'), elem.data('aid'), location.href);
			}
    });

    $("a[data-toggle='tooltip']").tooltip();

    $('.embed-snippet').hide();

    $('.btn-embed').click(function() {
    	$('.embed-snippet').toggle(400);
    	return false;
    });

    var el = $('.user-rating'),
        rating = el.data('rating');
    $($('input', el)[rating - 1]).attr('checked', 'checked');

    $('.auto-submit-star').rating({
        callback: function (value, link) {
		if(value==undefined){
			value=0;
		}
        	$('.rate-num-assert').html('('+value+')');
            caramel.post('/apis/rate', {
                asset: $('#assetp-tabs').data('aid'),
                value: value || 0
            }, function (data) {

            });
        }
    });

});
<commit_msg>white space changes.<commit_after>$(function () {
    if (!isSocial) {
        var comments = {
                interval: 5 * 1000,
                commentsUrl: caramel.context + '/apis/comments?asset=' + $('#assetp-tabs').data('aid') + '&page=',
                pagingUrl: '/apis/comments/paging?page=',
                partial: '/themes/store/partials/comments.hbs'
            },
            paging = {
                current: 1,
                partial: '/themes/store/partials/pagination.hbs'
            };

        $('#tab-reviews').on('click', '.pagination a', function (e) {
            e.preventDefault();
            var page,
                thiz = $(this),
                str = thiz.text(),
                url = thiz.attr('href');
            if (url === '#') {
                return;
            }
            if (str.indexOf('Next') !== -1) {
                page = paging.current + 1;
            } else if (str.indexOf('Prev') !== -1) {
                page = paging.current - 1
            } else {
                page = parseInt(str, 10);
            }
            loadReviews(url, page);
        });

        var loadReviews = function (url, page) {
            var iframe, iframeHeight,
                el = $('#tab-reviews').find('.content');
            comments.updated = new Date().getTime();
            async.parallel({
                comments: function (callback) {
                    $.get(url, function (data) {
                        callback(null, data);
                    }, 'json');
                },
                paging: function (callback) {
                    caramel.post(comments.pagingUrl + page, {
                        asset: $('#assetp-tabs').data('aid')
                    }, function (data) {
                        paging.current = data.current;
                        callback(null, data);
                    }, 'json');
                }
            }, function (error, result) {
                if (error) {
                    theme.loaded(el, '
Error while retrieving data.
')
                } else {
                    async.parallel({
                        comments: function (callback) {
                            var i, comment,
                                comments = result.comments,
                                length = comments.length;
                            for (i = 0; i < length; i++) {
                                comment = comments[i];
                                comment.created.time = moment(comment.created.time).format('LL');
                            }
                            caramel.render('comments', {
                                user: store.user,
                                comments: comments
                            }, callback);
                        },
                        paging: function (callback) {
                            caramel.render('pagination', result.paging, callback);
                        }
                    }, function (err, result) {
                        theme.loaded(el, result.comments);
                        el.append(result.paging);

                        iframe = $('#tab-reviews').find('iframe');
                        iframeHeight = iframe.contents().height();
                        iframe.height(iframeHeight);
                    });
                }
                $('#assetp-tabs').tab();
            });
            theme.loading(el);
        };

        $('#assetp-tabs').on('click', 'a[href="#tab-reviews"]',function (e) {
            var thiz = $(this),
                current = new Date().getTime();
            e.preventDefault();
            if (!comments.interval || (current - (comments.updated || 0) < comments.interval)) {
                thiz.tab('show');
                return;
            }
            loadReviews(comments.commentsUrl + paging.current, paging.current);
            thiz.tab('show');
        }).on('click', 'a[href="#tab-properties"]', function (e) {

            });

        $('#tab-review-box').find('.btn-primary').live('click', function (e) {
            if (!$("#form-review").valid()) return;
            caramel.post('/apis/comment', {
                asset: $('#assetp-tabs').data('aid'),
                content: $('#tab-review-box').find('.content').val()
            }, function (data) {
                loadReviews(comments.commentsUrl + paging.current, paging.current);
            }, 'json');
        });

        $('.text-review-box').live('keyup focus', function (e) {
            if ($('#comment-content').hasClass('user-review')) {
                $(".btn-review").removeClass("btn-primary");
                $(".btn-review").addClass("disabled");
                $('.text-review-box-charCount-msg').hide();
                $('.error-text').show();
                return false;
            }
            var chars = this.value.length;
            $('.text-review-box-charCount-msg').show();
            var limit = 490;
            if (chars > limit) {
                src.value = src.value.substr(0, limit);
                chars = limit;
            }
            $("#charCount").html(limit - chars);
            return false;

        });

        /*    $('#btn-copy-gadget-code').click(function(){
         var script = $('#modal-add-gadget code').html().trim();
         localStorage['gadget-code'] = script;
         $(this).fadeOut("fast", function(){
         $(this).attr('id', 'btn-open-editor').text('Open Editor').fadeIn("fast", function(){
         $('.copy-status').html('Code copied to clipboard').delay(1000).fadeIn();
         });

         })

         })
         $('#btn-open-editor').live('click', function(){
         location.href = '/portal/dashboard.jag';
         })*/
        /*
         $(document).scroll(function(){
         var h = $(this).scrollTop();
         if(h>19){
         $('.asset-description-header').addClass('asset-description-header-scroll');
         } else {
         $('.asset-description-header').removeClass('asset-description-header-scroll');
         }
         })*/
    }
    $('#btn-add-gadget').click(function () {
        var elem = $(this);
        if (store.user) {
            isAssertTrue(elem.data('aid'), elem.data('type'));
        } else {
            asset.process(elem.data('type'), elem.data('aid'), location.href);
        }
    });

    $("a[data-toggle='tooltip']").tooltip();

    $('.embed-snippet').hide();

    $('.btn-embed').click(function () {
        $('.embed-snippet').toggle(400);
        return false;
    });

    var el = $('.user-rating'),
        rating = el.data('rating');
    $($('input', el)[rating - 1]).attr('checked', 'checked');

    $('.auto-submit-star').rating({
        callback: function (value, link) {
            if (value == undefined) {
                value = 0;
            }
            $('.rate-num-assert').html('(' + value + ')');
            caramel.post('/apis/rate', {
                asset: $('#assetp-tabs').data('aid'),
                value: value || 0
            }, function (data) {

            });
        }
    });

});
<|endoftext|>