<commit_before>/**
 * This class is used for upload in TinyMCE editor.
 * If one of methods is not commented look for comment in Upload.js.
*/
TinyMCEImageEnhancement = Class.create();
TinyMCEImageEnhancement.prototype = {
    initialize: function() {
        this.filesUploaded = 0;
        this.processInProgress = false;
        Event.observe(window,'load',this.onWindowLoad.bind(this));
    },

    addListeners: function() {
        $('Form_EditorToolbarImageForm_FolderID').value = "";

        Event.observe($('AddFolder'),'click',this.onAddFolder.bind(this));
        Event.observe($('FolderOk'),'click',this.onFolderOk.bind(this));
        Event.observe($('FolderCancel'),'click',this.onFolderCancel.bind(this));
        Event.observe($('UploadFiles'),'click',this.onUpload.bind(this));

		// Image alignment/style changing link
		Event.observe($('ImageAligmentStyle_left'),'click',this.onChangeImageAlignmentStyle.bind(this));
		Event.observe($('ImageAligmentStyle_leftAlone'),'click',this.onChangeImageAlignmentStyle.bind(this));
		Event.observe($('ImageAligmentStyle_right'),'click',this.onChangeImageAlignmentStyle.bind(this));
		Event.observe($('ImageAligmentStyle_center'),'click',this.onChangeImageAlignmentStyle.bind(this));
    },

    /**
     * Method creates HTML element, only reason for this method is DRY.
    */

    addElement: function(tag, className, parent, properties) {
        var e = document.createElement(tag);
        Element.addClassName(e,className);
        parent.appendChild(e);
        Object.extend(e,properties);
        return e;
    },

    onUpload: function(event) {
        Event.stop(event);
        if(!this.processInProgress) {
	        if(this.getParentID() != 'root') {
	            this.upload.browse();
	        } else {
	            statusMessage("Please choose folder","bad");
	        }
	    }
    },

	onChangeImageAlignmentStyle: function(event) {
		Event.stop(event);
		id = event.target.id ;
		jQuery(event.target).siblings().removeClass('selected');
		jQuery(event.target).addClass('selected');

		// get alignment from id, e.g. ImageAlignment_center -> center
		aligment = id.split('_')[1];
		$('Form_EditorToolbarImageForm_CSSClass').value = aligment;
	},

    /**
     * Called when user clicks "add folder" anchor.
    */

    onAddFolder: function(event) {
        Event.stop(event);
        Element.hide('AddFolder');
        Element.show('NewFolderName','FolderOk','FolderCancel');
        this.applyIE6Hack();
    },

	/**
	 * The user clicks the "ok" anchor link, the click event calls up
	 * this function which creates a new AJAX request to add a new folder
	 * using the addfolder function in AssetAdmin.php (admin/assets/addfolder).
	 */
	onFolderOk: function(event) {
		Event.stop(event);
		var folderName = $('NewFolderName').value;
		var options = {
			method: 'post',
			postBody: 'ParentID=' + this.getParentID() + '&ajax=1&returnID=1' + ($('SecurityID') ? '&SecurityID=' + $('SecurityID').value : ''),
			onSuccess: this.onFolderGetSuccess.bind(this),
			onFailure: function(transport) {
				errorMessage('Error: Folder not added', transport);
			}
		};

		new Ajax.Request('admin/assets/addfolder', options);
	},

	/**
	 * If the "addFolderOk" function does a successful AJAX post, call this
	 * function. Take the folder ID that was created in "addFolderOk"
	 * via ajax and send data to modify that folder record.
	 */
	onFolderGetSuccess: function(transport) {
		var folderID = transport.responseText;

		var date = new Date();
		var year = date.getFullYear();
		var month = date.getMonth() < 10 ? '0' + date.getMonth() : date.getMonth();
		var day = date.getDay() < 10  ? '0' + date.getDay() : date.getDay();
		var hours = date.getHours() < 10  ? '0' + date.getHours() : date.getHours();
		var minutes = date.getMinutes() < 10  ? '0' + date.getMinutes() : date.getMinutes();
		var seconds = date.getSeconds() < 10  == 1 ? '0' + date.getSeconds() : date.getSeconds();
		var currentDate = year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds;

		var folderName = $('NewFolderName').value;

		this.folderID = folderID;

		var options = {
			method: 'post',
			postBody: 'Created=' + currentDate + '&Name=' + folderName + '&ClassName=Folder&ID=' + folderID + '&ajax=1&action_save=1' + ($('SecurityID') ? '&SecurityID=' + $('SecurityID').value : ''),
			onSuccess: this.onFolderAddSuccess.bind(this),
			onFailure: function(transport) {
				errorMessage('Error: Folder not added', transport);
			}
		};

		new Ajax.Request('admin/assets/EditForm', options);
    },

    /**
     * When folder name has been changed we need to refresh folder list and return to initial state of UI.
    */

    onFolderAddSuccess: function(transport) {
        statusMessage('Creating new folder');
        $('TreeDropdownField_Form_EditorToolbarImageForm_FolderID').itemTree = null;
        $('TreeDropdownField_Form_EditorToolbarImageForm_FolderID').setValue(this.folderID);
        $('NewFolderName').value = '';
        Element.show('AddFolder');
        Element.hide('NewFolderName','FolderOk','FolderCancel');
        this.removeIE6Hack();
    },

    /**
     * If user doesn't want to add folder return to default UI.
    */

    onFolderCancel: function(event) {
        $('NewFolderName').value = '';
        Element.show('AddFolder');
        Element.hide('NewFolderName','FolderOk','FolderCancel');
        this.removeIE6Hack();
    },

    /**
     * Called on window.onload
    */

    onWindowLoad: function() {
        // Due to a bug in the flash plugin on Linux and Mac, we need at least version 9.0.64 to use SWFUpload
        if(navigator.appVersion.indexOf("Mac") != -1 || navigator.appVersion.indexOf("X11") != -1 || navigator.appVersion.indexOf("Linux") != -1) {
           pv = getFlashPlayerVersion();
           if(pv.major < 9 || (pv.major == 9 && pv.minor == 0 && pv.rev < 64)) {
              if($('AddFolderGroup')) $('AddFolderGroup').style.display = 'none';
              if($('PipeSeparator')) $('PipeSeparator').style.display = 'none';
              if($('UploadGroup')) $('UploadGroup').style.display = 'none';
              return;
           }
        }

        if($('FolderID') != null) {
        	if($('SecurityID')) var securityid=$('SecurityID').value;
	        else var securityid=null;
	        this.upload = new Upload(
	            {
	               fileTypes : '*.jpeg;*.jpg;*.jpe;*.png;*.gif;',
	               fileTypesDescription : 'Image files',
	               fileUploadLimit : '100',
	               securityID : securityid,
	               beginUploadOnQueue : true,
                   buildUI : this.addListeners.bind(this),
                   fileQueued : this.uploadFileQueuedCallback.bind(this),
                   fileComplete : this.uploadFileCompleteCallback.bind(this),
                   queueComplete : this.uploadQueueCompleteCallback.bind(this)
	            }
            );
        }
    },

    uploadFileQueuedCallback: function(file,queueLength) {
        this.processInProgress = true;
        this.upload.setFolderID(this.getParentID());
        $('UploadFiles').innerHTML = "Uploading ... 1/" + this.upload.getFilesToUpload();
        this.upload.startUpload();
    },

    uploadFileCompleteCallback: function(file,serverData) {
        Element.addClassName($('UploadFiles'),'link');//Safari hack
        $('UploadFiles').innerHTML = 'Uploading ... ' + this.upload.getFilesUploaded() + "/" + this.upload.getFilesToUpload();
    },

    uploadQueueCompleteCallback: function() {
        this.filesUploaded = this.upload.getFilesUploaded();
        $('UploadFiles').innerHTML = "upload";
        statusMessage('Uploaded ' + this.upload.getFilesUploaded() + ' files','good');
        if(this.getParentID() != 'root') {
            $('Image').ajaxGetFiles(this.getParentID(), null, this.insertImages.bind(this));
        }
    },

    /**
     * Iterates over all uploaded images and add them to TinyMCE editor
     *
     * @param transport object
    */
    insertImages: function(transport) {
        //HACK FOR STRANGE ERROR OCCURING UNDER SAFARI
        if(transport.responseText == '') {
            $('Image').ajaxGetFiles(this.getParentID(), null, this.insertImages.bind(this));
            return;
        }
        //END OF HACK

        $('Image').reapplyBehaviour();

        this.addToTinyMCE = this.addToTinyMCE.bind(this);

			this.processInProgress = false;
    },

    /**
     * Adds particular image to TinyMCE. Most of code has been copied from tiny_mce_improvements.js / ImageThumbnail.onclick
     * Sorry for not following DRY, I didn't want to break smth in tiny_mce_improvements.
     *
     *  @param target object
    */

    addToTinyMCE: function(target) {
		var formObj = $('Form_EditorToolbarImageForm');
        var altText = formObj.elements.AltText.value;
        var cssClass = formObj.elements.CSSClass.value;
        var baseURL = document.getElementsByTagName('base')[0].href;
        var relativeHref = target.href.substr(baseURL.length)
        if(!tinyMCE.selectedInstance) tinyMCE.selectedInstance = Toolbar.instance().editor;
        if(tinyMCE.selectedInstance.contentWindow.focus) tinyMCE.selectedInstance.contentWindow.focus();
        // Extract dest width and dest height from the class name
        var destWidth = null;
        var destHeight = null;
        try {
            var imgTag = target.getElementsByTagName('img')[0];
            destWidth = imgTag.className.match(/destwidth=([0-9.\-]+)([, ]|$)/) ? RegExp.$1 : null;
            destHeight = imgTag.className.match(/destheight=([0-9.\-]+)([, ]|$)/) ? RegExp.$1 : null;
        } catch(er) {
        }
        TinyMCE_AdvancedTheme._insertImage(relativeHref, altText, 0, null, null, destWidth, destHeight, null, null, cssClass);
    },

    /**
     * Under IE6 when we click on "add folder" anchor, rest of anchors loose their correct position
     *
    */

    applyIE6Hack: function() {
        if(BrowserDetect.browser == 'Explorer') {
	        elements = [$('FolderOk'),$('FolderCancel'),$('UploadFiles')];
	        $A(elements).each(function(element) {
	            element.style.position = "relative";
	            element.style.top = "-3px";
	        });
	   }
    },

    removeIE6Hack: function() {
        if(BrowserDetect.browser == 'Explorer') {
	        elements = [$('FolderOk'),$('FolderCancel'),$('UploadFiles')];
	        $A(elements).each(function(element) {
	            element.style.position = "";
	        });
	    }
    },

    /**
     * Returns id of upload folder.
     *
    */

    getParentID: function() {
        return  $('Form_EditorToolbarImageForm_FolderID').value == '' ? 'root' : $('Form_EditorToolbarImageForm_FolderID').value;
    }
}
tinyMCEImageEnhancement = new TinyMCEImageEnhancement();
<commit_msg>BUGFIX: didn't work on IE<commit_after>/**
 * This class is used for upload in TinyMCE editor.
 * If one of methods is not commented look for comment in Upload.js.
