<commit_before>(function (mw, $, shaka) {
	"use strict";
	if (!window.Promise) {
		shaka.polyfill.installAll();
	}
	if (shaka.Player.isBrowserSupported() && !mw.isDesktopSafari()) {
		$(mw).bind('EmbedPlayerUpdateMediaPlayers', function (event, mediaPlayers) {
			mw.log("Dash::Register shaka player for application/dash+xml mime type");
			var shakaPlayer = new mw.MediaPlayer('shakaPlayer', ['application/dash+xml'], 'Native');
			mediaPlayers.addPlayer(shakaPlayer);
			mw.EmbedTypes.mediaPlayers.setMIMETypePlayers('application/dash+xml', 'Native');
		});
		var dash = mw.KBasePlugin.extend({

			/** type {boolean} */
			loaded: false,

			/**
			 * Check is shaka is supported
			 * @returns {boolean}
			 */
			isSafeEnviornment: function () {
				return shaka.Player.isBrowserSupported();
			},
			/**
			 * Setup the shaka playback engine wrapper with supplied config options
			 */
			setup: function () {
				this.addBindings();
			},
			/**
			 *
			 */
			addBindings: function () {
				this.bind("playerReady", this.initShaka.bind(this));
				this.bind("switchAudioTrack", this.onSwitchAudioTrack.bind(this));
				this.bind("selectClosedCaptions", this.onSwitchTextTrack.bind(this));
				this.bind("onChangeMedia", this.clean.bind(this));
			},

			/**
			 * Register the playback events and attach the playback engine to the video element
			 */
			initShaka: function () {
				if (!this.loaded) {
					this.log("Init shaka");
					var _this = this;
					//Disable update of video source tag, MSE uses blob urls!
					this.getPlayer().skipUpdateSource = true;
					this.overridePlayerMethods();

					//Set streamerType to dash
					this.embedPlayer.streamerType = 'dash';

					this.setEmbedPlayerConfig(this.getPlayer());

					// Create a Player instance.
					var player = new shaka.Player(this.getPlayer().getPlayerElement());

					player.configure(this.getConfig("shakaConfig"));

					// Attach player to the window to make it easy to access in the JS console.
					window.player = player;

					// Listen for error events.
					player.addEventListener('error', this.onErrorEvent.bind(this));

					var manifestSrc = this.getPlayer().getSrc();

					this.bind("firstPlay", function(){
						// Try to load a manifest.
						player.load(manifestSrc).then(function () {
							_this.log('The video has now been loaded!');
							_this.addTracks();
						}).catch(this.onError.bind(this));  // onError is executed if the asynchronous load fails.
					}.bind(this));
				}
			},

			setEmbedPlayerConfig: function (embedPlayer) {
				//Get user configuration
				var userConfig = embedPlayer.getKalturaConfig("dash");
				//Get default config
				var dashConfig = this.getDefaultDashConfig();
				//Deep extend custom config
				$.extend(true, dashConfig, userConfig);
				embedPlayer.setKalturaConfig("dash", dashConfig);
			},

			getDefaultDashConfig: function () {
				var drmConfig = this.getDrmConfig();
				var defaultConfig = {
					shakaConfig: {
						drm: {
							servers: {
								'com.widevine.alpha': drmConfig.licenseBaseUrl + "/cenc/widevine/license?" + drmConfig.licenseData,
								'com.microsoft.playready': drmConfig.licenseBaseUrl + "/cenc/playready/license?" + drmConfig.licenseData
							}
						}
					}
				};
				return defaultConfig;
			},

			getDrmConfig: function () {
				var licenseBaseUrl = mw.getConfig('Kaltura.UdrmServerURL');
				if (!licenseBaseUrl) {
					this.log('Error:: failed to retrieve UDRM license URL ');
				}

				var licenseData = this.getPlayer().mediaElement.getLicenseUriComponent();
				var drmConfig = {
					licenseBaseUrl: licenseBaseUrl,
					licenseData: licenseData
				};
				return drmConfig;
			},

			addTracks: function () {
				this.addAbrFlavors();
				this.addAudioTracks();
				this.addSubtitleTracks();
				if (mw.isEdge() || mw.isIE()) {
					// Shaka handles the tracks by itself,
					// so the native player doesn't need to handle them on 'firstPlay'
					this.getPlayer().unbindHelper('firstPlay');
				}
			},

			getTracksByType: function (trackType) {
				var tracks = player.getTracks().filter(function (track) {
					return track.type == trackType;
				});
				return tracks;
			},

			addAbrFlavors: function () {
				var videoTracks = this.getTracksByType("video");
				if (videoTracks && videoTracks.length > 0) {
					var flavors = videoTracks.map(function (rep) {
						var sourceAspect = Math.round(( rep.width / rep.height ) * 100) / 100;
						// Setup a source object:
						return {
							'data-bandwidth': rep.bandwidth,
							'data-width': rep.width,
							'data-height': rep.height,
							'data-aspect': sourceAspect,
							'type': 'video/mp4',
							'data-assetid': rep.id
						};
					});
					mw.log("Dash::" + videoTracks.length + " ABR flavors were found: ",videoTracks);
					this.getPlayer().onFlavorsListChanged(flavors);
				}
			},

			addAudioTracks: function () {
				var audioTracks = this.getTracksByType("audio");
				if (audioTracks && audioTracks.length > 0) {
					var audioTrackData = {languages: []};
					$.each(audioTracks, function (index, audioTrack) {
						audioTrackData.languages.push({
							'kind': 'audioTrack',
							'language': audioTrack.language,
							'srclang': audioTrack.language,
							'label': audioTrack.language,
							'title': audioTrack.language,
							'id': audioTrack.id,
							'index': audioTrackData.languages.length
						});
					});
					mw.log("Dash::" + audioTracks.length + " audio tracks were found: ",audioTracks);
					this.onAudioTracksReceived(audioTrackData);
				}
			},

			addSubtitleTracks: function () {
				var textTracks = this.getTracksByType("text");
				if (textTracks && textTracks.length > 0) {
					window.VTTCue = this.getPlayer().getOriginalVTTCue();
					var textTrackData = {languages: []};
					$.each(textTracks, function (index, subtitleTrack) {
						textTrackData.languages.push({
							'kind': 'subtitle',
							'language': subtitleTrack.language,
							'srclang': subtitleTrack.language,
							'label': subtitleTrack.language,
							'title': subtitleTrack.language,
							'id': subtitleTrack.id,
							'index': textTrackData.languages.length
						});
					});
					mw.log("Dash::" + textTracks.length + " text tracks were found: ",textTracks);
					this.onTextTracksReceived(textTrackData);
				}
			},

			onAudioTracksReceived: function (data) {
				this.getPlayer().triggerHelper('audioTracksReceived', data);
			},

			onTextTracksReceived: function (data) {
				this.getPlayer().triggerHelper('textTracksReceived', data);
			},

			/**
			 * Override player method for source switch
			 * @param source
			 */
			switchSrc: function (source) {
				if (source !== -1) {
					var selectedAbrTrack = this.getTracksByType("video").filter(function (abrTrack) {
						return abrTrack.id === source.getAssetId();
					})[0];
					if (selectedAbrTrack) {
						player.selectTrack(selectedAbrTrack, true);
						this.getPlayer().triggerHelper('bitrateChange', source.getBitrate());
						mw.log("switchSrc to ", selectedAbrTrack);
					}
				} else { // "Auto" option is selected
					player.configure({
						abr: {
							enabled: true
						}
					});
					this.log("switchSrc to Auto");
				}
			},

			onSwitchAudioTrack: function (event, data) {
				var selectedAudioTracks = this.getTracksByType("audio")[data.index];
				player.configure({
					preferredAudioLanguage: selectedAudioTracks.language
				});
				mw.log("onSwitchAudioTrack switch to ", selectedAudioTracks);
			},

			onSwitchTextTrack: function (event, data) {
				if (data === "Off") {
					player.setTextTrackVisibility(false);
					this.log("onSwitchTextTrack disable subtitles");
				} else {
					player.configure({
						preferredTextLanguage: data
					});
					this.log("onSwitchTextTrack switch to " + data);
				}
			},

			onErrorEvent: function (event) {
				// Extract the shaka.util.Error object from the event.
				this.onError(event.detail);
			},

			/**
			 * Error handler
			 * @param event
			 * @param data
			 */
			onError: function (event, data) {
				var errorData = data ? data.type + ", " + data.details : event;
				this.log("Error: " + errorData);
			},

			/**
			 * Clean method
			 */
			clean: function () {
				this.log("Clean");
				this.restorePlayerMethods();
			},

			/**
			 * Enable override player methods for HLS playback
			 */
			overridePlayerMethods: function () {
				this.orig_switchSrc = this.getPlayer().switchSrc;
				this.getPlayer().switchSrc = this.switchSrc.bind(this);
			},
			/**
			 * Disable override player methods for HLS playback
			 */
			restorePlayerMethods: function () {
				this.getPlayer().switchSrc = this.orig_switchSrc;
			}

		});

		mw.PluginManager.add('Dash', dash);
	}
})(window.mw, window.jQuery, window.shaka);<commit_msg>Resolve the source URL before letting Shaka to load it<commit_after>(function (mw, $, shaka) {
	"use strict";
	if (!window.Promise) {
		shaka.polyfill.installAll();
	}
	if (shaka.Player.isBrowserSupported() && !mw.isDesktopSafari()) {
		$(mw).bind('EmbedPlayerUpdateMediaPlayers', function (event, mediaPlayers) {
			mw.log("Dash::Register shaka player for application/dash+xml mime type");
			var shakaPlayer = new mw.MediaPlayer('shakaPlayer', ['application/dash+xml'], 'Native');
			mediaPlayers.addPlayer(shakaPlayer);
			mw.EmbedTypes.mediaPlayers.setMIMETypePlayers('application/dash+xml', 'Native');
		});
		var dash = mw.KBasePlugin.extend({

			/** type {boolean} */
			loaded: false,

			/**
			 * Check is shaka is supported
			 * @returns {boolean}
			 */
			isSafeEnviornment: function () {
				return shaka.Player.isBrowserSupported();
			},
			/**
			 * Setup the shaka playback engine wrapper with supplied config options
			 */
			setup: function () {
				this.addBindings();
			},
			/**
			 *
			 */
			addBindings: function () {
				this.bind("playerReady", this.initShaka.bind(this));
				this.bind("switchAudioTrack", this.onSwitchAudioTrack.bind(this));
				this.bind("selectClosedCaptions", this.onSwitchTextTrack.bind(this));
				this.bind("onChangeMedia", this.clean.bind(this));
			},

			/**
			 * Register the playback events and attach the playback engine to the video element
			 */
			initShaka: function () {
				if (!this.loaded) {
					this.log("Init shaka");
					var _this = this;
					//Disable update of video source tag, MSE uses blob urls!
					this.getPlayer().skipUpdateSource = true;
					this.overridePlayerMethods();

					//Set streamerType to dash
					this.embedPlayer.streamerType = 'dash';

					this.setEmbedPlayerConfig(this.getPlayer());

					// Create a Player instance.
					var player = new shaka.Player(this.getPlayer().getPlayerElement());

					player.configure(this.getConfig("shakaConfig"));

					// Attach player to the window to make it easy to access in the JS console.
					window.player = player;

					// Listen for error events.
					player.addEventListener('error', this.onErrorEvent.bind(this));

					var selectedSource = this.getPlayer().getSrc();

					this.bind("firstPlay", function () {
						_this.getPlayer().resolveSrcURL(selectedSource)
							.done(function (manifestSrc) {  // success
								selectedSource = manifestSrc;
							})
							.always(function () {  // both success or error
									//// Try to load a manifest.
									player.load(selectedSource).then(function () {
										// This runs if the asynchronous load is successful.
										_this.log('The video has now been loaded!');
										_this.addTracks();
									}).catch(_this.onError.bind(_this));  // onError is executed if the asynchronous load fails.
								}
							);
					}.bind(this));
				}
			},

			setEmbedPlayerConfig: function (embedPlayer) {
				//Get user configuration
				var userConfig = embedPlayer.getKalturaConfig("dash");
				//Get default config
				var dashConfig = this.getDefaultDashConfig();
				//Deep extend custom config
				$.extend(true, dashConfig, userConfig);
				embedPlayer.setKalturaConfig("dash", dashConfig);
			},

			getDefaultDashConfig: function () {
				var drmConfig = this.getDrmConfig();
				var defaultConfig = {
					shakaConfig: {
						drm: {
							servers: {
								'com.widevine.alpha': drmConfig.licenseBaseUrl + "/cenc/widevine/license?" + drmConfig.licenseData,
								'com.microsoft.playready': drmConfig.licenseBaseUrl + "/cenc/playready/license?" + drmConfig.licenseData
							}
						}
					}
				};
				return defaultConfig;
			},

			getDrmConfig: function () {
				var licenseBaseUrl = mw.getConfig('Kaltura.UdrmServerURL');
				if (!licenseBaseUrl) {
					this.log('Error:: failed to retrieve UDRM license URL ');
				}

				var licenseData = this.getPlayer().mediaElement.getLicenseUriComponent();
				var drmConfig = {
					licenseBaseUrl: licenseBaseUrl,
					licenseData: licenseData
				};
				return drmConfig;
			},

			addTracks: function () {
				this.addAbrFlavors();
				this.addAudioTracks();
				this.addSubtitleTracks();
				if (mw.isEdge() || mw.isIE()) {
					// Shaka handles the tracks by itself,
					// so the native player doesn't need to handle them on 'firstPlay'
					this.getPlayer().unbindHelper('firstPlay');
				}
			},

			getTracksByType: function (trackType) {
				var tracks = player.getTracks().filter(function (track) {
					return track.type == trackType;
				});
				return tracks;
			},

			addAbrFlavors: function () {
				var videoTracks = this.getTracksByType("video");
				if (videoTracks && videoTracks.length > 0) {
					var flavors = videoTracks.map(function (rep) {
						var sourceAspect = Math.round(( rep.width / rep.height ) * 100) / 100;
						// Setup a source object:
						return {
							'data-bandwidth': rep.bandwidth,
							'data-width': rep.width,
							'data-height': rep.height,
							'data-aspect': sourceAspect,
							'type': 'video/mp4',
							'data-assetid': rep.id
						};
					});
					mw.log("Dash::" + videoTracks.length + " ABR flavors were found: ", videoTracks);
					this.getPlayer().onFlavorsListChanged(flavors);
				}
			},

			addAudioTracks: function () {
				var audioTracks = this.getTracksByType("audio");
				if (audioTracks && audioTracks.length > 0) {
					var audioTrackData = {languages: []};
					$.each(audioTracks, function (index, audioTrack) {
						audioTrackData.languages.push({
							'kind': 'audioTrack',
							'language': audioTrack.language,
							'srclang': audioTrack.language,
							'label': audioTrack.language,
							'title': audioTrack.language,
							'id': audioTrack.id,
							'index': audioTrackData.languages.length
						});
					});
					mw.log("Dash::" + audioTracks.length + " audio tracks were found: ", audioTracks);
					this.onAudioTracksReceived(audioTrackData);
				}
			},

			addSubtitleTracks: function () {
				var textTracks = this.getTracksByType("text");
				if (textTracks && textTracks.length > 0) {
					window.VTTCue = this.getPlayer().getOriginalVTTCue();
					var textTrackData = {languages: []};
					$.each(textTracks, function (index, subtitleTrack) {
						textTrackData.languages.push({
							'kind': 'subtitle',
							'language': subtitleTrack.language,
							'srclang': subtitleTrack.language,
							'label': subtitleTrack.language,
							'title': subtitleTrack.language,
							'id': subtitleTrack.id,
							'index': textTrackData.languages.length
						});
					});
					mw.log("Dash::" + textTracks.length + " text tracks were found: ", textTracks);
					this.onTextTracksReceived(textTrackData);
				}
			},

			onAudioTracksReceived: function (data) {
				this.getPlayer().triggerHelper('audioTracksReceived', data);
			},

			onTextTracksReceived: function (data) {
				this.getPlayer().triggerHelper('textTracksReceived', data);
			},

			/**
			 * Override player method for source switch
			 * @param source
			 */
			switchSrc: function (source) {
				if (source !== -1) {
					var selectedAbrTrack = this.getTracksByType("video").filter(function (abrTrack) {
						return abrTrack.id === source.getAssetId();
					})[0];
					if (selectedAbrTrack) {
						player.selectTrack(selectedAbrTrack, true);
						this.getPlayer().triggerHelper('bitrateChange', source.getBitrate());
						mw.log("switchSrc to ", selectedAbrTrack);
					}
				} else { // "Auto" option is selected
					player.configure({
						abr: {
							enabled: true
						}
					});
					this.log("switchSrc to Auto");
				}
			},

			onSwitchAudioTrack: function (event, data) {
				var selectedAudioTracks = this.getTracksByType("audio")[data.index];
				player.configure({
					preferredAudioLanguage: selectedAudioTracks.language
				});
				mw.log("onSwitchAudioTrack switch to ", selectedAudioTracks);
			},

			onSwitchTextTrack: function (event, data) {
				if (data === "Off") {
					player.setTextTrackVisibility(false);
					this.log("onSwitchTextTrack disable subtitles");
				} else {
					player.configure({
						preferredTextLanguage: data
					});
					this.log("onSwitchTextTrack switch to " + data);
				}
			},

			onErrorEvent: function (event) {
				// Extract the shaka.util.Error object from the event.
				this.onError(event.detail);
			},

			/**
			 * Error handler
			 * @param event
			 * @param data
			 */
			onError: function (event, data) {
				var errorData = data ? data.type + ", " + data.details : event;
				this.log("Error: " + errorData);
			},

			/**
			 * Clean method
			 */
			clean: function () {
				this.log("Clean");
				this.restorePlayerMethods();
			},

			/**
			 * Enable override player methods for HLS playback
			 */
			overridePlayerMethods: function () {
				this.orig_switchSrc = this.getPlayer().switchSrc;
				this.getPlayer().switchSrc = this.switchSrc.bind(this);
			},
			/**
			 * Disable override player methods for HLS playback
			 */
			restorePlayerMethods: function () {
				this.getPlayer().switchSrc = this.orig_switchSrc;
			}

		});

		mw.PluginManager.add('Dash', dash);
	}
})(window.mw, window.jQuery, window.shaka);<|endoftext|>


