<commit_before>'use strict';

/**
 * @class FileUploader - javascriptová komponenta pro upload dat do datové služby
 * @author Stanislav Vojíř
 * @param {Object} [params={}]
 * @constructor
 */
var FileUploader=function(params){
  var apiKey='';
  var dataServiceUrl='';
  var inputElementId='';

  /**
   * @type {number} maxFileSize=100MB Maximální velikost uploadovaných souborů
   */
  var maxFileSize=1024*1024*1000;
  /**
   * @type {int} chunkSize=300kB - Velikost jednoho uploadovaného bloku
   */
  var chunkSize=1024*300;
  /*interní pracovní proměnné*/
  var uploadInProgress=false;
  var file=null;
  var lastUploadedChunkId=0;
  var uploadRequestUrl="";
  var fileReader=null;
  var self=this;
  /**
   * @type {string} uploadId - ID daného uploadu
   */
  var uploadId="";
  /**
   * Custom function triggered on progress update
   */
  this.onProgressUpdate=function(){};
  /**
   * Custom function triggered on upload start
   */
  this.onUploadStart=function(){};
  /**
   * Custom function triggered on upload finished
   */
  this.onUploadFinished=function(){};
  /**
   * Custom function triggered on upload stop
   */
  this.onUploadStop=function(){};
  /**
   * Custom function triggered after last file send.
   */
  this.onFileSent=function(){};
  /**
   * Custom function triggered on message alert
   */
  this.onShowMessage=function(){};

  const SLOW_DOWN_INTERVAL=500;//interval pro zpomalení uploadu (v milisekundách)
  const CODE_SLOW_DOWN=429;
  const CODE_CONTINUE=202;
  const CODE_OK=200;

  /**
   * Funkce pro začátek uploadu
   * @param {object} uploadFileParams
   * @returns {boolean}
   */
  var start=function(uploadFileParams){
    var ajaxData=JSON.stringify(uploadFileParams);
    var ajaxUrl=prepareUrl('start');
    //noinspection JSUnusedGlobalSymbols
    jQuery.ajax(ajaxUrl,{
      type: 'post',
      data: ajaxData,
      contentType: 'application/json; charset=utf-8',
      success: function(result){
        //došlo k úspěšné inicializaci -> uložíme si ID uploadu a zahájíme posílání...
        uploadId=result;
        initFileReader();
        uploadInProgress=true;
        self.onProgressUpdate();
        sendChunk();
      },
      error: function(xhr, status, error){
        //došlo k chybě - zobrazíme info o chybě a následně stornujeme posílání
        showMessage("Upload failed: "+error);
        self.stopUpload();
      }
    });
  };

  var initFileReader = function(){
    fileReader=new FileReader();
    fileReader.onload=function(){
      //data načtena -> odešleme je
      //noinspection JSUnusedGlobalSymbols
      jQuery.ajax(prepareUrl(uploadId),{
        type: 'post',
        data: fileReader.result,
        //contentType: 'text/plain',
        processData:false,
        success: function(result,status,xhr){
          if (xhr.status==CODE_CONTINUE){
            //pokud máme pokračovat, zobrazíme stavovou zprávu
            showMessage(result);
          }
          //došlo k vrácení odpovědi
          self.onProgressUpdate();
          lastUploadedChunkId++;
          sendChunk();
        },
        error: function(xhr, status, error){
          //došlo k chybě - zobrazíme info o chybě a následně stornujeme posílání
          var errorCode=xhr.status;
          if (errorCode==CODE_SLOW_DOWN){
            //byl obdržen požadavek na zpomalení uploadu
            setTimeout(function(){
              sendChunk();
            },SLOW_DOWN_INTERVAL);
          }else{
            showMessage("Upload failed: "+error);
            self.stopUpload();
          }
        }
      });
    };
    fileReader.onerror=function(){
      //akce volaná při chybě čtení souboru
      showMessage("File read failed!","error");
      self.stopUpload();
    };
  };

  /**
   * Funkce pro odeslání další části souboru
   */
  var sendChunk=function(){
    //určení začátku a konce daného uploadu
    var dataStart=lastUploadedChunkId*chunkSize;
    var dataEnd=Math.min(dataStart+chunkSize,file.size);
    if (dataStart>=dataEnd){
      //pokud už byl odeslán celý soubor, pošleme ukončovací zprávu
      sendLastChunk();
      return;
    }
    self.onProgressUpdate();
    //načteme data (událost pro odeslání již je připojena k instanci objektu FileReader)
    fileReader.readAsArrayBuffer(file.slice(dataStart,dataEnd));
    //fileReader.readAsBinaryString(file.slice(dataStart,dataEnd));
  };

  /**
   * Funkce pro odeslání poslední zprávy - pro ukončení uploadu
   */
  var sendLastChunk=function(){
    //noinspection JSUnusedGlobalSymbols
    jQuery.ajax(prepareUrl(uploadId),{
      type: 'post',
      data: "",
      contentType: 'text/plain',
      success: function(result,status,xhr){
        //došlo k vrácení odpovědi
        if (xhr.status==CODE_OK){
          showMessage("File uploaded successfully, data preparation in progress...");
          self.onFileSent();
          self.onUploadFinished(result);
        }else{
          if(xhr.status==CODE_CONTINUE){
            self.onFileSent();
            showMessage(result);
          }
          setTimeout(function(){
            sendLastChunk();
          },SLOW_DOWN_INTERVAL);
        }
      },
      error: function(xhr, status, error){
        //došlo k chybě - zobrazíme info o chybě a následně stornujeme posílání
        if (xhr.status==CODE_SLOW_DOWN){
          //byl obdržen požadavek na zpomalení uploadu
          setTimeout(function(){
            sendLastChunk();
          },SLOW_DOWN_INTERVAL);
        }else{
          showMessage("Upload failed: "+error);
          self.stopUpload();
        }
      }
    });
  };

  /**
   * Funkce pro zahájení uploadu souboru
   * @param {string} requestUrl
   * @param {object|[]} uploadFileParams parametry, které je nutné zaslat při požadavku na zahájení uploadu
   * @returns {boolean}
   */
  this.startUpload=function(requestUrl,uploadFileParams){
    //pokud prohlížeč metody nepodporuje, zkusíme odeslat formulář klasicky...
    if (!this.checkBrowserSupport()){
      showMessage("This browser does not support this component.","error");
      return false;
    }
    if (uploadInProgress) {
      showMessage("Upload is currently in progress...", 'error');
      return false;
    }
    var inputElement=document.getElementById(inputElementId);
    if (inputElement.files.length!=1){
      showMessage("You have to select one file for upload!","error");
      return false;
    }
    file=inputElement.files[0];
    if (file.size>maxFileSize){
      showMessage("Uploaded file is too big!","error");
      return false;
    }
    self.onUploadStart();
    //začneme nahrávat souboru...
    if (requestUrl.substr(0,1)=='/'){
      uploadRequestUrl=requestUrl.substr(1);
    }else{
      uploadRequestUrl=requestUrl;
    }
    start(uploadFileParams);
  };

  /**
   * Funkce vracející vyjádření aktuálně naimportovaných částí
   * @returns {number}
   */
  this.getProgressState=function(){
    if (file==null){
      return 0;
    }
    return (lastUploadedChunkId*chunkSize)/file.size;
  };

  /**
   * Funkce pro zastavení běžícího uploadu
   */
  this.stopUpload=function(){
    uploadInProgress=false;
    lastUploadedChunkId=0;
    file=null;
    self.onUploadStop();
  };

  /**
   * Funkce pro kontrolu, jestli browser podporuje potřebné javascriptové objekty
   */
  this.checkBrowserSupport=function(){
    return window.File && window.FileReader && window.FileList && window.Blob;
  };

  /**
   * Funkce pro připravení URL adresy pro odeslání požadavku
   * @param {string} action
   * @returns {string}
   */
  var prepareUrl=function(action){
    if (action.substr(0,1)=='/'){
      action=action.substr(1);
    }
    return dataServiceUrl+uploadRequestUrl+'/'+action+'?apiKey='+apiKey;
  };

  /**
   * Funkce pro zobrazení příslušné zprávy
   * @param {string} text
   * @param {string} [type="info"]
   */
  var showMessage = function (text, type) {
    if (type == undefined) {
      type = "info";
    }
    //log the message into console
    if (type=='error' || type=='warning'){
      console.warn("Uploader: " + text);
    }else{
      console.log("Uploader: " + text);
    }
    //execute binded function
    self.onShowMessage(text, type);
  };

  this.setDataServiceUrl=function(url){
    dataServiceUrl=url;
    if(dataServiceUrl.substring(dataServiceUrl.length-1)!='/'){
      dataServiceUrl+='/';
    }
  };

  /**
   * Inicializační funkce pro nastavení potřebných parametrů
   * @param {object} [params]
   */
  this.init=function(params){
    if (params.dataServiceUrl!=null){
      this.setDataServiceUrl(params.dataServiceUrl);
    }
    if (params.apiKey!=null){
      apiKey=params.apiKey;
    }
    if (params.inputElementId!=null){
      inputElementId=params.inputElementId;
    }
    if (params.maxFileSize!=null && params.maxFileSize>0){
      maxFileSize=params.maxFileSize;
    }
    //custom functions
    if (params.onProgressUpdate!=null){
      this.onProgressUpdate=params.onProgressUpdate;
    }
    if (params.onUploadFinished!=null){
      this.onUploadFinished=params.onUploadFinished;
    }
    if (params.onUploadStart!=null){
      this.onUploadStart=params.onUploadStart;
    }
    if (params.onUploadStop!=null){
      this.onUploadStop=params.onUploadStop;
    }
    if (params.onShowMessage!=null){
      this.onShowMessage=params.onShowMessage;
    }
  };
  if (params!=undefined){
    this.init(params);
  }
};
<commit_msg>úprava velikosti bloku při nahrávání dat do datové služby<commit_after>'use strict';

/**
 * @class FileUploader - javascriptová komponenta pro upload dat do datové služby
 * @author Stanislav Vojíř
 * @param {Object} [params={}]
 * @constructor
 */