*/
TinyMCEImageEnhancement = Class.create();
TinyMCEImageEnhancement.prototype = {
    initialize: function() {
        this.filesUploaded = 0;
        this.processInProgress = false;
        Event.observe(window,'load',this.onWindowLoad.bind(this));
    },

    addListeners: function() {
        $('Form_EditorToolbarImageForm_FolderID').value = "";

        Event.observe($('AddFolder'),'click',this.onAddFolder.bind(this));
        Event.observe($('FolderOk'),'click',this.onFolderOk.bind(this));
        Event.observe($('FolderCancel'),'click',this.onFolderCancel.bind(this));
        Event.observe($('UploadFiles'),'click',this.onUpload.bind(this));

		jQuery("#ImageAligmentStyle a").click(function() {
			id = jQuery(this).attr('id');
			jQuery(this).siblings().removeClass('selected');
			jQuery(this).addClass('selected');
			// get alignment from id, e.g. ImageAlignment_center -> center
			aligment = id.split('_')[1];
			$('Form_EditorToolbarImageForm_CSSClass').value = aligment;

			return false;
		});
    },

    /**
     * Method creates HTML element, only reason for this method is DRY.
    */

    addElement: function(tag, className, parent, properties) {
        var e = document.createElement(tag);
        Element.addClassName(e,className);
        parent.appendChild(e);
        Object.extend(e,properties);
        return e;
    },

    onUpload: function(event) {
        Event.stop(event);
        if(!this.processInProgress) {
	        if(this.getParentID() != 'root') {
	            this.upload.browse();
	        } else {
	            statusMessage("Please choose folder","bad");
	        }
	    }
    },

    /**
     * Called when user clicks "add folder" anchor.
    */

    onAddFolder: function(event) {
        Event.stop(event);
        Element.hide('AddFolder');
        Element.show('NewFolderName','FolderOk','FolderCancel');
        this.applyIE6Hack();
    },

	/**
	 * The user clicks the "ok" anchor link, the click event calls up
	 * this function which creates a new AJAX request to add a new folder
	 * using the addfolder function in AssetAdmin.php (admin/assets/addfolder).
	 */
	onFolderOk: function(event) {
		Event.stop(event);
		var folderName = $('NewFolderName').value;
		var options = {
			method: 'post',
			postBody: 'ParentID=' + this.getParentID() + '&ajax=1&returnID=1' + ($('SecurityID') ? '&SecurityID=' + $('SecurityID').value : ''),
			onSuccess: this.onFolderGetSuccess.bind(this),
			onFailure: function(transport) {
				errorMessage('Error: Folder not added', transport);
			}
		};

		new Ajax.Request('admin/assets/addfolder', options);
	},

	/**
	 * If the "addFolderOk" function does a successful AJAX post, call this
	 * function. Take the folder ID that was created in "addFolderOk"
	 * via ajax and send data to modify that folder record.
	 */
	onFolderGetSuccess: function(transport) {
		var folderID = transport.responseText;

		var date = new Date();
		var year = date.getFullYear();
		var month = date.getMonth() < 10 ? '0' + date.getMonth() : date.getMonth();
		var day = date.getDay() < 10  ? '0' + date.getDay() : date.getDay();
		var hours = date.getHours() < 10  ? '0' + date.getHours() : date.getHours();
		var minutes = date.getMinutes() < 10  ? '0' + date.getMinutes() : date.getMinutes();
		var seconds = date.getSeconds() < 10  == 1 ? '0' + date.getSeconds() : date.getSeconds();
		var currentDate = year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds;

		var folderName = $('NewFolderName').value;

		this.folderID = folderID;

		var options = {
			method: 'post',
			postBody: 'Created=' + currentDate + '&Name=' + folderName + '&ClassName=Folder&ID=' + folderID + '&ajax=1&action_save=1' + ($('SecurityID') ? '&SecurityID=' + $('SecurityID').value : ''),
			onSuccess: this.onFolderAddSuccess.bind(this),
			onFailure: function(transport) {
				errorMessage('Error: Folder not added', transport);
			}
		};

		new Ajax.Request('admin/assets/EditForm', options);
    },

    /**
     * When folder name has been changed we need to refresh folder list and return to initial state of UI.
    */

    onFolderAddSuccess: function(transport) {
        statusMessage('Creating new folder');
        $('TreeDropdownField_Form_EditorToolbarImageForm_FolderID').itemTree = null;
        $('TreeDropdownField_Form_EditorToolbarImageForm_FolderID').setValue(this.folderID);
        $('NewFolderName').value = '';
        Element.show('AddFolder');
        Element.hide('NewFolderName','FolderOk','FolderCancel');
        this.removeIE6Hack();
    },

    /**
     * If user doesn't want to add folder return to default UI.
    */

    onFolderCancel: function(event) {
        $('NewFolderName').value = '';
        Element.show('AddFolder');
        Element.hide('NewFolderName','FolderOk','FolderCancel');
        this.removeIE6Hack();
    },

    /**
     * Called on window.onload
    */

    onWindowLoad: function() {
        // Due to a bug in the flash plugin on Linux and Mac, we need at least version 9.0.64 to use SWFUpload
        if(navigator.appVersion.indexOf("Mac") != -1 || navigator.appVersion.indexOf("X11") != -1 || navigator.appVersion.indexOf("Linux") != -1) {
           pv = getFlashPlayerVersion();
           if(pv.major < 9 || (pv.major == 9 && pv.minor == 0 && pv.rev < 64)) {
              if($('AddFolderGroup')) $('AddFolderGroup').style.display = 'none';
              if($('PipeSeparator')) $('PipeSeparator').style.display = 'none';
              if($('UploadGroup')) $('UploadGroup').style.display = 'none';
              return;
           }
        }

        if($('FolderID') != null) {
        	if($('SecurityID')) var securityid=$('SecurityID').value;
	        else var securityid=null;
	        this.upload = new Upload(
	            {
	               fileTypes : '*.jpeg;*.jpg;*.jpe;*.png;*.gif;',
	               fileTypesDescription : 'Image files',
	               fileUploadLimit : '100',
	               securityID : securityid,
	               beginUploadOnQueue : true,
                   buildUI : this.addListeners.bind(this),
                   fileQueued : this.uploadFileQueuedCallback.bind(this),
                   fileComplete : this.uploadFileCompleteCallback.bind(this),
                   queueComplete : this.uploadQueueCompleteCallback.bind(this)
	            }
            );
        }
    },

    uploadFileQueuedCallback: function(file,queueLength) {
        this.processInProgress = true;
        this.upload.setFolderID(this.getParentID());
        $('UploadFiles').innerHTML = "Uploading ... 1/" + this.upload.getFilesToUpload();
        this.upload.startUpload();
    },

    uploadFileCompleteCallback: function(file,serverData) {
        Element.addClassName($('UploadFiles'),'link');//Safari hack
        $('UploadFiles').innerHTML = 'Uploading ... ' + this.upload.getFilesUploaded() + "/" + this.upload.getFilesToUpload();
    },

    uploadQueueCompleteCallback: function() {
        this.filesUploaded = this.upload.getFilesUploaded();
        $('UploadFiles').innerHTML = "upload";
        statusMessage('Uploaded ' + this.upload.getFilesUploaded() + ' files','good');
        if(this.getParentID() != 'root') {
            $('Image').ajaxGetFiles(this.getParentID(), null, this.insertImages.bind(this));
        }
    },

    /**
     * Iterates over all uploaded images and add them to TinyMCE editor
     *
     * @param transport object
    */
    insertImages: function(transport) {
        //HACK FOR STRANGE ERROR OCCURING UNDER SAFARI
        if(transport.responseText == '') {
            $('Image').ajaxGetFiles(this.getParentID(), null, this.insertImages.bind(this));
            return;
        }
        //END OF HACK

        $('Image').reapplyBehaviour();

        this.addToTinyMCE = this.addToTinyMCE.bind(this);

			this.processInProgress = false;
    },

    /**
     * Adds particular image to TinyMCE. Most of code has been copied from tiny_mce_improvements.js / ImageThumbnail.onclick
     * Sorry for not following DRY, I didn't want to break smth in tiny_mce_improvements.
     *
     *  @param target object
    */

    addToTinyMCE: function(target) {
		var formObj = $('Form_EditorToolbarImageForm');
        var altText = formObj.elements.AltText.value;
        var cssClass = formObj.elements.CSSClass.value;
        var baseURL = document.getElementsByTagName('base')[0].href;
        var relativeHref = target.href.substr(baseURL.length)
        if(!tinyMCE.selectedInstance) tinyMCE.selectedInstance = Toolbar.instance().editor;
        if(tinyMCE.selectedInstance.contentWindow.focus) tinyMCE.selectedInstance.contentWindow.focus();
        // Extract dest width and dest height from the class name
        var destWidth = null;
        var destHeight = null;
        try {
            var imgTag = target.getElementsByTagName('img')[0];
            destWidth = imgTag.className.match(/destwidth=([0-9.\-]+)([, ]|$)/) ? RegExp.$1 : null;
            destHeight = imgTag.className.match(/destheight=([0-9.\-]+)([, ]|$)/) ? RegExp.$1 : null;
        } catch(er) {
        }
        TinyMCE_AdvancedTheme._insertImage(relativeHref, altText, 0, null, null, destWidth, destHeight, null, null, cssClass);
    },

    /**
     * Under IE6 when we click on "add folder" anchor, rest of anchors loose their correct position
     *
    */

    applyIE6Hack: function() {
        if(BrowserDetect.browser == 'Explorer') {
	        elements = [$('FolderOk'),$('FolderCancel'),$('UploadFiles')];
	        $A(elements).each(function(element) {
	            element.style.position = "relative";
	            element.style.top = "-3px";
	        });
	   }
    },

    removeIE6Hack: function() {
        if(BrowserDetect.browser == 'Explorer') {
	        elements = [$('FolderOk'),$('FolderCancel'),$('UploadFiles')];
	        $A(elements).each(function(element) {
	            element.style.position = "";
	        });
	    }
    },

    /**
     * Returns id of upload folder.
     *
    */

    getParentID: function() {
        return  $('Form_EditorToolbarImageForm_FolderID').value == '' ? 'root' : $('Form_EditorToolbarImageForm_FolderID').value;
    }
}
tinyMCEImageEnhancement = new TinyMCEImageEnhancement();
<|endoftext|>