<commit_before>define(['js/data/Entity', 'sprd/entity/Offset', 'sprd/entity/Size', 'sprd/entity/PrintArea', 'sprd/model/PrintType', 'js/core/List' , "sprd/entity/Price", "sprd/type/Matrix2d", "sprd/util/ProductUtil", "sprd/entity/PrintTypeColor", "underscore", "js/core/Bus"], function (Entity, Offset, Size, PrintArea, PrintType, List, Price, Matrix2d, ProductUtil, PrintTypeColor, _, Bus) {

    return Entity.inherit('sprd.entity.Configuration', {

        schema: {
            offset: Offset,
            printArea: {
                type: PrintArea,
                isReference: true
            },
            printType: PrintType,
            printColors: [PrintTypeColor],

            content: Object,
            restrictions: Object,
            type: String
        },

        defaults: {
            printArea: null,
            printType: null,
            offset: Offset,
            scale: {
                x: 1,
                y: 1
            },
            rotation: 0,
            printColors: List,

            // bind this
            _size: "{size()}",
            _x: "{offset.x}",
            _y: "{offset.y}",

            _isDeletable: true,

            _printTypePrice: "{printType.price}"
        },

        inject: {
            bus: Bus
        },

        save: function(callback) {
            callback && callback();
        },

        _commitChangedAttributes: function ($, options) {

            var delay = options && options.userInteraction ? 300 : 0,
                self = this,
                combinedAttributes = {};

            this.callBase();

            if (this._hasSome($, ["scale", "rotation", "printArea", "printColors", "printArea", "printType"])) {
                if ($.printType && !options.printTypeTransformed) {
                    // manually changed print type
                    this.$.printTypeWasScaled = false;
                }
                if ($.printType && !options.printTypeEqualized) {
                    this.trigger('printTypeSwitched', {printType: $.printType, scaledDown: !!options.scaledDown}, this);
                }
                if (!options.preventValidation && !options.initial) {
                    validate($);
                }
                this.trigger('configurationChanged');
            } else if ($.hasOwnProperty("offset") && $.offset && !$.offset.isDeepEqual(this.$previousAttributes["offset"])) {
                if (!options.preventValidation && !options.initial) {
                    validate($);
                }
                this.trigger('configurationChanged');
            }

            function validate(attributes) {
                _.extend(combinedAttributes, attributes);
                self._debounceFunctionCall(performValidate, "validateTransform", delay, self);
            }

            function performValidate() {
                self._setError(self._validateTransform(combinedAttributes));
                combinedAttributes = {};
            }

        },

        _validateTransform: function ($) {

            var rotationChanged = this._hasSome($, ["rotation"]),
                sizeChanged = this._hasSome($, ["_size", "_x", "_y", "scale", "offset", "bound"]),
                printTypeChanged = this._hasSome($, ["printType"]),
                width, height,
                printType = $.printType || this.$.printType,
                scale = $.scale || this.$.scale,
                rotation = $.rotation || this.$.rotation,
                ret = {},
                printArea = this.$.printArea;

            if (sizeChanged || rotationChanged) {
                width = this.width(scale.x);
                height = this.height(scale.y);

                if (printArea) {

                    if (printArea.hasSoftBoundary()) {
                        ret.hardBoundary = false;
                    } else {
                        ret.hardBoundary = this._hasHardBoundaryError($.offset || this.$.offset, width, height, rotation, scale);
                    }
                }

            }

            if (sizeChanged || printTypeChanged) {
                width = width || this.width();
                height = height || this.height();
                _.extend(ret, this._validatePrintTypeSize(printType, width, height, scale));
            }

            var printTypeTooSmall = ret.minBound,
                printTypeWasScaled = false;

            // try to scale back when one configuration of the print area was scaled
            if (this.$context && this.$context.$contextModel) {
                var printAreaConfigurations = this.$context.$contextModel.getConfigurationsOnPrintAreas([printArea]);
                for (var k = 0; k < printAreaConfigurations.length; k++) {
                    var c = printAreaConfigurations[k];
                    if (c.$.printTypeWasScaled) {
                        printTypeWasScaled = true;
                        break;
                    }
                }
            }

            // when configuration is too small for print type or it is a DD print type try to find another print type that fits better
            if (printType && (printTypeTooSmall || printTypeWasScaled) && this.$context && this.$context.$contextModel && !printTypeChanged && sizeChanged) {
                var product = this.$context.$contextModel,
                    appearanceId = this.$context.$contextModel.get('appearance.id'),
                    originalPrintType = this.$.originalPrintType;
                if (product.$.configurations.size() > 0 && !printTypeTooSmall && originalPrintType) {
                    var revertPossible = true;
                    var configurations = product.$.configurations.toArray();
                    for (var j = 0; j < configurations.length; j++) {
                        var config = configurations[j];

                        var possiblePrintTypes = config.getPossiblePrintTypesForPrintArea(printArea, appearanceId);

                        if (config !== this && config.$.printArea === printArea && (possiblePrintTypes.indexOf(originalPrintType) === -1 || !config.isPrintTypeAvailable(originalPrintType))) {
                            revertPossible = false;
                        }

                    }
                    // don't transform
                    if (!revertPossible) {
                        return ret;
                    }
                }

                var printTypes = this.getPossiblePrintTypesForPrintArea(this.$.printArea, appearanceId);
                var preferredPrintType = null,
                    val,
                    newPrintType;

                for (var i = 0; i < printTypes.length; i++) {
                    newPrintType = printTypes[i];
                    val = this._validatePrintTypeSize(newPrintType, width, height, scale);
                    if (!(val.printTypeScaling || val.maxBound || val.minBound || val.dpiBound)) {
                        // if the previous print type is valid, use it
                        if (printTypeWasScaled && this.$.originalPrintType === newPrintType) {
                            preferredPrintType = newPrintType;
                            this.$.originalPrintType = null;
                            this.$.printTypeWasScaled = false;
                            break;
                        } else if (printTypeTooSmall) {
                            preferredPrintType = newPrintType;
                            this.$.originalPrintType = printType;
                            this.$.printTypeWasScaled = true;
                            break;
                        }
                    }
                }

                if (preferredPrintType && preferredPrintType !== printType) {
                    this.$.bus && this.$.bus.trigger("Configuration.automaticallyPrintTypeChange", {
                        printType: preferredPrintType
                    });
                    this.set('printType', preferredPrintType, {preventValidation: true, printTypeTransformed: true});
                    ret.minBound = false;
                }
            }

            return ret;

        },

        _validatePrintTypeSize: function (printType, width, height, scale) {
            if (!printType) {
                return {};
            }

            var printArea = this.$.printArea;
            if (printArea && printArea.hasSoftBoundary()) {
                // if we use softboundaries the size of the configuration is maximum the
                // size of the softboudary. As long as we haven't the size of the softboundary
                // we use the size of the print area
                width = Math.min(width, printArea.width());
                height = Math.min(height, printArea.height());
            }

            return {
                printTypeScaling: !printType.isScalable() && (scale.x != 1 || scale.y != 1),
                maxBound: width > printType.get("size.width") || height > printType.get("size.height"),
                minBound: false
            };

        },

        isPrintTypeAvailable: function (printType) {

            var ret = this._validatePrintTypeSize(printType, this.get('size.width'), this.get('size.height'), this.$.scale);

            return !ret.maxBound && !ret.minBound && !ret.printTypeScaling && !ret.dpiBound;
        }.onChange('_size.width', '_size.height', 'scale'),

        _hasHardBoundaryError: function (offset, width, height, rotation, scale) {

            var printArea = this.$.printArea;

            if (!(printArea && offset)) {
                return null;
            }

            var boundingBox = this._getBoundingBox(offset, width, height, rotation, scale, true);

            return !(boundingBox.x >= -0.1 && boundingBox.y >= -0.1 &&
                (boundingBox.x + boundingBox.width - 0.1) <= printArea.get("boundary.size.width") &&
                (boundingBox.y + boundingBox.height - 0.1) <= printArea.get("boundary.size.height"));

        },

        _getBoundingBox: function (offset, width, height, rotation, scale, onlyContent, xOffset) {

            offset = offset || this.$.offset;
            width = width || this.width();
            height = height || this.height();
            rotation = rotation || this.$.rotation;

            var x = offset.$.x,
                y = offset.$.y;

            if (!(rotation % 360)) {
                return {
                    x: x,
                    y: y,
                    height: height,
                    width: width
                };
            }

            var minX,
                maxX,
                minY,
                maxY,
                matrix = new Matrix2d().rotateDeg(rotation);

            xOffset = xOffset || 0;

            var halfW = width / 2,
                halfH = height / 2;

            var points = [
                [-halfW + xOffset, -halfH],
                [halfW + xOffset, -halfH],
                [halfW + xOffset, halfH],
                [-halfW + xOffset, halfH]
            ];

            var point = matrix.transformPoint(points[0]);
            minX = maxX = point[0];
            minY = maxY = point[1];

            for (var i = 1; i < points.length; i++) {
                point = matrix.transformPoint(points[i]);

                minX = Math.min(point[0], minX);
                maxX = Math.max(point[0], maxX);
                minY = Math.min(point[1], minY);
                maxY = Math.max(point[1], maxY);
            }

            return {
                x: minX + halfW + x - xOffset,
                y: minY + halfH + y,
                width: maxX - minX,
                height: maxY - minY
            };

        },

        size: function () {
            this.log("size() not implemented", "debug");
            return Size.empty;
        },

        height: function (scale) {

            if (!scale && scale !== 0) {
                scale = this.$.scale.y;
            }

            return Math.abs(this.size().$.height * scale);
        }.onChange("scale", "size()").on("sizeChanged"),

        width: function (scale) {

            if (!scale && scale !== 0) {
                scale = this.$.scale.x;
            }

            return Math.abs(this.size().$.width * scale);
        }.onChange("scale", "size()").on("sizeChanged"),

        isScalable: function () {
            return this.get("printType.isScalable()");
        }.onChange("printType"),

        isRotatable: function () {
            return true;
        },

        isRemovable: function () {
            return true;
        },

        price: function () {
            var printTypePrice = this.get('printType.price');
            if (printTypePrice) {
                return printTypePrice.clone();
            }
            return new Price();
        },

        /***
         *
         * @param {sprd.model.PrintType} printType
         * @return {sprd.entity.Size}
         */
        getSizeForPrintType: function (printType) {
            return Size.empty;
        },

        possiblePrintTypes: function (appearance) {
            var ret = [],
                printArea = this.$.printArea;

            if (printArea && appearance) {
                ret = ProductUtil.getPossiblePrintTypesForPrintAreas([printArea], appearance.$.id);
            }

            return ret;
        }.onChange("printArea"),

        isAllowedOnPrintArea: function (printArea) {
            return false;
        },

        getPossiblePrintTypesForPrintArea: function () {
            return [];
        },

        allowScale: function () {
            return true;
        },

        minimumScale: function () {
            return 0;
        },

        isReadyForCompose: function () {
            return true;
        }
    });
});
<commit_msg>DEV-76707 - Cannot read property 'x' of null<commit_after>define(['js/data/Entity', 'sprd/entity/Offset', 'sprd/entity/Size', 'sprd/entity/PrintArea', 'sprd/model/PrintType', 'js/core/List' , "sprd/entity/Price", "sprd/type/Matrix2d", "sprd/util/ProductUtil", "sprd/entity/PrintTypeColor", "underscore", "js/core/Bus"], function (Entity, Offset, Size, PrintArea, PrintType, List, Price, Matrix2d, ProductUtil, PrintTypeColor, _, Bus) {

    return Entity.inherit('sprd.entity.Configuration', {

        schema: {
            offset: Offset,
            printArea: {
                type: PrintArea,
                isReference: true
            },
            printType: PrintType,
            printColors: [PrintTypeColor],

            content: Object,
            restrictions: Object,
            type: String
        },

        defaults: {
            printArea: null,
            printType: null,
            offset: Offset,
            scale: {
                x: 1,
                y: 1
            },
            rotation: 0,
            printColors: List,

            // bind this
            _size: "{size()}",
            _x: "{offset.x}",
            _y: "{offset.y}",

            _isDeletable: true,

            _printTypePrice: "{printType.price}"
        },

        inject: {
            bus: Bus
        },

        save: function(callback) {
            callback && callback();
        },

        _commitChangedAttributes: function ($, options) {

            var delay = options && options.userInteraction ? 300 : 0,
                self = this,
                combinedAttributes = {};

            this.callBase();

            if (this._hasSome($, ["scale", "rotation", "printArea", "printColors", "printArea", "printType"])) {
                if ($.printType && !options.printTypeTransformed) {
                    // manually changed print type
                    this.$.printTypeWasScaled = false;
                }
                if ($.printType && !options.printTypeEqualized) {
                    this.trigger('printTypeSwitched', {printType: $.printType, scaledDown: !!options.scaledDown}, this);
                }
                if (!options.preventValidation && !options.initial) {
                    validate($);
                }
                this.trigger('configurationChanged');
            } else if ($.hasOwnProperty("offset") && $.offset && !$.offset.isDeepEqual(this.$previousAttributes["offset"])) {
                if (!options.preventValidation && !options.initial) {
                    validate($);
                }
                this.trigger('configurationChanged');
            }

            function validate(attributes) {
                _.extend(combinedAttributes, attributes);
                self._debounceFunctionCall(performValidate, "validateTransform", delay, self);
            }

            function performValidate() {
                self._setError(self._validateTransform(combinedAttributes));
                combinedAttributes = {};
            }

        },

        _validateTransform: function ($) {

            var rotationChanged = this._hasSome($, ["rotation"]),
                sizeChanged = this._hasSome($, ["_size", "_x", "_y", "scale", "offset", "bound"]),
                printTypeChanged = this._hasSome($, ["printType"]),
                width, height,
                printType = $.printType || this.$.printType,
                scale = $.scale || this.$.scale,
                rotation = $.rotation || this.$.rotation,
                ret = {},
                printArea = this.$.printArea;

            if (sizeChanged || rotationChanged) {
                width = this.width(scale.x);
                height = this.height(scale.y);

                if (printArea) {

                    if (printArea.hasSoftBoundary()) {
                        ret.hardBoundary = false;
                    } else {
                        ret.hardBoundary = this._hasHardBoundaryError($.offset || this.$.offset, width, height, rotation, scale);
                    }
                }

            }

            if (sizeChanged || printTypeChanged) {
                width = width || this.width();
                height = height || this.height();
                _.extend(ret, this._validatePrintTypeSize(printType, width, height, scale));
            }

            var printTypeTooSmall = ret.minBound,
                printTypeWasScaled = false;

            // try to scale back when one configuration of the print area was scaled
            if (this.$context && this.$context.$contextModel) {
                var printAreaConfigurations = this.$context.$contextModel.getConfigurationsOnPrintAreas([printArea]);
                for (var k = 0; k < printAreaConfigurations.length; k++) {
                    var c = printAreaConfigurations[k];
                    if (c.$.printTypeWasScaled) {
                        printTypeWasScaled = true;
                        break;
                    }
                }
            }

            // when configuration is too small for print type or it is a DD print type try to find another print type that fits better
            if (printType && (printTypeTooSmall || printTypeWasScaled) && this.$context && this.$context.$contextModel && !printTypeChanged && sizeChanged) {
                var product = this.$context.$contextModel,
                    appearanceId = this.$context.$contextModel.get('appearance.id'),
                    originalPrintType = this.$.originalPrintType;
                if (product.$.configurations.size() > 0 && !printTypeTooSmall && originalPrintType) {
                    var revertPossible = true;
                    var configurations = product.$.configurations.toArray();
                    for (var j = 0; j < configurations.length; j++) {
                        var config = configurations[j];

                        var possiblePrintTypes = config.getPossiblePrintTypesForPrintArea(printArea, appearanceId);

                        if (config !== this && config.$.printArea === printArea && (possiblePrintTypes.indexOf(originalPrintType) === -1 || !config.isPrintTypeAvailable(originalPrintType))) {
                            revertPossible = false;
                        }

                    }
                    // don't transform
                    if (!revertPossible) {
                        return ret;
                    }
                }

                var printTypes = this.getPossiblePrintTypesForPrintArea(this.$.printArea, appearanceId);
                var preferredPrintType = null,
                    val,
                    newPrintType;

                for (var i = 0; i < printTypes.length; i++) {
                    newPrintType = printTypes[i];
                    val = this._validatePrintTypeSize(newPrintType, width, height, scale);
                    if (!(val.printTypeScaling || val.maxBound || val.minBound || val.dpiBound)) {
                        // if the previous print type is valid, use it
                        if (printTypeWasScaled && this.$.originalPrintType === newPrintType) {
                            preferredPrintType = newPrintType;
                            this.$.originalPrintType = null;
                            this.$.printTypeWasScaled = false;
                            break;
                        } else if (printTypeTooSmall) {
                            preferredPrintType = newPrintType;
                            this.$.originalPrintType = printType;
                            this.$.printTypeWasScaled = true;
                            break;
                        }
                    }
                }

                if (preferredPrintType && preferredPrintType !== printType) {
                    this.$.bus && this.$.bus.trigger("Configuration.automaticallyPrintTypeChange", {
                        printType: preferredPrintType
                    });
                    this.set('printType', preferredPrintType, {preventValidation: true, printTypeTransformed: true});
                    ret.minBound = false;
                }
            }

            return ret;

        },

        _validatePrintTypeSize: function (printType, width, height, scale) {
            if (!printType) {
                return {};
            }

            var printArea = this.$.printArea;
            if (printArea && printArea.hasSoftBoundary()) {
                // if we use softboundaries the size of the configuration is maximum the
                // size of the softboudary. As long as we haven't the size of the softboundary
                // we use the size of the print area
                width = Math.min(width, printArea.width());
                height = Math.min(height, printArea.height());
            }

            return {
                printTypeScaling: !printType.isScalable() && (scale.x != 1 || scale.y != 1),
                maxBound: width > printType.get("size.width") || height > printType.get("size.height"),
                minBound: false
            };

        },

        isPrintTypeAvailable: function (printType) {

            var ret = this._validatePrintTypeSize(printType, this.get('size.width'), this.get('size.height'), this.$.scale);

            return !ret.maxBound && !ret.minBound && !ret.printTypeScaling && !ret.dpiBound;
        }.onChange('_size.width', '_size.height', 'scale'),

        _hasHardBoundaryError: function (offset, width, height, rotation, scale) {

            var printArea = this.$.printArea;

            if (!(printArea && offset)) {
                return null;
            }

            var boundingBox = this._getBoundingBox(offset, width, height, rotation, scale, true);

            return !(boundingBox.x >= -0.1 && boundingBox.y >= -0.1 &&
                (boundingBox.x + boundingBox.width - 0.1) <= printArea.get("boundary.size.width") &&
                (boundingBox.y + boundingBox.height - 0.1) <= printArea.get("boundary.size.height"));

        },

        _getBoundingBox: function (offset, width, height, rotation, scale, onlyContent, xOffset) {

            offset = offset || this.$.offset;
            width = width || this.width();
            height = height || this.height();
            rotation = rotation || this.$.rotation;

            var x = offset.$.x,
                y = offset.$.y;

            if (!(rotation % 360)) {
                return {
                    x: x,
                    y: y,
                    height: height,
                    width: width
                };
            }

            var minX,
                maxX,
                minY,
                maxY,
                matrix = new Matrix2d().rotateDeg(rotation);

            xOffset = xOffset || 0;

            var halfW = width / 2,
                halfH = height / 2;

            var points = [
                [-halfW + xOffset, -halfH],
                [halfW + xOffset, -halfH],
                [halfW + xOffset, halfH],
                [-halfW + xOffset, halfH]
            ];

            var point = matrix.transformPoint(points[0]);
            minX = maxX = point[0];
            minY = maxY = point[1];

            for (var i = 1; i < points.length; i++) {
                point = matrix.transformPoint(points[i]);

                minX = Math.min(point[0], minX);
                maxX = Math.max(point[0], maxX);
                minY = Math.min(point[1], minY);
                maxY = Math.max(point[1], maxY);
            }

            return {
                x: minX + halfW + x - xOffset,
                y: minY + halfH + y,
                width: maxX - minX,
                height: maxY - minY
            };

        },

        size: function () {
            this.log("size() not implemented", "debug");
            return Size.empty;
        },

        height: function (scale) {

            if (!scale && scale !== 0) {
                scale = this.get('scale.y') || 0;
            }

            return Math.abs(this.size().$.height * scale);
        }.onChange("scale", "size()").on("sizeChanged"),

        width: function (scale) {

            if (!scale && scale !== 0) {
                scale = this.get('scale.x') || 0;
            }

            return Math.abs(this.size().$.width * scale);
        }.onChange("scale", "size()").on("sizeChanged"),

        isScalable: function () {
            return this.get("printType.isScalable()");
        }.onChange("printType"),

        isRotatable: function () {
            return true;
        },

        isRemovable: function () {
            return true;
        },

        price: function () {
            var printTypePrice = this.get('printType.price');
            if (printTypePrice) {
                return printTypePrice.clone();
            }
            return new Price();
        },

        /***
         *
         * @param {sprd.model.PrintType} printType
         * @return {sprd.entity.Size}
         */
        getSizeForPrintType: function (printType) {
            return Size.empty;
        },

        possiblePrintTypes: function (appearance) {
            var ret = [],
                printArea = this.$.printArea;

            if (printArea && appearance) {
                ret = ProductUtil.getPossiblePrintTypesForPrintAreas([printArea], appearance.$.id);
            }

            return ret;
        }.onChange("printArea"),

        isAllowedOnPrintArea: function (printArea) {
            return false;
        },

        getPossiblePrintTypesForPrintArea: function () {
            return [];
        },

        allowScale: function () {
            return true;
        },

        minimumScale: function () {
            return 0;
        },

        isReadyForCompose: function () {
            return true;
        }
    });
});
<|endoftext|>