var FileUploader=function(params){
  var apiKey='';
  var dataServiceUrl='';
  var inputElementId='';

  /**
   * @type {number} maxFileSize=100MB Maximální velikost uploadovaných souborů
   */
  var maxFileSize=1024*1024*1000;
  /**
   * @type {int} chunkSize=500kB - Velikost jednoho uploadovaného bloku
   */
  var chunkSize=1024*500;
  /*interní pracovní proměnné*/
  var uploadInProgress=false;
  var file=null;
  var lastUploadedChunkId=0;
  var uploadRequestUrl="";
  var fileReader=null;
  var self=this;
  /**
   * @type {string} uploadId - ID daného uploadu
   */
  var uploadId="";
  /**
   * Custom function triggered on progress update
   */
  this.onProgressUpdate=function(){};
  /**
   * Custom function triggered on upload start
   */
  this.onUploadStart=function(){};
  /**
   * Custom function triggered on upload finished
   */
  this.onUploadFinished=function(){};
  /**
   * Custom function triggered on upload stop
   */
  this.onUploadStop=function(){};
  /**
   * Custom function triggered after last file send.
   */
  this.onFileSent=function(){};
  /**
   * Custom function triggered on message alert
   */
  this.onShowMessage=function(){};

  const SLOW_DOWN_INTERVAL=500;//interval pro zpomalení uploadu (v milisekundách)
  const CODE_SLOW_DOWN=429;
  const CODE_CONTINUE=202;
  const CODE_OK=200;

  /**
   * Funkce pro začátek uploadu
   * @param {object} uploadFileParams
   * @returns {boolean}
   */
  var start=function(uploadFileParams){
    var ajaxData=JSON.stringify(uploadFileParams);
    var ajaxUrl=prepareUrl('start');
    //noinspection JSUnusedGlobalSymbols
    jQuery.ajax(ajaxUrl,{
      type: 'post',
      data: ajaxData,
      contentType: 'application/json; charset=utf-8',
      success: function(result){
        //došlo k úspěšné inicializaci -> uložíme si ID uploadu a zahájíme posílání...
        uploadId=result;
        initFileReader();
        uploadInProgress=true;
        self.onProgressUpdate();
        sendChunk();
      },
      error: function(xhr, status, error){
        //došlo k chybě - zobrazíme info o chybě a následně stornujeme posílání
        showMessage("Upload failed: "+error);
        self.stopUpload();
      }
    });
  };

  var initFileReader = function(){
    fileReader=new FileReader();
    fileReader.onload=function(){
      //data načtena -> odešleme je
      //noinspection JSUnusedGlobalSymbols
      jQuery.ajax(prepareUrl(uploadId),{
        type: 'post',
        data: fileReader.result,
        //contentType: 'text/plain',
        processData:false,
        success: function(result,status,xhr){
          if (xhr.status==CODE_CONTINUE){
            //pokud máme pokračovat, zobrazíme stavovou zprávu
            showMessage(result);
          }
          //došlo k vrácení odpovědi
          self.onProgressUpdate();
          lastUploadedChunkId++;
          sendChunk();
        },
        error: function(xhr, status, error){
          //došlo k chybě - zobrazíme info o chybě a následně stornujeme posílání
          var errorCode=xhr.status;
          if (errorCode==CODE_SLOW_DOWN){
            //byl obdržen požadavek na zpomalení uploadu
            setTimeout(function(){
              sendChunk();
            },SLOW_DOWN_INTERVAL);
          }else{
            showMessage("Upload failed: "+error);
            self.stopUpload();
          }
        }
      });
    };
    fileReader.onerror=function(){
      //akce volaná při chybě čtení souboru
      showMessage("File read failed!","error");
      self.stopUpload();
    };
  };

  /**
   * Funkce pro odeslání další části souboru
   */
  var sendChunk=function(){
    //určení začátku a konce daného uploadu
    var dataStart=lastUploadedChunkId*chunkSize;
    var dataEnd=Math.min(dataStart+chunkSize,file.size);
    if (dataStart>=dataEnd){
      //pokud už byl odeslán celý soubor, pošleme ukončovací zprávu
      sendLastChunk();
      return;
    }
    self.onProgressUpdate();
    //načteme data (událost pro odeslání již je připojena k instanci objektu FileReader)
    fileReader.readAsArrayBuffer(file.slice(dataStart,dataEnd));
    //fileReader.readAsBinaryString(file.slice(dataStart,dataEnd));
  };

  /**
   * Funkce pro odeslání poslední zprávy - pro ukončení uploadu
   */
  var sendLastChunk=function(){
    //noinspection JSUnusedGlobalSymbols
    jQuery.ajax(prepareUrl(uploadId),{
      type: 'post',
      data: "",
      contentType: 'text/plain',
      success: function(result,status,xhr){
        //došlo k vrácení odpovědi
        if (xhr.status==CODE_OK){
          showMessage("File uploaded successfully, data preparation in progress...");
          self.onFileSent();
          self.onUploadFinished(result);
        }else{
          if(xhr.status==CODE_CONTINUE){
            self.onFileSent();
            showMessage(result);
          }
          setTimeout(function(){
            sendLastChunk();
          },SLOW_DOWN_INTERVAL);
        }
      },
      error: function(xhr, status, error){
        //došlo k chybě - zobrazíme info o chybě a následně stornujeme posílání
        if (xhr.status==CODE_SLOW_DOWN){
          //byl obdržen požadavek na zpomalení uploadu
          setTimeout(function(){
            sendLastChunk();
          },SLOW_DOWN_INTERVAL);
        }else{
          showMessage("Upload failed: "+error);
          self.stopUpload();
        }
      }
    });
  };

  /**
   * Funkce pro zahájení uploadu souboru
   * @param {string} requestUrl
   * @param {object|[]} uploadFileParams parametry, které je nutné zaslat při požadavku na zahájení uploadu
   * @returns {boolean}
   */
  this.startUpload=function(requestUrl,uploadFileParams){
    //pokud prohlížeč metody nepodporuje, zkusíme odeslat formulář klasicky...
    if (!this.checkBrowserSupport()){
      showMessage("This browser does not support this component.","error");
      return false;
    }
    if (uploadInProgress) {
      showMessage("Upload is currently in progress...", 'error');
      return false;
    }
    var inputElement=document.getElementById(inputElementId);
    if (inputElement.files.length!=1){
      showMessage("You have to select one file for upload!","error");
      return false;
    }
    file=inputElement.files[0];
    if (file.size>maxFileSize){
      showMessage("Uploaded file is too big!","error");
      return false;
    }
    self.onUploadStart();
    //začneme nahrávat souboru...
    if (requestUrl.substr(0,1)=='/'){
      uploadRequestUrl=requestUrl.substr(1);
    }else{
      uploadRequestUrl=requestUrl;
    }
    start(uploadFileParams);
  };

  /**
   * Funkce vracející vyjádření aktuálně naimportovaných částí
   * @returns {number}
   */
  this.getProgressState=function(){
    if (file==null){
      return 0;
    }
    return (lastUploadedChunkId*chunkSize)/file.size;
  };

  /**
   * Funkce pro zastavení běžícího uploadu
   */
  this.stopUpload=function(){
    uploadInProgress=false;
    lastUploadedChunkId=0;
    file=null;
    self.onUploadStop();
  };

  /**
   * Funkce pro kontrolu, jestli browser podporuje potřebné javascriptové objekty
   */
  this.checkBrowserSupport=function(){
    return window.File && window.FileReader && window.FileList && window.Blob;
  };

  /**
   * Funkce pro připravení URL adresy pro odeslání požadavku
   * @param {string} action
   * @returns {string}
   */
  var prepareUrl=function(action){
    if (action.substr(0,1)=='/'){
      action=action.substr(1);
    }
    return dataServiceUrl+uploadRequestUrl+'/'+action+'?apiKey='+apiKey;
  };

  /**
   * Funkce pro zobrazení příslušné zprávy
   * @param {string} text
   * @param {string} [type="info"]
   */
  var showMessage = function (text, type) {
    if (type == undefined) {
      type = "info";
    }
    //log the message into console
    if (type=='error' || type=='warning'){
      console.warn("Uploader: " + text);
    }else{
      console.log("Uploader: " + text);
    }
    //execute binded function
    self.onShowMessage(text, type);
  };

  this.setDataServiceUrl=function(url){
    dataServiceUrl=url;
    if(dataServiceUrl.substring(dataServiceUrl.length-1)!='/'){
      dataServiceUrl+='/';
    }
  };

  /**
   * Inicializační funkce pro nastavení potřebných parametrů
   * @param {object} [params]
   */
  this.init=function(params){
    if (params.dataServiceUrl!=null){
      this.setDataServiceUrl(params.dataServiceUrl);
    }
    if (params.apiKey!=null){
      apiKey=params.apiKey;
    }
    if (params.inputElementId!=null){
      inputElementId=params.inputElementId;
    }
    if (params.maxFileSize!=null && params.maxFileSize>0){
      maxFileSize=params.maxFileSize;
    }
    //custom functions
    if (params.onProgressUpdate!=null){
      this.onProgressUpdate=params.onProgressUpdate;
    }
    if (params.onUploadFinished!=null){
      this.onUploadFinished=params.onUploadFinished;
    }
    if (params.onUploadStart!=null){
      this.onUploadStart=params.onUploadStart;
    }
    if (params.onUploadStop!=null){
      this.onUploadStop=params.onUploadStop;
    }
    if (params.onShowMessage!=null){
      this.onShowMessage=params.onShowMessage;
    }
  };
  if (params!=undefined){
    this.init(params);
  }
};
<|endoftext|>


<commit_before>// main.js
// Dependencies:
// Description: singleton object
// This object will be our main "controller" class and will contain references
// to most of the other objects in the game.

"use strict";

// if app exists use the existing copy
// else create a new object literal
var app = app || {};

/*
 .main is an object literal that is a property of the app global
 This object literal has its own properties and methods (functions)

 */
app.main =
{
    WIDTH : 480, 				// Canvas width
    HEIGHT : 480,				// Canvas height
    canvas : undefined,			// Canvas
    ctx : undefined,			// Canvas context
   	lastTime : 0, 				// used by calculateDeltaTime()
    debug : true,				// debug
	animationID : 0,			//ID index of the current frame.

	radius : 12,

	testImage : undefined,

    //Initialization
	init : function()
	{
		//Init log
		console.log("app.main.init() called");

		// init canvas
		this.canvas = document.querySelector('canvas');
		this.canvas.width = this.WIDTH;
		this.canvas.height = this.HEIGHT;
		this.ctx = this.canvas.getContext('2d');
		this.ctx.mozImageSmoothingEnabled = false;
		this.ctx.msImageSmoothingEnabled = false;
		this.ctx.imageSmoothingEnabled = false;

		//Test image
		this.testImage = new Image(16, 16);
		this.testImage.src = "assets/temp.png";
		console.log(this.testImage);

		// start the game loop
		this.update();
	},

	//Core update
	update : function()
	{
		//LOOP
	 	this.animationID = requestAnimationFrame(this.update.bind(this));

	 	//Calculate Delta Time of frame
	 	var dt = this.calculateDeltaTime();

		//Clear
		this.ctx.save();
		//this.ctx.fillStyle = "#000";
		//this.ctx.fillRect(0, 0, this.WIDTH, this.HEIGHT);
		this.ctx.clearRect(0, 0, this.WIDTH, this.HEIGHT);
		this.ctx.restore();

		//Stuff
		this.ctx.save();
		this.ctx.arc(
			this.radius,
			this.radius,
			this.radius,
			0,
			Math.PI * 2);
		this.ctx.fillStyle = "#FFF";
		this.ctx.fill();
		/*
		this.ctx.drawImage(
			this.canvas,
			0,
			0,
			this.radius * 2,
			this.radius * 2,
			0,
			0,
			this.WIDTH,
			this.HEIGHT);
		*/
		this.ctx.drawImage(
			this.testImage,
			0,
			0,
			this.testImage.width,
			this.testImage.height,
			0,
			0,
			this.WIDTH,
			this.HEIGHT);
		this.ctx.restore();

		//Draw debug info
		if (this.debug)
		{
			// draw dt in bottom right corner
			this.fillText("dt: " + dt.toFixed(3), this.WIDTH - 140, this.HEIGHT - 10, "18pt courier", "white");
		}
	},

	//Draw filled text
	fillText : function(string, x, y, css, color)
	{
		this.ctx.save();
		// https://developer.mozilla.org/en-US/docs/Web/CSS/font
		this.ctx.font = css;
		this.ctx.fillStyle = color;
		this.ctx.fillText(string, x, y);
		this.ctx.restore();
	},

	//Calculate delta-time
	calculateDeltaTime : function()
	{
		// what's with (+ new Date) below?
		// + calls Date.valueOf(), which converts it from an object to a
		// primitive (number of milliseconds since January 1, 1970 local time)
		var now,fps;
		now = (+new Date);
		fps = 1000 / (now - this.lastTime);
		fps = clamp(fps, 12, 60);
		this.lastTime = now;
		return 1/fps;
	},
}; // end app.main<commit_msg>Added some starter for a draw-to-scale function.<commit_after>// main.js
// Dependencies:
// Description: singleton object
// This object will be our main "controller" class and will contain references
// to most of the other objects in the game.

"use strict";

// if app exists use the existing copy
// else create a new object literal
var app = app || {};

/*
 .main is an object literal that is a property of the app global
 This object literal has its own properties and methods (functions)

 */