<commit_before>define(["backbone", "underscore" ], function(Backbone, _) {
    var BaseValues = Backbone.Model.extend({
      // data attributes
      defaults: {
        carclasses: [
          { name: "EstateCar", value: "EstateCar", score: 0 },
          { name: "Cabrio", value: "Cabrio", score: 0 },
          { name: "OffRoad", value: "OffRoad", score: 0 },
          { name: "Limousine", value: "Limousine", score: 0 },
          { name: "SmallCar", value: "SmallCar", score: 0 },
          { name: "SportsCar", value: "SportsCar", score: 0 },
          { name: "Van", value: "Van", score: 0 },
          { name: "OtherCar", value: "OtherCar", score: 0 },
        ],
        colors: [
          { name: "beige", value: "beige", score: 0 },
          { name: "gold", value: "gold", score: 0 },
          { name: "violett", value: "violett", score: 0 },
          { name: "yellow", value: "yellow", score: 0 },
          { name: "black", value: "black", score: 0 },
          { name: "green", value: "green", score: 0 },
          { name: "red", value: "red", score: 0 },
          { name: "blue", value: "blue", score: 0 },
          { name: "gray", value: "gray", score: 0 },
          { name: "silver", value: "silver", score: 0 }
        ],
        seats: [
          { name: "2", value: 2, score: 0 },
          { name: "4", value: 4, score: 0 },
          { name: "5", value: 5, score: 0 },
          { name: "7", value: 7, score: 0 },
          { name: "8", value: 8, score: 0 },
          { name: "9", value: 9, score: 0 }
        ],
        priceclasses: [
          { name: "0", value: { from: 0, to: 2000 }, score: 0 },
          { name: "2001", value: { from: 2001, to: 4000 }, score: 0 },
          { name: "4001", value: { from: 4001, to: 8000 }, score: 0 },
          { name: "8001", value: { from: 8001, to: 12000 }, score: 0 },
          { name: "12001", value: { from: 12001, to: 20000 }, score: 0 },
          { name: "20001", value: { from: 20001, to: 30000 }, score: 0 },
          { name: "30001", value: { from: 30001, to: 50000 }, score: 0 },
          { name: "50001", value: { from: 50001, to: 90000 }, score: 0 }
        ]
      },

      // converters
      addBaseValue: function(category, name) {
        _.find(this.attributes[category], name).score += 1;
      },

      resetBaseValue: function(category, name) {
        _.find(this.attributes[category], name).score = 0;
      },

      getOverallScore: function() {
        return _(this.attributes).pluck("score")
          .reduce(values, function(memo, num){return memo + num;}, 0);
      },

      getFullScore: function(category) {
        return _(this.attributes[category]).pluck("score")
          .reduce(function(memo, num) { return memo + num; }, 0);
      },

      getAverageOf: function(category) {
        if (category === "seats") {
          throw new Error("average of seats is useless");
        }

        var average = [];
        var sorted = _.sortBy(this.attributes[category], "score");
        var fullScore = this.getFullScore(category);
        var score = 0;

        while (score/fullScore <= 0.5) {
          var obj = sorted.shift();
          average.push(obj.value);
          score += obj.score;
        }

        return average;
      },

      getMinOf: function(category) {
        if (category !== "seats") {
          throw new Error("only minimum of seats is allowed");
        }

        var min = [];
        var sorted = _.sortBy(this.attributes[category], "score").reverse();
        var fullScore = this.getFullScore(category);
        var score = 0;

        while (score/fullScore <= 0.1) {
          var obj = sorted.shift();
          min.push(obj.value);
          score += obj.score;
        }

        return min[min.length-1];
      },

      getMaxOf: function(category) {
        if (category !== "seats") {
          throw new Error("only minimum of seats is allowed");
        }

        var max = [];
        var sorted = _.sortBy(this.attributes[category], "score");
        var fullScore = this.getFullScore(category);
        var score = 0;

        while (score/fullScore <= 0.1) {
          var obj = sorted.shift();
          max.push(obj.value);
          score += obj.score;
        }

        return max[max.length-1];
      },

      generateAverageCartype: function() {

      }

    });

  return BaseValues;
});
<commit_msg>fixed data access<commit_after>define(["backbone", "underscore" ], function(Backbone, _) {
    var BaseValues = Backbone.Model.extend({
      // data attributes
      defaults: {
        carclasses: [
          { name: "EstateCar", value: "EstateCar", score: 0 },
          { name: "Cabrio", value: "Cabrio", score: 0 },
          { name: "OffRoad", value: "OffRoad", score: 0 },
          { name: "Limousine", value: "Limousine", score: 0 },
          { name: "SmallCar", value: "SmallCar", score: 0 },
          { name: "SportsCar", value: "SportsCar", score: 0 },
          { name: "Van", value: "Van", score: 0 },
          { name: "OtherCar", value: "OtherCar", score: 0 },
        ],
        colors: [
          { name: "beige", value: "beige", score: 0 },
          { name: "gold", value: "gold", score: 0 },
          { name: "violett", value: "violett", score: 0 },
          { name: "yellow", value: "yellow", score: 0 },
          { name: "black", value: "black", score: 0 },
          { name: "green", value: "green", score: 0 },
          { name: "red", value: "red", score: 0 },
          { name: "blue", value: "blue", score: 0 },
          { name: "gray", value: "gray", score: 0 },
          { name: "silver", value: "silver", score: 0 }
        ],
        seats: [
          { name: "2", value: 2, score: 0 },
          { name: "4", value: 4, score: 0 },
          { name: "5", value: 5, score: 0 },
          { name: "7", value: 7, score: 0 },
          { name: "8", value: 8, score: 0 },
          { name: "9", value: 9, score: 0 }
        ],
        priceclasses: [
          { name: "0", value: { from: 0, to: 2000 }, score: 0 },
          { name: "2001", value: { from: 2001, to: 4000 }, score: 0 },
          { name: "4001", value: { from: 4001, to: 8000 }, score: 0 },
          { name: "8001", value: { from: 8001, to: 12000 }, score: 0 },
          { name: "12001", value: { from: 12001, to: 20000 }, score: 0 },
          { name: "20001", value: { from: 20001, to: 30000 }, score: 0 },
          { name: "30001", value: { from: 30001, to: 50000 }, score: 0 },
          { name: "50001", value: { from: 50001, to: 90000 }, score: 0 }
        ]
      },

      // converters
      addBaseValue: function(category, name) {
        var attr = _.find(this.attributes[category], { name: name });
        if (attr !== undefined) {
          attr.score++;
        }
      },

      resetBaseValue: function(category, name) {
        _.find(this.attributes[category], { name: name }).score = 0;
      },

      getOverallScore: function() {
        return _.reduce(
          _.map(this.attributes, function(values, category) {
            return this.getFullScore(category);
          }),
          function(sum, num) { return sum + num; },
          0
        );
      },

      getFullScore: function(category) {
        return _(this.attributes[category]).pluck("score")
          .reduce(function(memo, num) { return memo + num; }, 0);
      },

      getAverageOf: function(category) {
        if (category === "seats") {
          throw new Error("average of seats is useless");
        }

        var average = [];
        var sorted = _.sortBy(this.attributes[category], "score");
        var fullScore = this.getFullScore(category);
        var score = 0;

        while (score/fullScore <= 0.5) {
          var obj = sorted.shift();
          average.push(obj.value);
          score += obj.score;
        }

        return average;
      },

      getMinOf: function(category) {
        if (category !== "seats") {
          throw new Error("only minimum of seats is allowed");
        }

        var min = [];
        var sorted = _.sortBy(this.attributes[category], "score").reverse();
        var fullScore = this.getFullScore(category);
        var score = 0;

        while (score/fullScore <= 0.1) {
          var obj = sorted.shift();
          min.push(obj.value);
          score += obj.score;
        }

        return min[min.length-1];
      },

      getMaxOf: function(category) {
        if (category !== "seats") {
          throw new Error("only minimum of seats is allowed");
        }

        var max = [];
        var sorted = _.sortBy(this.attributes[category], "score");
        var fullScore = this.getFullScore(category);
        var score = 0;

        while (score/fullScore <= 0.1) {
          var obj = sorted.shift();
          max.push(obj.value);
          score += obj.score;
        }

        return max[max.length-1];
      },

      generateAverageCartype: function() {

      }

    });

  return BaseValues;
});
<|endoftext|>


<commit_before>// ==UserScript==
// @name		Mega Scratch Userscript (base/bootstrap)
// @author		MegaScratchUserscript (collab with some Scratch ATers: https://github.com/MegaScratchUserscript/Mega-Scratch-Userscript#-mega-scratch-userscript)
// @description	A mega userscript with tons of epic uses!
// @include		http://scratch.mit.edu/*
// @version		0.2.1
// @grant		unsafeWindow
// @grant		GM_getResourceText
// @grant		GM_addStyle
// @icon		resources/icon.png
// @require		https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// @require		https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js
// @require		resources/waitForKeyElements.js
// @require		resources/msuinit.js
// @require		resources/extensions.js
// @require		parts/scratchforum.part.js
// @require		parts/scratchtheme.part.js
// @require		parts/scratchystuff.part.js
// @require		parts/feed.part.js
// @require		parts/profileenhancer.part.js
// @resource	settingshtml resources/settings.htmlpart
// @resource	settingscss resources/settings.css
// ==/UserScript==