<commit_before>Exhibit.jQuery(document).bind("registerLocales.exhibit", function() {
    Exhibit.jQuery(document).trigger("beforeLocalesRegistered.exhibit");
    new Exhibit.Locale("default", Exhibit.urlPrefix + "locales/en/locale.js");
    new Exhibit.Locale("en", Exhibit.urlPrefix + "locales/en/locale.js");
    new Exhibit.Locale("de", Exhibit.urlPrefix + "locales/de/locale.js");
    new Exhibit.Locale("es", Exhibit.urlPrefix + "locales/es/locale.js");
    new Exhibit.Locale("fr", Exhibit.urlPrefix + "locales/fr/locale.js");
    new Exhibit.Locale("nl", Exhibit.urlPrefix + "locales/nl/locale.js");
    new Exhibit.Locale("no", Exhibit.urlPrefix + "locales/no/locale.js");
    new Exhibit.Locale("sv", Exhibit.urlPrefix + "locales/sv/locale.js");
    new Exhibit.Locale("pt-BR", Exhibit.urlPrefix + "locales/pt-BR/locale.js");
    new Exhibit.Locale("fi", Exhibit.urlPrefix + "locales/fi/locale.js");
    Exhibit.jQuery(document).trigger("localesRegistered.exhibit");
});
<commit_msg>Update manifest.js<commit_after>Exhibit.jQuery(document).bind("registerLocales.exhibit", function() {
    Exhibit.jQuery(document).trigger("beforeLocalesRegistered.exhibit");
    new Exhibit.Locale("default", Exhibit.urlPrefix + "locales/en/locale.js");
    new Exhibit.Locale("en", Exhibit.urlPrefix + "locales/en/locale.js");
    new Exhibit.Locale("el", Exhibit.urlPrefix + "locales/el/locale.js");
    new Exhibit.Locale("de", Exhibit.urlPrefix + "locales/de/locale.js");
    new Exhibit.Locale("es", Exhibit.urlPrefix + "locales/es/locale.js");
    new Exhibit.Locale("fr", Exhibit.urlPrefix + "locales/fr/locale.js");
    new Exhibit.Locale("nl", Exhibit.urlPrefix + "locales/nl/locale.js");
    new Exhibit.Locale("no", Exhibit.urlPrefix + "locales/no/locale.js");
    new Exhibit.Locale("sv", Exhibit.urlPrefix + "locales/sv/locale.js");
    new Exhibit.Locale("pt-BR", Exhibit.urlPrefix + "locales/pt-BR/locale.js");
    new Exhibit.Locale("fi", Exhibit.urlPrefix + "locales/fi/locale.js");
    Exhibit.jQuery(document).trigger("localesRegistered.exhibit");
});
<|endoftext|>