app.main =
{
    WIDTH : 480, 				// Canvas width
    HEIGHT : 480,				// Canvas height
    canvas : undefined,			// Canvas
    ctx : undefined,			// Canvas context
   	lastTime : 0, 				// used by calculateDeltaTime()
    debug : true,				// debug
	animationID : 0,			//ID index of the current frame.

	radius : 12,

	testImage : undefined,

    //Initialization
	init : function()
	{
		//Init log
		console.log("app.main.init() called");

		// init canvas
		this.canvas = document.querySelector('canvas');
		this.canvas.width = this.WIDTH;
		this.canvas.height = this.HEIGHT;
		this.ctx = this.canvas.getContext('2d');
		this.ctx.mozImageSmoothingEnabled = false;
		this.ctx.msImageSmoothingEnabled = false;
		this.ctx.imageSmoothingEnabled = false;

		//Test image
		this.testImage = new Image(16, 16);
		this.testImage.src = "assets/temp.png";

		var scale1 = [];
		var scale2 = [];
		var scale4 = [];

		scale1.push(testImage);

		// start the game loop
		this.update();
	},

	//Core update
	update : function()
	{
		//LOOP
	 	this.animationID = requestAnimationFrame(this.update.bind(this));

	 	//Calculate Delta Time of frame
	 	var dt = this.calculateDeltaTime();

		//Clear
		this.ctx.save();
		//this.ctx.fillStyle = "#000";
		//this.ctx.fillRect(0, 0, this.WIDTH, this.HEIGHT);
		this.ctx.clearRect(0, 0, this.WIDTH, this.HEIGHT);
		this.ctx.restore();

		//Stuff
		this.ctx.save();
		this.ctx.arc(
			this.radius,
			this.radius,
			this.radius,
			0,
			Math.PI * 2);
		this.ctx.fillStyle = "#FFF";
		this.ctx.fill();
		/*
		this.ctx.drawImage(
			this.canvas,
			0,
			0,
			this.radius * 2,
			this.radius * 2,
			0,
			0,
			this.WIDTH,
			this.HEIGHT);
		*/
		this.ctx.drawImage(
			this.testImage,
			0,
			0,
			this.testImage.width,
			this.testImage.height,
			0,
			0,
			this.WIDTH,
			this.HEIGHT);
		this.ctx.restore();

		//Draw debug info
		if (this.debug)
		{
			// draw dt in bottom right corner
			this.fillText("dt: " + dt.toFixed(3), this.WIDTH - 140, this.HEIGHT - 10, "18pt courier", "white");
		}
	},

	drawScene : function(ctx, scale, images)
	{
		for(var i = 0; i < images.length; i++)
		{

		}
	}

	//Draw filled text
	fillText : function(string, x, y, css, color)
	{
		this.ctx.save();
		// https://developer.mozilla.org/en-US/docs/Web/CSS/font
		this.ctx.font = css;
		this.ctx.fillStyle = color;
		this.ctx.fillText(string, x, y);
		this.ctx.restore();
	},

	//Calculate delta-time
	calculateDeltaTime : function()
	{
		// what's with (+ new Date) below?
		// + calls Date.valueOf(), which converts it from an object to a
		// primitive (number of milliseconds since January 1, 1970 local time)
		var now,fps;
		now = (+new Date);
		fps = 1000 / (now - this.lastTime);
		fps = clamp(fps, 12, 60);
		this.lastTime = now;
		return 1/fps;
	},
}; // end app.main<|endoftext|>


<commit_before>// ==UserScript==
// @name        OSN HAX
// @namespace   com.oracle.osn.hax
// @description Hacks and modifications to enhance your Oracle Social Network user experience
// @include     https://osn-fusioncrm.oracle.com/osn/web/*
// @version     1.0
// @grant       none
// @run-at      document-start
// ==/UserScript==
function waitAndInstall(){
  var userName = document.getElementById('userName');
  if(userName === null){
    setTimeout(function(){waitAndInstall();},1000);
  }
  else{
    window.OSNH = {
        BASE_URLS: {
            'release':'https://stbeehive.oracle.com/content/dav/st/osn-hax/release/',
            'testing':'https://osn-hax.herokuapp.com/',
            'development':'https://c9.io/exjones/osn-hax/workspace/'
        },
        loadConfig:function(){
            var config = (typeof(window.localStorage) !== 'undefined') ? window.localStorage['OSNHAX_config'] : null;
            if(config === null || config === "") config = '{"channel":"release","components":null}';
            return JSON.parse(config);
        },
        saveConfig:function(obj){
            if(typeof(window.localStorage) !== 'undefined'){
                window.localStorage['OSNHAX_config'] = JSON.stringify(obj);
            }
        },
        log:function(msg){
            if(typeof(console) !== 'undefined' && typeof(console.log) !== 'undefined') console.log(msg);
        },
        injectScript:function(src){
            var el=document.createElement('script');
            el.type='text/javascript';
            el.src=src;
            document.body.appendChild(el);
        }
    };

    window.OSNH.config = window.OSNH.loadConfig();
    window.OSNH.saveConfig(window.OSNH.config);

    window.OSNH.log('Injecting OSN HAX bootstrap code from ' + window.OSNH.BASE_URLS[window.OSNH.config.channel]);
    window.OSNH.injectScript(window.OSNH.BASE_URLS[window.OSNH.config.channel] + 'osnh-bootstrap.js');
  }
}
// Don't run on frames or iframes
if (window.top != window.self) return;
else waitAndInstall();
<commit_msg>Changed null checking in config load<commit_after>// ==UserScript==
// @name        OSN HAX
// @namespace   com.oracle.osn.hax
// @description Hacks and modifications to enhance your Oracle Social Network user experience
// @include     https://osn-fusioncrm.oracle.com/osn/web/*
// @version     1.0
// @grant       none
// @run-at      document-start
// ==/UserScript==
function waitAndInstall(){
  var userName = document.getElementById('userName');
  if(userName === null){
    setTimeout(function(){waitAndInstall();},1000);
  }
  else{
    window.OSNH = {
        BASE_URLS: {
            'release':'https://stbeehive.oracle.com/content/dav/st/osn-hax/release/',
            'testing':'https://osn-hax.herokuapp.com/',
            'development':'https://c9.io/exjones/osn-hax/workspace/'
        },
        loadConfig:function(){
            var config = (typeof(window.localStorage) !== 'undefined') ? window.localStorage['OSNHAX_config'] : null;
            if(typeof(config) === 'undefined' || config === '') config = '{"channel":"release","components":null}';
            return JSON.parse(config);
        },
        saveConfig:function(obj){
            if(typeof(window.localStorage) !== 'undefined'){
                window.localStorage['OSNHAX_config'] = JSON.stringify(obj);
            }
        },
        log:function(msg){
            if(typeof(console) !== 'undefined' && typeof(console.log) !== 'undefined') console.log(msg);
        },
        injectScript:function(src){
            var el=document.createElement('script');
            el.type='text/javascript';
            el.src=src;
            document.body.appendChild(el);
        }
    };

    window.OSNH.config = window.OSNH.loadConfig();
    window.OSNH.saveConfig(window.OSNH.config);

    window.OSNH.log('Injecting OSN HAX bootstrap code from ' + window.OSNH.BASE_URLS[window.OSNH.config.channel]);
    window.OSNH.injectScript(window.OSNH.BASE_URLS[window.OSNH.config.channel] + 'osnh-bootstrap.js');
  }
}
// Don't run on frames or iframes
if (window.top != window.self) return;
else waitAndInstall();
<|endoftext|>