// I called this base.user.js in case this is the main script
var ScratchUserscript = {
    MODE_DEV: true, // change to false in the release; use this flag to print data to console for debug, etc
	_settingsHTML: $("

"),
	_partsEnabled: {},
	_init: function(){
		if(typeof localStorage != 'undefined'){
			if(typeof localStorage.msuPartsEnabled == 'undefined'){
				localStorage.msuPartsEnabled = "{themeeffects:false}";
			}
			ScratchUserscript._partsEnabled = JSON.parse(localStorage.msuPartsEnabled);
		}
		ScratchUserscript._settingsHTML.css("display","none").appendTo(document.body).dialog({dialogClass:"jqui-modal", autoOpen: false, width: 800, height: 400});
		$("#msu-settings-dialog").parent().append('<html><head></head><body></body></html>');
		ScratchUserscript._settingsHTML.html(GM_getResourceText("settingshtml"));
		GM_addStyle(GM_getResourceText("settingscss"));
		var openSettings = $("<acronym title='Mega Scratch Userscript'>MSU</acronym> Settings");
		openSettings.click(function(){
			ScratchUserscript._settingsHTML.dialog("open");
		});
		$("

").append(openSettings).insertBefore($(".user-nav .logout"));

		for(x in msuParts){
			if(typeof msuParts[x] !== "undefined"){
				(msuParts[x])(ScratchUserscript);
			}
		}
		if(ScratchUserscript.MODE_DEV){
			console.log("Scratchuserscript started!");
		}
	},
	readSetting: function(partName, settingName, defaultValue){
		if(typeof localStorage != 'undefined'){
			var settings = {};
			if(typeof localStorage.msuSettingsStorage != 'undefined'){
				settings = JSON.parse(localStorage.msuSettingsStorage);
			}
			if(settings.hasOwnProperty(partName+"-"+settingName)){
				return settings[partName+"-"+settingName];
			} else return defaultValue;
		}
	},
	writeSetting: function(partName, settingName, settingValue){
		if(typeof localStorage != 'undefined'){
			var settings = {};
			if(typeof localStorage.msuSettingsStorage != 'undefined'){
				settings = JSON.parse(localStorage.msuSettingsStorage);
			}
			settings[partName+"-"+settingName] = settingValue;
			localStorage.msuSettingsStorage = JSON.stringify(settings);
		}
	},
	/**
	 * Returns if a part is enabled (as per the settings GUI)
	 * It's up to parts to call this and check
	 * @return true if enabled, false otherwise
	 */
	isPartEnabled: function(name){
		if(!ScratchUserscript._partsEnabled.hasOwnProperty(name.replace(/[^a-zA-Z\d]/g, "").toLowerCase())){
			return true; // not in the object = enabled
		}
		if(ScratchUserscript._partsEnabled[name.replace(/[^a-zA-Z\d]/g, "").toLowerCase()]){
			return true;
		}
		return false;
	},
	/**
	 * Registers a part of the userscript onto the settings dialog
	 * @param name The name of the part
	 * @param description A description
	 * @param settings HTML for the part's settings page, if any
	 */
	registerPart: function(name, description, settings){
		// almost verbatim copied from my test JSFiddle: http://jsfiddle.net/a8cewv3u/
		// very messy, should be cleaned up

		var qualifiedName = name.replace(/[^a-zA-Z\d]/g, "").toLowerCase();
		if(ScratchUserscript.MODE_DEV)
			console.log("Part registered name="+name+" qualifiedName="+qualifiedName);
		var li = $("

");
		var isEnabled = ScratchUserscript.isPartEnabled(name);
		li.append($("<input data-ischeck='yup' type='checkbox' title='Enable this' id='enable-" + qualifiedName + "' data-for='" + qualifiedName + "' />")
				.bind('change', function () {
			ck = $(this).is(":checked");
			$("#isenabled-" + $(this).attr("data-for")).text(ck ? "yes":"no");
			ScratchUserscript._partsEnabled[$(this).attr("data-for")] = ck;
			if(typeof localStorage != 'undefined'){
				localStorage.msuPartsEnabled = JSON.stringify(ScratchUserscript._partsEnabled);
			}
		}).attr("checked", isEnabled));
		li.append($("" + name + "").attr("data-for", qualifiedName));
		li.click(function (e) {
			if ($(e.target).attr("data-ischeck") == 'yup') return;
			ScratchUserscript._settingsHTML.find(".msu-settings-content-div").slideUp();
			ScratchUserscript._settingsHTML.find("#msu-settings-content-" + $(this).find("label").attr("data-for")).slideDown();
			ScratchUserscript._settingsHTML.find(".msu-settings-side-tabs li").removeClass("sel");
			$(this).addClass("sel");
		});
		ScratchUserscript._settingsHTML.find(".msu-settings-side-tabs").append(li);
		var content = $("

");
		content.append("
" + name + "
").append("Enabled: no
");
		if(isEnabled) content.find("#isenabled-"+qualifiedName).text("yes");
		content.append("Description: "+description + "

")
			.append(settings == null ? "No additional settings" : settings);
		content.attr("id", "msu-settings-content-" + qualifiedName)
			.css("display", "none").addClass("msu-settings-content-div")
			.appendTo(ScratchUserscript._settingsHTML.find(".msu-settings-content"));
		if(ScratchUserscript._settingsHTML.find('.msu-settings-side-tabs li.sel').length==0){
			li.addClass("sel");
			content.show();
		}
	},
	/**
	 * Gets the page type
	 * @return The type, in the form of a JSON object:
	 *		type: either project, studio, messages, mystuff, settings, forum, profile, or unknown
	 *		subtype: in forums, either section, topic, or null
	 *  	id: the forum topic id, project id, studio id, etc
	 */
	getPageType: function(){
		var obj = {type: "unknown", subtype: null, id: null};
		if (/^\/projects\/\d+\/$/.test(location.pathname)){
			obj.type = "project";
			obj.id = parseInt(/^\/projects\/(\d+)\/$/.exec(location.pathname)[1]);
		}
		if (/^\/studios\/\d+\/$/.test(location.pathname)){
			obj.type = "studio";
			obj.id = parseInt(/^\/studios\/(\d+)\/$/.exec(location.pathname)[1]);
		}
		if (/^\/users\/[a-zA-Z0-9\-_]+\/$/.test(location.pathname)){
			obj.type = "profile";
			obj.id = /^\/users\/([a-zA-Z0-9\-_]+)\/$/.exec(location.pathname)[1];
		}
		if(/^\/discuss\//.test(location.pathname)){
			obj.type = "forum";
			if(/^\/discuss\/\d+\/$/.test(location.pathname)){
				obj.subtype = "section";
				obj.id = parseInt(/^\/discuss\/(\d+)\/$/.exec(location.pathname)[1]);
			}
			if(/^\/discuss\/topic\/\d+\//.test(location.pathname)){
				obj.subtype = "topic";
				obj.id = parseInt(/^\/discuss\/topic\/(\d+)\//.exec(location.pathname)[1]);
			}
		}
		if (/^\/accounts\/(password_change|email_change|change_country)\/$/.test(location.pathname)){
			obj.type = "settings";
		}
		if (location.pathname == '/messages/'){
			obj.type = "messages";
		}
		if (location.pathname == '/mystuff/'){
			obj.type = "mystuff";
		}
		return obj;
	},
	/**
	 * @return The username of the currently logged in user, or null if not logged in
	 */
	getUsername: function(){
		return unsafeWindow.Scratch.INIT_DATA.LOGGED_IN_USER.model ? unsafeWindow.Scratch.INIT_DATA.LOGGED_IN_USER.model.username : null;
	}
};

$(document).ready(ScratchUserscript._init);
<commit_msg>Change version for auto-update<commit_after>// ==UserScript==
// @name		Mega Scratch Userscript (base/bootstrap)
// @author		MegaScratchUserscript (collab with some Scratch ATers: https://github.com/MegaScratchUserscript/Mega-Scratch-Userscript#-mega-scratch-userscript)
// @description	A mega userscript with tons of epic uses!
// @include		http://scratch.mit.edu/*
// @version		0.2.2
// @grant		unsafeWindow
// @grant		GM_getResourceText
// @grant		GM_addStyle
// @icon		resources/icon.png
// @require		https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// @require		https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js
// @require		resources/waitForKeyElements.js
// @require		resources/msuinit.js
// @require		resources/extensions.js
// @require		parts/scratchforum.part.js
// @require		parts/scratchtheme.part.js
// @require		parts/scratchystuff.part.js
// @require		parts/feed.part.js
// @require		parts/profileenhancer.part.js
// @resource	settingshtml resources/settings.htmlpart
// @resource	settingscss resources/settings.css
// ==/UserScript==

// I called this base.user.js in case this is the main script
var ScratchUserscript = {
    MODE_DEV: true, // change to false in the release; use this flag to print data to console for debug, etc
	_settingsHTML: $("

"),
	_partsEnabled: {},
	_init: function(){
		if(typeof localStorage != 'undefined'){
			if(typeof localStorage.msuPartsEnabled == 'undefined'){
				localStorage.msuPartsEnabled = "{themeeffects:false}";
			}
			ScratchUserscript._partsEnabled = JSON.parse(localStorage.msuPartsEnabled);
		}
		ScratchUserscript._settingsHTML.css("display","none").appendTo(document.body).dialog({dialogClass:"jqui-modal", autoOpen: false, width: 800, height: 400});
		$("#msu-settings-dialog").parent().append('<html><head></head><body></body></html>');
		ScratchUserscript._settingsHTML.html(GM_getResourceText("settingshtml"));
		GM_addStyle(GM_getResourceText("settingscss"));
		var openSettings = $("<acronym title='Mega Scratch Userscript'>MSU</acronym> Settings");
		openSettings.click(function(){
			ScratchUserscript._settingsHTML.dialog("open");
		});
		$("

").append(openSettings).insertBefore($(".user-nav .logout"));

		for(x in msuParts){
			if(typeof msuParts[x] !== "undefined"){
				(msuParts[x])(ScratchUserscript);
			}
		}
		if(ScratchUserscript.MODE_DEV){
			console.log("Scratchuserscript started!");
		}
	},
	readSetting: function(partName, settingName, defaultValue){
		if(typeof localStorage != 'undefined'){
			var settings = {};
			if(typeof localStorage.msuSettingsStorage != 'undefined'){
				settings = JSON.parse(localStorage.msuSettingsStorage);
			}
			if(settings.hasOwnProperty(partName+"-"+settingName)){
				return settings[partName+"-"+settingName];
			} else return defaultValue;
		}
	},
	writeSetting: function(partName, settingName, settingValue){
		if(typeof localStorage != 'undefined'){
			var settings = {};
			if(typeof localStorage.msuSettingsStorage != 'undefined'){
				settings = JSON.parse(localStorage.msuSettingsStorage);
			}
			settings[partName+"-"+settingName] = settingValue;
			localStorage.msuSettingsStorage = JSON.stringify(settings);
		}
	},
	/**
	 * Returns if a part is enabled (as per the settings GUI)
	 * It's up to parts to call this and check
	 * @return true if enabled, false otherwise
	 */
	isPartEnabled: function(name){
		if(!ScratchUserscript._partsEnabled.hasOwnProperty(name.replace(/[^a-zA-Z\d]/g, "").toLowerCase())){
			return true; // not in the object = enabled
		}
		if(ScratchUserscript._partsEnabled[name.replace(/[^a-zA-Z\d]/g, "").toLowerCase()]){
			return true;
		}
		return false;
	},
	/**
	 * Registers a part of the userscript onto the settings dialog
	 * @param name The name of the part
	 * @param description A description
	 * @param settings HTML for the part's settings page, if any
	 */
	registerPart: function(name, description, settings){
		// almost verbatim copied from my test JSFiddle: http://jsfiddle.net/a8cewv3u/
		// very messy, should be cleaned up

		var qualifiedName = name.replace(/[^a-zA-Z\d]/g, "").toLowerCase();
		if(ScratchUserscript.MODE_DEV)
			console.log("Part registered name="+name+" qualifiedName="+qualifiedName);
		var li = $("

");
		var isEnabled = ScratchUserscript.isPartEnabled(name);
		li.append($("<input data-ischeck='yup' type='checkbox' title='Enable this' id='enable-" + qualifiedName + "' data-for='" + qualifiedName + "' />")
				.bind('change', function () {
			ck = $(this).is(":checked");
			$("#isenabled-" + $(this).attr("data-for")).text(ck ? "yes":"no");
			ScratchUserscript._partsEnabled[$(this).attr("data-for")] = ck;
			if(typeof localStorage != 'undefined'){
				localStorage.msuPartsEnabled = JSON.stringify(ScratchUserscript._partsEnabled);
			}
		}).attr("checked", isEnabled));
		li.append($("" + name + "").attr("data-for", qualifiedName));
		li.click(function (e) {
			if ($(e.target).attr("data-ischeck") == 'yup') return;
			ScratchUserscript._settingsHTML.find(".msu-settings-content-div").slideUp();
			ScratchUserscript._settingsHTML.find("#msu-settings-content-" + $(this).find("label").attr("data-for")).slideDown();
			ScratchUserscript._settingsHTML.find(".msu-settings-side-tabs li").removeClass("sel");
			$(this).addClass("sel");
		});
		ScratchUserscript._settingsHTML.find(".msu-settings-side-tabs").append(li);
		var content = $("

");
		content.append("
" + name + "
").append("Enabled: no
");
		if(isEnabled) content.find("#isenabled-"+qualifiedName).text("yes");
		content.append("Description: "+description + "

")
			.append(settings == null ? "No additional settings" : settings);
		content.attr("id", "msu-settings-content-" + qualifiedName)
			.css("display", "none").addClass("msu-settings-content-div")
			.appendTo(ScratchUserscript._settingsHTML.find(".msu-settings-content"));
		if(ScratchUserscript._settingsHTML.find('.msu-settings-side-tabs li.sel').length==0){
			li.addClass("sel");
			content.show();
		}
	},
	/**
	 * Gets the page type
	 * @return The type, in the form of a JSON object:
	 *		type: either project, studio, messages, mystuff, settings, forum, profile, or unknown
	 *		subtype: in forums, either section, topic, or null
	 *  	id: the forum topic id, project id, studio id, etc
	 */
	getPageType: function(){
		var obj = {type: "unknown", subtype: null, id: null};
		if (/^\/projects\/\d+\/$/.test(location.pathname)){
			obj.type = "project";
			obj.id = parseInt(/^\/projects\/(\d+)\/$/.exec(location.pathname)[1]);
		}
		if (/^\/studios\/\d+\/$/.test(location.pathname)){
			obj.type = "studio";
			obj.id = parseInt(/^\/studios\/(\d+)\/$/.exec(location.pathname)[1]);
		}
		if (/^\/users\/[a-zA-Z0-9\-_]+\/$/.test(location.pathname)){
			obj.type = "profile";
			obj.id = /^\/users\/([a-zA-Z0-9\-_]+)\/$/.exec(location.pathname)[1];
		}
		if(/^\/discuss\//.test(location.pathname)){
			obj.type = "forum";
			if(/^\/discuss\/\d+\/$/.test(location.pathname)){
				obj.subtype = "section";
				obj.id = parseInt(/^\/discuss\/(\d+)\/$/.exec(location.pathname)[1]);
			}
			if(/^\/discuss\/topic\/\d+\//.test(location.pathname)){
				obj.subtype = "topic";
				obj.id = parseInt(/^\/discuss\/topic\/(\d+)\//.exec(location.pathname)[1]);
			}
		}
		if (/^\/accounts\/(password_change|email_change|change_country)\/$/.test(location.pathname)){
			obj.type = "settings";
		}
		if (location.pathname == '/messages/'){
			obj.type = "messages";
		}
		if (location.pathname == '/mystuff/'){
			obj.type = "mystuff";
		}
		return obj;
	},
	/**
	 * @return The username of the currently logged in user, or null if not logged in
	 */
	getUsername: function(){
		return unsafeWindow.Scratch.INIT_DATA.LOGGED_IN_USER.model ? unsafeWindow.Scratch.INIT_DATA.LOGGED_IN_USER.model.username : null;
	}
};

$(document).ready(ScratchUserscript._init);
<|endoftext|>


<commit_before>var jsPropertyDetails=new function () {
    this.GetPropertyAddress=function () {

        var searchKey=$("#propSearch").val();
                $.ajax({
                    url: "http://localhost:63683/api/EmployeeDetails/GetPropertyAddresses",
                    type: "Get",
                    data: {
                        searchKey: searchKey,
                    },
                    success: function (data) {
                        $('.divATC').find('ul li').remove()
                        $(".divATC").show()
                        if(data.length>0) {
                            $(data).each(function () {
                                $(".divATC").find('ul').append("
" + this.StreetNumber + " " + this.StreetName + ", " + this.City + ", " + this.County + " " + this.Zipcode + "
")
                            })
                        }else
                        {
                            $(".divATC").hide()
                        }
                    },
                    error: function () {
                        alert("Error Occurred");
                    },
                });
    }

    this.GetPropertyDetails=function (_e) {
        var currZip=$(_e).attr('zipCode');
        $.ajax({
            url: "http://localhost:63683/api/EmployeeDetails/GetPropertyAddresses",
            type: "Get",
            data: {
                searchKey: currZip,
            },
            success: function (data) {
                $(".divATC").hide();
                $("#divpropDetail").find('table tbody tr').remove()
                $("#divpropDetail").show();
                if(data.length>0) {
                    $(data).each(function () {
                        $("#divpropDetail").find('table tbody').append("
"+this.StreetNumber+"	"+this.StreetName+"	"+this.City+"	"+this.Zipcode+"	"+this.County+"
>")
                    })
                }else
                {
                    $("#divpropDetail").append('
No Records Found!!
>')
                }
            },
            error: function () {
                alert("Error Occurred");
            },
        });
    }

    this.OnSearchPropDetails=function () {
        var currSearch=$("#propSearch").val();
        $.ajax({
            url: "http://localhost:63683/api/EmployeeDetails/GetPropertyAddresses",
            type: "Get",
            data: {
                searchKey: currSearch,
            },
            success: function (data) {
                $(".divATC").hide();
                $("#divpropDetail").find('table tbody tr').remove()
                $("#divpropDetail").show();
                if(data.length>0) {
                    $(data).each(function () {
                        $("#divpropDetail").find('table tbody').append("
"+this.StreetNumber+"	"+this.StreetName+"	"+this.City+"	"+this.Zipcode+"	"+this.County+"
>")
                    })
                }else
                {
                    $("#divpropDetail").find('table tbody tr').remove()
                    $("#divpropDetail").find('table tbody').append('
No Records Found!!
>')
                }
            },
            error: function () {
                alert("Error Occurred");
            },
        });
    }
}<commit_msg>Autom Complete<commit_after>var jsPropertyDetails=new function () {
    this.GetPropertyAddress=function () {

        var searchKey=$("#propSearch").val();
                $.ajax({
                    url: "http://192.168.6.40:63683/api/EmployeeDetails/GetPropertyAddresses",
                    type: "Get",
                    data: {
                        searchKey: searchKey,
                    },
                    success: function (data) {
                        $('.divATC').find('ul li').remove()
                        $(".divATC").show()
                        if(data.length>0) {
                            $(data).each(function () {
                                $(".divATC").find('ul').append("
" + this.StreetNumber + " " + this.StreetName + ", " + this.City + ", " + this.County + " " + this.Zipcode + "
")
                            })
                        }else
                        {
                            $(".divATC").hide()
                        }
                    },
                    error: function () {
                        alert("Error Occurred");
                    },
                });
    }

    this.GetPropertyDetails=function (_e) {
        var currZip=$(_e).attr('zipCode');
        $.ajax({
            url: "http://192.168.6.40:63683/api/EmployeeDetails/GetPropertyAddresses",
            type: "Get",
            data: {
                searchKey: currZip,
            },
            success: function (data) {
                $(".divATC").hide();
                $("#divpropDetail").find('table tbody tr').remove()
                $("#divpropDetail").show();
                if(data.length>0) {
                    $(data).each(function () {
                        $("#divpropDetail").find('table tbody').append("
"+this.StreetNumber+"	"+this.StreetName+"	"+this.City+"	"+this.Zipcode+"	"+this.County+"
>")
                    })
                }else
                {
                    $("#divpropDetail").append('
No Records Found!!
>')
                }
            },
            error: function () {
                alert("Error Occurred");
            },
        });
    }

    this.OnSearchPropDetails=function () {
        var currSearch=$("#propSearch").val();
        $.ajax({
            url: "http://192.168.6.40:63683/api/EmployeeDetails/GetPropertyAddresses",
            type: "Get",
            data: {
                searchKey: currSearch,
            },
            success: function (data) {
                $(".divATC").hide();
                $("#divpropDetail").find('table tbody tr').remove()
                $("#divpropDetail").show();
                if(data.length>0) {
                    $(data).each(function () {
                        $("#divpropDetail").find('table tbody').append("
"+this.StreetNumber+"	"+this.StreetName+"	"+this.City+"	"+this.Zipcode+"	"+this.County+"
>")
                    })
                }else
                {
                    $("#divpropDetail").find('table tbody tr').remove()
                    $("#divpropDetail").find('table tbody').append('
No Records Found!!
>')
                }
            },
            error: function () {
                alert("Error Occurred");
            },
        });
    }
}<|endoftext|>


<commit_before>var annots;

var _sbs_source = _viewer_source;
var _sbs_id = tissueId;

// call this function before minidraw to open a different image
function change_image(id, url){
  _sbs_source = url;
  _sbs_id = id;
}

function show_minidraw(){
  // calibrate our canvas
  var c1 = delayer({});
  var c1_c = ViewportCalibratedCanvas(c1, rhs_viewer);
  var rhs_imagingHelper = new OpenSeadragonImaging.ImagingHelper({
        viewer: rhs_viewer
      });
  // handle algorithm selection
  annots = new annotations(_sbs_id, rhs_viewer, c1_c, rhs_imagingHelper, {});

  // get new data each pass
  rhs_viewer.addHandler("zoom", function(){
    annots.draw();
  })

  rhs_viewer.addHandler("pan", function(){
    annots.draw();
  });

  // by default, for demo, select all algorithms
  annots.store.getAlgList(function(data){
    data.forEach((x)=>annots.select(x.title));
  });

  console.log(annots.selection);

  // redraw all active annotations each redraw
  // clearing and re-fetching is inefficient, c1 can be used as a cache
  var overlay = rhs_viewer.canvasOverlay({
      clearBeforeRedraw:true,
      onRedraw:function() {
        var lw = 50 / (viewer.viewport.getZoom(true));
        overlay.context2d().lineWidth = lw
        c1.__apply_all(overlay.context2d());
      }
  });
  // // dummy response
  //  d = [{ "_id" : { "$oid" : "5ad11630e4b0dd37ccda6ee3"} , "geometry" : { "type" : "Polygon" , "coordinates" : [ [ [ 0 , 0] , [ 0.37133497911441 , 0.55870962366762] , [ 0 , 1] , [ 0.36813129206405 , 0.57044250168238] , [ 0.36813129206405 , 0.55870962366762]]]} , "footprint" : 69980.14639099 , "provenance" : { "analysis" : { "execution_id" : "tammy.diprima_Tumor_Region" , "source" : "human"} , "image" : { "case_id" : "TEST"}}},{ "_id" : { "$oid" : "5ad11630e4b0dd37ccda6ee5"} , "geometry" : { "type" : "Polygon" , "coordinates" : [ [ [ 0.36813129206405 , 0.55870962366762] , [ 0.37133497911441 , 0.55870962366762] , [ 0.37133497911441 , 0.57044250168238] , [ 0.36813129206405 , 0.57044250168238] , [ 0.36813129206405 , 0.55870962366762]]]} , "footprint" : 69980.14639099 , "provenance" : { "analysis" : { "execution_id" : "tammy.diprima_Tumor_Region" , "source" : "human"} , "image" : { "case_id" : "TEST"}}}];
  // //
  // drawFromList(d, c1_c)
}

// functions to change

document.addEventListener("sidesplit", function(e){
  if (document.getElementById("right_sidebyside").style.display == "block"){
    hide_sbs();
  } else {
    //var demoimg = {"CMU1jp2k": "http://localhost:8081/fcgi-bin/iipsrv.fcgi?DeepZoom=/data/images/CMU-1-JP2K-33005-274ju.svs", "CMU1jp2k": "http://localhost:8081/fcgi-bin/iipsrv.fcgi?DeepZoom=/data/images/CMU-1-JP2K-33005-274ju.svs.dzi"};
    show_sbs();
    // need viewers to be up to draw
    show_minidraw();
    rhs_viewer.open(_sbs_source); // for now
  }
});
<commit_msg>try basic selection menu<commit_after>var annots;

var _sbs_source = _viewer_source;
var _sbs_id = tissueId;

// call this function before minidraw to open a different image
function change_image(id, url){
  _sbs_source = url;
  _sbs_id = id;
}

// create a div for the algorithm selector
var algsel = document.createElement("div");
algsel.style.zIndex = "99";
algsel.style.position = "absolute";
algsel.style.height = "10%";
algsel.style.width = "10%";
algsel.style.top = "10%";
algsel.style.left = "10%";
algsel.style.display = "none";

algsel.id = "algsel_sbs";
document.body.appendChild(algsel)

function show_minidraw(){
  // calibrate our canvas
  var c1 = delayer({});
  var c1_c = ViewportCalibratedCanvas(c1, rhs_viewer);
  var rhs_imagingHelper = new OpenSeadragonImaging.ImagingHelper({
        viewer: rhs_viewer
      });
  // handle algorithm selection
  annots = new annotations(_sbs_id, rhs_viewer, c1_c, rhs_imagingHelper, {});

  // get new data each pass
  rhs_viewer.addHandler("zoom", function(){
    annots.draw();
  })

  rhs_viewer.addHandler("pan", function(){
    annots.draw();
  });

  // algorithm selector
  annots.store.getAlgList(function(data){
    let algsel = document.getElementById("algsel_sbs")
    algsel.style.display = "";
    let title = document.createElement("div");
    title.innerHTML = "Select algorithms: <br/>"
    algsel.appendChild(title);
    // add title
    data.forEach((function(x){
      let select_item = document.createElement("div");
      select_item.innerHTML = ax.title;
      select_item.onclick = function(x){
        x.style.display="none";
        annots.select(x.innerHTML);
      }.bind(this);
      // TODO add a little color indicator
      algsel.appendChild(select_item);
    });
    let done = document.createElement("div");
    done.innerHTML = "DONE"
    done.onclick = function(){
      document.getElementById("algsel_sbs").style.display="none";
    }
    algsel.appendChild("done")
  });

  console.log(annots.selection);

  // redraw all active annotations each redraw
  // clearing and re-fetching is inefficient, c1 can be used as a cache
  var overlay = rhs_viewer.canvasOverlay({
      clearBeforeRedraw:true,
      onRedraw:function() {
        var lw = 50 / (viewer.viewport.getZoom(true));
        overlay.context2d().lineWidth = lw
        c1.__apply_all(overlay.context2d());
      }
  });
  // // dummy response
  //  d = [{ "_id" : { "$oid" : "5ad11630e4b0dd37ccda6ee3"} , "geometry" : { "type" : "Polygon" , "coordinates" : [ [ [ 0 , 0] , [ 0.37133497911441 , 0.55870962366762] , [ 0 , 1] , [ 0.36813129206405 , 0.57044250168238] , [ 0.36813129206405 , 0.55870962366762]]]} , "footprint" : 69980.14639099 , "provenance" : { "analysis" : { "execution_id" : "tammy.diprima_Tumor_Region" , "source" : "human"} , "image" : { "case_id" : "TEST"}}},{ "_id" : { "$oid" : "5ad11630e4b0dd37ccda6ee5"} , "geometry" : { "type" : "Polygon" , "coordinates" : [ [ [ 0.36813129206405 , 0.55870962366762] , [ 0.37133497911441 , 0.55870962366762] , [ 0.37133497911441 , 0.57044250168238] , [ 0.36813129206405 , 0.57044250168238] , [ 0.36813129206405 , 0.55870962366762]]]} , "footprint" : 69980.14639099 , "provenance" : { "analysis" : { "execution_id" : "tammy.diprima_Tumor_Region" , "source" : "human"} , "image" : { "case_id" : "TEST"}}}];
  // //
  // drawFromList(d, c1_c)
}

// functions to change

document.addEventListener("sidesplit", function(e){
  if (document.getElementById("right_sidebyside").style.display == "block"){
    hide_sbs();
  } else {
    //var demoimg = {"CMU1jp2k": "http://localhost:8081/fcgi-bin/iipsrv.fcgi?DeepZoom=/data/images/CMU-1-JP2K-33005-274ju.svs", "CMU1jp2k": "http://localhost:8081/fcgi-bin/iipsrv.fcgi?DeepZoom=/data/images/CMU-1-JP2K-33005-274ju.svs.dzi"};
    show_sbs();
    // need viewers to be up to draw
    show_minidraw();
    rhs_viewer.open(_sbs_source); // for now
  }
});
<|endoftext|>


<commit_before>angular.module('foundation.notification', []);

angular.module('foundation.notification')
  .controller('FaNotificationController', ['$scope', 'FoundationApi', function FaTabsController($scope, foundationApi) {
    var controller = this;
    var notifications = controller.notifications = $scope.notifications = [];

    controller.addNotification = function(info) {
      var id = foundationApi.generateUuid();
      info.id = id;
      notifications.push(info);
    };

    controller.removeNotification = function(id) {
      angular.forEach(notifications, function(notification) {
        if(notification.id === id) {
          var ind = notifications.indexOf(notification);
          notifications.splice(ind, 1);
        }
      });
    };

    controller.clearAll = function() {
      notifications = [];
    };

}]);

angular.module('foundation.notification')
  .directive('faNotificationSet', ['FoundationApi', function(foundationApi) {
  return {
    restrict: 'EA',
    templateUrl: '/partials/notification-set.html',
    controller: 'FaNotificationController',
    link:function(scope, element, attrs, controller) {
      foundationApi.subscribe(attrs.id, function(msg) {
        if(msg === 'clearall') {
          controller.clearAll();
        } else {
          controller.addNotification(msg);
        }

        scope.$apply();
      });

    },
  };
}]);

angular.module('foundation.notification')
  .directive('faNotification', function() {
  return {
    restrict: 'EA',
    templateUrl: '/partials/notification.html',
    replace: true,
    transclude: true,
    require: '^faNotificationSet',
    controller: function() { },
    scope: {
      title: '=?',
      content: '=?',
      image: '=?',
      notifId: '=',
      position: '=?',
      color: '=?'
    },
    link: function(scope, element, attrs, controller) {
      scope.active = true;

      scope.remove = function() {
        controller.removeNotification(scope.notifId);
      };
    },
  };
});

angular.module('foundation.notification')
  .directive('faNotificationStatic', ['FoundationApi', function(foundationApi) {
  return {
    restrict: 'EA',
    templateUrl: '/partials/notification.html',
    replace: true,
    transclude: true,
    scope: {
      title: '@?',
      content: '@?',
      image: '@?',
      position: '@?',
      color: '@?'
    },
    link: function(scope, element, attrs, controller) {
      scope.position = scope.position.split(' ').join('-');

      foundationApi.subscribe(attrs.id, function(msg) {
        if(msg == 'show' || msg == 'open') {
          scope.show();
        } else if (msg == 'close' || msg == 'hide') {
          scope.hide();
        } else if (msg == 'toggle') {
          scope.toggle();
        }

        scope.$apply();

        return;
      });

      scope.hide = function() {
        scope.active = false;
        return;
      };

      scope.remove = function() { scope.hide(); };

      scope.show = function() {
        scope.active = true;
        return;
      };

      scope.toggle = function() {
        scope.active = !scope.active;
        return;
      };

    },
  };
}]);

angular.module('foundation.notification')
  .directive('faNotify', ['FoundationApi', function(foundationApi) {
  return {
    restrict: 'A',
    scope: {
      title: '@?',
      content: '@?',
      position: '@?',
      color: '@?'
    },
    link: function(scope, element, attrs, controller) {
      element.on('click', function(e) {
        foundationApi.publish(attrs.faNotify, { title: scope.title, content: scope.content, position: scope.position, color: scope.color });
        e.preventDefault();
      });
    },
  };
}]);
<commit_msg>Fixed notification, standardized behavior<commit_after>angular.module('foundation.notification', []);

angular.module('foundation.notification')
  .controller('FaNotificationController', ['$scope', 'FoundationApi', function FaTabsController($scope, foundationApi) {
    var controller = this;
    var notifications = controller.notifications = $scope.notifications = [];

    controller.addNotification = function(info) {
      var id = foundationApi.generateUuid();
      info.id = id;
      notifications.push(info);
    };

    controller.removeNotification = function(id) {
      angular.forEach(notifications, function(notification) {
        if(notification.id === id) {
          var ind = notifications.indexOf(notification);
          notifications.splice(ind, 1);
        }
      });
    };

    controller.clearAll = function() {
      notifications = [];
    };

}]);

angular.module('foundation.notification')
  .directive('faNotificationSet', ['FoundationApi', function(foundationApi) {
  return {
    restrict: 'EA',
    templateUrl: '/partials/notification-set.html',
    controller: 'FaNotificationController',
    link:function(scope, element, attrs, controller) {
      foundationApi.subscribe(attrs.id, function(msg) {
        if(msg === 'clearall') {
          controller.clearAll();
        } else {
          controller.addNotification(msg);
        }

        scope.$apply();
      });

    },
  };
}]);

angular.module('foundation.notification')
  .directive('faNotification', function() {
  return {
    restrict: 'EA',
    templateUrl: '/partials/notification.html',
    replace: true,
    transclude: true,
    require: '^faNotificationSet',
    controller: function() { },
    scope: {
      title: '=?',
      content: '=?',
      image: '=?',
      notifId: '=',
      position: '=?',
      color: '=?'
    },
    link: function(scope, element, attrs, controller) {
      scope.active = false;

      //allow DOM to change before activating
      setTimeout(function() {
        scope.active = true;
        scope.$apply();
      }, 50);

      scope.remove = function() {
        scope.active = false;
        setTimeout(function() {
          controller.removeNotification(scope.notifId);
        }, 200);
      };
    },
  };
});

angular.module('foundation.notification')
  .directive('faNotificationStatic', ['FoundationApi', function(foundationApi) {
  return {
    restrict: 'EA',
    templateUrl: '/partials/notification.html',
    replace: true,
    transclude: true,
    scope: {
      title: '@?',
      content: '@?',
      image: '@?',
      position: '@?',
      color: '@?'
    },
    link: function(scope, element, attrs, controller) {
      scope.position = scope.position ? scope.position.split(' ').join('-') : '';

      foundationApi.subscribe(attrs.id, function(msg) {
        if(msg == 'show' || msg == 'open') {
          scope.show();
        } else if (msg == 'close' || msg == 'hide') {
          scope.hide();
        } else if (msg == 'toggle') {
          scope.toggle();
        }

        scope.$apply();

        return;
      });

      scope.hide = function() {
        scope.active = false;
        return;
      };

      scope.remove = function() { scope.hide(); };

      scope.show = function() {
        scope.active = true;
        return;
      };

      scope.toggle = function() {
        scope.active = !scope.active;
        return;
      };

    },
  };
}]);

angular.module('foundation.notification')
  .directive('faNotify', ['FoundationApi', function(foundationApi) {
  return {
    restrict: 'A',
    scope: {
      title: '@?',
      content: '@?',
      position: '@?',
      color: '@?'
    },
    link: function(scope, element, attrs, controller) {
      element.on('click', function(e) {
        foundationApi.publish(attrs.faNotify, { title: scope.title, content: scope.content, position: scope.position, color: scope.color });
        e.preventDefault();
      });
    },
  };
}]);
<|endoftext|>


<commit_before>'use strict';

define(['backend/port', 'util/protocol', 'util/btc', 'dwutil/multisig', 'bitcoinjs-lib'], function(Port, Protocol, BtcUtils, MultisigFund, Bitcoin) {

  var convert = Bitcoin.convert;

  /*
   * Service tracking and sending multisig actions
   * @constructor
   */
  function MultisigTrackService(core) {
    var self = this;
    this.name = 'multisigTrack';
    this.core = core;
    this.ongoing = {};

    // Connect to wallet port for identity cleanup and startup
    Port.connect('wallet', function(data) {
      // Cleanup on identity change;
      if (data.type == 'ready') {
        self.checkFinishedTasks();
      }
      else if (data.type == 'closing') {
        self.ongoing = {};
      }
    });

    // Connect to contacts port to know about contacts becoming available
    Port.connect('contacts', function(data) {
        if (data.type == 'contact') {
            self.onContactAvailable(data.peer);
        }
    });
    Port.connect('channel', function(data) {
        if (data.type == 'initChannel') {
            console.log("[msTrack] connecting", data.name);
            var channel = core.getLobbyTransport().getChannel(data.name);
            channel.addCallback('MultisigAnnounce', function(msg) { self.onMultisigAnnounce(msg) });
            channel.addCallback('MultisigSpend', function(msg) { self.onMultisigSpend(msg) } );
            channel.addCallback('MultisigAck', function(msg) { self.onMultisigAck(msg) } );
            channel.addCallback('MultisigSign', function(msg) { self.onMultisigSign(msg) } );
        }
    });

  }

  /**
   * Check a peer task
   */
  MultisigTrackService.prototype.checkPeerTask = function(peer, section, task) {
      var self = this;
      var identity = this.core.getCurrentIdentity();
      var contact = peer.contact;

      if (!task.participants) {
          var multisig = identity.wallet.multisig.search({address: task.inPocket});
          if (!multisig) {
              return
          }
          self.prepareTask(task, multisig);
      }

      task.participants.forEach(function(participant) {
          participant.available = true;
          if (!participant.sent || (participant.peer != peer.fingerprint)) {
              var taskContact = identity.contacts.findByPubKey(participant.pubKey);
              if (taskContact == contact) {
                  participant.peer = peer.fingerprint;
                  console.log("[msTrack]", section);
                  self.send(peer, section, task, participant);
              }
          }
      });
  }

  /**
   * Check for peer tasks
   */
  MultisigTrackService.prototype.checkPeerTasks = function(peer, section) {
      var self = this;
      var identity = this.core.getCurrentIdentity();

      var tasks = identity.tasks.getTasks(section);

      // Iterate over tasks
      tasks.forEach(function(task) {
          self.checkPeerTask(peer, section, task);
      });
  }

  /**
   * Process a transaction arriving to the wallet to see if we need
   * to close any of the available tasks
   */
  MultisigTrackService.prototype.processTx = function(serializedTx) {
      var identity = this.core.getCurrentIdentity();
      var txHash = BtcUtils.hash256(serializedTx);

      var tasks = identity.tasks.getTasks('multisig');
      tasks = tasks.concat(identity.tasks.getTasks('multisig-sign'));

      tasks.forEach(function(task) {
            if ((task.tx == serializedTx) || (task.hash == txHash)) {
                task.state = 'finished';
            }
      });
  }

  /**
   * Check all tasks to see if any are finished
   */
  MultisigTrackService.prototype.checkFinishedTasks = function() {
      var identity = this.core.getCurrentIdentity();

      // Check spends in case relevant tx already propagated on the network
      // then we can finish the task.
      var tasks = identity.tasks.getTasks('multisig');
      tasks = tasks.concat(identity.tasks.getTasks('multisig-sign'));

      tasks.forEach(function(task) {
          // Generate the tx hash to check or get it from the task if available
          var hash = task.hash || BtcUtils.hash256(task.tx);

          // Check if some row references this
          identity.history.history.some(function(row) {
              if (row.hash == hash) {
                  task.state = 'finished';
                  return true;
              }
          });
      });
  }

  /**
   * A contact becomes available.
   */
  MultisigTrackService.prototype.onContactAvailable = function(peer) {
      // See if we have anything to send to this contact
      this.checkPeerTasks(peer, 'multisig');
      this.checkPeerTasks(peer, 'multisig-announce');
      this.checkPeerTasks(peer, 'multisig-sign');

  }

  /**
   * Start a task for a multisig with slots for every participant.
   * @private
   */
  MultisigTrackService.prototype.prepareTask = function(task, multisig) {
      // Prepare the announce multisig task
      task.participants = [];
      task.started = Date.now();
      multisig.pubKeys.forEach(function(pubKey) {
          // pubkey, available, sent, ack, signature
          var state = {pubKey: pubKey.slice(), available: false, sent: false, ack: false, sig: null};
          task.participants.push(state)
      });
      task.address = multisig.address;
      return task;
  }

  /**
   * Add a task and check if we can send it to any peers
   * @private
   */
  MultisigTrackService.prototype.addTask = function(section, task) {
      var self = this;
      var identity = this.core.getCurrentIdentity();

      // Store the task so we can keep track of it
      identity.tasks.addTask(section, task);

      // Now see if we're connected and check contacts
      var transport = this.core.service.lobby.lobbyTransport;
      if (transport) {
          transport.peers.forEach(function(peer) {
              if (peer.contact) {
                  self.checkPeerTask(peer, section, task);
              }
          });
      }
  }

  /**
   * Queue announcing the multisig to all peers
   */
  MultisigTrackService.prototype.announce = function(multisig, walletAddress) {
      var task = this.prepareTask({}, multisig);

      // Add the task
      this.addTask('multisig-announce', task);
      return task;
  }

  MultisigTrackService.prototype.accept = function(task) {
      var identity = this.core.getCurrentIdentity();

      task.state  = 'finished';

      var exists = identity.wallet.multisig.search({address: task.fund.address});
      if (!exists) {
          var multisig = task.fund;
          multisig.name = task.name;
          multisig.participants = multisig.pubKeys.slice();
          var walletAddress = identity.wallet.multisig.addFund(multisig);
          this.core.initAddress(walletAddress);
      }

      // identity.tasks.removeTask('multisig-invite', task);
  }

  /**
   * Create a task for sending the sign
   */
  MultisigTrackService.prototype.sign = function(multisig, tx, signature) {
      var task = this.prepareTask({}, multisig);
      task.hash = convert.bytesToHex(tx.getHash());
      task.signature = convert.bytesToHex(signature);

      // Add the task
      this.addTask('multisig-sign', task);
      return task;
  }

  /**
   * Send the spend to other peers so it can be spent
   */
  MultisigTrackService.prototype.spend = function(txHex, pending) {
      var identity = this.core.getCurrentIdentity();

      // TODO: only supporting one in pocket/multisig here
      var address = pending[0].address;
      var multisig = identity.wallet.multisig.search({address: address});
      if (!multisig) {
          throw Error("The selected multisig does not exist");
      }
      var task = this.prepareTask({}, multisig);
      task.tx = txHex;
      task.pending = pending;

      // TODO inPocket must be removed in favour of task.address
      task.inPocket = address;

      // Add the task
      this.addTask('multisig', task);
      return task;
  }

  /**
   * Send a task to a contact
   * @private
   */
  MultisigTrackService.prototype.send = function(peer, section, task, tracking) {
      var msg;
      if (section == 'multisig') {
          msg = Protocol.MultisigSpendMsg(task.address, task.tx);
          msg.body.pending = task.pending;
      } else if (section == 'multisig-announce') {
          var identity = this.core.getCurrentIdentity();
          var multisig = identity.wallet.multisig.search({address: task.address});
          msg = Protocol.MultisigAnnounceMsg(multisig.script);
          msg.body.name = multisig.name;
      } else if (section == 'multisig-sign') {
          msg = Protocol.MultisigSignMsg(task.address, task.hash, [task.signature]);
      }

      if (msg) {
          // keep track of sent until ack arrives
          msg.body.id = Math.random();
          tracking.sent = msg.body.id;
          this.ongoing[msg.body.id] = tracking;
      }

      peer.channel.postDH(peer.pubKey, msg, function() {});
  }

  /**
   * A new multisig was received, queue for accepting
   */
  MultisigTrackService.prototype.onMultisigAnnounce = function(msg) {
      var identity = this.core.getCurrentIdentity();
      var peer = msg.peer;
      var script = msg.body.script;

      // parse the multisig
      var multisig = BtcUtils.importMultiSig(script, identity.wallet.versions.p2sh);

      // see if we already have this multisig
      var prevFund = identity.wallet.multisig.search({address: multisig.address});
      if (!prevFund) {
          var task = { fund: multisig, name: msg.body.name };
          this.addTask('multisig-invite', task);
      }
  }

  /**
   * Acknowledge receiving a spend request
   * @private
   */
  MultisigTrackService.prototype.sendAck = function(peer, spend) {
      // Add the task
      var msg = Protocol.MultisigAckMsg(spend.id);
      peer.channel.postDH(peer.pubKey, msg, function() {});
  }

  /**
   * A new spend arrived from a peer, queue for spending
   */
  MultisigTrackService.prototype.onMultisigSign = function(msg) {
      var identity = this.core.getCurrentIdentity();
      var peer = msg.peer;
      var txHash = msg.body.hash;
      var address = msg.body.address;
      var sigHex = msg.body.sig[0];

      // Ack
      this.sendAck(peer, msg.body);

      // TODO: only supporting one in pocket/multisig here
      var multisig = identity.wallet.multisig.search({address: address});
      if (!multisig) {
          return;
          // throw Error("The selected multisig does not exist");
      }
      var fund = new MultisigFund(multisig);

      var spend = fund.getSpend(txHash);
      if (spend) {
          fund.importSignature(sigHex, spend);
      }
  }

  /**
   * A new spend arrived from a peer, queue for spending
   */
  MultisigTrackService.prototype.onMultisigSpend = function(msg) {
      var identity = this.core.getCurrentIdentity();
      var peer = msg.peer;
      var txHex = msg.body.tx;
      var address = msg.body.address;

      // Ack
      this.sendAck(peer, msg.body);

      // TODO: only supporting one in pocket/multisig here
      var multisig = identity.wallet.multisig.search({address: address});
      if (!multisig) {
          return;
          // throw Error("The selected multisig does not exist");
      }
      var prev = identity.tasks.search('multisig', 'tx', txHex);
      if (!prev) {
          var fund = new MultisigFund(multisig);
          var spend = fund.importTransaction(txHex);
          if (spend) {
              // add list of participants to contact
              this.prepareTask(spend.task, multisig);
          }
      }
  }

  /**
   * A new multisig ack has arrived
   */
  MultisigTrackService.prototype.onMultisigAck = function(msg) {
      var identity = this.core.getCurrentIdentity();
      var peer = msg.peer;
      var tracking = this.ongoing[msg.body.id];
      if (tracking) {
          tracking.ack = true;
          delete this.ongoing[msg.body.id];
      }
  }

  return MultisigTrackService;

});
<commit_msg>Fix some lint errors.<commit_after>'use strict';

define(['backend/port', 'util/protocol', 'util/btc', 'dwutil/multisig', 'bitcoinjs-lib'], function(Port, Protocol, BtcUtils, MultisigFund, Bitcoin) {

  var convert = Bitcoin.convert;

  /*
   * Service tracking and sending multisig actions
   * @constructor
   */
  function MultisigTrackService(core) {
    var self = this;
    this.name = 'multisigTrack';
    this.core = core;
    this.ongoing = {};

    // Connect to wallet port for identity cleanup and startup
    Port.connect('wallet', function(data) {
      // Cleanup on identity change;
      if (data.type === 'ready') {
        self.checkFinishedTasks();
      }
      else if (data.type === 'closing') {
        self.ongoing = {};
      }
    });

    // Connect to contacts port to know about contacts becoming available
    Port.connect('contacts', function(data) {
        if (data.type === 'contact') {
            self.onContactAvailable(data.peer);
        }
    });
    Port.connect('channel', function(data) {
        if (data.type === 'initChannel') {
            console.log("[msTrack] connecting", data.name);
            var channel = core.getLobbyTransport().getChannel(data.name);
            channel.addCallback('MultisigAnnounce', function(msg) { self.onMultisigAnnounce(msg); });
            channel.addCallback('MultisigSpend', function(msg) { self.onMultisigSpend(msg); } );
            channel.addCallback('MultisigAck', function(msg) { self.onMultisigAck(msg); } );
            channel.addCallback('MultisigSign', function(msg) { self.onMultisigSign(msg); } );
        }
    });

  }

  /**
   * Check a peer task
   */
  MultisigTrackService.prototype.checkPeerTask = function(peer, section, task) {
      var self = this;
      var identity = this.core.getCurrentIdentity();
      var contact = peer.contact;

      if (!task.participants) {
          var multisig = identity.wallet.multisig.search({address: task.inPocket});
          if (!multisig) {
              return;
          }
          self.prepareTask(task, multisig);
      }

      task.participants.forEach(function(participant) {
          participant.available = true;
          if (!participant.sent || (participant.peer !== peer.fingerprint)) {
              var taskContact = identity.contacts.findByPubKey(participant.pubKey);
              if (taskContact == contact) {
                  participant.peer = peer.fingerprint;
                  console.log("[msTrack]", section);
                  self.send(peer, section, task, participant);
              }
          }
      });
  };

  /**
   * Check for peer tasks
   */
  MultisigTrackService.prototype.checkPeerTasks = function(peer, section) {
      var self = this;
      var identity = this.core.getCurrentIdentity();

      var tasks = identity.tasks.getTasks(section);

      // Iterate over tasks
      tasks.forEach(function(task) {
          self.checkPeerTask(peer, section, task);
      });
  };

  /**
   * Process a transaction arriving to the wallet to see if we need
   * to close any of the available tasks
   */
  MultisigTrackService.prototype.processTx = function(serializedTx) {
      var identity = this.core.getCurrentIdentity();
      var txHash = BtcUtils.hash256(serializedTx);

      var tasks = identity.tasks.getTasks('multisig');
      tasks = tasks.concat(identity.tasks.getTasks('multisig-sign'));

      tasks.forEach(function(task) {
            if ((task.tx === serializedTx) || (task.hash === txHash)) {
                task.state = 'finished';
            }
      });
  };

  /**
   * Check all tasks to see if any are finished
   */
  MultisigTrackService.prototype.checkFinishedTasks = function() {
      var identity = this.core.getCurrentIdentity();

      // Check spends in case relevant tx already propagated on the network
      // then we can finish the task.
      var tasks = identity.tasks.getTasks('multisig');
      tasks = tasks.concat(identity.tasks.getTasks('multisig-sign'));

      tasks.forEach(function(task) {
          // Generate the tx hash to check or get it from the task if available
          var hash = task.hash || BtcUtils.hash256(task.tx);

          // Check if some row references this
          identity.history.history.some(function(row) {
              if (row.hash === hash) {
                  task.state = 'finished';
                  return true;
              }
          });
      });
  };

  /**
   * A contact becomes available.
   */
  MultisigTrackService.prototype.onContactAvailable = function(peer) {
      // See if we have anything to send to this contact
      this.checkPeerTasks(peer, 'multisig');
      this.checkPeerTasks(peer, 'multisig-announce');
      this.checkPeerTasks(peer, 'multisig-sign');

  };

  /**
   * Start a task for a multisig with slots for every participant.
   * @private
   */
  MultisigTrackService.prototype.prepareTask = function(task, multisig) {
      // Prepare the announce multisig task
      task.participants = [];
      task.started = Date.now();
      multisig.pubKeys.forEach(function(pubKey) {
          // pubkey, available, sent, ack, signature
          var state = {pubKey: pubKey.slice(), available: false, sent: false, ack: false, sig: null};
          task.participants.push(state);
      });
      task.address = multisig.address;
      return task;
  };

  /**
   * Add a task and check if we can send it to any peers
   * @private
   */
  MultisigTrackService.prototype.addTask = function(section, task) {
      var self = this;
      var identity = this.core.getCurrentIdentity();

      // Store the task so we can keep track of it
      identity.tasks.addTask(section, task);

      // Now see if we're connected and check contacts
      var transport = this.core.service.lobby.lobbyTransport;
      if (transport) {
          transport.peers.forEach(function(peer) {
              if (peer.contact) {
                  self.checkPeerTask(peer, section, task);
              }
          });
      }
  };

  /**
   * Queue announcing the multisig to all peers
   */
  MultisigTrackService.prototype.announce = function(multisig, walletAddress) {
      var task = this.prepareTask({}, multisig);

      // Add the task
      this.addTask('multisig-announce', task);
      return task;
  };

  MultisigTrackService.prototype.accept = function(task) {
      var identity = this.core.getCurrentIdentity();

      task.state  = 'finished';

      var exists = identity.wallet.multisig.search({address: task.fund.address});
      if (!exists) {
          var multisig = task.fund;
          multisig.name = task.name;
          multisig.participants = multisig.pubKeys.slice();
          var walletAddress = identity.wallet.multisig.addFund(multisig);
          this.core.initAddress(walletAddress);
      }

      // identity.tasks.removeTask('multisig-invite', task);
  };

  /**
   * Create a task for sending the sign
   */
  MultisigTrackService.prototype.sign = function(multisig, tx, signature) {
      var task = this.prepareTask({}, multisig);
      task.hash = convert.bytesToHex(tx.getHash());
      task.signature = convert.bytesToHex(signature);

      // Add the task
      this.addTask('multisig-sign', task);
      return task;
  };

  /**
   * Send the spend to other peers so it can be spent
   */
  MultisigTrackService.prototype.spend = function(txHex, pending) {
      var identity = this.core.getCurrentIdentity();

      // TODO: only supporting one in pocket/multisig here
      var address = pending[0].address;
      var multisig = identity.wallet.multisig.search({address: address});
      if (!multisig) {
          throw new Error("The selected multisig does not exist");
      }
      var task = this.prepareTask({}, multisig);
      task.tx = txHex;
      task.pending = pending;

      // TODO inPocket must be removed in favour of task.address
      task.inPocket = address;

      // Add the task
      this.addTask('multisig', task);
      return task;
  };

  /**
   * Send a task to a contact
   * @private
   */
  MultisigTrackService.prototype.send = function(peer, section, task, tracking) {
      var msg;
      if (section === 'multisig') {
          msg = Protocol.MultisigSpendMsg(task.address, task.tx);
          msg.body.pending = task.pending;
      } else if (section === 'multisig-announce') {
          var identity = this.core.getCurrentIdentity();
          var multisig = identity.wallet.multisig.search({address: task.address});
          msg = Protocol.MultisigAnnounceMsg(multisig.script);
          msg.body.name = multisig.name;
      } else if (section === 'multisig-sign') {
          msg = Protocol.MultisigSignMsg(task.address, task.hash, [task.signature]);
      }

      if (msg) {
          // keep track of sent until ack arrives
          msg.body.id = Math.random();
          tracking.sent = msg.body.id;
          this.ongoing[msg.body.id] = tracking;
      }

      peer.channel.postDH(peer.pubKey, msg, function() {});
  };

  /**
   * A new multisig was received, queue for accepting
   */
  MultisigTrackService.prototype.onMultisigAnnounce = function(msg) {
      var identity = this.core.getCurrentIdentity();
      var peer = msg.peer;
      var script = msg.body.script;

      // parse the multisig
      var multisig = BtcUtils.importMultiSig(script, identity.wallet.versions.p2sh);

      // see if we already have this multisig
      var prevFund = identity.wallet.multisig.search({address: multisig.address});
      if (!prevFund) {
          var task = { fund: multisig, name: msg.body.name };
          this.addTask('multisig-invite', task);
      }
  };

  /**
   * Acknowledge receiving a spend request
   * @private
   */
  MultisigTrackService.prototype.sendAck = function(peer, spend) {
      // Add the task
      var msg = Protocol.MultisigAckMsg(spend.id);
      peer.channel.postDH(peer.pubKey, msg, function() {});
  };

  /**
   * A new spend arrived from a peer, queue for spending
   */
  MultisigTrackService.prototype.onMultisigSign = function(msg) {
      var identity = this.core.getCurrentIdentity();
      var peer = msg.peer;
      var txHash = msg.body.hash;
      var address = msg.body.address;
      var sigHex = msg.body.sig[0];

      // Ack
      this.sendAck(peer, msg.body);

      // TODO: only supporting one in pocket/multisig here
      var multisig = identity.wallet.multisig.search({address: address});
      if (!multisig) {
          return;
          // throw Error("The selected multisig does not exist");
      }
      var fund = new MultisigFund(multisig);

      var spend = fund.getSpend(txHash);
      if (spend) {
          fund.importSignature(sigHex, spend);
      }
  };

  /**
   * A new spend arrived from a peer, queue for spending
   */
  MultisigTrackService.prototype.onMultisigSpend = function(msg) {
      var identity = this.core.getCurrentIdentity();
      var peer = msg.peer;
      var txHex = msg.body.tx;
      var address = msg.body.address;

      // Ack
      this.sendAck(peer, msg.body);

      // TODO: only supporting one in pocket/multisig here
      var multisig = identity.wallet.multisig.search({address: address});
      if (!multisig) {
          return;
          // throw Error("The selected multisig does not exist");
      }
      var prev = identity.tasks.search('multisig', 'tx', txHex);
      if (!prev) {
          var fund = new MultisigFund(multisig);
          var spend = fund.importTransaction(txHex);
          if (spend) {
              // add list of participants to contact
              this.prepareTask(spend.task, multisig);
          }
      }
  };

  /**
   * A new multisig ack has arrived
   */
  MultisigTrackService.prototype.onMultisigAck = function(msg) {
      var peer = msg.peer;
      var tracking = this.ongoing[msg.body.id];
      if (tracking) {
          tracking.ack = true;
          delete this.ongoing[msg.body.id];
      }
  };

  return MultisigTrackService;

});
<|endoftext|>