<commit_before>'use strict';

var
	_ = require('underscore'),
	ko = require('knockout'),

	Types = require('core/js/utils/Types.js'),

	App = require('core/js/App.js'),
	MainTab = App.isNewTab() && window.opener ? window.opener.MainTabMailMethods : null,
	Routing = require('core/js/Routing.js'),

	Ajax = require('modules/Mail/js/Ajax.js'),
	LinksUtils = require('modules/Mail/js/utils/Links.js'),
	Settings = require('modules/Mail/js/Settings.js'),
	CAccountModel = require('modules/Mail/js/models/CAccountModel.js'),
	CIdentityModel = require('modules/Mail/js/models/CIdentityModel.js'),
	CFetcherListModel = require('modules/Mail/js/models/CFetcherListModel.js')
;

/**
 * @constructor
 * @param {number} iDefaultAccountId
 */
function CAccountListModel(iDefaultAccountId)
{
	this.defaultId = ko.observable(iDefaultAccountId);
	this.currentId = ko.observable(iDefaultAccountId);
	this.editedId = ko.observable(iDefaultAccountId);

	this.isCurrentAllowsMail = ko.observable(true);

	this.bLockEditedWhenCurrentChange = true;

	this.currentId.subscribe(function(value) {
		var oCurrentAccount = this.getCurrent();
		if (oCurrentAccount)
		{
			oCurrentAccount.requestExtensions();

			this.checkIfMailAllowed();

			if (!this.bLockEditedWhenCurrentChange)
			{
				// deferred execution to edited account has changed a bit later and did not make a second request
				// of the folder list of the same account.
				_.delay(_.bind(function () {
					this.editedId(value);
				}, this), 1000);
			}
		}
	}, this);

	this.collection = ko.observableArray([]);
}

CAccountListModel.prototype.checkIfMailAllowed = function ()
{
	var oCurrentAccount = this.getCurrent();
	this.isCurrentAllowsMail(oCurrentAccount.allowMail());
};

/**
 * Sets a flag that indicates whether it is necessary to change editable account during changing the current account.
 * No need to change the edited account during application first running.
 */
CAccountListModel.prototype.unlockEditedWhenCurrentChange = function ()
{
	this.bLockEditedWhenCurrentChange = false;
};

/**
 * Changes current account. Sets hash to show new account data.
 *
 * @param {number} iNewCurrentId
 * @param {boolean} bPassToMail
 */
CAccountListModel.prototype.changeCurrentAccount = function (iNewCurrentId, bPassToMail)
{
	var
		oCurrentAccount = this.getCurrent(),
		oNewCurrentAccount = this.getAccount(iNewCurrentId)
	;

	if (oNewCurrentAccount && this.currentId() !== iNewCurrentId)
	{
		oCurrentAccount.isCurrent(false);
		this.currentId(iNewCurrentId);
		oNewCurrentAccount.isCurrent(true);
	}

	if (bPassToMail)
	{
		Routing.setHash(LinksUtils.getInbox());
	}
};

/**
 * Changes editable account.
 *
 * @param {number} iNewEditedId
 */
CAccountListModel.prototype.changeEditedAccount = function (iNewEditedId)
{
	var
		oEditedAccount = this.getEdited(),
		oNewEditedAccount = this.getAccount(iNewEditedId)
	;

	if (oNewEditedAccount && this.editedId() !== iNewEditedId)
	{
		oEditedAccount.isEdited(false);
		this.editedId(iNewEditedId);
		oNewEditedAccount.isEdited(true);
	}
};

/**
 * Fills the collection of accounts. Checks for default account. If it is not listed,
 * then assigns a credit default the first account from the list.
 *
 * @param {number} iDefaultId
 * @param {Array} aAccounts
 */
CAccountListModel.prototype.parse = function (iDefaultId, aAccounts)
{
	var
		oAccount = null,
		bHasDefault = false,
		oDefaultAccount = null,
		oFirstMailAccount = null
	;

	if (_.isArray(aAccounts))
	{
		this.collection(_.map(aAccounts, function (oRawAccount)
		{
			var oTempAccount = new CAccountModel();
			oTempAccount.parse(oRawAccount, iDefaultId);
			if (oTempAccount.id() === iDefaultId)
			{
				bHasDefault = true;
			}
			return oTempAccount;
		}));
	}

	if (!bHasDefault && this.collection.length > 0)
	{
		oAccount = this.collection()[0];
		iDefaultId = oAccount.id();
		bHasDefault = true;
	}

	if (bHasDefault)
	{
		this.defaultId(iDefaultId);

		oDefaultAccount = this.getDefault();

		if (!oDefaultAccount.allowMail())
		{
			oFirstMailAccount = _.find(this.collection(), function (oTempAccount) {
				return oTempAccount.allowMail();
			});
		}

		if (oFirstMailAccount)
		{
			this.currentId(oFirstMailAccount.id());
			this.editedId(iDefaultId);
		}
		else
		{
			this.currentId(iDefaultId);
			this.editedId(iDefaultId);
		}

		oDefaultAccount.isDefault(true);
	}
};

/**
 * @return {boolean}
 */
CAccountListModel.prototype.hasMailAccount = function ()
{
	var oAccount = _.find(this.collection(), function (oAcct) {
		return oAcct.allowMail();
	}, this);

	return !!oAccount;
};

/**
 * @param {number} iId
 *
 * @return {Object|undefined}
 */
CAccountListModel.prototype.getAccount = function (iId)
{
	var oAccount = _.find(this.collection(), function (oAcct) {
		return oAcct.id() === iId;
	}, this);

	/**	@type {Object|undefined} */
	return oAccount;
};

/**
 * @return {Object|undefined}
 */
CAccountListModel.prototype.getCurrent = function ()
{
	return this.getAccount(this.currentId());
};

/**
 * @return {Object|undefined}
 */
CAccountListModel.prototype.getDefault = function ()
{
	return this.getAccount(this.defaultId());
};