<commit_before>enyo.kind({
	name: "ServiceRegistry",
	debug: false,
	kind: enyo.Component,
	events: {
		onServicesChange: ""
	},
	components: [
		{name: "errorPopup", kind: "Ares.ErrorPopup"}
	],
	published: {
		services: []
	},
	create: function() {
		this.inherited(arguments);
		if (!ServiceRegistry.instance) {
			ServiceRegistry.instance = this;
			this.reloadServices();
		}
	},
	listServices: function(inType) {
		if (this.services.length === 0) {
			this.reloadServices();
		} else {
			this.notifyServicesChange();
		}
	},
	serviceFailure: function(serviceType, serviceId) {
		this.error("type="+ serviceType + ", id=" + serviceId);
		this.reloadServices();
	},
	reloadServices: function() {
		var self = this;
		this._reloadServices(function(err) {
			if (err) {
					self._handleReloadError(err);
			} else {
					self.notifyServicesChange();
			}
		});
	},
	/**
	 * @private
	 */
	_reloadServices: function(next) {
		if (this.debug) this.log("Refreshing the list of available services");
		var origin = window.location.origin || window.location.protocol + "//" + window.location.host; // Webkit/FF vs IE
		var url = origin + '/res/services';
		this.services = [];

		/* built-in services */

		// http://www.html5rocks.com/en/tutorials/file/filesystem/
		if (null /*window.requestFileSystem*/) {
			this.services.push({
				type: "filesystem",
				provider: "browser",
				name: "Browser Local Storage",
				icon: "server",
				moniker: "Browser Local Storage"
			});
		}

		/* Hermes Services (reload from the IDE server) */
		if (origin.match('^http')) {
			var req = new enyo.Ajax({url: url, handleAs: 'json'})
				.response(this, function(inSender, inValue) {
					var configs, self = this;
					if (inValue) {
						if (inValue.services && inValue.services[0]) {
							// dis-regard inactive service providers
							configs = inValue.services.filter(function(config){
								return config.active;
							});
							enyo.forEach(configs, function(config){
								this.services.push({
									config: config
								});
							}, this);
							this.complete(next);
						}
					} else {
						next(new Error("Empty response from Ares IDE Server"));
					}
					if (this.debug) this.log(this.services);
				})
				.error(this, function(err){
					next(err);
				})
				.go();
		}

	},
	/**
	 * Complete services configuration using localStorage
	 *
	 * Complement services loaded from the server with per-service
	 * data in the browser localStorage (for example the 'auth'
	 * property).  The completion vallbaclk is invoked once every
	 * configured services are completed.
	 *
	 * @param {Function} next a CommonJS callback
	 * @private
	 */
	complete: function(next) {
		var self = this,
		    tasks = enyo.map(this.services, function(service){
			return function(cb) {
				var key = [self.SERVICES_STORAGE_KEY, service.config.id].join('.');
				if (self.debug) self.log("localStorage[" + key + "]...");
				Ares.LocalStorage.get(key, function(str) {
					if (self.debug) self.log("localStorage[" + key + "] = ", str);
					var obj;
					try {
						obj = JSON.parse(str);
					} catch(e) {
						obj = {};
					}
					ares.extend(service.config, obj);
					self.instanciate(service, cb);
				});
			};
		});
		async.parallel(tasks, next);
	},
	instanciate: function(service, next) {
		if (this.debug) this.log("id:", service.config.id, "config:", service.config);
		try {
			if (service.config.type === "filesystem" && service.config.provider === "hermes") {
				// hermes type of services use
				// a common front-end
				service.impl = new HermesFileSystem();
				service.impl.notifyFailure = enyo.bind(this, this.serviceFailure, service.config.type, service.config.id);
			} else if (service.config.type === "build" && service.config.provider === "hermes" && service.config.id === "phonegap") {
				service.impl = new Phonegap.Build();
			} else if (service.config.type === "other" && service.config.provider === "hermes" && service.config.id === "prj-toolkit") {
				service.impl = new ProjectToolkit();
			} else if (service.config.type === "plugin") {
				// TODO: TBC
			}
			if (service.impl) {
				if (this.debug) this.log("id:", service.config.id, "created");
				// If the service does not define an
				// 'authorize()' entry point (which optionally
				// returns user acccount information), stub it
				// using a Common-JS pass-through.
				if (service.impl && !service.impl.authorize) {
					if (this.debug) this.log("Adding " + service.config.id + "#authorize() stub");
					service.impl.authorize = enyo.bind(service.impl, function(next) {
						if (this.debug) this.log('authorize(): stubbed');
						next(null, {});
					});
				}

				// Make sure both the service configuration
				// Object & the resulting implementation
				// Object know the serviceId.
				service.impl.id = service.config.id;

				service.impl.setConfig(service.config);
				if (this.debug) this.log("id:", service.config.id, "configured");
			} else {
				this.log("Ignoring service: " + service.config.id);
			}
			next();
		} catch(err) {
			this.error(err);
			next(err);
		}
	},
	/**
	 * @private
	 */
	SERVICES_STORAGE_KEY: "com.enyojs.ares.services",
	/**
	 * Set the given value in the given serviceId configuration
	 *
	 * Update the living instances & save the modified
	 * configuration in the localStorage, if applicable.
	 *
	 * Today, only auth part of the given config object is saved
	 * to localStorage.
	 * @param {String} inServiceId
	 * @param {Object} inConfig
	 * @param {Function} inCallback a CommonJS callback
	 */
	setConfig: function (inServiceId, inConfig, inCallback) {
		if (this.debug) this.log("serviceId:", inServiceId, "config:", inConfig);
		var service = this.resolveServiceId(inServiceId);
		if (!service) return;	// should we rather fail here?
		ares.extend(service.config, inConfig);
		service.setConfig(service.config);

		var key = [this.SERVICES_STORAGE_KEY, service.config.id].join('.');
		Ares.LocalStorage.set(key, JSON.stringify({auth: service.config.auth}), inCallback);
	},
	/**
	 * @param {String} serviceId
	 * @return {Object} service associated with the given serviceId
	 * @public
	 * @deprecated
	 * @see ServiceRegistry#filter
	 */
	resolveServiceId: function(serviceId) {
		var services = this.filter({properties: ['id'], id: serviceId});
		return services && services[0];
	},
	/**
	 * Give services whose type matches the given one
	 *
	 * If type is not provided or falsy, this method returns every
	 * registered & active services.
	 *
	 * @param {String} type one of ['filesystem', 'build', undefined]
	 * @return {Array} services matching the required type
	 * @public
	 * @deprecated
	 * @see ServiceRegistry#filter
	 */
	getServicesByType: function(type) {
		return this.filter({properties: ['type'], type: type});
	},
	/**
	 * Get {Array} or service matching the given criteria
	 * @param {Object} criteria
	 * @return {Array} services matching the required criteria
	 * @public
	 */
	filter: function(criteria) {
		//if (this.debug) this.log("criteria:", criteria, ", services:", this.services);
		var matches = enyo.filter(this.services, function(service){
			var match = true;
			if (criteria &&
			    criteria.properties &&
			    criteria.properties.length &&
			    criteria.properties[0]) {
				enyo.forEach(criteria.properties, function(prop) {
					if (criteria[prop]) {
						// filter on criteria property value
						match = match && (service.config[prop] === criteria[prop]);
					} else {
						// filter on criteria property presence
						match = match && (service.config[prop] !== undefined);
					}
				}, this);
			}
			//if (this.debug) this.log("match:", match, "<= service:", service.config);
			return match;
		}, this);
		var services = [];
		//if (this.debug) this.log("matches:", matches);
		enyo.forEach(matches, function(match){
			if (match.impl) {
				services.push(match.impl);
			}
		}, this);
		if (this.debug) this.log("criteria:", criteria , " => services:", services);
		return services;
	},
	/**
	 * Calls the given callback for each instanciated service
	 *
	 * The service implementation instance is the first & only
	 * parameter of the callback.
	 *
	 * @param {Function} fn the callback
	 * @return nothing
	 */
	forEach: function(fn) {
		enyo.forEach(this.services, function(service) {
			if (service.impl) {
				fn(service.impl);
			}
		}, this);
	},
	//* @private
	_handleReloadError: function(err) {
		this.$.errorPopup.setErrorMsg("Ares IDE Server returned an error");
		this.$.errorPopup.show();
		this.error("Error: "+JSON.stringify(err));
	},
	/**
	 * Notify every possible users of a change in the list of providers
	 *
	 * For example, there might be many instances of the
	 * {ProvidersList} control (widget) in the application.
	 *
	 * @private
	 */
	notifyServicesChange: function() {
		if (this.debug) this.log("sending signal...");
		enyo.Signals.send("onServicesChange", {serviceRegistry: this});
	},
	statics: {
		instance: null
	}
});
<commit_msg>ENYO-1783: Put in place plugin mechanism<commit_after>enyo.kind({
	name: "ServiceRegistry",
	debug: false,
	kind: enyo.Component,
	events: {
		onServicesChange: ""
	},
	components: [
		{name: "errorPopup", kind: "Ares.ErrorPopup"}
	],
	published: {
		services: []
	},
	create: function() {
		this.inherited(arguments);
		if (!ServiceRegistry.instance) {
			ServiceRegistry.instance = this;
			this.reloadServices();
		}
	},
	listServices: function(inType) {
		if (this.services.length === 0) {
			this.reloadServices();
		} else {
			this.notifyServicesChange();
		}
	},
	serviceFailure: function(serviceType, serviceId) {
		this.error("type="+ serviceType + ", id=" + serviceId);
		this.reloadServices();
	},
	reloadServices: function() {
		var self = this;
		this._reloadServices(function(err) {
			if (err) {
					self._handleReloadError(err);
			} else {
					self.notifyServicesChange();
			}
		});
	},
	/**
	 * @private
	 */
	_reloadServices: function(next) {
		if (this.debug) this.log("Refreshing the list of available services");
		var origin = window.location.origin || window.location.protocol + "//" + window.location.host; // Webkit/FF vs IE
		var url = origin + '/res/services';
		this.services = [];

		/* built-in services */

		// http://www.html5rocks.com/en/tutorials/file/filesystem/
		if (null /*window.requestFileSystem*/) {
			this.services.push({
				type: "filesystem",
				provider: "browser",
				name: "Browser Local Storage",
				icon: "server",
				moniker: "Browser Local Storage"
			});
		}

		/* Hermes Services (reload from the IDE server) */
		if (origin.match('^http')) {
			var req = new enyo.Ajax({url: url, handleAs: 'json'})
				.response(this, function(inSender, inValue) {
					var configs, self = this;
					if (inValue) {
						if (inValue.services && inValue.services[0]) {
							// dis-regard inactive service providers
							configs = inValue.services.filter(function(config){
								return config.active;
							});
							enyo.forEach(configs, function(config){
								this.services.push({
									config: config
								});
							}, this);
							this.complete(next);
						}
					} else {
						next(new Error("Empty response from Ares IDE Server"));
					}
					if (this.debug) this.log(this.services);
				})
				.error(this, function(err){
					next(err);
				})
				.go();
		}

	},
	/**
	 * Complete services configuration using localStorage
	 *
	 * Complement services loaded from the server with per-service
	 * data in the browser localStorage (for example the 'auth'
	 * property).  The completion vallbaclk is invoked once every
	 * configured services are completed.
	 *
	 * @param {Function} next a CommonJS callback
	 * @private
	 */
	complete: function(next) {
		var self = this,
		    tasks = enyo.map(this.services, function(service){
			return function(cb) {
				var key = [self.SERVICES_STORAGE_KEY, service.config.id].join('.');
				if (self.debug) self.log("localStorage[" + key + "]...");
				Ares.LocalStorage.get(key, function(str) {
					if (self.debug) self.log("localStorage[" + key + "] = ", str);
					var obj;
					try {
						obj = JSON.parse(str);
					} catch(e) {
						obj = {};
					}
					ares.extend(service.config, obj);
					self.instanciate(service, cb);
				});
			};
		});
		async.parallel(tasks, next);
	},
	instanciate: function(service, next) {
		if (this.debug) this.log("id:", service.config.id, "config:", service.config);
		try {
			if (service.config.type === "filesystem" && service.config.provider === "hermes") {
				// hermes type of services use
				// a common front-end
				service.impl = new HermesFileSystem();
				service.impl.notifyFailure = enyo.bind(this, this.serviceFailure, service.config.type, service.config.id);
				this.configureService(service, next);
			} else if (service.config.type === "build" && service.config.provider === "hermes" && service.config.id === "phonegap") {
				service.impl = new Phonegap.Build();
				this.configureService(service, next);
			} else if (service.config.type === "other" && service.config.provider === "hermes" && service.config.id === "prj-toolkit") {
				service.impl = new ProjectToolkit();
				this.configureService(service, next);
			} else if (service.config.type === "plugin") {
				if (this.debug) this.log("Loading browser side code: " + service.config.plugin.browsercode);
				enyo.load(service.config.plugin.browsercode, function() {
					if (this.debug) this.log("LOADED browser side code: " + service.config.plugin.browsercode);
				}.bind(this));
				next();		// configuration will be applied later on
			} else {
				if (this.debug) this.log("Ignoring service: " + service.config.id);
				next();
			}
		} catch(err) {
			this.error(err);
			next(err);
		}
	},
	configureService: function(service, next) {
		if (this.debug) this.log("id:", service.config.id, "config:", service.config);
		try {
			if (service.impl) {
				if (this.debug) this.log("id:", service.config.id, "created");
				// If the service does not define an
				// 'authorize()' entry point (which optionally
				// returns user acccount information), stub it
				// using a Common-JS pass-through.
				if (service.impl && !service.impl.authorize) {
					if (this.debug) this.log("Adding " + service.config.id + "#authorize() stub");
					service.impl.authorize = enyo.bind(service.impl, function(next) {
						if (this.debug) this.log('authorize(): stubbed');
						next(null, {});
					});
				}

				// Make sure both the service configuration
				// Object & the resulting implementation
				// Object know the serviceId.
				service.impl.id = service.config.id;

				service.impl.setConfig(service.config);
				if (this.debug) this.log("id:", service.config.id, "configured");
			} else {
				if (this.debug) this.log("Ignoring service: " + service.config.id);
			}
			next();
		} catch(err) {
			this.error(err);
			next(err);
		}
	},
	/**
	 * @private
	 */
	SERVICES_STORAGE_KEY: "com.enyojs.ares.services",
	/**
	 * Set the given value in the given serviceId configuration
	 *
	 * Update the living instances & save the modified
	 * configuration in the localStorage, if applicable.
	 *
	 * Today, only auth part of the given config object is saved
	 * to localStorage.
	 * @param {String} inServiceId
	 * @param {Object} inConfig
	 * @param {Function} inCallback a CommonJS callback
	 */
	setConfig: function (inServiceId, inConfig, inCallback) {
		if (this.debug) this.log("serviceId:", inServiceId, "config:", inConfig);
		var service = this.resolveServiceId(inServiceId);
		if (!service) return;	// should we rather fail here?
		ares.extend(service.config, inConfig);
		service.setConfig(service.config);

		var key = [this.SERVICES_STORAGE_KEY, service.config.id].join('.');
		Ares.LocalStorage.set(key, JSON.stringify({auth: service.config.auth}), inCallback);
	},
	/**
	 * @param {String} serviceId
	 * @return {Object} service associated with the given serviceId
	 * @public
	 * @deprecated
	 * @see ServiceRegistry#filter
	 */
	resolveServiceId: function(serviceId) {
		var services = this.filter({properties: ['id'], id: serviceId});
		return services && services[0];
	},
	/**
	 * Give services whose type matches the given one
	 *
	 * If type is not provided or falsy, this method returns every
	 * registered & active services.
	 *
	 * @param {String} type one of ['filesystem', 'build', undefined]
	 * @return {Array} services matching the required type
	 * @public
	 * @deprecated
	 * @see ServiceRegistry#filter
	 */
	getServicesByType: function(type) {
		return this.filter({properties: ['type'], type: type});
	},
	/**
	 * Get {Array} or service matching the given criteria
	 * @param {Object} criteria
	 * @return {Array} services matching the required criteria
	 * @public
	 */
	filter: function(criteria, withNoImpl) {
		withNoImpl = withNoImpl || false;
		//if (this.debug) this.log("criteria:", criteria, ", services:", this.services);
		var matches = enyo.filter(this.services, function(service){
			var match = true;
			if (criteria &&
			    criteria.properties &&
			    criteria.properties.length &&
			    criteria.properties[0]) {
				enyo.forEach(criteria.properties, function(prop) {
					if (criteria[prop]) {
						// filter on criteria property value
						match = match && (service.config[prop] === criteria[prop]);
					} else {
						// filter on criteria property presence
						match = match && (service.config[prop] !== undefined);
					}
				}, this);
			}
			//if (this.debug) this.log("match:", match, "<= service:", service.config);
			return match;
		}, this);
		var services = [];
		//if (this.debug) this.log("matches:", matches);
		enyo.forEach(matches, function(match){
			if (match.impl)  {
				services.push(match.impl);
			} else if (withNoImpl === true) {
				services.push(match);
			}
		}, this);
		if (this.debug) this.log("withNoImpl:", withNoImpl, "criteria:", criteria , " => services:", services);
		return services;
	},
	/**
	 * Calls the given callback for each instanciated service
	 *
	 * The service implementation instance is the first & only
	 * parameter of the callback.
	 *
	 * @param {Function} fn the callback
	 * @return nothing
	 */
	forEach: function(fn) {
		enyo.forEach(this.services, function(service) {
			if (service.impl) {
				fn(service.impl);
			}
		}, this);
	},
	//* @private
	_handleReloadError: function(err) {
		this.$.errorPopup.setErrorMsg("Ares IDE Server returned an error");
		this.$.errorPopup.show();
		this.error("Error: "+JSON.stringify(err));
	},
	/**
	 * Notify every possible users of a change in the list of providers
	 *
	 * For example, there might be many instances of the
	 * {ProvidersList} control (widget) in the application.
	 *
	 * @private
	 */
	notifyServicesChange: function() {
		if (this.debug) this.log("sending signal...");
		enyo.Signals.send("onServicesChange", {serviceRegistry: this});
	},
	pluginReady: function(id, impl) {
		if (this.debug) this.log("New plugin ready: " + id);
		var services = this.filter({properties: ['id'], id: id}, true);
		var error = true;
		if (services.length === 1) {
			var service = services[0];
			if (service.config.type === 'plugin' && ( ! service.impl)) {
				error = false;
				service.impl = impl;
				impl.setConfig(service.config);
				if (this.debug) this.log("New plugin registered: " + id);
			}
		}

		if (error) {
			if (this.debug) this.log("Unexpected plugin ready request for: " + id);
		}
	},
	statics: {
		instance: null
	}
});
<|endoftext|>


<commit_before>enyo.kind({
	name: "ServiceRegistry",
	debug: false,
	kind: enyo.Component,
	events: {
		onServicesChange: ""
	},
	components: [
		{name: "errorPopup", kind: "Ares.ErrorPopup"}
	],
	published: {
		services: []
	},
	create: function() {
		this.inherited(arguments);
		if (!ServiceRegistry.instance) {
			ServiceRegistry.instance = this;
			this.reloadServices();
		}
	},
	listServices: function(inType) {
		if (this.services.length === 0) {
			this.reloadServices();
		} else {
			this.notifyServicesChange();
		}
	},
	serviceFailure: function(serviceType, serviceId) {
		this.error("type="+ serviceType + ", id=" + serviceId);
		this.reloadServices();
	},
	reloadServices: function() {
		var self = this;
		this._reloadServices(function(err) {
			if (err) {
					self._handleReloadError(err);
			} else {
					self.notifyServicesChange();
			}
		});
	},
	/**
	 * @private
	 */
	_reloadServices: function(next) {
		if (this.debug) this.log("Refreshing the list of available services");
		var origin = window.location.origin || window.location.protocol + "//" + window.location.host; // Webkit/FF vs IE
		var url = origin + '/res/services';
		this.services = [];

		/* built-in services */

		// http://www.html5rocks.com/en/tutorials/file/filesystem/
		if (null /*window.requestFileSystem*/) {
			this.services.push({
				type: "filesystem",
				provider: "browser",
				name: "Browser Local Storage",
				icon: "server",
				moniker: "Browser Local Storage"
			});
		}

		/* Hermes Services (reload from the IDE server) */
		if (origin.match('^http')) {
			var req = new enyo.Ajax({url: url, handleAs: 'json'})
				.response(this, function(inSender, inValue) {
					var configs, self = this;
					if (inValue) {
						if (inValue.services && inValue.services[0]) {
							// dis-regard inactive service providers
							configs = inValue.services.filter(function(config){
								return config.active;
							});
							enyo.forEach(configs, function(config){
								this.services.push({
									config: config
								});
							}, this);
							this.complete(next);
						}
					} else {
						next(new Error("Empty response from Ares IDE Server"));
					}
					if (this.debug) this.log(this.services);
				})
				.error(this, function(err){
					next(err);
				})
				.go();
		}
	},
	/**
	 * Complete services configuration using localStorage
	 *
	 * Complement services loaded from the server with per-service
	 * data in the browser localStorage (for example the 'auth'
	 * property).  The completion vallbaclk is invoked once every
	 * configured services are completed.
	 *
	 * @param {Function} next a CommonJS callback
	 * @private
	 */
	complete: function(next) {
		var self = this,
			tasks = enyo.map(this.services, function(service){
			return function(cb) {
				var key = [self.SERVICES_STORAGE_KEY, service.config.id].join('.');
				if (self.debug) self.log("localStorage[" + key + "]...");
				Ares.LocalStorage.get(key, function(str) {
					if (self.debug) self.log("localStorage[" + key + "] = ", str);
					var obj;
					try {
						obj = JSON.parse(str);
					} catch(e) {
						obj = {};
					}
					ares.extend(service.config, obj);

					// Add an helper function to check interfaces implemented by a service
					ares.extend(service, {
						implementsType: function(expected) {
							return enyo.filter(this.config.type, function(type) {
								return type === expected;
							}).length > 0;
						}
					});
					self.instanciate(service, cb);
				});
			};
		});
		async.series(tasks, next);
	},
	instanciate: function(service, next) {
		if (this.debug) this.log("id:", service.config.id, "config:", service.config);
		try {
			if (service.config.pluginUrl) {
				if (this.debug) this.log("Loading browser side code: " + service.config.pluginUrl);
				enyo.load(service.config.pluginUrl, function() {
					if (this.debug) this.log("LOADED browser side code: " + service.config.pluginUrl);
				}.bind(this));
				next();		// configuration will be applied later on
			} else if (service.config.provider === 'hermes' && service.implementsType("filesystem")) {
				// hermes type of services use
				// a common front-end
				service.impl = new HermesFileSystem();
				service.impl.notifyFailure = enyo.bind(this, this.serviceFailure, service.config.type, service.config.id);
				this.configureService(service, next);
			} else if (service.implementsType("build") && service.config.id === "phonegap") {
				service.impl = new Phonegap.Build();
				this.configureService(service, next);
			} else if (service.implementsType("generate") && service.config.id === "genZip") {
				service.impl = new ProjectToolkit();
				this.configureService(service, next);
			} else {
				this.log("Ignoring service: " + service.config.id);
				next();
			}
		} catch(err) {
			this.error(err);
			next(err);
		}
	},
	configureService: function(service, next) {
		if (this.debug) this.log("id:", service.config.id, "config:", service.config);
		try {
			if (service.impl) {
				if (this.debug) this.log("id:", service.config.id, "created");
				// If the service does not define an
				// 'authorize()' entry point (which optionally
				// returns user acccount information), stub it
				// using a Common-JS pass-through.
				if (service.impl && !service.impl.authorize) {
					if (this.debug) this.log("Adding " + service.config.id + "#authorize() stub");
					service.impl.authorize = enyo.bind(service.impl, function(next) {
						if (this.debug) this.log('authorize(): stubbed');
						next(null, {});
					});
				}

				// Make sure both the service configuration
				// Object & the resulting implementation
				// Object know the serviceId.
				service.impl.id = service.config.id;

				try {
					service.impl.setConfig(service.config);
				} catch(pluginError) {
					var msg = "Unexpected error in setConfig() of service '" + service.config.id + "'";
					this.error(msg, pluginError);
					pluginError.msg = msg;
					throw pluginError;
				}
				if (this.debug) this.log("id:", service.config.id, "configured");
			} else {
				if (this.debug) this.log("Ignoring service: " + service.config.id);
			}
			next();
		} catch(err) {
			this.error(err);
			next(err);
		}
	},
	/**
	 * @private
	 */
	SERVICES_STORAGE_KEY: "com.enyojs.ares.services",
	/**
	 * Set the given value in the given serviceId configuration
	 *
	 * Update the living instances & save the modified
	 * configuration in the localStorage, if applicable.
	 *
	 * Today, only auth part of the given config object is saved
	 * to localStorage.
	 * @param {String} inServiceId
	 * @param {Object} inConfig
	 * @param {Function} inCallback a CommonJS callback
	 */
	setConfig: function (inServiceId, inConfig, inCallback) {
		if (this.debug) this.log("serviceId:", inServiceId, "config:", inConfig);
		var service = this.resolveServiceId(inServiceId);
		if (!service) return;	// should we rather fail here?
		ares.extend(service.config, inConfig);
		service.setConfig(service.config);

		var key = [this.SERVICES_STORAGE_KEY, service.config.id].join('.');
		Ares.LocalStorage.set(key, JSON.stringify({auth: service.config.auth}), inCallback);
	},
	/**
	 * @param {String} serviceId
	 * @return {Object} service associated with the given serviceId
	 * @public
	 * @deprecated
	 * @see ServiceRegistry#filter
	 */
	resolveServiceId: function(serviceId) {
		var services = this.filter(function(service) {
			return service.config.id === serviceId;
		});
		return services && services[0];
	},
	/**
	 * Give services whose type matches the given one
	 *
	 * If type is not provided or falsy, this method returns every
	 * registered & active services.
	 *
	 * @param {String} type one of ['filesystem', 'build', undefined]
	 * @return {Array} services matching the required type
	 * @public
	 * @deprecated
	 * @see ServiceRegistry#filter
	 */
	getServicesByType: function(type) {
		return this.filter(function(service) {
			return service.implementsType(type);
		});
	},
	/**
	 * Get {Array} or service matching the given criteria
	 * @param {Object} criteria
	 * @return {Array} services matching the required criteria
	 * @public
	 */
	filter: function(inFilterFunc, withNoImpl) {
		try {
			if (typeof inFilterFunc !== 'function') {
				throw new Error("Parameter 'inFilterFunc' must be a function");
			}
			withNoImpl = withNoImpl || false;
			var matches = enyo.filter(this.services, inFilterFunc, this);
			var services = [];
			//if (this.debug) this.log("matches:", matches);
			enyo.forEach(matches, function(match){
				if (match.impl)  {
					services.push(match.impl);
				} else if (withNoImpl === true) {
					services.push(match);
				}
			}, this);
			if (this.debug) this.log("withNoImpl:", withNoImpl, " => services:", services);
			return services;
		} catch(error) {
			this.error("Unexpected error", error);
			return [];
		}
	},
	/**
	 * Calls the given callback for each instanciated service
	 *
	 * The service implementation instance is the first & only
	 * parameter of the callback.
	 *
	 * @param {Function} fn the callback
	 * @return nothing
	 */
	forEach: function(fn) {
		enyo.forEach(this.services, function(service) {
			if (service.impl) {
				fn(service.impl);
			}
		}, this);
	},
	//* @private
	_handleReloadError: function(err) {
		this.$.errorPopup.setErrorMsg("Ares IDE Server returned an error");
		this.$.errorPopup.show();
		this.error("Error: "+JSON.stringify(err));
	},
	/**
	 * Notify every possible users of a change in the list of providers
	 *
	 * For example, there might be many instances of the
	 * {ProvidersList} control (widget) in the application.
	 *
	 * @private
	 */
	notifyServicesChange: function() {
		if (this.debug) this.log("sending signal...");
		enyo.Signals.send("onServicesChange", {serviceRegistry: this});
	},
	pluginReady: function(serviceId, kindInformation) {
		if (this.debug) this.log("New plugin ready: " + serviceId);
		var services = this.filter(function(service) {
			return service.config.id === serviceId;
		}, true);
		var error = true;
		if (services.length === 1) {
			var service = services[0];
			if (service.config.pluginUrl && ( ! service.impl)) {
				try {
					var plugImplementaion = Ares.instance.createComponent(kindInformation);
					service.impl = plugImplementaion;
					plugImplementaion.setConfig(service.config);
					error = false;
					if (this.debug) this.log("New plugin registered: " + serviceId);
				} catch(err) {
					this.error("Unexpected error while creating '" + kindInformation.kind + "' for service " + serviceId , err);
					return;
				}
			}
		}

		if (error) {
			this.error("Unexpected plugin ready request for: " + serviceId);
		}
	},
	statics: {
		instance: null
	}
});
<commit_msg>ENYO-2053: review comment hook plugin implementation to ServiceRegistry<commit_after>enyo.kind({
	name: "ServiceRegistry",
	debug: false,
	kind: enyo.Component,
	events: {
		onServicesChange: ""
	},
	components: [
		{name: "errorPopup", kind: "Ares.ErrorPopup"}
	],
	published: {
		services: []
	},
	create: function() {
		this.inherited(arguments);
		if (!ServiceRegistry.instance) {
			ServiceRegistry.instance = this;
			this.reloadServices();
		}
	},
	listServices: function(inType) {
		if (this.services.length === 0) {
			this.reloadServices();
		} else {
			this.notifyServicesChange();
		}
	},
	serviceFailure: function(serviceType, serviceId) {
		this.error("type="+ serviceType + ", id=" + serviceId);
		this.reloadServices();
	},
	reloadServices: function() {
		var self = this;
		this._reloadServices(function(err) {
			if (err) {
					self._handleReloadError(err);
			} else {
					self.notifyServicesChange();
			}
		});
	},
	/**
	 * @private
	 */
	_reloadServices: function(next) {
		if (this.debug) this.log("Refreshing the list of available services");
		var origin = window.location.origin || window.location.protocol + "//" + window.location.host; // Webkit/FF vs IE
		var url = origin + '/res/services';
		this.services = [];

		/* built-in services */

		// http://www.html5rocks.com/en/tutorials/file/filesystem/
		if (null /*window.requestFileSystem*/) {
			this.services.push({
				type: "filesystem",
				provider: "browser",
				name: "Browser Local Storage",
				icon: "server",
				moniker: "Browser Local Storage"
			});
		}

		/* Hermes Services (reload from the IDE server) */
		if (origin.match('^http')) {
			var req = new enyo.Ajax({url: url, handleAs: 'json'})
				.response(this, function(inSender, inValue) {
					var configs, self = this;
					if (inValue) {
						if (inValue.services && inValue.services[0]) {
							// dis-regard inactive service providers
							configs = inValue.services.filter(function(config){
								return config.active;
							});
							enyo.forEach(configs, function(config){
								this.services.push({
									config: config
								});
							}, this);
							this.complete(next);
						}
					} else {
						next(new Error("Empty response from Ares IDE Server"));
					}
					if (this.debug) this.log(this.services);
				})
				.error(this, function(err){
					next(err);
				})
				.go();
		}
	},
	/**
	 * Complete services configuration using localStorage
	 *
	 * Complement services loaded from the server with per-service
	 * data in the browser localStorage (for example the 'auth'
	 * property).  The completion vallbaclk is invoked once every
	 * configured services are completed.
	 *
	 * @param {Function} next a CommonJS callback
	 * @private
	 */
	complete: function(next) {
		var self = this,
			tasks = enyo.map(this.services, function(service){
			return function(cb) {
				var key = [self.SERVICES_STORAGE_KEY, service.config.id].join('.');
				if (self.debug) self.log("localStorage[" + key + "]...");
				Ares.LocalStorage.get(key, function(str) {
					if (self.debug) self.log("localStorage[" + key + "] = ", str);
					var obj;
					try {
						obj = JSON.parse(str);
					} catch(e) {
						obj = {};
					}
					ares.extend(service.config, obj);

					// Add an helper function to check interfaces implemented by a service
					ares.extend(service, {
						implementsType: function(expected) {
							return enyo.filter(this.config.type, function(type) {
								return type === expected;
							}).length > 0;
						}
					});
					self.instanciate(service, cb);
				});
			};
		});
		async.series(tasks, next);
	},
	instanciate: function(service, next) {
		if (this.debug) this.log("id:", service.config.id, "config:", service.config);
		try {
			if (service.config.pluginUrl) {
				if (this.debug) this.log("Loading browser side code: " + service.config.pluginUrl);
				enyo.load(service.config.pluginUrl, function() {
					if (this.debug) this.log("LOADED browser side code: " + service.config.pluginUrl);
				}.bind(this));
				next();		// configuration will be applied later on
			} else if (service.config.provider === 'hermes' && service.implementsType("filesystem")) {
				// hermes type of services use
				// a common front-end
				service.impl = new HermesFileSystem();
				service.impl.notifyFailure = enyo.bind(this, this.serviceFailure, service.config.type, service.config.id);
				this.configureService(service, next);
			} else if (service.implementsType("build") && service.config.id === "phonegap") {
				service.impl = new Phonegap.Build();
				this.configureService(service, next);
			} else if (service.implementsType("generate") && service.config.id === "genZip") {
				service.impl = new ProjectToolkit();
				this.configureService(service, next);
			} else {
				this.log("Ignoring service: " + service.config.id);
				next();
			}
		} catch(err) {
			this.error(err);
			next(err);
		}
	},
	configureService: function(service, next) {
		if (this.debug) this.log("id:", service.config.id, "config:", service.config);
		try {
			if (service.impl) {
				if (this.debug) this.log("id:", service.config.id, "created");
				// If the service does not define an
				// 'authorize()' entry point (which optionally
				// returns user acccount information), stub it
				// using a Common-JS pass-through.
				if (service.impl && !service.impl.authorize) {
					if (this.debug) this.log("Adding " + service.config.id + "#authorize() stub");
					service.impl.authorize = enyo.bind(service.impl, function(next) {
						if (this.debug) this.log('authorize(): stubbed');
						next(null, {});
					});
				}

				// Make sure both the service configuration
				// Object & the resulting implementation
				// Object know the serviceId.
				service.impl.id = service.config.id;

				try {
					service.impl.setConfig(service.config);
				} catch(pluginError) {
					var msg = "Unexpected error in setConfig() of service '" + service.config.id + "'";
					this.error(msg, pluginError);
					pluginError.msg = msg;
					throw pluginError;
				}
				if (this.debug) this.log("id:", service.config.id, "configured");
			} else {
				if (this.debug) this.log("Ignoring service: " + service.config.id);
			}
			next();
		} catch(err) {
			this.error(err);
			next(err);
		}
	},
	/**
	 * @private
	 */
	SERVICES_STORAGE_KEY: "com.enyojs.ares.services",
	/**
	 * Set the given value in the given serviceId configuration
	 *
	 * Update the living instances & save the modified
	 * configuration in the localStorage, if applicable.
	 *
	 * Today, only auth part of the given config object is saved
	 * to localStorage.
	 * @param {String} inServiceId
	 * @param {Object} inConfig
	 * @param {Function} inCallback a CommonJS callback
	 */
	setConfig: function (inServiceId, inConfig, inCallback) {
		if (this.debug) this.log("serviceId:", inServiceId, "config:", inConfig);
		var service = this.resolveServiceId(inServiceId);
		if (!service) return;	// should we rather fail here?
		ares.extend(service.config, inConfig);
		service.setConfig(service.config);

		var key = [this.SERVICES_STORAGE_KEY, service.config.id].join('.');
		Ares.LocalStorage.set(key, JSON.stringify({auth: service.config.auth}), inCallback);
	},
	/**
	 * @param {String} serviceId
	 * @return {Object} service associated with the given serviceId
	 * @public
	 * @deprecated
	 * @see ServiceRegistry#filter
	 */
	resolveServiceId: function(serviceId) {
		var services = this.filter(function(service) {
			return service.config.id === serviceId;
		});
		return services && services[0];
	},
	/**
	 * Give services whose type matches the given one
	 *
	 * If type is not provided or falsy, this method returns every
	 * registered & active services.
	 *
	 * @param {String} type one of ['filesystem', 'build', undefined]
	 * @return {Array} services matching the required type
	 * @public
	 * @deprecated
	 * @see ServiceRegistry#filter
	 */
	getServicesByType: function(type) {
		return this.filter(function(service) {
			return service.implementsType(type);
		});
	},
	/**
	 * Get {Array} or service matching the given criteria
	 * @param {Object} criteria
	 * @return {Array} services matching the required criteria
	 * @public
	 */
	filter: function(inFilterFunc, withNoImpl) {
		try {
			if (typeof inFilterFunc !== 'function') {
				throw new Error("Parameter 'inFilterFunc' must be a function");
			}
			withNoImpl = withNoImpl || false;
			var matches = enyo.filter(this.services, inFilterFunc, this);
			var services = [];
			//if (this.debug) this.log("matches:", matches);
			enyo.forEach(matches, function(match){
				if (match.impl)  {
					services.push(match.impl);
				} else if (withNoImpl === true) {
					services.push(match);
				}
			}, this);
			if (this.debug) this.log("withNoImpl:", withNoImpl, " => services:", services);
			return services;
		} catch(error) {
			this.error("Unexpected error", error);
			return [];
		}
	},
	/**
	 * Calls the given callback for each instanciated service
	 *
	 * The service implementation instance is the first & only
	 * parameter of the callback.
	 *
	 * @param {Function} fn the callback
	 * @return nothing
	 */
	forEach: function(fn) {
		enyo.forEach(this.services, function(service) {
			if (service.impl) {
				fn(service.impl);
			}
		}, this);
	},
	//* @private
	_handleReloadError: function(err) {
		this.$.errorPopup.setErrorMsg("Ares IDE Server returned an error");
		this.$.errorPopup.show();
		this.error("Error: "+JSON.stringify(err));
	},
	/**
	 * Notify every possible users of a change in the list of providers
	 *
	 * For example, there might be many instances of the
	 * {ProvidersList} control (widget) in the application.
	 *
	 * @private
	 */
	notifyServicesChange: function() {
		if (this.debug) this.log("sending signal...");
		enyo.Signals.send("onServicesChange", {serviceRegistry: this});
	},
	pluginReady: function(serviceId, kindInformation) {
		if (this.debug) this.log("New plugin ready: " + serviceId);
		var services = this.filter(function(service) {
			return service.config.id === serviceId;
		}, true);
		var error = true;
		if (services.length === 1) {
			var service = services[0];
			if (service.config.pluginUrl && ( ! service.impl)) {
				try {
					var plugImplementaion = ServiceRegistry.instance.createComponent(kindInformation);
					service.impl = plugImplementaion;
					plugImplementaion.setConfig(service.config);
					error = false;
					if (this.debug) this.log("New plugin registered: " + serviceId);
				} catch(err) {
					this.error("Unexpected error while creating '" + kindInformation.kind + "' for service " + serviceId , err);
					return;
				}
			}
		}

		if (error) {
			this.error("Unexpected plugin ready request for: " + serviceId);
		}
	},
	statics: {
		instance: null
	}
});
<|endoftext|>