/**
 * @return {Object|undefined}
 */
CAccountListModel.prototype.getEdited = function ()
{
	return this.getAccount(this.editedId());
};

/**
 * @param {number=} iAccountId
 * @return {string}
 */
CAccountListModel.prototype.getEmail = function (iAccountId)
{
	iAccountId = iAccountId || this.currentId();

	var
		sEmail = '',
		oAccount = this.getAccount(iAccountId)
	;

	if (oAccount)
	{
		sEmail = oAccount.email();
	}

	return sEmail;
};

/**
 * @param {Object} oAccount
 */
CAccountListModel.prototype.addAccount = function (oAccount)
{
	var oCurrAccount = this.getCurrent();

	this.collection.push(oAccount);

	if (!oCurrAccount.allowMail())
	{
		this.changeCurrentAccount(oAccount.id(), false);
	}
};

/**
 * @param {number} iId
 */
CAccountListModel.prototype.deleteAccount = function (iId)
{
	if (this.currentId() === iId)
	{
		this.changeCurrentAccount(this.defaultId(), false);
	}

	if (this.editedId() === iId)
	{
		this.changeEditedAccount(this.defaultId());
	}

	this.collection.remove(function (oAcct){return oAcct.id() === iId;});
};

/**
 * @param {number} iId
 *
 * @return {boolean}
 */
CAccountListModel.prototype.hasAccountWithId = function (iId)
{
	var oAccount = _.find(this.collection(), function (oAcct) {
		return oAcct.id() === iId;
	}, this);

	return !!oAccount;
};

CAccountListModel.prototype.populateFetchersIdentities = function ()
{
	this.populateFetchers();
	this.populateIdentities();
};

CAccountListModel.prototype.populateFetchers = function ()
{
	if (Settings.AllowFetcher)
	{
		Ajax.send('GetFetchers', { 'AccountID': this.defaultId() }, this.onGetFetchersResponse, this);
	}
};

/**
 * @param {Object} oResponse
 * @param {Object} oRequest
 */
CAccountListModel.prototype.onGetFetchersResponse = function (oResponse, oRequest)
{
	var
		oFetcherList = null,
		oDefaultAccount = this.getDefault()
	;

	if (Types.isNonEmptyArray(oResponse.Result))
	{
		oFetcherList = new CFetcherListModel();
		oFetcherList.parse(this.defaultId(), oResponse.Result);
	}

	oDefaultAccount.fetchers(oFetcherList);
};

CAccountListModel.prototype.populateIdentities = function ()
{
	if (Settings.AllowIdentities && (this.isCurrentAllowsMail() || this.collection().length > 1))
	{
		Ajax.send('GetIdentities', null, this.onGetIdentitiesResponse, this);
	}
};

/**
 * @param {Object} oResponse
 * @param {Object} oRequest
 */
CAccountListModel.prototype.onGetIdentitiesResponse = function (oResponse, oRequest)
{
	var oIdentities = {};

	if (Types.isNonEmptyArray(oResponse.Result))
	{
		_.each(oResponse.Result, function (oIdentityData) {
			var
				oIdentity = new CIdentityModel(),
				iAccountId = -1
			;

			oIdentity.parse(oIdentityData);
			iAccountId = oIdentity.accountId();
			if (!oIdentities[iAccountId])
			{
				oIdentities[iAccountId] = [];
			}
			oIdentities[iAccountId].push(oIdentity);
		});
	}

	_.each(this.collection(), function (oAccount) {
		var
			aIdentities = oIdentities[oAccount.id()],
			oIdentity = new CIdentityModel()
		;

		if (!Types.isNonEmptyArray(aIdentities))
		{
			aIdentities = [];
		}

		oIdentity.parse({
			'@Object': 'Object/CIdentity',
			Loyal: true,
			Default: !_.find(aIdentities, function(oIdentity){ return oIdentity.isDefault(); }),
			Email: oAccount.email(),
			Enabled: true,
			FriendlyName: oAccount.friendlyName(),
			IdAccount: oAccount.id(),
			IdIdentity: oAccount.id() * 100000,
			Signature: oAccount.signature(),
			UseSignature: oAccount.useSignature()
		});
		aIdentities.unshift(oIdentity);

		oAccount.identities(aIdentities);
	});
};

/**
 * @param {Object} oSrcAccounts
 */
CAccountListModel.prototype.populateIdentitiesFromSourceAccount = function (oSrcAccounts)
{
	if (oSrcAccounts)
	{
		_.each(this.collection(), function (oAccount) {
			var oSrcAccount = oSrcAccounts.getAccount(oAccount.id());
			if (oSrcAccount)
			{
				oAccount.fetchers(oSrcAccount.fetchers());
				oAccount.identities(oSrcAccount.identities());
				oAccount.signature(oSrcAccount.signature());
				oAccount.useSignature(oSrcAccount.useSignature());
			}
		});
	}
};

CAccountListModel.prototype.getAccountsEmails = function ()
{
	return _.uniq(_.map(this.collection(), function (oAccount) {
		return oAccount.email();
	}));
};

CAccountListModel.prototype.getAllFullEmails = function ()
{
	var aFullEmails = [];

	_.each(this.collection(), function (oAccount) {
		if (oAccount)
		{
			aFullEmails.push(oAccount.fullEmail());
			if (oAccount.fetchers() && Types.isNonEmptyArray(oAccount.fetchers().collection()))
			{
				_.each(oAccount.fetchers().collection(), function (oFetcher) {
					if (oFetcher.isOutgoingEnabled() && oFetcher.fullEmail() !== '')
					{
						aFullEmails.push(oFetcher.fullEmail());
					}
				});
			}
			if (Types.isNonEmptyArray(oAccount.identities()))
			{
				_.each(oAccount.identities(), function (oIdentity) {
					aFullEmails.push(oIdentity.fullEmail());
				});
			}
		}
	});

	return aFullEmails;
};

CAccountListModel.prototype.getCurrentFetchersAndFiltersFolderNames = function ()
{
	var
		oAccount = this.getCurrent(),
		aFolders = []
	;

	if (oAccount)
	{
		if (oAccount.filters())
		{
			_.each(oAccount.filters().collection(), function (oFilter) {
				aFolders.push(oFilter.folder());
			}, this);
		}

		if (oAccount.fetchers())
		{
			_.each(oAccount.fetchers().collection(), function (oFetcher) {
				aFolders.push(oFetcher.folder());
			}, this);
		}
	}

	return aFolders;
};

/**
 * @param {Array} aEmails
 * @returns {string}
 */
CAccountListModel.prototype.getAttendee = function (aEmails)
{
	var
		aAccountsEmails = [],
		sAttendee = ''
	;

	_.each(this.collection(), function (oAccount) {
		if (oAccount.isCurrent())
		{
			aAccountsEmails = _.union([oAccount.email()], oAccount.getFetchersIdentitiesEmails(), aAccountsEmails);
		}
		else
		{
			aAccountsEmails = _.union(aAccountsEmails, [oAccount.email()], oAccount.getFetchersIdentitiesEmails());
		}
	});

	aAccountsEmails = _.uniq(aAccountsEmails);

	_.each(aAccountsEmails, _.bind(function (sAccountEmail) {
		if (sAttendee === '')
		{
			var sFoundEmail = _.find(aEmails, function (sEmail) {
				return (sEmail === sAccountEmail);
			});
			if (sFoundEmail === sAccountEmail)
			{
				sAttendee = sAccountEmail;
			}
		}
	}, this));

	return sAttendee;
};

var AccountList = new CAccountListModel(Types.pInt(window.pSevenAppData.Default));

AccountList.parse(window.pSevenAppData.Default, window.pSevenAppData.Accounts);

if (MainTab)
{
	AccountList.populateIdentitiesFromSourceAccount(MainTab.getAccountList());
}

module.exports = AccountList;
<commit_msg>JS - Mail - unlockEditedWhenCurrentChange<commit_after>'use strict';

var
	_ = require('underscore'),
	ko = require('knockout'),

	Types = require('core/js/utils/Types.js'),

	App = require('core/js/App.js'),
	MainTab = App.isNewTab() && window.opener ? window.opener.MainTabMailMethods : null,
	Routing = require('core/js/Routing.js'),

	Ajax = require('modules/Mail/js/Ajax.js'),
	LinksUtils = require('modules/Mail/js/utils/Links.js'),
	Settings = require('modules/Mail/js/Settings.js'),
	CAccountModel = require('modules/Mail/js/models/CAccountModel.js'),
	CIdentityModel = require('modules/Mail/js/models/CIdentityModel.js'),
	CFetcherListModel = require('modules/Mail/js/models/CFetcherListModel.js')
;

/**
 * @constructor
 * @param {number} iDefaultAccountId
 */
function CAccountListModel(iDefaultAccountId)
{
	this.defaultId = ko.observable(iDefaultAccountId);
	this.currentId = ko.observable(iDefaultAccountId);
	this.editedId = ko.observable(iDefaultAccountId);

	this.isCurrentAllowsMail = ko.observable(true);

	this.bLockEditedWhenCurrentChange = true;

	this.currentId.subscribe(function(value) {
		var oCurrentAccount = this.getCurrent();
		if (oCurrentAccount)
		{
			oCurrentAccount.requestExtensions();

			this.checkIfMailAllowed();

			if (!this.bLockEditedWhenCurrentChange)
			{
				// deferred execution to edited account has changed a bit later and did not make a second request
				// of the folder list of the same account.
				_.delay(_.bind(function () {
					this.editedId(value);
				}, this), 1000);
			}
		}
	}, this);

	this.collection = ko.observableArray([]);
}

CAccountListModel.prototype.checkIfMailAllowed = function ()
{
	var oCurrentAccount = this.getCurrent();
	this.isCurrentAllowsMail(oCurrentAccount.allowMail());
};

/**
 * Sets a flag that indicates whether it is necessary to change editable account during changing the current account.
 * No need to change the edited account during application first running.
 */
CAccountListModel.prototype.unlockEditedWhenCurrentChange = function ()
{
	this.bLockEditedWhenCurrentChange = false;
};

/**
 * Changes current account. Sets hash to show new account data.
 *
 * @param {number} iNewCurrentId
 * @param {boolean} bPassToMail
 */
CAccountListModel.prototype.changeCurrentAccount = function (iNewCurrentId, bPassToMail)
{
	var
		oCurrentAccount = this.getCurrent(),
		oNewCurrentAccount = this.getAccount(iNewCurrentId)
	;

	if (oNewCurrentAccount && this.currentId() !== iNewCurrentId)
	{
		oCurrentAccount.isCurrent(false);
		this.currentId(iNewCurrentId);
		oNewCurrentAccount.isCurrent(true);
	}

	if (bPassToMail)
	{
		Routing.setHash(LinksUtils.getInbox());
	}
};

/**
 * Changes editable account.
 *
 * @param {number} iNewEditedId
 */
CAccountListModel.prototype.changeEditedAccount = function (iNewEditedId)
{
	var
		oEditedAccount = this.getEdited(),
		oNewEditedAccount = this.getAccount(iNewEditedId)
	;

	if (oNewEditedAccount && this.editedId() !== iNewEditedId)
	{
		oEditedAccount.isEdited(false);
		this.editedId(iNewEditedId);
		oNewEditedAccount.isEdited(true);
	}
};

/**
 * Fills the collection of accounts. Checks for default account. If it is not listed,
 * then assigns a credit default the first account from the list.
 *
 * @param {number} iDefaultId
 * @param {Array} aAccounts
 */
CAccountListModel.prototype.parse = function (iDefaultId, aAccounts)
{
	var
		oAccount = null,
		bHasDefault = false,
		oDefaultAccount = null,
		oFirstMailAccount = null
	;

	if (_.isArray(aAccounts))
	{
		this.collection(_.map(aAccounts, function (oRawAccount)
		{
			var oTempAccount = new CAccountModel();
			oTempAccount.parse(oRawAccount, iDefaultId);
			if (oTempAccount.id() === iDefaultId)
			{
				bHasDefault = true;
			}
			return oTempAccount;
		}));
	}

	if (!bHasDefault && this.collection.length > 0)
	{
		oAccount = this.collection()[0];
		iDefaultId = oAccount.id();
		bHasDefault = true;
	}

	if (bHasDefault)
	{
		this.defaultId(iDefaultId);

		oDefaultAccount = this.getDefault();

		if (!oDefaultAccount.allowMail())
		{
			oFirstMailAccount = _.find(this.collection(), function (oTempAccount) {
				return oTempAccount.allowMail();
			});
		}

		if (oFirstMailAccount)
		{
			this.currentId(oFirstMailAccount.id());
			this.editedId(iDefaultId);
		}
		else
		{
			this.currentId(iDefaultId);
			this.editedId(iDefaultId);
		}

		oDefaultAccount.isDefault(true);
	}
};