<commit_before>/* global jasmine, cordova */
/**
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you 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.
*/

function Paramedic() {

}

Paramedic.prototype.initialize = function() {
    this.injectJasmineReporter();
};

Paramedic.prototype.injectJasmineReporter = function () {
    var EventCache = require('cordova-plugin-paramedic-event-cache.EventCache');
    var eventCache = new EventCache();
    var testsModule = cordova.require("cordova-plugin-test-framework.cdvtests");
    var defineAutoTestsOriginal = testsModule.defineAutoTests;

    testsModule.defineAutoTests = function () {
        defineAutoTestsOriginal();
        jasmine.getEnv().addReporter(eventCache);
    };
};

new Paramedic().initialize();

module.exports = Paramedic;
<commit_msg>CB-11430 Set SAUCELABS_ENV when running on Sauce<commit_after>/* global jasmine, cordova */
/**
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you 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.
*/

/* global window */

// CB-11430 Inject SAUCELABS_ENV global variable to indicate we're running on Saucelabs
window.SAUCELABS_ENV = true;

function Paramedic() {

}

Paramedic.prototype.initialize = function() {
    this.injectJasmineReporter();
};

Paramedic.prototype.injectJasmineReporter = function () {
    var EventCache = require('cordova-plugin-paramedic-event-cache.EventCache');
    var eventCache = new EventCache();
    var testsModule = cordova.require("cordova-plugin-test-framework.cdvtests");
    var defineAutoTestsOriginal = testsModule.defineAutoTests;

    testsModule.defineAutoTests = function () {
        defineAutoTestsOriginal();
        jasmine.getEnv().addReporter(eventCache);
    };
};