/**
 * @return {boolean}
 */
CAccountListModel.prototype.hasMailAccount = function ()
{
	var oAccount = _.find(this.collection(), function (oAcct) {
		return oAcct.allowMail();
	}, this);

	return !!oAccount;
};

/**
 * @param {number} iId
 *
 * @return {Object|undefined}
 */
CAccountListModel.prototype.getAccount = function (iId)
{
	var oAccount = _.find(this.collection(), function (oAcct) {
		return oAcct.id() === iId;
	}, this);

	/**	@type {Object|undefined} */
	return oAccount;
};

/**
 * @return {Object|undefined}
 */
CAccountListModel.prototype.getCurrent = function ()
{
	return this.getAccount(this.currentId());
};

/**
 * @return {Object|undefined}
 */
CAccountListModel.prototype.getDefault = function ()
{
	return this.getAccount(this.defaultId());
};

/**
 * @return {Object|undefined}
 */
CAccountListModel.prototype.getEdited = function ()
{
	return this.getAccount(this.editedId());
};

/**
 * @param {number=} iAccountId
 * @return {string}
 */
CAccountListModel.prototype.getEmail = function (iAccountId)
{
	iAccountId = iAccountId || this.currentId();

	var
		sEmail = '',
		oAccount = this.getAccount(iAccountId)
	;

	if (oAccount)
	{
		sEmail = oAccount.email();
	}

	return sEmail;
};

/**
 * @param {Object} oAccount
 */
CAccountListModel.prototype.addAccount = function (oAccount)
{
	var oCurrAccount = this.getCurrent();

	this.collection.push(oAccount);

	if (!oCurrAccount.allowMail())
	{
		this.changeCurrentAccount(oAccount.id(), false);
	}
};

/**
 * @param {number} iId
 */
CAccountListModel.prototype.deleteAccount = function (iId)
{
	if (this.currentId() === iId)
	{
		this.changeCurrentAccount(this.defaultId(), false);
	}

	if (this.editedId() === iId)
	{
		this.changeEditedAccount(this.defaultId());
	}

	this.collection.remove(function (oAcct){return oAcct.id() === iId;});
};

/**
 * @param {number} iId
 *
 * @return {boolean}
 */
CAccountListModel.prototype.hasAccountWithId = function (iId)
{
	var oAccount = _.find(this.collection(), function (oAcct) {
		return oAcct.id() === iId;
	}, this);

	return !!oAccount;
};

CAccountListModel.prototype.populateFetchersIdentities = function ()
{
	this.populateFetchers();
	this.populateIdentities();
};

CAccountListModel.prototype.populateFetchers = function ()
{
	if (Settings.AllowFetcher)
	{
		Ajax.send('GetFetchers', { 'AccountID': this.defaultId() }, this.onGetFetchersResponse, this);
	}
};

/**
 * @param {Object} oResponse
 * @param {Object} oRequest
 */
CAccountListModel.prototype.onGetFetchersResponse = function (oResponse, oRequest)
{
	var
		oFetcherList = null,
		oDefaultAccount = this.getDefault()
	;

	if (Types.isNonEmptyArray(oResponse.Result))
	{
		oFetcherList = new CFetcherListModel();
		oFetcherList.parse(this.defaultId(), oResponse.Result);
	}

	oDefaultAccount.fetchers(oFetcherList);
};

CAccountListModel.prototype.populateIdentities = function ()
{
	if (Settings.AllowIdentities && (this.isCurrentAllowsMail() || this.collection().length > 1))
	{
		Ajax.send('GetIdentities', null, this.onGetIdentitiesResponse, this);
	}
};

/**
 * @param {Object} oResponse
 * @param {Object} oRequest
 */
CAccountListModel.prototype.onGetIdentitiesResponse = function (oResponse, oRequest)
{
	var oIdentities = {};

	if (Types.isNonEmptyArray(oResponse.Result))
	{
		_.each(oResponse.Result, function (oIdentityData) {
			var
				oIdentity = new CIdentityModel(),
				iAccountId = -1
			;

			oIdentity.parse(oIdentityData);
			iAccountId = oIdentity.accountId();
			if (!oIdentities[iAccountId])
			{
				oIdentities[iAccountId] = [];
			}
			oIdentities[iAccountId].push(oIdentity);
		});
	}

	_.each(this.collection(), function (oAccount) {
		var
			aIdentities = oIdentities[oAccount.id()],
			oIdentity = new CIdentityModel()
		;

		if (!Types.isNonEmptyArray(aIdentities))
		{
			aIdentities = [];
		}

		oIdentity.parse({
			'@Object': 'Object/CIdentity',
			Loyal: true,
			Default: !_.find(aIdentities, function(oIdentity){ return oIdentity.isDefault(); }),
			Email: oAccount.email(),
			Enabled: true,
			FriendlyName: oAccount.friendlyName(),
			IdAccount: oAccount.id(),
			IdIdentity: oAccount.id() * 100000,
			Signature: oAccount.signature(),
			UseSignature: oAccount.useSignature()
		});
		aIdentities.unshift(oIdentity);

		oAccount.identities(aIdentities);
	});
};

/**
 * @param {Object} oSrcAccounts
 */
CAccountListModel.prototype.populateIdentitiesFromSourceAccount = function (oSrcAccounts)
{
	if (oSrcAccounts)
	{
		_.each(this.collection(), function (oAccount) {
			var oSrcAccount = oSrcAccounts.getAccount(oAccount.id());
			if (oSrcAccount)
			{
				oAccount.fetchers(oSrcAccount.fetchers());
				oAccount.identities(oSrcAccount.identities());
				oAccount.signature(oSrcAccount.signature());
				oAccount.useSignature(oSrcAccount.useSignature());
			}
		});
	}
};

CAccountListModel.prototype.getAccountsEmails = function ()
{
	return _.uniq(_.map(this.collection(), function (oAccount) {
		return oAccount.email();
	}));
};

CAccountListModel.prototype.getAllFullEmails = function ()
{
	var aFullEmails = [];

	_.each(this.collection(), function (oAccount) {
		if (oAccount)
		{
			aFullEmails.push(oAccount.fullEmail());
			if (oAccount.fetchers() && Types.isNonEmptyArray(oAccount.fetchers().collection()))
			{
				_.each(oAccount.fetchers().collection(), function (oFetcher) {
					if (oFetcher.isOutgoingEnabled() && oFetcher.fullEmail() !== '')
					{
						aFullEmails.push(oFetcher.fullEmail());
					}
				});
			}
			if (Types.isNonEmptyArray(oAccount.identities()))
			{
				_.each(oAccount.identities(), function (oIdentity) {
					aFullEmails.push(oIdentity.fullEmail());
				});
			}
		}
	});

	return aFullEmails;
};

CAccountListModel.prototype.getCurrentFetchersAndFiltersFolderNames = function ()
{
	var
		oAccount = this.getCurrent(),
		aFolders = []
	;

	if (oAccount)
	{
		if (oAccount.filters())
		{
			_.each(oAccount.filters().collection(), function (oFilter) {
				aFolders.push(oFilter.folder());
			}, this);
		}

		if (oAccount.fetchers())
		{
			_.each(oAccount.fetchers().collection(), function (oFetcher) {
				aFolders.push(oFetcher.folder());
			}, this);
		}
	}

	return aFolders;
};

/**
 * @param {Array} aEmails
 * @returns {string}
 */
CAccountListModel.prototype.getAttendee = function (aEmails)
{
	var
		aAccountsEmails = [],
		sAttendee = ''
	;

	_.each(this.collection(), function (oAccount) {
		if (oAccount.isCurrent())
		{
			aAccountsEmails = _.union([oAccount.email()], oAccount.getFetchersIdentitiesEmails(), aAccountsEmails);
		}
		else
		{
			aAccountsEmails = _.union(aAccountsEmails, [oAccount.email()], oAccount.getFetchersIdentitiesEmails());
		}
	});

	aAccountsEmails = _.uniq(aAccountsEmails);

	_.each(aAccountsEmails, _.bind(function (sAccountEmail) {
		if (sAttendee === '')
		{
			var sFoundEmail = _.find(aEmails, function (sEmail) {
				return (sEmail === sAccountEmail);
			});
			if (sFoundEmail === sAccountEmail)
			{
				sAttendee = sAccountEmail;
			}
		}
	}, this));

	return sAttendee;
};

var AccountList = new CAccountListModel(Types.pInt(window.pSevenAppData.Default));

AccountList.parse(window.pSevenAppData.Default, window.pSevenAppData.Accounts);

if (MainTab)
{
	AccountList.populateIdentitiesFromSourceAccount(MainTab.getAccountList());
}

AccountList.unlockEditedWhenCurrentChange();

module.exports = AccountList;
<|endoftext|>


<commit_before>var path                       = require('path')
  ,  fs                        = require('fs-extra')
  ,  exec                      = require('child_process').exec
  ,  chalk                     = require('chalk')
  ,  rp                        = require('request-promise-native')
  ,  print                     = console.log
  ,  AdmZip                    = require('adm-zip')
  ,  UPDATING_SERVICE_MSG      = chalk.white(`Updating Service...\n`)
  ,  SERVICE_UPDATED_MSG       = chalk.green(`✅ Service Updated.`)
  ,  SERVICE_UPDATE_FAILED_MSG = chalk.white(`Service failed to update. Please contact support@clay.run`)
  ,  clui                      = require('clui')
  ,  Spinner                   = clui.Spinner;

module.exports = function(deployConfig) {
  return new Promise((resolve, reject) =>  {

    const dir                     = deployConfig.dir
    const currentProjectConfig    = require(path.resolve(dir,  'clay-config.json'));
    const USER_NOT_AUTHORIZED_ERR = chalk.white(`The current user is not authorized to create or update this service. You are signed as: `)+chalk.red(`${this.credentials.username}\n`)
    const SERVICE_URL_MSG         = chalk.white(`🚀 Your service is available here: `)+chalk.green.underline(`${this.apis.servicePage}/${this.credentials.username}/${currentProjectConfig.serviceName}`)

    var execOptions = {
      maxBuffer: 1024 * 50000,
      cwd: dir
    };

    var status = new Spinner('Verifying config file');
    status.start();

    status.message('Building your service..');
    var zip = new AdmZip();

    zip.addLocalFolder(deployConfig.dir)

    var zipPromise = new Promise((resolve, reject) => {
      zip.toBuffer((buffer, err) => {
        if(err) reject(err)
        resolve(buffer)
      })

    })

    this.lintConfig(deployConfig.dir, true)
    .then(() => {
      return zipPromise
    })
    .then((zipBuffer) => {
      status.message('Deploying ' + currentProjectConfig.serviceDisplayName + ' on Clay Cloud..');
      var requestOptions = {
        uri: this.apis.methodsApi,
        method: deployConfig.mode ,
        body: {
          commandDescription: currentProjectConfig.serviceDescription,
          methodDisplayName: currentProjectConfig.serviceDisplayName,
          commandName: currentProjectConfig.serviceName,
          function_input: JSON.stringify(currentProjectConfig.inputs),
          apiToken: this.credentials.token,
          serviceType: currentProjectConfig.serviceType,
          fileData: zipBuffer.toString('base64')
        },
        timeout: 0,
        json: true
      }
      return rp(requestOptions)
    })
    .then((response) => {
      status.stop();
      if(response.result == true && deployConfig.mode  == 'PUT') {
        var time = new Date();
        if(!deployConfig.suppressProgressMessages) {
          print(SERVICE_UPDATED_MSG, time.toLocaleDateString(), time.toLocaleTimeString())
        }
        print(SERVICE_URL_MSG)
      }
      resolve(response);
    })
    .catch((err) => {
      console.log(err);
      status.stop();
      if(process.env.CLAY_DEV) console.log(err);
      if(err.statusCode == 401) print(USER_NOT_AUTHORIZED_ERR)
      else if(deployConfig.mode == 'PUT') print(SERVICE_UPDATE_FAILED_MSG)
    })
  })
}