new Paramedic().initialize();

module.exports = Paramedic;
<|endoftext|>


<commit_before>(function(env) {
    env.ddg_spice_meta_cpan = function(api_response) {
        "use strict";

        if (!(api_response && api_response.author && api_response.version)) {
            return;
        }

        var query = DDG.get_query().replace(/\s*(metacpan|meta cpan|cpanm?)\s*/i, '').replace(/-/g, '::');
        var link = "search?q=" + encodeURIComponent(query);
        if (api_response.module && api_response.module.length > 0 && api_response.module[0].associated_pod) {
            link = "module/" + api_response.module[0].associated_pod;
        }

        Spice.add({
            id: "meta_cpan",
            name: "MetaCPAN",
            data: {response: api_response, list: ['Abstract','Author','Version','Description']},
            meta: {
                sourceName: "MetaCPAN",
                sourceUrl: 'https://metacpan.org/' + link,
            },

            normalize : function(item) {
                var desc = item.response.pod;
                return {
                    'Author': item.response.author || null,
                    'Description': ((desc.length > 340) ? desc.slice(0, 340) + ' ...' : null),
                    'Version': item.response.version || null,
                    'Abstract': item.response.abstract || null
                };
            },
            templates: {
                detail: DDG.templates.record_detail,
            }
        });
    }
}(this));<commit_msg>cpan: update for record template<commit_after>(function(env) {
    env.ddg_spice_meta_cpan = function(api_result) {
        "use strict";

        if (!(api_result && api_result.author && api_result.version)) {
            return;
        }

        var query = DDG.get_query().replace(/\s*(metacpan|meta cpan|cpanm?)\s*/i, '').replace(/-/g, '::');
        var link = "search?q=" + encodeURIComponent(query);
        if (api_result.module && api_result.module.length > 0 && api_result.module[0].associated_pod) {
            link = "module/" + api_result.module[0].associated_pod;
        }

        Spice.add({
            id: "meta_cpan",
            name: "MetaCPAN",
            data: {record_values : api_result, record_keys: ['abstract','author','version','description']},
            meta: {
                sourceName: "MetaCPAN",
                sourceUrl: 'https://metacpan.org/' + link,
            },
            templates: {
                detail: DDG.templates.record
            }
        });
    }
}(this));<|endoftext|>


<commit_before>/**
 * A rate-limiting Throttle model, by IP address
 *
 */
var mongoose = require('mongoose')
var ipRegex = require('ip-regex')
var Schema = mongoose.Schema
mongoose.Promise = global.Promise
/**
 * Register the Throttle model
 *
 * @access public
 * @param {object} defaults
 * @return {object} Mongoose Model
 */
module.exports = function createThrottle (defaults) {
  if (defaults.mongoose.uri) {
    mongoose.createConnection(defaults.mongoose.uri)
  }
  if (!mongoose.connection.readyState) {
    console.warn('MongoDB connection not set. Skipping. Fix this by specifying the mongoose:uri option.')
  }
  var Throttle = new Schema({
    createdAt: {
      type: Date,
      required: true,
      default: Date.now,
      expires: defaults.rateLimit.ttl
    },
    ip: {
      type: String,
      required: true,
      trim: true,
      match: ipRegex()
    },
    hits: {
      type: Number,
      default: 1,
      required: true,
      max: defaults.rateLimit.max,
      min: 0
    }
  })

  Throttle.index(
    { createdAt: 1 },
    { expireAfterSeconds: defaults.rateLimit.ttl }
  )

  return mongoose.model('Throttle', Throttle)
}
<commit_msg>Remove Regex validation on Throttle<commit_after>/**
 * A rate-limiting Throttle model, by IP address
 *
 */
var mongoose = require('mongoose')
var Schema = mongoose.Schema
mongoose.Promise = global.Promise
/**
 * Register the Throttle model
 *
 * @access public
 * @param {object} defaults
 * @return {object} Mongoose Model
 */
module.exports = function createThrottle (defaults) {
  if (defaults.mongoose.uri) {
    mongoose.createConnection(defaults.mongoose.uri)
  }
  if (!mongoose.connection.readyState) {
    console.warn('MongoDB connection not set. Skipping. Fix this by specifying the mongoose:uri option.')
  }
  var Throttle = new Schema({
    createdAt: {
      type: Date,
      required: true,
      default: Date.now,
      expires: defaults.rateLimit.ttl
    },
    ip: {
      type: String,
      required: true,
      trim: true
    },
    hits: {
      type: Number,
      default: 1,
      required: true,
      max: defaults.rateLimit.max,
      min: 0
    }
  })

  Throttle.index(
    { createdAt: 1 },
    { expireAfterSeconds: defaults.rateLimit.ttl }
  )

  return mongoose.model('Throttle', Throttle)
}
<|endoftext|>


<commit_before>var server = "http://" + window.location.hostname + "/janus/";

var janus = null;
var streaming = null;
var started = false;
var spinner = null;

var selectedStream = null;

$(document).ready(function() {
	// Initialize the library (all console debuggers enabled)
	Janus.init({debug: "all", callback: function() {
		// Use a button to start the demo
		$('#start').click(function() {
			if(started)
				return;
			started = true;
			$(this).attr('disabled', true).unbind('click');
			// Make sure the browser supports WebRTC
			if(!Janus.isWebrtcSupported()) {
				bootbox.alert("No WebRTC support... ");
				return;
			}
			// Create session
			janus = new Janus(
				{
					server: server,
					success: function() {
						// Attach to streaming plugin
						janus.attach(
							{
								plugin: "janus.plugin.streaming",
								success: function(pluginHandle) {
									$('#details').remove();
									streaming = pluginHandle;
									Janus.log("Plugin attached! (" + streaming.getPlugin() + ", id=" + streaming.getId() + ")");
									// Setup streaming session
									$('#update-streams').click(updateStreamsList);
									updateStreamsList();
									$('#start').removeAttr('disabled').html("Stop")
										.click(function() {
											$(this).attr('disabled', true);
											janus.destroy();
											$('#streamslist').attr('disabled', true);
											$('#watch').attr('disabled', true).unbind('click');
											$('#start').attr('disabled', true).html("Bye").unbind('click');
										});
								},
								error: function(error) {
									Janus.error("  -- Error attaching plugin... ", error);
									bootbox.alert("Error attaching plugin... " + error);
								},
								onmessage: function(msg, jsep) {
									Janus.debug(" ::: Got a message :::");
									Janus.debug(JSON.stringify(msg));
									var result = msg["result"];
									if(result !== null && result !== undefined) {
										if(result["status"] !== undefined && result["status"] !== null) {
											var status = result["status"];
											if(status === 'starting')
												$('#status').removeClass('hide').text("Starting, please wait...").show();
											else if(status === 'started')
												$('#status').removeClass('hide').text("Started").show();
											else if(status === 'stopped')
												stopStream();
										}
									} else if(msg["error"] !== undefined && msg["error"] !== null) {
										bootbox.alert(msg["error"]);
										stopStream();
										return;
									}
									if(jsep !== undefined && jsep !== null) {
										Janus.debug("Handling SDP as well...");
										Janus.debug(jsep);
										// Answer
										streaming.createAnswer(
											{
												jsep: jsep,
												media: { audioSend: false, videoSend: false },	// We want recvonly audio/video
												success: function(jsep) {
													Janus.debug("Got SDP!");
													Janus.debug(jsep);
													var body = { "request": "start" };
													streaming.send({"message": body, "jsep": jsep});
													$('#watch').html("Stop").removeAttr('disabled').click(stopStream);
												},
												error: function(error) {
													Janus.error("WebRTC error:", error);
													bootbox.alert("WebRTC error... " + JSON.stringify(error));
												}
											});
									}
								},
								onremotestream: function(stream) {
									Janus.debug(" ::: Got a remote stream :::");
									Janus.debug(JSON.stringify(stream));
									if($('#remotevideo').length === 0)
										$('#stream').append('<video class="rounded centered hide" id="remotevideo" width=320 height=240 autoplay/>');
									// Show the stream and hide the spinner when we get a playing event
									$("#remotevideo").bind("playing", function () {
										$('#waitingvideo').remove();
										$('#remotevideo').removeClass('hide');
										if(spinner !== null && spinner !== undefined)
											spinner.stop();
										spinner = null;
									});
									attachMediaStream($('#remotevideo').get(0), stream);
								},
								oncleanup: function() {
									Janus.log(" ::: Got a cleanup notification :::");
									$('#waitingvideo').remove();
									$('#remotevideo').remove();
								}
							});
					},
					error: function(error) {
						Janus.error(error);
						bootbox.alert(error, function() {
							window.location.reload();
						});
					},
					destroyed: function() {
						window.location.reload();
					}
				});
		});
	}});
});