<commit_msg>removing old deploy service file<commit_after><|endoftext|>


<commit_before>// DialogTriggerJS
// Copyright (c) 2016 Shahzad Malik
// MIT License
//
// Triggers a callback to pop up a dialog (or do anything else) with the specified trigger options.
//
// "trigger" can be one of the following:
//    'exit_intent': Call 'callback' when a user intends to exit (such as moving cursor off page or coming back to the top)
//    'target': Call 'callback' when a user reaches a particular target element (set 'target' to the name of the element, such as '#mytarget')
//    'scrollDown': Call 'callback' when a user scrolls down by a certain percent from when the object is instantiated (set 'percentDown' to the percentage 0-100)
//    'scrollUp': Call 'callback' when a user scrolls up by a certain percent from when the object is instantiated (set 'percentUp' to the percentage 0-100)
//    'timeout': Call 'callback' after a certain number of milliseconds have elapsed (set 'timeout' to the desired milliseconds)
//
// Examples:
// Setting up individual triggers:
//    var dt = new DialogTrigger(triggerNagPopup, { trigger: 'timeout', timeout: 5000 });
//    var dt = new DialogTrigger(triggerNagPopup, { trigger: 'target', target: '#all' });
//    var dt = new DialogTrigger(triggerNagPopup, { trigger: 'scrollDown', percentDown: 50 });
//    var dt = new DialogTrigger(triggerNagPopup, { trigger: 'exit_intent' });
//
// Triggers can also be chained for a sequence of behaviors (such as scroll down by 50%, then exit):
//    var dtPercent = new DialogTrigger(function() {
//       var dtExit = new DialogTrigger(triggerNagPopup, { trigger: 'exit_intent' });
//    }, { trigger: 'scrollDown', percentDown: 50 });
function DialogTrigger(callback, options) {
	// Becomes this.options
	var defaults = {
		trigger	: 'timeout',
		target	: '',
		timeout	: 0,
		percentDown : 50, // Used for 'percent' to define a down scroll threshold of significance (based on page height)
		percentUp : 10, // Used for 'percent' to define a threshold of upward scroll after down threshold is reached
		scrollInterval: 1000 // Frequency (in ms) to check for scroll changes (to avoid bogging the UI)
	}

	this.complete = false; // Let's us know if the popup has been triggered

	this.callback = callback;
	this.timer = null;
	this.interval = null;

	this.options = jQuery.extend(defaults, options);

	this.init = function() {
		if(this.options.trigger == 'exit_intent') {
			var parentThis = this;

			$(document).on('mouseleave', function(e) {
				//console.log(e.clientX + ',' + e.clientY); // IE returns negative values on all sides

				if(!parentThis.complete && e.clientY < 0) { // Check if the cursor went above the top of the browser window
					parentThis.callback();
					parentThis.complete = true;
					$(document).off('mouseleave');
				}
			});

		} else if(this.options.trigger == 'target') {
			if(this.options.target !== '') {
				// Make sure the target exists
				if($(this.options.target).length == 0) {
					this.complete = true;
				} else {
					var targetScroll = $(this.options.target).offset().top;

					var parentThis = this;

					// Only check the scroll position every few seconds, to avoid bogging the UI
					this.interval = setInterval(function() {
						if($(window).scrollTop() >= targetScroll) {
							clearInterval(parentThis.interval);
							parentThis.interval = null;

							if(!parentThis.complete) {
								parentThis.callback();
								parentThis.complete = true;
							}
						}
					}, this.options.scrollInterval);
				}
			}

		} else if(this.options.trigger == 'scrollDown') {
			// Let the user scroll down by some significant amount
			var scrollStart = $(window).scrollTop();
			var pageHeight = $(document).height();

			var parentThis = this;

			if(pageHeight > 0) {
				// Only check the scroll position every few seconds, to avoid bogging the UI
				this.interval = setInterval(function() {
					var scrollAmount = $(window).scrollTop() - scrollStart;
					if(scrollAmount < 0) {
						scrollAmount = 0;
						scrollStart = $(window).scrollTop();
					}
					var downScrollPercent = parseFloat(scrollAmount) / parseFloat(pageHeight);

					if(downScrollPercent > parseFloat(parentThis.options.percentDown) / 100) {
						clearInterval(parentThis.interval);
						parentThis.interval = null;

						if(!parentThis.complete) {
							parentThis.callback();
							parentThis.complete = true;
						}
					}

				}, this.options.scrollInterval);
			}

		} else if(this.options.trigger == 'scrollUp') {
			// Let the user scroll down by some significant amount
			var scrollStart = $(window).scrollTop();
			var pageHeight = $(document).height();

			var parentThis = this;

			if(pageHeight > 0) {
				// Only check the scroll position every few seconds, to avoid bogging the UI
				this.interval = setInterval(function() {
					var scrollAmount = scrollStart - $(window).scrollTop();
					if(scrollAmount < 0) {
						scrollAmount = 0;
						scrollStart = $(window).scrollTop();
					}
					var upScrollPercent = parseFloat(scrollAmount) / parseFloat(pageHeight);

					if(upScrollPercent > parseFloat(parentThis.options.percentUp) / 100) {
						clearInterval(parentThis.interval);
						parentThis.interval = null;

						if(!parentThis.complete) {
							parentThis.callback();
							parentThis.complete = true;
						}
					}

				}, this.options.scrollInterval);
			}

		} else if(this.options.trigger == 'timeout') {
			this.timer = setTimeout(this.callback, this.options.timeout);
		}

    };

	this.cancel = function() {
		if(this.timer !== null) {
			clearTimeout(this.timer);
			this.timer = null;
		}

		if(this.interval !== null) {
			clearInterval(this.interval);
			this.interval = null;
		}

		this.complete = true;
	}

    this.init();
}
<commit_msg>renamed exit_intent to exitIntent (with backward compatibility); using jQuery instead of $ to help with noConflict mode<commit_after>// DialogTriggerJS
// Copyright (c) 2016-2017 Shahzad Malik
// MIT License
//
// Triggers a callback to pop up a dialog (or do anything else) with the specified trigger options.
//
// "trigger" can be one of the following:
//    'exitIntent': Call 'callback' when a user intends to exit (such as moving cursor off page or coming back to the top)
//    'target': Call 'callback' when a user reaches a particular target element (set 'target' to the name of the element, such as '#mytarget')
//    'scrollDown': Call 'callback' when a user scrolls down by a certain percent from when the object is instantiated (set 'percentDown' to the percentage 0-100)
//    'scrollUp': Call 'callback' when a user scrolls up by a certain percent from when the object is instantiated (set 'percentUp' to the percentage 0-100)
//    'timeout': Call 'callback' after a certain number of milliseconds have elapsed (set 'timeout' to the desired milliseconds)
//
// Examples:
// Setting up individual triggers:
//    var dt = new DialogTrigger(triggerNagPopup, { trigger: 'timeout', timeout: 5000 });
//    var dt = new DialogTrigger(triggerNagPopup, { trigger: 'target', target: '#all' });
//    var dt = new DialogTrigger(triggerNagPopup, { trigger: 'scrollDown', percentDown: 50 });
//    var dt = new DialogTrigger(triggerNagPopup, { trigger: 'exitIntent' });
//
// Triggers can also be chained for a sequence of behaviors (such as scroll down by 50%, then exit):
//    var dtPercent = new DialogTrigger(function() {
//       var dtExit = new DialogTrigger(triggerNagPopup, { trigger: 'exitIntent' });
//    }, { trigger: 'scrollDown', percentDown: 50 });
function DialogTrigger(callback, options) {
	// Becomes this.options
	var defaults = {
		trigger	: 'timeout',
		target	: '',
		timeout	: 0,
		percentDown : 50, // Used for 'percent' to define a down scroll threshold of significance (based on page height)
		percentUp : 10, // Used for 'percent' to define a threshold of upward scroll after down threshold is reached
		scrollInterval: 1000 // Frequency (in ms) to check for scroll changes (to avoid bogging the UI)
	}

	this.complete = false; // Let's us know if the popup has been triggered

	this.callback = callback;
	this.timer = null;
	this.interval = null;

	this.options = jQuery.extend(defaults, options);

	this.init = function() {
		if(this.options.trigger == 'exitIntent' || this.options.trigger == 'exit_intent') {
			var parentThis = this;

			jQuery(document).on('mouseleave', function(e) {
				//console.log(e.clientX + ',' + e.clientY); // IE returns negative values on all sides

				if(!parentThis.complete && e.clientY < 0) { // Check if the cursor went above the top of the browser window
					parentThis.callback();
					parentThis.complete = true;
					jQuery(document).off('mouseleave');
				}
			});

		} else if(this.options.trigger == 'target') {
			if(this.options.target !== '') {
				// Make sure the target exists
				if(jQuery(this.options.target).length == 0) {
					this.complete = true;
				} else {
					var targetScroll = jQuery(this.options.target).offset().top;

					var parentThis = this;

					// Only check the scroll position every few seconds, to avoid bogging the UI
					this.interval = setInterval(function() {
						if(jQuery(window).scrollTop() >= targetScroll) {
							clearInterval(parentThis.interval);
							parentThis.interval = null;

							if(!parentThis.complete) {
								parentThis.callback();
								parentThis.complete = true;
							}
						}
					}, this.options.scrollInterval);
				}
			}

		} else if(this.options.trigger == 'scrollDown') {
			// Let the user scroll down by some significant amount
			var scrollStart = jQuery(window).scrollTop();
			var pageHeight = jQuery(document).height();

			var parentThis = this;

			if(pageHeight > 0) {
				// Only check the scroll position every few seconds, to avoid bogging the UI
				this.interval = setInterval(function() {
					var scrollAmount = jQuery(window).scrollTop() - scrollStart;
					if(scrollAmount < 0) {
						scrollAmount = 0;
						scrollStart = jQuery(window).scrollTop();
					}
					var downScrollPercent = parseFloat(scrollAmount) / parseFloat(pageHeight);

					if(downScrollPercent > parseFloat(parentThis.options.percentDown) / 100) {
						clearInterval(parentThis.interval);
						parentThis.interval = null;

						if(!parentThis.complete) {
							parentThis.callback();
							parentThis.complete = true;
						}
					}

				}, this.options.scrollInterval);
			}

		} else if(this.options.trigger == 'scrollUp') {
			// Let the user scroll down by some significant amount
			var scrollStart = jQuery(window).scrollTop();
			var pageHeight = jQuery(document).height();

			var parentThis = this;

			if(pageHeight > 0) {
				// Only check the scroll position every few seconds, to avoid bogging the UI
				this.interval = setInterval(function() {
					var scrollAmount = scrollStart - jQuery(window).scrollTop();
					if(scrollAmount < 0) {
						scrollAmount = 0;
						scrollStart = jQuery(window).scrollTop();
					}
					var upScrollPercent = parseFloat(scrollAmount) / parseFloat(pageHeight);

					if(upScrollPercent > parseFloat(parentThis.options.percentUp) / 100) {
						clearInterval(parentThis.interval);
						parentThis.interval = null;

						if(!parentThis.complete) {
							parentThis.callback();
							parentThis.complete = true;
						}
					}

				}, this.options.scrollInterval);
			}

		} else if(this.options.trigger == 'timeout') {
			this.timer = setTimeout(this.callback, this.options.timeout);
		}

    };

	this.cancel = function() {
		if(this.timer !== null) {
			clearTimeout(this.timer);
			this.timer = null;
		}

		if(this.interval !== null) {
			clearInterval(this.interval);
			this.interval = null;
		}

		this.complete = true;
	}

    this.init();
}
<|endoftext|>


<commit_before>Game.name = 'Sandbox';

Game.tools = [
	{
		title: 'place',
		func: function( pl ) {
			var rs = world.fireRay( pl.getEyeCast() );
			world.createBlock( meta.blocks.availableTypes[this.currentBlock], rs.worldHit.x + (rs.normal.x /2),  rs.worldHit.y + (rs.normal.y /2),  rs.worldHit.z + (rs.normal.z /2) );
		}
	},
	{
		title: 'remove',
		func: function( pl ) {
			var rs = world.fireRay( pl.getEyeCast() );
			world.removeBlock( rs.worldHit.x - (rs.normal.x /2),  rs.worldHit.y - (rs.normal.y /2),  rs.worldHit.z - (rs.normal.z /2) );
		}
	},
	{
		title: 'explode',
		func: function( pl ) {
			var ex = new Explosion();
			var rs = world.fireRay( pl.getEyeCast() );
			ex.origin = rs.worldHit;
			ex.power = 10;
			ex.radius = 5;
			ex.explode();
		}
	}
	];
Game.toolIndex = 0;

Game.onLoad = function()
{
	var ray = new Ray();
	ray.origin = { x: 10, y: 200, z : 10 };
	ray.direction = { x: 0, y: -1, z: 0 };
	var result = world.fireRay( ray );
	if( result.block )
	{
		console.log( 'type: ' + result.block.type );
	}
	this.currentBlock = 0;
}

Game.onSpawn = function( p )
{
	this.player = p;
	this.player.setPosition( { x: 10, y: 130, z: 10 } );
	this.player.moveDir = { x: 0, y: 0, z: 0 };
}

Game.changeBlock = function( v )
{
	this.currentBlock += v;
	if( this.currentBlock < 0 )
		this.currentBlock = meta.blocks.availableTypes.length - 1;
	else if( this.currentBlock > meta.blocks.availableTypes.length - 1 )
	{
		this.currentBlock = 0;
	}
	console.log( meta.blocks.availableTypes[this.currentBlock] );
}

Game.keyDown = function(k)
{
	switch( k )
	{
		case 68:
			this.changeBlock(-1);
			break;
		case 67:
			this.changeBlock( 1);
			break;
		case 22:
			// W
			this.player.moveDir.z = -10;
			break;
		case 0:
			// A
			this.player.moveDir.x = 10;
			break;
		case 18:
			// S
			this.player.moveDir.z = 10;
			break;
		case 3:
			// D
			this.player.moveDir.x = -10;
			break;
		case 16:
			this.player.moveDir.y = 10;
			break;
		case 4:
			this.player.moveDir.y = -10;
			break;
	}
}

Game.keyUp = function(k)
{
	switch( k )
	{
		case 22:
			// W
			this.player.moveDir.z = 0;
			break;
		case 0:
			// A
			this.player.moveDir.x = -0;
			break;
		case 18:
			// S
			this.player.moveDir.z = -0;
			break;
		case 3:
			// D
			this.player.moveDir.x = 0;
			break;
		case 16:
		case 4:
			this.player.moveDir.y = 0;
			break;
	}
}

Game.onPrimary = function( player )
{
	this.tools[ this.toolIndex % this.tools.length ].func.call( this, player );
}

Game.onAlt = function( player )
{
	this.toolIndex++;
}

Game.think = function( dt )
{
	if( this.player.moveDir.x != 0 || this.player.moveDir.y != 0 || this.player.moveDir.z != 0 )
	{
		this.player.move( this.player.moveDir.z * dt,  this.player.moveDir.y * dt, this.player.moveDir.x * dt );
	}
}

Game.draw = function()
{
	console.drawText( 10, 10, this.tools[ this.toolIndex % this.tools.length ].title );
}<commit_msg>Added smooth camera<commit_after>Game.name = 'Sandbox';

Number.prototype.sign = function() {
  if(this > 0) {
    return 1;
  } else if (this < 0) {
    return -1;
  } else {
    return 0;
  }
}

Game.tools = [
	{
		title: 'place',
		func: function( pl ) {
			var rs = world.fireRay( pl.getEyeCast() );
			world.createBlock( meta.blocks.availableTypes[this.currentBlock], rs.worldHit.x + (rs.normal.x /2),  rs.worldHit.y + (rs.normal.y /2),  rs.worldHit.z + (rs.normal.z /2) );
		}
	},
	{
		title: 'remove',
		func: function( pl ) {
			var rs = world.fireRay( pl.getEyeCast() );
			world.removeBlock( rs.worldHit.x - (rs.normal.x /2),  rs.worldHit.y - (rs.normal.y /2),  rs.worldHit.z - (rs.normal.z /2) );
		}
	},
	{
		title: 'explode',
		func: function( pl ) {
			var ex = new Explosion();
			var rs = world.fireRay( pl.getEyeCast() );
			ex.origin = rs.worldHit;
			ex.power = 10;
			ex.radius = 5;
			ex.explode();
		}
	}
	];
Game.toolIndex = 0;

Game.onLoad = function()
{
	var ray = new Ray();
	ray.origin = { x: 10, y: 200, z : 10 };
	ray.direction = { x: 0, y: -1, z: 0 };
	var result = world.fireRay( ray );
	if( result.block )
	{
		console.log( 'type: ' + result.block.type );
	}
	this.currentBlock = 0;
}

Game.onSpawn = function( p )
{
	this.player = p;
	this.player.setPosition( { x: 10, y: 130, z: 10 } );
	this.player.moveTarget = { x: 0, y: 0, z: 0 };
	this.player.moveSpeed = { x: 0, y: 0, z: 0 };
	this.player.movementSpeed = 1;
}

Game.changeBlock = function( v )
{
	this.currentBlock += v;
	if( this.currentBlock < 0 )
		this.currentBlock = meta.blocks.availableTypes.length - 1;
	else if( this.currentBlock > meta.blocks.availableTypes.length - 1 )
	{
		this.currentBlock = 0;
	}
	console.log( meta.blocks.availableTypes[this.currentBlock] );
}

Game.keyDown = function(k)
{
	switch( k )
	{
		case 68:
			this.changeBlock(-1);
			break;
		case 67:
			this.changeBlock( 1);
			break;
		case 22:
			// W
			this.player.moveTarget.z = -10;
			break;
		case 0:
			// A
			this.player.moveTarget.x = 10;
			break;
		case 18:
			// S
			this.player.moveTarget.z = 10;
			break;
		case 3:
			// D
			this.player.moveTarget.x = -10;
			break;
		case 16:
			this.player.moveTarget.y = 10;
			break;
		case 4:
			this.player.moveTarget.y = -10;
			break;
	}
}

Game.keyUp = function(k)
{
	switch( k )
	{
		case 22:
			// W
			this.player.moveTarget.z = 0;
			break;
		case 0:
			// A
			this.player.moveTarget.x = -0;
			break;
		case 18:
			// S
			this.player.moveTarget.z = -0;
			break;
		case 3:
			// D
			this.player.moveTarget.x = 0;
			break;
		case 16:
		case 4:
			this.player.moveTarget.y = 0;
			break;
	}
}

Game.onPrimary = function( player )
{
	this.tools[ this.toolIndex % this.tools.length ].func.call( this, player );
}

Game.onAlt = function( player )
{
	this.toolIndex++;
}

Game.think = function( dt )
{
	var accel = 5.0;
	var decel = 10.0;
	for( var d in this.player.moveTarget )
	{
		if( Math.abs(this.player.moveTarget[d]) - Math.abs(this.player.moveSpeed[d]) > 0.0001 )
		{
			var s = this.player.moveTarget[d].sign();
			this.player.moveSpeed[d] = s * Math.min( Math.abs(this.player.moveTarget[d]), Math.abs(this.player.moveSpeed[d]) + accel * dt);
		}
		else if( Math.abs(this.player.moveSpeed[d]) - Math.abs(this.player.moveTarget[d]) > 0.0001 )
		{
			var s = this.player.moveSpeed[d].sign();
			this.player.moveSpeed[d] = s * Math.max( Math.abs(this.player.moveTarget[d]), Math.abs(this.player.moveSpeed[d]) - decel * dt);
		}
	}
	if( this.player.moveSpeed.x != 0 || this.player.moveSpeed.y != 0 || this.player.moveSpeed.z != 0 )
	{
		this.player.move( this.player.moveSpeed.z * this.player.movementSpeed * dt, this.player.moveSpeed.y * this.player.movementSpeed * dt, this.player.moveSpeed.x * this.player.movementSpeed * dt );
	}
}

Game.draw = function()
{
	console.drawText( 10, 10, this.tools[ this.toolIndex % this.tools.length ].title );
}<|endoftext|>


<commit_before>///*
//Copyright Jesus Perez <jesusprubio gmail com>
//
//This program is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program.  If not, see <http://www.gnu.org/licenses/>.
//*/
//
//'use strict';
//
//var async   = require('async'),
//    namiLib = require('nami'),
//    Nami    = namiLib.Nami,
//
//    printer = require('../utils/printer');
//
//
//module.exports = (function () {
//
//    return {
//
//        info : {
//            name        : 'amiCoreShowChannels',
//            description : 'Use the Asterisk Manager service (AMI) to get channels of the server',
//            options     : {
//                target : {
//                    description  : 'IP address to brute-force',
//                    defaultValue : '127.0.0.1',
//                    type         : 'targetIp'
//                },
//                port : {
//                    description  : 'Port of the server',
//                    defaultValue : 5038,
//                    type         : 'port'
//                },
//                user : {
//                    description  : 'User to use in the request',
//                    defaultValue : 'admin',
//                    type         : 'anyValue'
//                },
//                password : {
//                    description  : 'Password to use in the request',
//                    defaultValue : 'amp111',
//                    type         : 'anyValue'
//                },
//                timeout : {
//                    description  : 'Time to wait for a response (ms.)',
//                    defaultValue : 5000,
//                    type         : 'positiveInt'
//                }
//            }
//        },
//
//        run : function (options, callback) {
//            var connected = false,
//                ami       = new Nami({
//                    host     : options.target,
//                    port     : options.port,
//                    username : options.user,
//                    secret   : options.password
//                });
//
//            ami.logger.setLevel('OFF');
//
//            ami.on('namiConnected', function () {
//                var action = new namiLib.Actions.CoreShowChannels();
//
//                connected = true;
//                ami.send(action, function (res) {
//                    ami.close();
//                    callback(null, res);
//                });
//            });
//
//            ami.on('namiLoginIncorrect', function () {
//                callback({
//                    type : 'login'
//                });
//            });
//
//            // The module do not supports connection timeout, so
//            // we add it manually ("connected" var), really dirty trick
//            setTimeout(function () {
//                if (!connected) {
//                    callback({
//                        type : 'timeout'
//                    });
//                }
//            }, options.timeout);
//            ami.open();
//        }
//    };
//
//}());
<commit_msg>amiCoreShowChannels module modified<commit_after>/*
Copyright Jesus Perez <jesusprubio gmail com>
		  Sergio García <s3rgio.gr gmail com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

'use strict';

// Private stuff

var async   = require('async'),
   	namiLib = require('nami'),
   	Nami    = namiLib.Nami,

   	printer = require('../utils/printer'),

	HELP = {
        description : 'Use the Asterisk Manager service (AMI) to get channels of the server',
        options     : {
            target : {
            	type : 'ip',
                description  : 'IP address to brute-force',
                defaultValue : '127.0.0.1'
            },
            port : {
            	type         : 'port',
                description  : 'Port of the server',
                defaultValue : 5038
            },
            user : {
            	type         : 'allValid',
                description  : 'User to use in the request',
                defaultValue : 'admin'
            },
            password : {
            	type         : 'allValid',
                description  : 'Password to use in the request',
                defaultValue : 'amp111'
            },
            timeout : {
            	type         : 'positiveInt',
                description  : 'Time to wait for a response (ms.)',
                defaultValue : 5000
            }
        }
    };

// Public stuff

module.exports.help = HELP;

module.exports.run = function (options, callback) {
   var connected = false,
       ami       = new Nami({
           host     : options.target,
           port     : options.port,
           username : options.user,
           secret   : options.password
       });

   ami.logger.setLevel('OFF');

   ami.on('namiConnected', function () {
       var action = new namiLib.Actions.CoreShowChannels();

       connected = true;
       ami.send(action, function (res) {
           ami.close();
           callback(null, res);
       });
   });

   ami.on('namiLoginIncorrect', function () {
       callback({
           type : 'login'
       });
   });

   // The module do not supports connection timeout, so
   // we add it manually ("connected" var), really dirty trick
   setTimeout(function () {
       if (!connected) {
           callback({
               type : 'timeout'
           });
       }
   }, options.timeout);
   ami.open();
};
<|endoftext|>