function updateStreamsList() {
	$('#update-streams').unbind('click').addClass('fa-spin');
	var body = { "request": "list" };
	Janus.debug("Sending message (" + JSON.stringify(body) + ")");
	streaming.send({"message": body, success: function(result) {
		setTimeout(function() {
			$('#update-streams').removeClass('fa-spin').click(updateStreamsList);
		}, 500);
		if(result === null || result === undefined) {
			bootbox.alert("Got no response to our query for available streams");
			return;
		}
		if(result["list"] !== undefined && result["list"] !== null) {
			$('#streams').removeClass('hide').show();
			$('#streamslist').empty();
			$('#watch').attr('disabled', true).unbind('click');
			var list = result["list"];
			Janus.log("Got a list of available streams");
			Janus.debug(list);
			for(var mp in list) {
				Janus.debug("  >> [" + list[mp]["id"] + "] " + list[mp]["description"] + " (" + list[mp]["type"] + ")");
				$('#streamslist').append("
" + list[mp]["description"] + " (" + list[mp]["type"] + ")" + "
");
			}
			$('#streamslist a').unbind('click').click(function() {
				selectedStream = $(this).attr("id");
				$('#streamset').html($(this).html()).parent().removeClass('open');
				return false;

			});
			$('#watch').removeAttr('disabled').click(startStream);

			Janus.log("Autostarting Stream 1");
			selectedStream = 1;
			startStream();
		}
	}});
}

function startStream() {
	Janus.log("Selected video id #" + selectedStream);
	if(selectedStream === undefined || selectedStream === null) {
		bootbox.alert("Select a stream from the list");
		return;
	}
	$('#streamset').attr('disabled', true);
	$('#streamslist').attr('disabled', true);
	$('#watch').attr('disabled', true).unbind('click');
	var body = { "request": "watch", id: parseInt(selectedStream) };
	streaming.send({"message": body});
	// No remote video yet
	$('#stream').append('<video class="rounded centered" id="waitingvideo" width=320 height=240 />');
	if(spinner == null) {
		var target = document.getElementById('stream');
		spinner = new Spinner({top:100}).spin(target);
	} else {
		spinner.spin();
	}
}

function stopStream() {
	$('#watch').attr('disabled', true).unbind('click');
	var body = { "request": "stop" };
	streaming.send({"message": body});
	streaming.hangup();
	$('#streamset').removeAttr('disabled');
	$('#streamslist').removeAttr('disabled');
	$('#watch').html("Watch or Listen").removeAttr('disabled').click(startStream);
	$('#status').empty().hide();
}
<commit_msg>vp8 switch<commit_after>var server = "http://" + window.location.hostname + "/janus/";

var janus = null;
var streaming = null;
var started = false;
var spinner = null;

// Select 1 for H264, 2 for VP8 (Chrome Support)
var selectedStream = 2;

$(document).ready(function() {
	// Initialize the library (all console debuggers enabled)
	Janus.init({debug: "all", callback: function() {
		// Use a button to start the demo
		$('#start').click(function() {
			if(started)
				return;
			started = true;
			$(this).attr('disabled', true).unbind('click');
			// Make sure the browser supports WebRTC
			if(!Janus.isWebrtcSupported()) {
				bootbox.alert("No WebRTC support... ");
				return;
			}
			// Create session
			janus = new Janus(
				{
					server: server,
					success: function() {
						// Attach to streaming plugin
						janus.attach(
							{
								plugin: "janus.plugin.streaming",
								success: function(pluginHandle) {
									$('#details').remove();
									streaming = pluginHandle;
									Janus.log("Plugin attached! (" + streaming.getPlugin() + ", id=" + streaming.getId() + ")");
									// Setup streaming session
									$('#update-streams').click(updateStreamsList);
									updateStreamsList();
									$('#start').removeAttr('disabled').html("Stop")
										.click(function() {
											$(this).attr('disabled', true);
											janus.destroy();
											$('#streamslist').attr('disabled', true);
											$('#watch').attr('disabled', true).unbind('click');
											$('#start').attr('disabled', true).html("Bye").unbind('click');
										});
								},
								error: function(error) {
									Janus.error("  -- Error attaching plugin... ", error);
									bootbox.alert("Error attaching plugin... " + error);
								},
								onmessage: function(msg, jsep) {
									Janus.debug(" ::: Got a message :::");
									Janus.debug(JSON.stringify(msg));
									var result = msg["result"];
									if(result !== null && result !== undefined) {
										if(result["status"] !== undefined && result["status"] !== null) {
											var status = result["status"];
											if(status === 'starting')
												$('#status').removeClass('hide').text("Starting, please wait...").show();
											else if(status === 'started')
												$('#status').removeClass('hide').text("Started").show();
											else if(status === 'stopped')
												stopStream();
										}
									} else if(msg["error"] !== undefined && msg["error"] !== null) {
										bootbox.alert(msg["error"]);
										stopStream();
										return;
									}
									if(jsep !== undefined && jsep !== null) {
										Janus.debug("Handling SDP as well...");
										Janus.debug(jsep);
										// Answer
										streaming.createAnswer(
											{
												jsep: jsep,
												media: { audioSend: false, videoSend: false },	// We want recvonly audio/video
												success: function(jsep) {
													Janus.debug("Got SDP!");
													Janus.debug(jsep);
													var body = { "request": "start" };
													streaming.send({"message": body, "jsep": jsep});
													$('#watch').html("Stop").removeAttr('disabled').click(stopStream);
												},
												error: function(error) {
													Janus.error("WebRTC error:", error);
													bootbox.alert("WebRTC error... " + JSON.stringify(error));
												}
											});
									}
								},
								onremotestream: function(stream) {
									Janus.debug(" ::: Got a remote stream :::");
									Janus.debug(JSON.stringify(stream));
									if($('#remotevideo').length === 0)
										$('#stream').append('<video class="rounded centered hide" id="remotevideo" width=320 height=240 autoplay/>');
									// Show the stream and hide the spinner when we get a playing event
									$("#remotevideo").bind("playing", function () {
										$('#waitingvideo').remove();
										$('#remotevideo').removeClass('hide');
										if(spinner !== null && spinner !== undefined)
											spinner.stop();
										spinner = null;
									});
									attachMediaStream($('#remotevideo').get(0), stream);
								},
								oncleanup: function() {
									Janus.log(" ::: Got a cleanup notification :::");
									$('#waitingvideo').remove();
									$('#remotevideo').remove();
								}
							});
					},
					error: function(error) {
						Janus.error(error);
						bootbox.alert(error, function() {
							window.location.reload();
						});
					},
					destroyed: function() {
						window.location.reload();
					}
				});
		});
	}});
});

function updateStreamsList() {
	$('#update-streams').unbind('click').addClass('fa-spin');
	var body = { "request": "list" };
	Janus.debug("Sending message (" + JSON.stringify(body) + ")");
	streaming.send({"message": body, success: function(result) {
		setTimeout(function() {
			$('#update-streams').removeClass('fa-spin').click(updateStreamsList);
		}, 500);
		if(result === null || result === undefined) {
			bootbox.alert("Got no response to our query for available streams");
			return;
		}
		if(result["list"] !== undefined && result["list"] !== null) {
			$('#streams').removeClass('hide').show();
			$('#streamslist').empty();
			$('#watch').attr('disabled', true).unbind('click');
			var list = result["list"];
			Janus.log("Got a list of available streams");
			Janus.debug(list);
			for(var mp in list) {
				Janus.debug("  >> [" + list[mp]["id"] + "] " + list[mp]["description"] + " (" + list[mp]["type"] + ")");
				$('#streamslist').append("
" + list[mp]["description"] + " (" + list[mp]["type"] + ")" + "
");
			}
			$('#streamslist a').unbind('click').click(function() {
				//selectedStream = $(this).attr("id");
				$('#streamset').html($(this).html()).parent().removeClass('open');
				return false;

			});
			$('#watch').removeAttr('disabled').click(startStream);

			Janus.log("Autostarting Stream 1");
			startStream();
		}
	}});
}

function startStream() {
	Janus.log("Selected video id #" + selectedStream);
	if(selectedStream === undefined || selectedStream === null) {
		bootbox.alert("Select a stream from the list");
		return;
	}
	$('#streamset').attr('disabled', true);
	$('#streamslist').attr('disabled', true);
	$('#watch').attr('disabled', true).unbind('click');
	var body = { "request": "watch", id: parseInt(selectedStream) };
	streaming.send({"message": body});
	// No remote video yet
	$('#stream').append('<video class="rounded centered" id="waitingvideo" width=320 height=240 />');
	if(spinner == null) {
		var target = document.getElementById('stream');
		spinner = new Spinner({top:100}).spin(target);
	} else {
		spinner.spin();
	}
}

function stopStream() {
	$('#watch').attr('disabled', true).unbind('click');
	var body = { "request": "stop" };
	streaming.send({"message": body});
	streaming.hangup();
	$('#streamset').removeAttr('disabled');
	$('#streamslist').removeAttr('disabled');
	$('#watch').html("Watch or Listen").removeAttr('disabled').click(startStream);
	$('#status').empty().hide();
}
<|endoftext|>


<commit_before>/******************************************
 * Form Handlers and page                 *
 * generators for TSSAA WebApp Fat Client *
 *****************************************/

/**
 * Login form handler
 */
$('#submit_button').on("click", function() {
		$.mobile.changePage("#options_page", "slideup", true, true);

		var formData = $("#login_form").serialize();

		$.ajax({
			type: "POST",
			url: "app_dev.php/login",
			cache: false,
			data: formData,
			success: onSuccess,
			error: onError
		});

		return false;
});

function onSuccess(response) {
}

function onError(error) {
		$("#response_output").text(error);
}

/**
 * Add user form ajax handler
 */
$('#add_user_submit').live('click', function() {

	var  formData = $('#add_user_form').serialize();

	$.ajax({
		type: "POST",
		url: "app_dev.php/add_user",
		cache: false,
		data: formData,
		success: popDBDialog,
	});

	return false;
});

/**
 * Add school form ajax handler
 */
$('#add_school_submit').live('click', function() {

	var  formData = $('#add_school_form').serialize();

	$.ajax({
		type: "POST",
		url: "app_dev.php/add_school",
		cache: false,
		data: formData,
        success: popDBDialog
	});

	return false;
});

/**
 * Get school list ajax handler
 */
$("#school_list_page").on("pagebeforechange", function(e, obj) {
        alert("we are post pagebeforechange");
        $.ajax({
            type: "GET",
            url:"app_dev.php/get_school_list",
            cache: "false",
            success: generateSchoolList
        });
});

/**
 * DB Dialog ajax success callback
 */
function popDBDialog(response) {
    try {
        var data = $.parseJSON(response);
    } catch(err) {
        alert(err);
    }

    var response_items = [];

    $.each(data, function(key, val) {
            response_items.push('
'+key+':	'+val+'
');
    });

    $('
',{
			'class': 'response_table',
			html: response_items.join('')
		}).replaceAll("#response");

    $.mobile.changePage("#db_confirm_dialog");
}

/**
 * School List response handler
 * generates ul of schools returned from DB
 */
function generateSchoolList(response) {

    try {
        var school_data = $.parseJSON(response);
    } catch(err) {
        alert(err);
    }

    var schools = [];

    $.each(school_data, function(school) {
                var name = school;
                var phone = school.phone;
                var address = school.address;

                //TODO expanding li for each school with phone, address, etc
                schools.push('
'+name+'
');
            });

    $('ul#school_list').html(schools.join(''));
    $('ul#school_list').listview("refresh");
};
<commit_msg>using .on for login page<commit_after>/******************************************
 * Form Handlers and page                 *
 * generators for TSSAA WebApp Fat Client *
 *****************************************/

/**
 * Login form handler
 */
$('#login_form').on("submit", function(e) {

		var formData = $("#login_form").serialize();

		$.ajax({
			type: "POST",
			url: "app_dev.php/login",
			cache: false,
			data: formData,
			success: onSuccess,
		});

		return false;
});

function onSuccess(response) {
    $.mobile.changePage("#options_page", "slideup", true, true);
}

/**
 * Add user form ajax handler
 */
$('#add_user_submit').live('click', function() {

	var  formData = $('#add_user_form').serialize();

	$.ajax({
		type: "POST",
		url: "app_dev.php/add_user",
		cache: false,
		data: formData,
		success: popDBDialog,
	});

	return false;
});

/**
 * Add school form ajax handler
 */
$('#add_school_submit').live('click', function() {

	var  formData = $('#add_school_form').serialize();

	$.ajax({
		type: "POST",
		url: "app_dev.php/add_school",
		cache: false,
		data: formData,
        success: popDBDialog
	});

	return false;
});

/**
 * Get school list ajax handler
 */
$("#school_list_page").on("pagebeforechange", function(e, obj) {
        alert("we are post pagebeforechange");
        $.ajax({
            type: "GET",
            url:"app_dev.php/get_school_list",
            cache: "false",
            success: generateSchoolList
        });
});

/**
 * DB Dialog ajax success callback
 */
function popDBDialog(response) {
    try {
        var data = $.parseJSON(response);
    } catch(err) {
        alert(err);
    }

    var response_items = [];

    $.each(data, function(key, val) {
            response_items.push('
'+key+':	'+val+'
');
    });

    $('
',{
			'class': 'response_table',
			html: response_items.join('')
		}).replaceAll("#response");

    $.mobile.changePage("#db_confirm_dialog");
}

/**
 * School List response handler
 * generates ul of schools returned from DB
 */
function generateSchoolList(response) {

    try {
        var school_data = $.parseJSON(response);
    } catch(err) {
        alert(err);
    }

    var schools = [];

    $.each(school_data, function(school) {
                var name = school;
                var phone = school.phone;
                var address = school.address;

                //TODO expanding li for each school with phone, address, etc
                schools.push('
'+name+'
');
            });

    $('ul#school_list').html(schools.join(''));
    $('ul#school_list').listview("refresh");
};
<|endoftext|>