<commit_before>/**
 * Pie Chart v0.1.0
 * https://github.com/gajus/pie-chart
 *
 * Licensed under the BSD.
 * https://github.com/gajus/pie-chart/blob/master/LICENSE
 *
 * Author: Gajus Kuizinas <g.kuizinas@anuary.com>
 */
define([], function(){
  return function (name, data, options) {
    'use strict';
    if (window.d3 === undefined) {
      throw 'Pie Chart requires presence of the d3.js library.';
    }
    var svg = d3.select('svg.' + name),
        chart_size = svg[0][0].clientWidth || svg[0][0].parentNode.clientWidth,
        settings = {
          radius_inner: 0,
          radius_outer: chart_size / 3,
          radius_label: chart_size / 3 + 20,
          percentage: true,
          value: false,
          label_margin: 10,
          group_data: 0
        },
        donut,
        arc,
        slices,
        labels_group,
        grouped_labels = {left: [], right: []},
        labels,
        label_boxes,
        label_texts,
        parameter,
        reposition_colliding_labels = function (group) {
          group
            .sort(function (a, b) {
              return (a.y + a.height) - (b.y + b.height);
            })
            .forEach(function (e, i) {
              if (group[i + 1]) {
                if (group[i + 1].y - (e.y + e.height) < settings.label_margin) {
                  group[i + 1].y = (e.y + e.height) + settings.label_margin;
                }
              }
              if (e.x < settings.label_margin) {
                e.x  = settings.label_margin;
              } else if (e.x + e.width > chart_size - settings.label_margin) {
                e.x = chart_size - e.width - settings.label_margin;
              }
              d3.select(labels[0][e.index])
                .attr('transform', 'translate(' + e.x + ', ' + e.y + ')');
              d3.select(label_boxes[0][e.index])
                .attr('x', 0)
                .attr('y', -e.height + 2)
                .attr('width', e.width + 4)
                .attr('height', e.height + 4);
              e.textNode
                .attr('x', 2)
                .attr('y', 2);
            });
        },
        group_data = function (data) {
          var data_size = 0,
            removed_data_size = 0,
            i;
          data.forEach(function (e) {
            data_size += e.value;
          });
          // Check if it is worth grouping the data.
          for (i = data.length-1; i >= 0; i--) {
            if ((data[i].value / data_size) * 100 < settings.group_data) {
              removed_data_size++;
            }
          }
          if(removed_data_size > 1) {
            removed_data_size = 0;
            for (i = data.length-1; i >= 0; i--) {
              if ((data[i].value / data_size) * 100 < settings.group_data) {
                removed_data_size += data.splice(i, 1)[0].value;
              }
            }
          }
          data.push({index: 0, name: 'Other', value: removed_data_size});
          return data;
        };
    if (data.map(function (d) { return d.index; }).indexOf(0) !== -1) {
      throw '0 index is reserved for grouped data.'
    }
    if (options !== undefined) {
      for (parameter in options) {
        if (options.hasOwnProperty(parameter) && settings[parameter] !== undefined) {
          settings[parameter]    = options[parameter];
        }
      }
    }
    if (settings.group_data) {
      data = group_data(data);
    }
    donut = svg
      .append('g')
      .attr('class', 'donut')
      .attr('transform', 'translate(' + (chart_size / 2) + ', ' + (chart_size / 2) +  ')');
    arc = d3.svg.arc()
      .innerRadius(settings.radius_inner)
      .outerRadius(settings.radius_outer);
    data = d3.layout.pie()
      .value(function (e) {
        return e.value;
      })
      .sort(function (a, b) {
        return b.index - a.index;
      })(data);
    slices = donut
      .selectAll('path')
      .data(data)
      .enter()
      .append('path')
      .attr('class', function (d) {
        return 'g-' + d.data.index;
      })
      .attr('d', arc)
      .on('mouseover', function (d, i) {
        d3.select(labels[0][i])
          .classed('active', true);
      })
      .on('mouseout', function (d, i) {
        d3.select(labels[0][i])
          .classed('active', false);
      });

    labels_group = svg
      .append('g')
      .attr('class', 'labels');
    labels = labels_group
      .selectAll('g.label')
      .data(data)
      .enter()
      .append('g')
      .filter(function (e) {
        if (settings.percentage) {
          return true;
        }
        return e.data.name !== undefined;
      })
      .attr('class', 'label');
    label_boxes = labels
      .append('rect');
    label_texts = labels
      .append('text').text(function (e) {
        var percentage = (((e.endAngle - e.startAngle) / (2 * Math.PI)) * 100).toFixed(2),
          label = [];
        if (e.data.name !== undefined) {
          label.push(e.data.name);
        }
        if (settings.value) {
            label.push(' - ' + e.data.value);
        }
        if (settings.percentage) {
          label.push(' (' +percentage + '%)');
        }
        return label.join(' ');
      })
      .each(function (d, i) {
        var center = arc.centroid(d),
          x = center[0],
          y = center[1],
          h = Math.sqrt(x * x + y * y),
          lx = x / h * settings.radius_label + chart_size / 2,
          ly = y / h * settings.radius_label + chart_size / 2,
          left_aligned = (d.endAngle - d.startAngle) * 0.5 + d.startAngle > Math.PI,
          text = d3.select(this),
          bb = this.getBBox();
        grouped_labels[left_aligned ? 'left' : 'right'].push({
          index: i,
          width: bb.width,
          height: bb.height,
          x: left_aligned ? lx - bb.width : lx,
          y: ly,
          textNode: text
        });
      });
    reposition_colliding_labels(grouped_labels.left);
    reposition_colliding_labels(grouped_labels.right);
  };
});
<commit_msg>Allow passing in an SVG element instead of selecting by a class name.<commit_after>/**
 * Pie Chart v0.1.0
 * https://github.com/gajus/pie-chart
 *
 * Licensed under the BSD.
 * https://github.com/gajus/pie-chart/blob/master/LICENSE
 *
 * Author: Gajus Kuizinas <g.kuizinas@anuary.com>
 */
define([], function(){
  return function (svg, data, options) {
    'use strict';
    if (window.d3 === undefined) {
      throw 'Pie Chart requires presence of the d3.js library.';
    }
    if (typeof svg === "string") {
      svg = d3.select('svg.'+name);
    }
    var chart_width = svg[0][0].clientWidth || svg[0][0].parentNode.clientWidth,
        chart_height = svg[0][0].clientHeight || svg[0][0].parentNode.clientHeight,
        chart_size = d3.min([chart_width, chart_height]),
        settings = {
          radius_inner: 0,
          radius_outer: chart_size / 3,
          radius_label: chart_size / 3 + 20,
          percentage: true,
          value: false,
          label_margin: 10,
          group_data: 0
        },
        donut,
        arc,
        slices,
        labels_group,
        grouped_labels = {left: [], right: []},
        labels,
        label_boxes,
        label_texts,
        parameter,
        reposition_colliding_labels = function (group) {
          group
            .sort(function (a, b) {
              return (a.y + a.height) - (b.y + b.height);
            })
            .forEach(function (e, i) {
              if (group[i + 1]) {
                if (group[i + 1].y - (e.y + e.height) < settings.label_margin) {
                  group[i + 1].y = (e.y + e.height) + settings.label_margin;
                }
              }
              if (e.x < settings.label_margin) {
                e.x  = settings.label_margin;
              } else if (e.x + e.width > chart_size - settings.label_margin) {
                e.x = chart_size - e.width - settings.label_margin;
              }
              d3.select(labels[0][e.index])
                .attr('transform', 'translate(' + e.x + ', ' + e.y + ')');
              d3.select(label_boxes[0][e.index])
                .attr('x', 0)
                .attr('y', -e.height + 2)
                .attr('width', e.width + 4)
                .attr('height', e.height + 4);
              e.textNode
                .attr('x', 2)
                .attr('y', 2);
            });
        },
        group_data = function (data) {
          var data_size = 0,
            removed_data_size = 0,
            i;
          data.forEach(function (e) {
            data_size += e.value;
          });
          // Check if it is worth grouping the data.
          for (i = data.length-1; i >= 0; i--) {
            if ((data[i].value / data_size) * 100 < settings.group_data) {
              removed_data_size++;
            }
          }
          if(removed_data_size > 1) {
            removed_data_size = 0;
            for (i = data.length-1; i >= 0; i--) {
              if ((data[i].value / data_size) * 100 < settings.group_data) {
                removed_data_size += data.splice(i, 1)[0].value;
              }
            }
          }
          data.push({index: 0, name: 'Other', value: removed_data_size});
          return data;
        };
    if (data.map(function (d) { return d.index; }).indexOf(0) !== -1) {
      throw '0 index is reserved for grouped data.'
    }
    if (options !== undefined) {
      for (parameter in options) {
        if (options.hasOwnProperty(parameter) && settings[parameter] !== undefined) {
          settings[parameter]    = options[parameter];
        }
      }
    }
    if (settings.group_data) {
      data = group_data(data);
    }
    donut = svg
      .append('g')
      .attr('class', 'donut')
      .attr('transform', 'translate(' + (chart_size / 2) + ', ' + (chart_size / 2) +  ')');
    arc = d3.svg.arc()
      .innerRadius(settings.radius_inner)
      .outerRadius(settings.radius_outer);
    data = d3.layout.pie()
      .value(function (e) {
        return e.value;
      })
      .sort(function (a, b) {
        return b.index - a.index;
      })(data);
    slices = donut
      .selectAll('path')
      .data(data)
      .enter()
      .append('path')
      .attr('class', function (d) {
        return 'g-' + d.data.index;
      })
      .attr('d', arc)
      .on('mouseover', function (d, i) {
        d3.select(labels[0][i])
          .classed('active', true);
      })
      .on('mouseout', function (d, i) {
        d3.select(labels[0][i])
          .classed('active', false);
      });

    labels_group = svg
      .append('g')
      .attr('class', 'labels');
    labels = labels_group
      .selectAll('g.label')
      .data(data)
      .enter()
      .append('g')
      .filter(function (e) {
        if (settings.percentage) {
          return true;
        }
        return e.data.name !== undefined;
      })
      .attr('class', 'label');
    label_boxes = labels
      .append('rect');
    label_texts = labels
      .append('text').text(function (e) {
        var percentage = (((e.endAngle - e.startAngle) / (2 * Math.PI)) * 100).toFixed(2),
          label = [];
        if (e.data.name !== undefined) {
          label.push(e.data.name);
        }
        if (settings.value) {
            label.push(' - ' + e.data.value);
        }
        if (settings.percentage) {
          label.push(' (' +percentage + '%)');
        }
        return label.join(' ');
      })
      .each(function (d, i) {
        var center = arc.centroid(d),
          x = center[0],
          y = center[1],
          h = Math.sqrt(x * x + y * y),
          lx = x / h * settings.radius_label + chart_size / 2,
          ly = y / h * settings.radius_label + chart_size / 2,
          left_aligned = (d.endAngle - d.startAngle) * 0.5 + d.startAngle > Math.PI,
          text = d3.select(this),
          bb = this.getBBox();
        grouped_labels[left_aligned ? 'left' : 'right'].push({
          index: i,
          width: bb.width,
          height: bb.height,
          x: left_aligned ? lx - bb.width : lx,
          y: ly,
          textNode: text
        });
      });
    reposition_colliding_labels(grouped_labels.left);
    reposition_colliding_labels(grouped_labels.right);
  };
});
<|endoftext|>


<commit_before>/*
 * This file is part of NectarJS
 * Copyright (c) 2017 - 2020 Adrien THIERRY
 * http://nectarjs.com - https://seraum.com/
 *
 * sources : https://github.com/nectarjs/nectarjs
 *
 * NectarJS 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.
 *
 * NectarJS 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 NectarJS.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

function UnaryExpression(_path)
{
	// typeof
	if (_path.node.operator == "typeof")
	{
		if (_path.node.argument.type == "MemberExpression")
		{
			VISITOR.memberExpression(_path.node.argument);
			_path.replaceWithSourceString("__NJS_typeof(" + babel.generate(_path.node.argument).code + ")");
		}
		else
		{
			_path.replaceWithSourceString("__NJS_typeof(" + babel.generate(_path.node.argument).code + ")");
		}

		//_path.skip();
	}
	// void
	else if(_path.node.operator == "void")
	{
		var _rnd = "__NJS_VOID_" + RND();
		COMPILER.DECL.push(`NJS::VAR ${_rnd}() { ${babel.generate(_path.node.arguments).code} return NJS::Global::undefined;};`);
		VISITOR.pushDeclVar(_rnd);
		_path.replaceWithSourceString(`${_rnd}()`);
	}
	else if(_path.node.operator == "delete")
	{
		if (_path.node.argument.type == "MemberExpression")
		{
			VISITOR.memberExpression(_path.node.argument);
			var _left = babel.generate(_path.node.argument).code.split("[\"");
			var _right = _left.splice(-1).join();
			_right = "\"" + _right.substring(0, _right.length - 1);
			_left = _left.join("[\"");

			_path.replaceWithSourceString(`__NJS_delete(${_left}, ${_right})`);
		}
		else
		{
			_path.replaceWithSourceString("__NJS_Boolean_FALSE");
		}
	}
}
module.exports = UnaryExpression;<commit_msg>Correct delete #117<commit_after>/*
 * This file is part of NectarJS
 * Copyright (c) 2017 - 2020 Adrien THIERRY
 * http://nectarjs.com - https://seraum.com/
 *
 * sources : https://github.com/nectarjs/nectarjs
 *
 * NectarJS 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.
 *
 * NectarJS 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 NectarJS.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

function UnaryExpression(_path)
{
	// typeof
	if (_path.node.operator == "typeof")
	{
		if (_path.node.argument.type == "MemberExpression")
		{
			VISITOR.memberExpression(_path.node.argument);
			_path.replaceWithSourceString("__NJS_typeof(" + babel.generate(_path.node.argument).code + ")");
		}
		else
		{
			_path.replaceWithSourceString("__NJS_typeof(" + babel.generate(_path.node.argument).code + ")");
		}

		//_path.skip();
	}
	// void
	else if(_path.node.operator == "void")
	{
		var _rnd = "__NJS_VOID_" + RND();
		COMPILER.DECL.push(`NJS::VAR ${_rnd}() { ${babel.generate(_path.node.arguments).code} return NJS::Global::undefined;};`);
		VISITOR.pushDeclVar(_rnd);
		_path.replaceWithSourceString(`${_rnd}()`);
	}
	else if(_path.node.operator == "delete")
	{
		if (_path.node.argument.type == "MemberExpression")
		{
			VISITOR.memberExpression(_path.node.argument);

			var _left = babel.generate(_path.node.argument.object).code;
			var _right = _path.node.argument.property.extra.raw;
			_path.replaceWithSourceString(`__NJS_delete(${_left}, ${_right})`);
		}
		else
		{
			_path.replaceWithSourceString("__NJS_Boolean_FALSE");
		}
	}
}
module.exports = UnaryExpression;<|endoftext|>


<commit_before>/**
 *
 *	Copyright (C) 2016 3D Repo Ltd
 *
 *	This program is free software: you can redistribute it and/or modify
 *	it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 *	You should have received a copy of the GNU Affero General Public License
 *	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

(function () {
	"use strict";

	angular.module("3drepo")
		.directive("accountModel", accountModel);

	function accountModel () {
		return {
			restrict: 'E',
			templateUrl: 'accountModel.html',
			scope: {
				account: "=",
				model: "=",
				project: "=",
				userAccount: "=",
				onUploadFile: "&",
				uploadedFile: "=",
				modelToUpload: "=",
				onShowPage: "&",
				onSetupDeleteModel: "&",
				quota: "=",
				isAccountAdmin: "=",
				subscriptions: "="
			},
			controller: AccountModelCtrl,
			controllerAs: 'vm',
			bindToController: true,
			link: function (scope, element) {
				// Cleanup when destroyed
				element.on('$destroy', function(){
					scope.vm.uploadedFileWatch(); // Disable events watch
					scope.vm.modelToUploadFileWatch();

				});
			}
		};
	}

	AccountModelCtrl.$inject = ["$scope", "$location", "$timeout", "$interval", "$filter", "UtilsService", "serverConfig", "RevisionsService", "NotificationService", "Auth", "AnalyticService", "AccountDataService"];

	function AccountModelCtrl ($scope, $location, $timeout, $interval, $filter, UtilsService, serverConfig, RevisionsService, NotificationService, Auth, AnalyticService, AccountDataService) {

		var vm = this,
			infoTimeout = 4000,
			isUserAccount = (vm.account === vm.userAccount),
			dialogCloseToId;

		// Init
		vm.modelToUpload = null;
		vm.dialogCloseTo = "accountModelsOptionsMenu_" + vm.account + "_" + vm.model.name;

		dialogCloseToId = "#" + vm.dialogCloseTo;
		if (vm.model.timestamp !== null) {
			vm.model.timestampPretty = $filter("prettyDate")(vm.model.timestamp, {showSeconds: true});
		}
		vm.model.canUpload = true;
		// Options
		vm.modelOptions = {
			upload: {
				label: "Upload file",
				icon: "cloud_upload",
				hidden: !Auth.hasPermission(serverConfig.permissions.PERM_UPLOAD_FILES, vm.model.permissions)
			},
			team: {
				label: "Team",
				icon: "group",
				// !isUserAccount will be changed to Auth.hasPermission... when someone can pay for other accounts other than their own
				hidden: !isUserAccount
			},
			revision: {
				label: "Revisions",
				icon: "settings_backup_restore",
				hidden: false
			},
			modelsetting: {
				label: "Settings",
				 icon: "settings",
				 hidden: !Auth.hasPermission(serverConfig.permissions.PERM_CHANGE_MODEL_SETTINGS, vm.model.permissions)
			}
		};
		if(vm.model.timestamp && !vm.model.federate){
			vm.modelOptions.download = {
				label: "Download",
				icon: "cloud_download",
				hidden: !Auth.hasPermission(serverConfig.permissions.PERM_DOWNLOAD_MODEL, vm.model.permissions)
			};
		}
		vm.uploadButtonDisabled = true;
		vm.modelOptions.delete = {
			label: "Delete",
			icon: "delete",
			hidden: !Auth.hasPermission(serverConfig.permissions.PERM_DELETE_MODEL, vm.model.permissions),
			color: "#F44336"
		};

		watchModelStatus();

		if (vm.model.status === "processing") {

			vm.model.uploading = true;
			vm.fileUploadInfo = 'Processing...';

		}

		/*
		 * Watch changes in upload file
		 */
		vm.uploadedFileWatch = $scope.$watch("vm.uploadedFile", function () {

			if (angular.isDefined(vm.uploadedFile) && (vm.uploadedFile !== null) && (vm.uploadedFile.model.name === vm.model.name) && (vm.uploadedFile.account === vm.account)) {

				uploadFileToModel(vm.uploadedFile.file, vm.uploadedFile.tag, vm.uploadedFile.desc);

			}
		});

		vm.modelToUploadFileWatch = $scope.$watch("vm.modelToUpload", function () {
			if(vm.modelToUpload){

				var names = vm.modelToUpload.name.split('.');

				vm.uploadErrorMessage = null;

				if(names.length === 1){
					vm.uploadErrorMessage = 'Filename must have extension';
					vm.modelToUpload = null;
					vm.uploadButtonDisabled = true;
				} else if(serverConfig.acceptedFormat.indexOf(names[names.length - 1].toLowerCase()) === -1) {
					vm.uploadErrorMessage = 'File format not supported';
					vm.modelToUpload = null;
					vm.uploadButtonDisabled = true;
				} else {
					vm.uploadButtonDisabled = false;
				}

			}
		});

		/**
		 * Go to the model viewer
		 */
		vm.goToModel = function () {
			if (!vm.model.uploading) {
				if (vm.model.timestamp === null) {
					// No timestamp indicates no model previously uploaded
					if(Auth.hasPermission(serverConfig.permissions.PERM_UPLOAD_FILES, vm.model.permissions)){
						vm.tag = null;
						vm.desc = null;
						vm.modelToUpload = null;
						UtilsService.showDialog("uploadModelDialog.html", $scope, event, true, null, false, dialogCloseToId);
					}
					else {
						console.warn("Incorrect permissions")
					}
				}
				else {
					$location.path("/" + vm.account + "/" + vm.model.name, "_self").search("page", null);
					AnalyticService.sendEvent({
						eventCategory: 'Model',
						eventAction: 'view'
					});
				}
			}
		};

		/**
		 * Handle model option selection
		 * @param event
		 * @param option
		 */
		vm.doModelOption = function (event, option) {
			switch (option) {
				case "modelsetting":
					$location.search("proj", vm.model.name);
					$location.search("targetAcct", vm.account);
					vm.onShowPage({page: "modelsetting", callingPage: "teamspaces"});
					break;

				case "upload":
					vm.uploadErrorMessage = null;
					vm.modelToUpload = null;
					vm.tag = null;
					vm.desc = null;
					UtilsService.showDialog("uploadModelDialog.html", $scope, event, true, null, false, dialogCloseToId);
					//vm.uploadFile();
					break;

				case "download":
					window.open(
						serverConfig.apiUrl(serverConfig.GET_API, vm.account + "/" + vm.model.name + "/download/latest"),
						'_blank'
					);

					AnalyticService.sendEvent({
						eventCategory: 'Model',
						eventAction: 'download'
					});

					break;

				case "team":
					setupEditTeam(event);
					break;

				case "delete":
					vm.onSetupDeleteModel({event: event, model: vm.model, account: vm.account, project: vm.project});
					break;

				case "revision":
					if(!vm.revisions){
						UtilsService.doGet(vm.account + "/" + vm.model.name + "/revisions.json").then(function(response){
							vm.revisions = response.data;
						});
					}
					UtilsService.showDialog("revisionsDialog.html", $scope, event, true, null, false, dialogCloseToId);
					break;
			}
		};

		/**
		 * Go to the billing page to add more licenses
		 */
		vm.setupAddLicenses = function () {
			vm.onShowPage({page: "billing", callingPage: "teamspaces"});
			UtilsService.closeDialog();
		};

		/**
		 * Close the dialog
		 */
		vm.closeDialog = function() {
			UtilsService.closeDialog();
		};

		/**
		 * When users click select file
		 */
		vm.selectFile = function(){
			vm.onUploadFile({model: vm.model, account: vm.account});
		};

		/**
		 * When users click upload after selecting
		 */
		vm.uploadFile = function () {
			var revisions;
			vm.uploadErrorMessage = null;

			if(vm.tag && RevisionsService.isTagFormatInValid(vm.tag)){
				vm.uploadErrorMessage = 'Invalid revision name';
			} else {
				UtilsService.doGet(vm.account + "/" + vm.model.name + "/revisions.json").then(function(response){
					revisions = response.data;
					if(vm.tag){
						revisions.forEach(function(rev){
							if(rev.tag === vm.tag){
								vm.uploadErrorMessage = 'Revision name already exists';
							}
						});
					}

					if(!vm.uploadErrorMessage){
						vm.uploadedFile = {model: vm.model, account: vm.account, file: vm.modelToUpload, tag: vm.tag, desc: vm.desc};
						vm.closeDialog();
					}
				});
			}
		};

		/**
		* Go to the specified revision
		*/
		vm.goToRevision = function(revId){
			$location.path("/" + vm.account + "/" + vm.model.name + "/" + revId , "_self");
			AnalyticService.sendEvent({
				eventCategory: 'Model',
				eventAction: 'view'
			});
		};

		/**
		 * Upload file/model to model
		 * @param file
		 * @param tag
		 * @param desc
		 */
		function uploadFileToModel(file, tag, desc) {
			var promise,
				formData;

			// Check the quota
			promise = UtilsService.doGet(vm.userAccount + ".json");

			promise.then(function (response) {

				var targetAccount = response.data.accounts.find(function(account){
					return account.account === vm.account;
				});

				//var quota = targetAccount.quota;

				// Check for file size limit
				if (file.size > serverConfig.uploadSizeLimit) {
					$timeout(function () {

						vm.fileUploadInfo = "File exceeds size limit";
						$timeout(function () {
							vm.fileUploadInfo = "";
						}, infoTimeout);
					});
				}
				else {

					formData = new FormData();
					formData.append("file", file);

					if(tag){
						formData.append('tag', tag);
					}

					if(desc){
						formData.append('desc', desc);
					}

					promise = UtilsService.doPost(formData, vm.account + "/" + vm.model.name + "/upload", {'Content-Type': undefined});

					promise.then(function (response) {
						if ((response.status === 400) || (response.status === 404)) {
							// Upload error
							vm.model.uploading = false;
							vm.fileUploadInfo = UtilsService.getErrorMessage(response.data);

							$timeout(function () {
								vm.fileUploadInfo = "";
							}, infoTimeout);
						}
						else {

							AnalyticService.sendEvent({
								eventCategory: 'Model',
								eventAction: 'upload'
							});
						}
					});
				}
			});
		}

		/**
		 * Watch file upload status
		 */
		function watchModelStatus(){

			NotificationService.subscribe.modelStatusChanged(vm.account, vm.model.model, function(data){

				if ((data.status === "ok") || (data.status === "failed")) {
					if (data.status === "ok"
						|| (data.errorReason.value === UtilsService.getResponseCode('FILE_IMPORT_MISSING_TEXTURES')
						|| data.errorReason.value === UtilsService.getResponseCode('FILE_IMPORT_MISSING_NODES'))) {
						vm.model.timestamp = new Date();
						vm.model.timestampPretty = $filter("prettyDate")(vm.model.timestamp, {showSeconds: true});
						vm.fileUploadInfo = "Model imported successfully";
						// clear revisions cache
						vm.revisions = null;
					}

					//status=ok can have an error message too
					if (data.hasOwnProperty("errorReason") && data.errorReason.message) {
						vm.fileUploadInfo = data.errorReason.message;
					} else if (data.status === "failed") {
						vm.fileUploadInfo = "Failed to import model";
					}

					vm.model.uploading = false;

					$scope.$apply();
					$timeout(function () {
						vm.fileUploadInfo = "";
					}, infoTimeout);

				} else if (data.status === 'uploading'){

					vm.model.uploading = true;
					vm.fileUploadInfo = 'Uploading...';
					$scope.$apply();

				} else if (data.status === 'processing'){
					vm.model.uploading = true;
					vm.fileUploadInfo = 'Processing...';
					$scope.$apply();
				}
			});

			$scope.$on('$destroy', function(){
				NotificationService.unsubscribe.modelStatusChanged(vm.account, vm.model.model);
			});
		}

		/**
		 * Set up team of model
		 *
		 * @param {Object} event
		 */
		function setupEditTeam (event) {
			vm.item = vm.model;
			UtilsService.showDialog("teamDialog.html", $scope, event, true, null, false, dialogCloseToId);
		}
	}
}());
<commit_msg>Correct paths for viewing and uploading<commit_after>/**
 *
 *	Copyright (C) 2016 3D Repo Ltd
 *
 *	This program is free software: you can redistribute it and/or modify
 *	it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 *	You should have received a copy of the GNU Affero General Public License
 *	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

(function () {
	"use strict";

	angular.module("3drepo")
		.directive("accountModel", accountModel);

	function accountModel () {
		return {
			restrict: 'E',
			templateUrl: 'accountModel.html',
			scope: {
				account: "=",
				model: "=",
				project: "=",
				userAccount: "=",
				onUploadFile: "&",
				uploadedFile: "=",
				modelToUpload: "=",
				onShowPage: "&",
				onSetupDeleteModel: "&",
				quota: "=",
				isAccountAdmin: "=",
				subscriptions: "="
			},
			controller: AccountModelCtrl,
			controllerAs: 'vm',
			bindToController: true,
			link: function (scope, element) {
				// Cleanup when destroyed
				element.on('$destroy', function(){
					scope.vm.uploadedFileWatch(); // Disable events watch
					scope.vm.modelToUploadFileWatch();

				});
			}
		};
	}

	AccountModelCtrl.$inject = ["$scope", "$location", "$timeout", "$interval", "$filter", "UtilsService", "serverConfig", "RevisionsService", "NotificationService", "Auth", "AnalyticService", "AccountDataService"];

	function AccountModelCtrl ($scope, $location, $timeout, $interval, $filter, UtilsService, serverConfig, RevisionsService, NotificationService, Auth, AnalyticService, AccountDataService) {

		var vm = this,
			infoTimeout = 4000,
			isUserAccount = (vm.account === vm.userAccount),
			dialogCloseToId;

		// Init
		vm.modelToUpload = null;
		vm.dialogCloseTo = "accountModelsOptionsMenu_" + vm.account + "_" + vm.model.name;

		dialogCloseToId = "#" + vm.dialogCloseTo;
		if (vm.model.timestamp !== null) {
			vm.model.timestampPretty = $filter("prettyDate")(vm.model.timestamp, {showSeconds: true});
		}
		vm.model.canUpload = true;
		// Options
		vm.modelOptions = {
			upload: {
				label: "Upload file",
				icon: "cloud_upload",
				hidden: !Auth.hasPermission(serverConfig.permissions.PERM_UPLOAD_FILES, vm.model.permissions)
			},
			team: {
				label: "Team",
				icon: "group",
				// !isUserAccount will be changed to Auth.hasPermission... when someone can pay for other accounts other than their own
				hidden: !isUserAccount
			},
			revision: {
				label: "Revisions",
				icon: "settings_backup_restore",
				hidden: false
			},
			modelsetting: {
				label: "Settings",
				 icon: "settings",
				 hidden: !Auth.hasPermission(serverConfig.permissions.PERM_CHANGE_MODEL_SETTINGS, vm.model.permissions)
			}
		};
		if(vm.model.timestamp && !vm.model.federate){
			vm.modelOptions.download = {
				label: "Download",
				icon: "cloud_download",
				hidden: !Auth.hasPermission(serverConfig.permissions.PERM_DOWNLOAD_MODEL, vm.model.permissions)
			};
		}
		vm.uploadButtonDisabled = true;
		vm.modelOptions.delete = {
			label: "Delete",
			icon: "delete",
			hidden: !Auth.hasPermission(serverConfig.permissions.PERM_DELETE_MODEL, vm.model.permissions),
			color: "#F44336"
		};

		watchModelStatus();

		if (vm.model.status === "processing") {

			vm.model.uploading = true;
			vm.fileUploadInfo = 'Processing...';

		}

		/*
		 * Watch changes in upload file
		 */
		vm.uploadedFileWatch = $scope.$watch("vm.uploadedFile", function () {

			if (angular.isDefined(vm.uploadedFile) && (vm.uploadedFile !== null) && (vm.uploadedFile.model.name === vm.model.name) && (vm.uploadedFile.account === vm.account)) {

				uploadFileToModel(vm.uploadedFile.file, vm.uploadedFile.tag, vm.uploadedFile.desc);

			}
		});

		vm.modelToUploadFileWatch = $scope.$watch("vm.modelToUpload", function () {
			if(vm.modelToUpload){

				var names = vm.modelToUpload.name.split('.');

				vm.uploadErrorMessage = null;

				if(names.length === 1){
					vm.uploadErrorMessage = 'Filename must have extension';
					vm.modelToUpload = null;
					vm.uploadButtonDisabled = true;
				} else if(serverConfig.acceptedFormat.indexOf(names[names.length - 1].toLowerCase()) === -1) {
					vm.uploadErrorMessage = 'File format not supported';
					vm.modelToUpload = null;
					vm.uploadButtonDisabled = true;
				} else {
					vm.uploadButtonDisabled = false;
				}

			}
		});

		/**
		 * Go to the model viewer
		 */
		vm.goToModel = function () {
			if (!vm.model.uploading) {
				if (vm.model.timestamp === null) {
					// No timestamp indicates no model previously uploaded
					if(Auth.hasPermission(serverConfig.permissions.PERM_UPLOAD_FILES, vm.model.permissions)){
						vm.tag = null;
						vm.desc = null;
						vm.modelToUpload = null;
						UtilsService.showDialog("uploadModelDialog.html", $scope, event, true, null, false, dialogCloseToId);
					}
					else {
						console.warn("Incorrect permissions")
					}
				}
				else {
					$location.path("/" + vm.account + "/" + vm.model.model, "_self").search("page", null);
					AnalyticService.sendEvent({
						eventCategory: 'Model',
						eventAction: 'view'
					});
				}
			}
		};

		/**
		 * Handle model option selection
		 * @param event
		 * @param option
		 */
		vm.doModelOption = function (event, option) {
			switch (option) {
				case "modelsetting":
					$location.search("proj", vm.model.name);
					$location.search("targetAcct", vm.account);
					vm.onShowPage({page: "modelsetting", callingPage: "teamspaces"});
					break;

				case "upload":
					vm.uploadErrorMessage = null;
					vm.modelToUpload = null;
					vm.tag = null;
					vm.desc = null;
					UtilsService.showDialog("uploadModelDialog.html", $scope, event, true, null, false, dialogCloseToId);
					//vm.uploadFile();
					break;

				case "download":
					window.open(
						serverConfig.apiUrl(serverConfig.GET_API, vm.account + "/" + vm.model.name + "/download/latest"),
						'_blank'
					);

					AnalyticService.sendEvent({
						eventCategory: 'Model',
						eventAction: 'download'
					});

					break;

				case "team":
					setupEditTeam(event);
					break;

				case "delete":
					vm.onSetupDeleteModel({event: event, model: vm.model, account: vm.account, project: vm.project});
					break;

				case "revision":
					if(!vm.revisions){
						UtilsService.doGet(vm.account + "/" + vm.model.name + "/revisions.json").then(function(response){
							vm.revisions = response.data;
						});
					}
					UtilsService.showDialog("revisionsDialog.html", $scope, event, true, null, false, dialogCloseToId);
					break;
			}
		};

		/**
		 * Go to the billing page to add more licenses
		 */
		vm.setupAddLicenses = function () {
			vm.onShowPage({page: "billing", callingPage: "teamspaces"});
			UtilsService.closeDialog();
		};

		/**
		 * Close the dialog
		 */
		vm.closeDialog = function() {
			UtilsService.closeDialog();
		};

		/**
		 * When users click select file
		 */
		vm.selectFile = function(){
			vm.onUploadFile({model: vm.model, account: vm.account});
		};

		/**
		 * When users click upload after selecting
		 */
		vm.uploadFile = function () {
			var revisions;
			vm.uploadErrorMessage = null;

			if(vm.tag && RevisionsService.isTagFormatInValid(vm.tag)){
				vm.uploadErrorMessage = 'Invalid revision name';
			} else {
				UtilsService.doGet(vm.account + "/" + vm.model.name + "/revisions.json").then(function(response){
					revisions = response.data;
					if(vm.tag){
						revisions.forEach(function(rev){
							if(rev.tag === vm.tag){
								vm.uploadErrorMessage = 'Revision name already exists';
							}
						});
					}

					if(!vm.uploadErrorMessage){
						vm.uploadedFile = {model: vm.model, account: vm.account, file: vm.modelToUpload, tag: vm.tag, desc: vm.desc};
						vm.closeDialog();
					}
				});
			}
		};

		/**
		* Go to the specified revision
		*/
		vm.goToRevision = function(revId){
			$location.path("/" + vm.account + "/" + vm.model.name + "/" + revId , "_self");
			AnalyticService.sendEvent({
				eventCategory: 'Model',
				eventAction: 'view'
			});
		};

		/**
		 * Upload file/model to model
		 * @param file
		 * @param tag
		 * @param desc
		 */
		function uploadFileToModel(file, tag, desc) {
			var promise,
				formData;

			// Check the quota
			promise = UtilsService.doGet(vm.userAccount + ".json");

			promise.then(function (response) {

				var targetAccount = response.data.accounts.find(function(account){
					return account.account === vm.account;
				});

				//var quota = targetAccount.quota;

				// Check for file size limit
				if (file.size > serverConfig.uploadSizeLimit) {
					$timeout(function () {

						vm.fileUploadInfo = "File exceeds size limit";
						$timeout(function () {
							vm.fileUploadInfo = "";
						}, infoTimeout);
					});
				}
				else {

					formData = new FormData();
					formData.append("file", file);

					if(tag){
						formData.append('tag', tag);
					}

					if(desc){
						formData.append('desc', desc);
					}

					promise = UtilsService.doPost(formData, vm.account + "/" + vm.model.model + "/upload", {'Content-Type': undefined});

					promise.then(function (response) {
						if ((response.status === 400) || (response.status === 404)) {
							// Upload error
							vm.model.uploading = false;
							vm.fileUploadInfo = UtilsService.getErrorMessage(response.data);

							$timeout(function () {
								vm.fileUploadInfo = "";
							}, infoTimeout);
						}
						else {

							AnalyticService.sendEvent({
								eventCategory: 'Model',
								eventAction: 'upload'
							});
						}
					});
				}
			});
		}

		/**
		 * Watch file upload status
		 */
		function watchModelStatus(){

			NotificationService.subscribe.modelStatusChanged(vm.account, vm.model.model, function(data){

				if ((data.status === "ok") || (data.status === "failed")) {
					if (data.status === "ok"
						|| (data.errorReason.value === UtilsService.getResponseCode('FILE_IMPORT_MISSING_TEXTURES')
						|| data.errorReason.value === UtilsService.getResponseCode('FILE_IMPORT_MISSING_NODES'))) {
						vm.model.timestamp = new Date();
						vm.model.timestampPretty = $filter("prettyDate")(vm.model.timestamp, {showSeconds: true});
						vm.fileUploadInfo = "Model imported successfully";
						// clear revisions cache
						vm.revisions = null;
					}

					//status=ok can have an error message too
					if (data.hasOwnProperty("errorReason") && data.errorReason.message) {
						vm.fileUploadInfo = data.errorReason.message;
					} else if (data.status === "failed") {
						vm.fileUploadInfo = "Failed to import model";
					}

					vm.model.uploading = false;

					$scope.$apply();
					$timeout(function () {
						vm.fileUploadInfo = "";
					}, infoTimeout);

				} else if (data.status === 'uploading'){

					vm.model.uploading = true;
					vm.fileUploadInfo = 'Uploading...';
					$scope.$apply();

				} else if (data.status === 'processing'){
					vm.model.uploading = true;
					vm.fileUploadInfo = 'Processing...';
					$scope.$apply();
				}
			});

			$scope.$on('$destroy', function(){
				NotificationService.unsubscribe.modelStatusChanged(vm.account, vm.model.model);
			});
		}

		/**
		 * Set up team of model
		 *
		 * @param {Object} event
		 */
		function setupEditTeam (event) {
			vm.item = vm.model;
			UtilsService.showDialog("teamDialog.html", $scope, event, true, null, false, dialogCloseToId);
		}
	}
}());
<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */
var URL = require('url')
  , NS = require('./namespaces')
  ;

/**
 * Safe hasOwnProperty
 * See: http://www.devthought.com/2012/01/18/an-object-is-not-a-hash/
 */
function has (obj, prop) {
  return Object.prototype.hasOwnProperty.call(obj, prop);
}
exports.has = has;

/**
 * Merge object b with object a.
 *
 * var a = { foo: 'bar' }
 *   , b = { foo: 'quux', bar: 'baz' };
 *
 * merge(a, b);
 * // => { foo: 'quux', bar: 'baz' }
 *
 * merge(a, b, true);
 * // => { foo: 'bar', bar: 'baz' }
 *
 * @param {Object} a
 * @param {Object} b
 * @param {Boolean} [noforce] Optionally, don't overwrite any existing keys in a found in b
 * @return {Object}
 */
function merge (a, b, noforce) {
  if (a && b && a === Object(a) && b === Object(b)) {
    for (var key in b) {
      if (has(b, key)) {
        if (noforce) {
          if (!a.hasOwnProperty(key)) a[key] = b[key];
        } else {
          a[key] = b[key];
        }
      }
    }
  }
  return a;
}
exports.merge = merge;

/**
 * Create an array containing the unique members of an array.
 *
 * var array = ['a', 'b', 1, 2, 'a', 3 ];
 *
 * unique(array);
 * // => ['b', 1, 2, 'a', 3 ]
 *
 * @param {Array} array
 * @return {Array}
 */
function unique (array) {
  var a = [];
  var l = array.length;
  for (var i=0; i<l; i++) {
    for (var j=i+1; j<l; j++) {
      // If array[i] is found later in the array
      if (array[i] === array[j])
        j = ++i;
    }
    a.push(array[i]);
  }
  return a;
}
exports.unique = unique;

/**
 * Utility function to test for and extract a subkey.
 *
 * var obj = { '#': 'foo', 'bar': 'baz' };
 *
 * get(obj);
 * // => 'foo'
 *
 * get(obj, 'bar');
 * // => 'baz'
 *
 * @param {Object} obj
 * @param {String} [subkey="#"] By default, use the '#' key, but you may pass any key you like
 * @return Returns the value of the selected key or 'null' if undefined.
 */
function get(obj, subkey) {
  if (!subkey)
    subkey = '#';

  if (Array.isArray(obj))
    obj = obj[0];

  if (obj && obj[subkey])
    return obj[subkey];
  else
    return null;
}
exports.get = get;

/*
 * Expose require('url').resolve
 */
function resolve (baseUrl, pathUrl) {
  return URL.resolve(baseUrl, pathUrl);
}
exports.resolve = resolve;

/*
 * Check whether a given namespace URI matches the given default
 *
 * @param {String} URI
 * @param {String} default, e.g., 'atom'
 * @return {Boolean}
 */
function nslookup (uri, def) {
  return NS[uri] === def;
}
exports.nslookup = nslookup;

/*
 * Return the "default" namespace prefix for a given namespace URI
 *
 * @param {String} URI
 * @return {String}
 */
function nsprefix (uri) {
  return NS[uri];
}
exports.nsprefix = nsprefix;

/*
 * Walk a node and re-resolve the urls using the given baseurl
 *
 * @param {Object} node
 * @param {String} baseurl
 * @return {Object} modified node
 */
function reresolve (node, baseurl) {
  if (!node || !baseurl) {
    return false; // Nothing to do.
  }

  function resolveLevel (level) {
    var els = Object.keys(level);
    els.forEach(function(el){
      if (Array.isArray(level[el])) {
        level[el].forEach(resolveLevel);
      } else {
        if (level[el].constructor.name === 'Object') {
          if (el == 'logo' || el == 'icon') {
            level[el]['#'] = URL.resolve(baseurl, level[el]['#']);
          } else {
            var attrs = Object.keys(level[el]);
            attrs.forEach(function(name){
              if (name == 'href' || name == 'src' || name == 'uri') {
                level[el][name] = URL.resolve(baseurl, level[el][name]);
              }
            });
          }
        }
      }
    });
    return level;
  }

  return resolveLevel(node);
}
exports.reresolve = reresolve;
<commit_msg>Fix reresolve function to not assume that node property is a string. Closes #50.<commit_after>
/**
 * Module dependencies.
 */
var URL = require('url')
  , NS = require('./namespaces')
  ;

/**
 * Safe hasOwnProperty
 * See: http://www.devthought.com/2012/01/18/an-object-is-not-a-hash/
 */
function has (obj, prop) {
  return Object.prototype.hasOwnProperty.call(obj, prop);
}
exports.has = has;

/**
 * Merge object b with object a.
 *
 * var a = { foo: 'bar' }
 *   , b = { foo: 'quux', bar: 'baz' };
 *
 * merge(a, b);
 * // => { foo: 'quux', bar: 'baz' }
 *
 * merge(a, b, true);
 * // => { foo: 'bar', bar: 'baz' }
 *
 * @param {Object} a
 * @param {Object} b
 * @param {Boolean} [noforce] Optionally, don't overwrite any existing keys in a found in b
 * @return {Object}
 */
function merge (a, b, noforce) {
  if (a && b && a === Object(a) && b === Object(b)) {
    for (var key in b) {
      if (has(b, key)) {
        if (noforce) {
          if (!a.hasOwnProperty(key)) a[key] = b[key];
        } else {
          a[key] = b[key];
        }
      }
    }
  }
  return a;
}
exports.merge = merge;

/**
 * Create an array containing the unique members of an array.
 *
 * var array = ['a', 'b', 1, 2, 'a', 3 ];
 *
 * unique(array);
 * // => ['b', 1, 2, 'a', 3 ]
 *
 * @param {Array} array
 * @return {Array}
 */
function unique (array) {
  var a = [];
  var l = array.length;
  for (var i=0; i<l; i++) {
    for (var j=i+1; j<l; j++) {
      // If array[i] is found later in the array
      if (array[i] === array[j])
        j = ++i;
    }
    a.push(array[i]);
  }
  return a;
}
exports.unique = unique;

/**
 * Utility function to test for and extract a subkey.
 *
 * var obj = { '#': 'foo', 'bar': 'baz' };
 *
 * get(obj);
 * // => 'foo'
 *
 * get(obj, 'bar');
 * // => 'baz'
 *
 * @param {Object} obj
 * @param {String} [subkey="#"] By default, use the '#' key, but you may pass any key you like
 * @return Returns the value of the selected key or 'null' if undefined.
 */
function get(obj, subkey) {
  if (!subkey)
    subkey = '#';

  if (Array.isArray(obj))
    obj = obj[0];

  if (obj && obj[subkey])
    return obj[subkey];
  else
    return null;
}
exports.get = get;

/*
 * Expose require('url').resolve
 */
function resolve (baseUrl, pathUrl) {
  return URL.resolve(baseUrl, pathUrl);
}
exports.resolve = resolve;

/*
 * Check whether a given namespace URI matches the given default
 *
 * @param {String} URI
 * @param {String} default, e.g., 'atom'
 * @return {Boolean}
 */
function nslookup (uri, def) {
  return NS[uri] === def;
}
exports.nslookup = nslookup;

/*
 * Return the "default" namespace prefix for a given namespace URI
 *
 * @param {String} URI
 * @return {String}
 */
function nsprefix (uri) {
  return NS[uri];
}
exports.nsprefix = nsprefix;

/*
 * Walk a node and re-resolve the urls using the given baseurl
 *
 * @param {Object} node
 * @param {String} baseurl
 * @return {Object} modified node
 */
function reresolve (node, baseurl) {
  if (!node || !baseurl) {
    return false; // Nothing to do.
  }

  function resolveLevel (level) {
    var els = Object.keys(level);
    els.forEach(function(el){
      if (Array.isArray(level[el])) {
        level[el].forEach(resolveLevel);
      } else {
        if (level[el].constructor.name === 'Object') {
          if (el == 'logo' || el == 'icon') {
            level[el]['#'] = URL.resolve(baseurl, level[el]['#']);
          } else {
            var attrs = Object.keys(level[el]);
            attrs.forEach(function(name){
              if (name == 'href' || name == 'src' || name == 'uri') {
                if ('string' === typeof level[el][name]) {
                  level[el][name] = URL.resolve(baseurl, level[el][name]);
                }
                else if ('#' in level[el][name]) {
                  level[el][name]['#'] = URL.resolve(baseurl, level[el][name]['#']);
                }
              }
            });
          }
        }
      }
    });
    return level;
  }

  return resolveLevel(node);
}
exports.reresolve = reresolve;
<|endoftext|>


<commit_before>Package.describe({
    summary: "Accounts Templates unstyled.",
    version: "0.9.16",
    name: "splendido:accounts-templates-unstyled",
    git: "https://github.com/splendido/accounts-templates-unstyled.git",
});

Package.on_use(function(api, where) {
    api.versionsFrom("METEOR@0.9.2.2");

    api.use([
        "less",
        "templating",
    ], "client");

    api.use([
        "splendido:accounts-templates-core",
    ], ["client", "server"]);

    api.imply([
        "splendido:accounts-templates-core@0.9.16",
    ], ["client", "server"]);

    api.add_files([
        "lib/at_error.html",
        "lib/at_error.js",
        "lib/at_form.html",
        "lib/at_form.js",
        "lib/at_input.html",
        "lib/at_input.js",
        "lib/at_oauth.html",
        "lib/at_oauth.js",
        "lib/at_pwd_form.html",
        "lib/at_pwd_form.js",
        "lib/at_pwd_form_btn.html",
        "lib/at_pwd_form_btn.js",
        "lib/at_pwd_link.html",
        "lib/at_pwd_link.js",
        "lib/at_result.html",
        "lib/at_result.js",
        "lib/at_sep.html",
        "lib/at_sep.js",
        "lib/at_signin_link.html",
        "lib/at_signin_link.js",
        "lib/at_signup_link.html",
        "lib/at_signup_link.js",
        "lib/at_social.html",
        "lib/at_social.js",
        "lib/at_terms_link.html",
        "lib/at_terms_link.js",
        "lib/at_title.html",
        "lib/at_title.js",
        "lib/full_page_at_form.html",
        "lib/at_unstyled.css"
    ], ["client"]);
});

Package.on_test(function(api) {
    api.use([
        "splendido:accounts-templates-unstyled",
        "splendido:accounts-templates-core@0.9.16",
    ]);

    api.use([
        "accounts-password",
        "tinytest",
        "test-helpers"
    ], ["client", "server"]);

    api.add_files([
        "tests/tests.js"
    ], ["client", "server"]);
});<commit_msg>minor release - Bump to version 0.10.0<commit_after>Package.describe({
    summary: "Accounts Templates unstyled.",
    version: "0.10.0",
    name: "splendido:accounts-templates-unstyled",
    git: "https://github.com/splendido/accounts-templates-unstyled.git",
});

Package.on_use(function(api, where) {
    api.versionsFrom("METEOR@0.9.2.2");

    api.use([
        "less",
        "templating",
    ], "client");

    api.use([
        "splendido:accounts-templates-core",
    ], ["client", "server"]);

    api.imply([
        "splendido:accounts-templates-core@0.10.0",
    ], ["client", "server"]);

    api.add_files([
        "lib/at_error.html",
        "lib/at_error.js",
        "lib/at_form.html",
        "lib/at_form.js",
        "lib/at_input.html",
        "lib/at_input.js",
        "lib/at_oauth.html",
        "lib/at_oauth.js",
        "lib/at_pwd_form.html",
        "lib/at_pwd_form.js",
        "lib/at_pwd_form_btn.html",
        "lib/at_pwd_form_btn.js",
        "lib/at_pwd_link.html",
        "lib/at_pwd_link.js",
        "lib/at_result.html",
        "lib/at_result.js",
        "lib/at_sep.html",
        "lib/at_sep.js",
        "lib/at_signin_link.html",
        "lib/at_signin_link.js",
        "lib/at_signup_link.html",
        "lib/at_signup_link.js",
        "lib/at_social.html",
        "lib/at_social.js",
        "lib/at_terms_link.html",
        "lib/at_terms_link.js",
        "lib/at_title.html",
        "lib/at_title.js",
        "lib/full_page_at_form.html",
        "lib/at_unstyled.css"
    ], ["client"]);
});

Package.on_test(function(api) {
    api.use([
        "splendido:accounts-templates-unstyled",
        "splendido:accounts-templates-core@0.10.0",
    ]);

    api.use([
        "accounts-password",
        "tinytest",
        "test-helpers"
    ], ["client", "server"]);

    api.add_files([
        "tests/tests.js"
    ], ["client", "server"]);
});<|endoftext|>


<commit_before>'use strict';

/* Controllers */

var builderControllers = angular.module('builderControllers', []);

builderControllers.controller('DebBuildListCtrl', ['$scope', '$http', 'BuildConf',
    function ($scope, $http, BuildConf) {
        $scope.build_confs = BuildConf.query();
        $scope.orderProp = '-fields.status';
        $scope.alerts = [];

        $scope.closeAlert = function (index) {
            $scope.alerts.splice(index, 1);
        };

        $scope.rebuild_pkg = function (build_conf_id) {
            $http.get('/api/rebuild_package/' + build_conf_id).success(function (data) {
                $scope.alerts.push(data);
            });
        }

        $scope.autobuild_on_off = function (build_conf_id) {
            $http.get('/api/autobuild_on_off/' + build_conf_id).success(function (data) {
                for (var build_conf in $scope.build_confs) {
                    if ($scope.build_confs[build_conf].pk == build_conf_id) {
                        $scope.build_confs[build_conf].fields.auto_build = data[0].fields.auto_build;
                    }
                }
            });
        }

        $scope.remove_build_conf = function (build_conf_id) {
            var is_confirm = confirm('Are you sure remove build config #' + build_conf_id + '?');
            if (is_confirm) {
                $http.get('/api/remove_build_conf/' + build_conf_id).success(function (data) {
                    $scope.alerts.push(data);
                });
            }
        }

        $scope.getData = function () {
            $http.get('/api/build_confs/').success(function (data) {
                if ($scope.build_confs.length != data.length) {
                    $scope.build_confs = data;
                }
            });
        };
        setInterval($scope.getData, 1000);
    }]);

builderControllers.controller('BranchestListCtrl', ['$scope', '$http', 'Branch',
    function ($scope, $http, Branch) {
        $scope.branches = Branch.query();
        $scope.alerts = [];

        $scope.closeAlert = function (index) {
            $scope.alerts.splice(index, 1);
        };

        $scope.remove_branch = function (branch_id) {
            var is_confirm = confirm('Are you sure remove branch #' + branch_id + '?');
            if (is_confirm) {
                $http.get('/api/remove_branch/' + branch_id).success(function (data) {
                    $scope.alerts.push(data);
                });
            }
        }

        $scope.getData = function () {
            $http.get('/api/branches/').success(function (data) {
                if ($scope.branches.length != data.length) {
                    $scope.branches = data;
                }
            });
        };
        setInterval($scope.getData, 1000);
    }]);

builderControllers.controller('MappingCtrl', ['$scope', '$http', 'Mapping',
    function ($scope, $http, Mapping) {
        $scope.mappings = Mapping.query();
        $scope.alerts = [];

        $scope.closeAlert = function (index) {
            $scope.alerts.splice(index, 1);
        };

        $scope.remove_mapping = function (mapping_id) {
            var is_confirm = confirm('Are you sure remove mapping #' + mapping_id + '?');
            if (is_confirm) {
                $http.get('/api/remove_mapping/' + mapping_id).success(function (data) {
                    $scope.alerts.push(data);
                });
            }
        }

        $scope.getData = function () {
            $http.get('/api/mapping/').success(function (data) {
                if ($scope.mappings.length != data.length) {
                    $scope.mappings = data;
                }
            });
        };
        setInterval($scope.getData, 1000);
    }]);
<commit_msg>migrate to angularjs interface<commit_after>'use strict';

/* Controllers */

var builderControllers = angular.module('builderControllers', []);

builderControllers.controller('DebBuildListCtrl', ['$scope', '$http', 'BuildConf',
    function ($scope, $http, BuildConf) {
        $scope.build_confs = BuildConf.query();
        $scope.orderProp = '-fields.status';
        $scope.alerts = [];

        $scope.closeAlert = function (index) {
            $scope.alerts.splice(index, 1);
        };

        $scope.rebuild_pkg = function (build_conf_id) {
            $http.get('/api/rebuild_package/' + build_conf_id).success(function (data) {
                $scope.alerts.push(data);
            });
        }

        $scope.autobuild_on_off = function (build_conf_id) {
            $http.get('/api/autobuild_on_off/' + build_conf_id).success(function (data) {
                for (var build_conf in $scope.build_confs) {
                    if ($scope.build_confs[build_conf].pk == build_conf_id) {
                        $scope.build_confs[build_conf].fields.auto_build = data[0].fields.auto_build;
                    }
                }
            });
        }

        $scope.remove_build_conf = function (build_conf_id) {
            var is_confirm = confirm('Are you sure remove build config #' + build_conf_id + '?');
            if (is_confirm) {
                $http.get('/api/remove_build_conf/' + build_conf_id).success(function (data) {
                    $scope.alerts.push(data);
                });
            }
        }

        $scope.getData = function () {
            $http.get('/api/build_confs/').success(function (data) {
                if ($scope.build_confs != data) {
                    $scope.build_confs = data;
                }
            });
        };
        setInterval($scope.getData, 1000);
    }]);

builderControllers.controller('BranchestListCtrl', ['$scope', '$http', 'Branch',
    function ($scope, $http, Branch) {
        $scope.branches = Branch.query();
        $scope.alerts = [];

        $scope.closeAlert = function (index) {
            $scope.alerts.splice(index, 1);
        };

        $scope.remove_branch = function (branch_id) {
            var is_confirm = confirm('Are you sure remove branch #' + branch_id + '?');
            if (is_confirm) {
                $http.get('/api/remove_branch/' + branch_id).success(function (data) {
                    $scope.alerts.push(data);
                });
            }
        }

        $scope.getData = function () {
            $http.get('/api/branches/').success(function (data) {
                if ($scope.branches != data) {
                    $scope.branches = data;
                }
            });
        };
        setInterval($scope.getData, 1000);
    }]);

builderControllers.controller('MappingCtrl', ['$scope', '$http', 'Mapping',
    function ($scope, $http, Mapping) {
        $scope.mappings = Mapping.query();
        $scope.alerts = [];

        $scope.closeAlert = function (index) {
            $scope.alerts.splice(index, 1);
        };

        $scope.remove_mapping = function (mapping_id) {
            var is_confirm = confirm('Are you sure remove mapping #' + mapping_id + '?');
            if (is_confirm) {
                $http.get('/api/remove_mapping/' + mapping_id).success(function (data) {
                    $scope.alerts.push(data);
                });
            }
        }

        $scope.getData = function () {
            $http.get('/api/mapping/').success(function (data) {
                if ($scope.mappings != data) {
                    $scope.mappings = data;
                }
            });
        };
        setInterval($scope.getData, 1000);
    }]);
<|endoftext|>


<commit_before>// Render Multiple URLs to file

var RenderUrlsToFile, arrayOfUrls, system;

system = require("system");

/*
Render given urls
@param array of URLs to render
@param callbackPerUrl Function called after finishing each URL, including the last URL
@param callbackFinal Function called after finishing everything
*/
RenderUrlsToFile = function(urls, callbackPerUrl, callbackFinal) {
    var getFilename, next, page, retrieve, urlIndex, webpage;
    urlIndex = 0;
    webpage = require("webpage");
    page = null;
    getFilename = function(theme, page) {
        var pg = page.split("8000/")[1];
        return theme + "-" + pg + ".png";
    };
    next = function(status, url, file) {
        page.close();
        callbackPerUrl(status, url, file);
        return retrieve();
    };
    retrieve = function() {
        var url;
        if (urls.length > 0) {
            url = urls.shift();
            urlIndex++;
            page = webpage.create();
            page.viewportSize = {
                width: 1920,
                height: 1280
            };
            page.settings.userAgent = "Phantom.js bot";
            return page.open("http://" + url, function(status) {
                var directory = "screens/";
                var file;
                var t = url.split("=")[1];
                var p = url.split(".html")[0];
                file = getFilename(t, p);
                if (status === "success") {
                    return window.setTimeout((function() {
                        page.render(directory + file);
                        return next(status, url, file);
                    }), 200);
                } else {
                    return next(status, url, file);
                }
            });
        } else {
            return callbackFinal();
        }
    };
    return retrieve();
};

arrayOfUrls = [];

var themes =  [ "composeconference"
              , "haskell.org"
              , "bronx"
              , "brooklyn"
              , "heraldsquare"
              , "queens"
              ];

function buildUrl(domain, theme) {
  var pages = ["index.html", "about.html", "contact.html", "archive.html"];
  var myURLs = [];
  for (var i in pages){
    var src = domain + pages[i];
    var url = src + "?theme=" + theme;
    myURLs.push(url);
  }
  return myURLs;
}

if (system.args.length > 1) {
    arrayOfUrls = Array.prototype.slice.call(system.args, 1);
} else {
    console.log("Usage: phantomjs render_multi_url.js [domain.name1, domain.name2, ...]");
    for (var t in themes){
      var domain = "localhost:8000/";
      arrayOfUrls.push.apply(arrayOfUrls, buildUrl(domain, themes[t]));
    }
}

RenderUrlsToFile(arrayOfUrls, (function(status, url, file) {
    if (status !== "success") {
        return console.log("Unable to render '" + url + "'");
    } else {
        return console.log("Rendered '" + url + "' at '" + file + "'");
    }
}), function() {
    return phantom.exit();
});
<commit_msg>1440x900 screengrabs<commit_after>// Render Multiple URLs to file

var RenderUrlsToFile, arrayOfUrls, system;

system = require("system");

/*
Render given urls
@param array of URLs to render
@param callbackPerUrl Function called after finishing each URL, including the last URL
@param callbackFinal Function called after finishing everything
*/
RenderUrlsToFile = function(urls, callbackPerUrl, callbackFinal) {
    var getFilename, next, page, retrieve, urlIndex, webpage;
    urlIndex = 0;
    webpage = require("webpage");
    page = null;
    getFilename = function(theme, page) {
        var pg = page.split("8000/")[1];
        return theme + "-" + pg + ".png";
    };
    next = function(status, url, file) {
        page.close();
        callbackPerUrl(status, url, file);
        return retrieve();
    };
    retrieve = function() {
        var url;
        if (urls.length > 0) {
            url = urls.shift();
            urlIndex++;
            page = webpage.create();
            page.viewportSize = {
                width: 1440,
                height: 900
            };
            page.settings.userAgent = "Phantom.js bot";
            return page.open("http://" + url, function(status) {
                var directory = "screens/";
                var file;
                var t = url.split("=")[1];
                var p = url.split(".html")[0];
                file = getFilename(t, p);
                if (status === "success") {
                    return window.setTimeout((function() {
                        page.render(directory + file);
                        return next(status, url, file);
                    }), 200);
                } else {
                    return next(status, url, file);
                }
            });
        } else {
            return callbackFinal();
        }
    };
    return retrieve();
};

arrayOfUrls = [];

var themes =  [ "composeconference"
              , "haskell.org"
              , "bronx"
              , "brooklyn"
              , "heraldsquare"
              , "queens"
              ];

function buildUrl(domain, theme) {
  var pages = ["index.html", "about.html", "contact.html", "archive.html"];
  var myURLs = [];
  for (var i in pages){
    var src = domain + pages[i];
    var url = src + "?theme=" + theme;
    myURLs.push(url);
  }
  return myURLs;
}

if (system.args.length > 1) {
    arrayOfUrls = Array.prototype.slice.call(system.args, 1);
} else {
    console.log("Usage: phantomjs render_multi_url.js [domain.name1, domain.name2, ...]");
    for (var t in themes){
      var domain = "localhost:8000/";
      arrayOfUrls.push.apply(arrayOfUrls, buildUrl(domain, themes[t]));
    }
}

RenderUrlsToFile(arrayOfUrls, (function(status, url, file) {
    if (status !== "success") {
        return console.log("Unable to render '" + url + "'");
    } else {
        return console.log("Rendered '" + url + "' at '" + file + "'");
    }
}), function() {
    return phantom.exit();
});
<|endoftext|>


<commit_before>angular.module('app.dashboard.directives').directive('myDeals', myDealsDirective);

function myDealsDirective() {
    return {
        scope: {},
        templateUrl: 'dashboard/directives/mydeals.html',
        controller: MyDealsController,
        controllerAs: 'vm',
    };
}

MyDealsController.$inject = ['$scope', 'Deal', 'HLUtils', 'LocalStorage', 'CaseDetail'];
function MyDealsController($scope, Deal, HLUtils, LocalStorage, CaseDetail) {
    var storage = LocalStorage('myDealsWidget');

    var vm = this;
    vm.highPrioDeals = 0;
    vm.table = {
        order: storage.get('order', {
            descending: true,
            column: 'next_step.date_increment', // string: current sorted column
        }),
        items: [],
        dueDateFilter: storage.get('dueDateFilter', ''),
        usersFilter: storage.get('usersFilter', ''),
    };

    vm.openPostponeWidget = openPostponeWidget;
    vm.getMyDeals = getMyDeals;
    vm.numOfDeals = 0;

    activate();

    /////

    function activate() {
        _watchTable();
    }

    function getMyDeals() {
        var field = 'next_step.position';
        var descending = false;

        var filterQuery = 'archived:false AND NOT next_step.name:"None"';

        if (vm.table.dueDateFilter) {
            filterQuery += ' AND ' + vm.table.dueDateFilter;
        } else {
            // Only display deals with a next step date.
            filterQuery += ' AND next_step_date:*';
        }

        if (vm.table.usersFilter) {
            filterQuery += ' AND (' + vm.table.usersFilter + ')';
        } else {
            filterQuery += ' AND assigned_to_id:' + currentUser.id;
        }

        var dealPromise = Deal.getDeals('', 1, 250, field, descending, filterQuery);
        dealPromise.then(function(data) {
            if (vm.table.dueDateFilter !== '') {
                // Add empty key to prevent showing a header and to not crash the for loop.
                vm.table.items = {
                    '': data,
                };
            } else {
                vm.table.items = HLUtils.timeCategorizeObjects(data, 'next_step_date');

                angular.forEach(data, function(deal) {
                    CaseDetail.query({filterquery: 'account:' + deal.account + ' AND archived:false'}).$promise.then(function(caseList) {
                        if (caseList.length > 0) {
                            deal.hasUnarchivedCases = true;
                        }
                    });
                });
            }

            vm.numOfDeals = data.length;
        });
    }

    function openPostponeWidget(deal) {
        var modalInstance = Deal.openPostponeWidget(deal, true);

        modalInstance.result.then(function() {
            getMyDeals();
        });
    }

    function _watchTable() {
        $scope.$watchGroup(['vm.table.dueDateFilter', 'vm.table.usersFilter'], function() {
            getMyDeals();
            storage.put('order', vm.table.order);
            storage.put('dueDateFilter', vm.table.dueDateFilter);
            storage.put('usersFilter', vm.table.usersFilter);
        });
    }
}
<commit_msg>LILY-1325: Show deals without next step date in my deals widget<commit_after>angular.module('app.dashboard.directives').directive('myDeals', myDealsDirective);

function myDealsDirective() {
    return {
        scope: {},
        templateUrl: 'dashboard/directives/mydeals.html',
        controller: MyDealsController,
        controllerAs: 'vm',
    };
}

MyDealsController.$inject = ['$scope', 'Deal', 'HLUtils', 'LocalStorage', 'CaseDetail'];
function MyDealsController($scope, Deal, HLUtils, LocalStorage, CaseDetail) {
    var storage = LocalStorage('myDealsWidget');

    var vm = this;
    vm.highPrioDeals = 0;
    vm.table = {
        order: storage.get('order', {
            descending: true,
            column: 'next_step.date_increment', // string: current sorted column
        }),
        items: [],
        dueDateFilter: storage.get('dueDateFilter', ''),
        usersFilter: storage.get('usersFilter', ''),
    };

    vm.openPostponeWidget = openPostponeWidget;
    vm.getMyDeals = getMyDeals;
    vm.numOfDeals = 0;

    activate();

    /////

    function activate() {
        _watchTable();
    }

    function getMyDeals() {
        var field = 'next_step.position';
        var descending = false;

        var filterQuery = 'archived:false AND NOT next_step.name:"None"';

        if (vm.table.dueDateFilter) {
            filterQuery += ' AND ' + vm.table.dueDateFilter;
        }

        if (vm.table.usersFilter) {
            filterQuery += ' AND (' + vm.table.usersFilter + ')';
        } else {
            filterQuery += ' AND assigned_to_id:' + currentUser.id;
        }

        var dealPromise = Deal.getDeals('', 1, 250, field, descending, filterQuery);
        dealPromise.then(function(data) {
            if (vm.table.dueDateFilter !== '') {
                // Add empty key to prevent showing a header and to not crash the for loop.
                vm.table.items = {
                    '': data,
                };
            } else {
                vm.table.items = HLUtils.timeCategorizeObjects(data, 'next_step_date');

                angular.forEach(data, function(deal) {
                    CaseDetail.query({filterquery: 'account:' + deal.account + ' AND archived:false'}).$promise.then(function(caseList) {
                        if (caseList.length > 0) {
                            deal.hasUnarchivedCases = true;
                        }
                    });
                });
            }

            vm.numOfDeals = data.length;
        });
    }

    function openPostponeWidget(deal) {
        var modalInstance = Deal.openPostponeWidget(deal, true);

        modalInstance.result.then(function() {
            getMyDeals();
        });
    }

    function _watchTable() {
        $scope.$watchGroup(['vm.table.dueDateFilter', 'vm.table.usersFilter'], function() {
            getMyDeals();
            storage.put('order', vm.table.order);
            storage.put('dueDateFilter', vm.table.dueDateFilter);
            storage.put('usersFilter', vm.table.usersFilter);
        });
    }
}
<|endoftext|>


<commit_before>Package.describe({
  name: 'svelte:tracker',
  version: '2.1.0',
  summary: 'Tracker integration for Svelte',
  git: 'https://github.com/meteor-svelte/svelte-tracker.git'
});

Package.onUse(function (api) {
  api.versionsFrom('1.4.2.3');
  api.use('tracker');

  // Compile ECMAScript and Svelte in this package.
  api.use([
    'ecmascript',
    'svelte:compiler@1.40.1_1'
  ]);

  api.mainModule('with-tracker.js');
});
<commit_msg>Make main module lazy<commit_after>Package.describe({
  name: 'svelte:tracker',
  version: '2.1.1',
  summary: 'Tracker integration for Svelte',
  git: 'https://github.com/meteor-svelte/svelte-tracker.git'
});

Package.onUse(function (api) {
  api.versionsFrom('1.4.2.3');
  api.use('tracker');

  // Compile ECMAScript and Svelte in this package.
  api.use([
    'ecmascript',
    'svelte:compiler@1.40.1_1'
  ]);

  api.mainModule('with-tracker.js', [
    'client',
    'server'
  ], { lazy: true });
});
<|endoftext|>


<commit_before>Package.describe({
    summary: "Meteor sign up and sign in templates core package.",
    version: "0.0.21",
    name: "splendido:accounts-templates-core",
    git: "https://github.com/splendido/accounts-templates-core.git",
});

Package.on_use(function(api) {
    api.versionsFrom("METEOR@0.9.0");

    api.use([
        'check',
        'deps',
        'accounts-base',
        'mrt:accounts-t9n@0.0.13',
        'iron:router@0.9.1',
        'underscore',
    ], ['client', 'server']);

    api.use([
        'minimongo',
        'mongo-livedata',
        'sha',
        'templating'
    ], 'client');

    api.add_files([
        'lib/core.js',
        'lib/server.js',
        'lib/methods.js',
    ], ['server']);

    api.add_files([
        'lib/utils.js',
        'lib/core.js',
        'lib/client.js',
        'lib/atForm.js',
        'lib/atInput.js',
        'lib/atSocial.js',
        'lib/methods.js',
    ], ['client']);

    api.imply([
        'accounts-base',
        'mrt:accounts-t9n@0.0.13',
        'iron:router@0.9.1',
    ], ['client', 'server']);

    api.export([
        'AccountsTemplates',
    ], ['client', 'server']);
});

Package.on_test(function(api) {
    api.use('splendido:accounts-templates-core');
    api.use([
        'tinytest',
        'test-helpers',
        'mrt:accounts-t9n@0.0.13',
        'iron:router@0.9.1',
    ], ['client', 'server']);
    api.add_files([
        'tests/accounts-templates-core_tests.js',
    ], ['client', 'server']);
});<commit_msg>package_0.8.3.js -> package.js<commit_after>Package.describe({
    summary: "Meteor sign up and sign in templates core package."
});

Package.on_use(function(api, where) {

    api.use([
        'check',
        'deps',
        'accounts-base',
        'accounts-t9n',
        'iron-router',
        'underscore',
    ], ['client', 'server']);

    api.use([
        'minimongo',
        'mongo-livedata',
        'sha',
        'templating'
    ], 'client');

    api.add_files([
        'lib/core.js',
        'lib/server.js',
        'lib/methods.js',
    ], ['server']);

    api.add_files([
        'lib/utils.js',
        'lib/core.js',
        'lib/client.js',
        'lib/atForm.js',
        'lib/atInput.js',
        'lib/atSocial.js',
        'lib/methods.js',
    ], ['client']);

    api.imply([
        'accounts-base',
        'accounts-t9n',
        'iron-router',
    ], ['client', 'server']);

    api.export([
        'AccountsTemplates',
    ], ['client', 'server']);
});

Package.on_test(function(api) {
    api.use('accounts-templates-core');
    api.use([
        'tinytest',
        'test-helpers',
        'accounts-t9n',
        'iron-router',
    ], ['client', 'server']);
    api.add_files([
        'tests/accounts-templates-core_tests.js',
    ], ['client', 'server']);
});<|endoftext|>


<commit_before>var namespace = new Namespace('ryepdx.openerp.quickship.kiosk');
var decorators = ryepdx.async.decorators;

/**
 * Handles communicating with the servers and providing data for the Controller class.
 *
 * @param api
 * @constructor
 */
namespace.Model = function Model (api, printerAPI, scaleAPI, actionAPI) {
    this._api = api;
    this._printerAPI = printerAPI;
    this._scaleAPI = scaleAPI;
    this._actionAPI = actionAPI;
    this._cache = {};
    this.reset();
};

/**
 * Clear out stateful data.
 */
namespace.Model.prototype.reset = function () {
    this._quotes = [];
};

/**
 * Gets a reading from the scale proxy server.
 * If no callback is passed in, it runs synchronously and returns the server's response as an object.
 * If a callback is passed in, it runs asynchronously and passes the server's response to the callback,
 * returning nothing.
 *
 * The callback should expect to take the server's response object as its first argument and an error
 * message as an optional second argument.
 *
 * @param timeout
 * @param callback (optional)
 * @returns undefined || {{ weight: *, unit: * }}
 */
namespace.Model.prototype.weigh = decorators.deferrable(function (ret, timeout) {
    // Scale input capturing.
    // "inf" = wait until the scale returns something, no timeouts.
    this._scaleAPI.weigh(timeout)
        .done(function (result) {
            if (!result || result.weight === undefined || result.unit === undefined) {
                ret.reject(result, "Unable to get scale reading!");
            } else {
                ret.resolve(result);
            }
        })
        .fail(function (result) {
            ret.reject(result);
        });
});

/**
 * Returns the user's Endicia/USPS account status.
 *
 * @param callback (optional)
 * @return {{*}}
 */
namespace.Model.prototype.getUspsAccount = decorators.deferrable(function (ret, test) {
    this._api.get_usps_account(test).done(function (response) {ret.resolve(response)});
});

/**
 * Returns the dimensions for a given package if a code is specified.
 * Returns a mapping of codes to dimensions if a code is not specified.
 *
 * @param code (optional)
 * @param bypassCache (optional)
 * @param callback (optional)
 * @return {{*}}
 */
namespace.Model.prototype.getPackageDimensions = decorators.deferrable(function (ret, code, bypassCache) {
    var that = this;

    if (bypassCache || typeof(that._cache.getPackageDimensions) == "undefined") {
        that._api.get_package_types().done(function (response) {
            var dimensions = {};

            for (var i=0; i < response.length; i++) {
                dimensions[response[i].code] = {
                    length: response[i].length,
                    width: response[i].width,
                    height: response[i].height
                };
            }
            that._cache.getPackageDimensions = dimensions;

            if (code) {
                ret.resolve(dimensions[code]);
            } else {
                ret.resolve(dimensions);
            }
        });
    } else {
        if (code) {
            ret.resolve(that._cache.getPackageDimensions[code]);
        } else {
            ret.resolve(that._cache.getPackageDimensions);
        }
    }
});

/**
 * Takes a sale order code and returns its OpenERP ID.
 *
 * @param sale_order_code
 * @return sale_order_id
 */
namespace.Model.prototype.getSaleOrderID = decorators.deferrable(function (ret, sale_order_code, bypassCache) {
    var that = this;

    if (typeof(that._cache.getSaleOrderID) == "undefined") {
        that._cache.getSaleOrderID = {};
    }

    if (bypassCache || typeof(that._cache.getSaleOrderID[sale_order_code] == "undefined")) {
        this._api.get_sale_order(sale_order_code).done(function (sale_orders) {
            if (sale_orders && sale_orders.length > 0) {
                that._cache.getSaleOrderID[sale_order_code] = sale_orders[0].id;
                ret.resolve(sale_orders[0].id);
            } else {
                ret.reject(sale_orders);
            }
        });
    } else {
        ret.resolve(that._cache.getSaleOrderID[sale_order_code]);
    }
});

/**
 * Create a package for the given sale order and get a list of shipping quotes for it.
 *
 * @param sale_order
 * @param package
 * @param include_library_mail
 * @param callback (optional)
 */
namespace.Model.prototype.getQuotes = decorators.deferrable(
    function (ret, pkg, sale_id, from_address, to_address, include_library_mail) {
        var that = this;

        that._api
        .get_quotes(pkg, sale_id, from_address, to_address)
        .done(function (result) {
           that._quotes = [];

           // Did we succeed or fail?
           if (result.error) {
               ret.reject(result);
               return;
           }

           // Sort quotes by price.
           result.quotes.sort(function (a, b) {
               return a.price - b.price;
           });

           // Filter out library mail, if user requested this.
           that._quotes = result.quotes.filter(function (quote) {
               return quote.service != "Library Mail" || include_library_mail;
           })

           ret.resolve(that._quotes);
        });
    }
);

/**
 * Create a package on the specified sale order.
 *
 * @param sale_order
 * @param package
 */
namespace.Model.prototype.createPackage = decorators.deferrable(function (ret, pkg, sale_id, num_packages) {
    var that = this;

    that._api
        .create_package(pkg, sale_id, num_packages)
        .done(function (response) {
           if (response.success) {
               that._pkg_id = response.id;
               ret.resolve(response);
           } else {
               that._pkg_id = null;
               ret.reject(response);
           }
        });
});

namespace.Model.prototype.getPackList = function (picking_id) {
    this._actionAPI.ir_actions_report_xml({
        "report_name": "stock.picking.list.out", "report_type":"pdf",
        "context": {"active_ids": [picking_id]}
    }, { on_close: function () {} });
}

/**
 * Return a quote in our quotes cache, specified by 0-based index.
 *
 * @param index
 * @returns {*}
 */
namespace.Model.prototype.getQuote = function (index) {
    if (!this._quotes) {
        throw "No quotes to pick from!"
    }

    if ((index % 1) != 0 || index >= this._quotes.length) {
        throw "'" + index + "' is not a valid label index.";
    }
    return this._quotes[index];
};

/**
 * Generates a label from a package ID.
 * If no callback is passed in, it runs synchronously and returns the server's response as an object.
 * If a callback is passed in, it runs asynchronously and passes the server's response to the callback,
 * returning nothing.
 *
 * The callback should expect to take the server's response object as its first argument and an error
 * message as an optional second argument.
 *
 * @param package_id
 * @param quote
 * @param callback (optional)
 * @returns undefined || {{*}}
 */
namespace.Model.prototype.getLabelByPackageID = decorators.deferrable(function (ret, package_id, quote, customs) {
    this._api.get_label_by_package_id(package_id, quote, customs)
        .done(function (result) {
            if (!result || !result.label) {
                ret.reject(result, "Unable to generate label!");
            } else {
                ret.resolve(result);
            }
        });
});

/**
 * Generates a label from a package object.
 * If no callback is passed in, it runs synchronously and returns the server's response as an object.
 * If a callback is passed in, it runs asynchronously and passes the server's response to the callback,
 * returning nothing.
 *
 * The callback should expect to take the server's response object as its first argument and an error
 * message as an optional second argument.
 *
 * @param package_id
 * @param quote
 * @param callback (optional)
 * @returns undefined || {{*}}
 */
namespace.Model.prototype.getLabelByPackage = decorators.deferrable(function (ret, pkg, from_address, to_address, quote, customs) {
    this._api.get_label_by_package(pkg, from_address, to_address, quote, customs)
        .done(function (result) {
            if (!result || !result.label) {
                ret.reject(result, "Unable to generate label!");
            } else {
                ret.resolve(result);
            }
        });
});

/**
 * Sends data of the specified format to the printer proxy.
 *
 * @param format
 * @param data
 * @param callback (optional)
 * @returns undefined || {{ weight: *, unit: * }}
 */
namespace.Model.prototype.print = decorators.deferrable(function (ret, format, data) {
    ret.resolve(this._printerAPI.print(format, data));
});

/**
 * Optionally takes a user ID and returns the user's QuickShip ID.
 * If no user ID is passed in, returns the current user's QuickShip ID.
 *
 * @param user_id (optional)
 * @return quickship_id
 */
namespace.Model.prototype.getQuickshipID = decorators.deferrable(function (ret, user_id) {
    this._api.get_quickship_id(user_id)
        .done(function (quickship_id) {
            ret.resolve(quickship_id);
        })
        .fail(function (response) {
            ret.reject(response);
        });
});<commit_msg>get_sale_order always returns an array.<commit_after>var namespace = new Namespace('ryepdx.openerp.quickship.kiosk');
var decorators = ryepdx.async.decorators;

/**
 * Handles communicating with the servers and providing data for the Controller class.
 *
 * @param api
 * @constructor
 */
namespace.Model = function Model (api, printerAPI, scaleAPI, actionAPI) {
    this._api = api;
    this._printerAPI = printerAPI;
    this._scaleAPI = scaleAPI;
    this._actionAPI = actionAPI;
    this._cache = {};
    this.reset();
};

/**
 * Clear out stateful data.
 */
namespace.Model.prototype.reset = function () {
    this._quotes = [];
};

/**
 * Gets a reading from the scale proxy server.
 * If no callback is passed in, it runs synchronously and returns the server's response as an object.
 * If a callback is passed in, it runs asynchronously and passes the server's response to the callback,
 * returning nothing.
 *
 * The callback should expect to take the server's response object as its first argument and an error
 * message as an optional second argument.
 *
 * @param timeout
 * @param callback (optional)
 * @returns undefined || {{ weight: *, unit: * }}
 */
namespace.Model.prototype.weigh = decorators.deferrable(function (ret, timeout) {
    // Scale input capturing.
    // "inf" = wait until the scale returns something, no timeouts.
    this._scaleAPI.weigh(timeout)
        .done(function (result) {
            if (!result || result.weight === undefined || result.unit === undefined) {
                ret.reject(result, "Unable to get scale reading!");
            } else {
                ret.resolve(result);
            }
        })
        .fail(function (result) {
            ret.reject(result);
        });
});

/**
 * Returns the user's Endicia/USPS account status.
 *
 * @param callback (optional)
 * @return {{*}}
 */
namespace.Model.prototype.getUspsAccount = decorators.deferrable(function (ret, test) {
    this._api.get_usps_account(test).done(function (response) {ret.resolve(response)});
});

/**
 * Returns the dimensions for a given package if a code is specified.
 * Returns a mapping of codes to dimensions if a code is not specified.
 *
 * @param code (optional)
 * @param bypassCache (optional)
 * @param callback (optional)
 * @return {{*}}
 */
namespace.Model.prototype.getPackageDimensions = decorators.deferrable(function (ret, code, bypassCache) {
    var that = this;

    if (bypassCache || typeof(that._cache.getPackageDimensions) == "undefined") {
        that._api.get_package_types().done(function (response) {
            var dimensions = {};

            for (var i=0; i < response.length; i++) {
                dimensions[response[i].code] = {
                    length: response[i].length,
                    width: response[i].width,
                    height: response[i].height
                };
            }
            that._cache.getPackageDimensions = dimensions;

            if (code) {
                ret.resolve(dimensions[code]);
            } else {
                ret.resolve(dimensions);
            }
        });
    } else {
        if (code) {
            ret.resolve(that._cache.getPackageDimensions[code]);
        } else {
            ret.resolve(that._cache.getPackageDimensions);
        }
    }
});

/**
 * Takes a sale order code and returns its OpenERP ID.
 *
 * @param sale_order_code
 * @return sale_order_id
 */
namespace.Model.prototype.getSaleOrderID = decorators.deferrable(function (ret, sale_order_code, bypassCache) {
    var that = this;

    if (typeof(that._cache.getSaleOrderID) == "undefined") {
        that._cache.getSaleOrderID = {};
    }

    if (bypassCache || typeof(that._cache.getSaleOrderID[sale_order_code] == "undefined")) {
        this._api.get_sale_order(sale_order_code).done(function (sale_orders) {
            var sale_order = sale_orders[0];

            if (sale_order) {
                that._cache.getSaleOrderID[sale_order_code] = sale_orders[0].id;
                ret.resolve(sale_order.id);
            } else {
                ret.reject(sale_order);
            }
        });
    } else {
        ret.resolve(that._cache.getSaleOrderID[sale_order_code]);
    }
});

/**
 * Create a package for the given sale order and get a list of shipping quotes for it.
 *
 * @param sale_order
 * @param package
 * @param include_library_mail
 * @param callback (optional)
 */
namespace.Model.prototype.getQuotes = decorators.deferrable(
    function (ret, pkg, sale_id, from_address, to_address, include_library_mail) {
        var that = this;

        that._api
        .get_quotes(pkg, sale_id, from_address, to_address)
        .done(function (result) {
           that._quotes = [];

           // Did we succeed or fail?
           if (result.error) {
               ret.reject(result);
               return;
           }

           // Sort quotes by price.
           result.quotes.sort(function (a, b) {
               return a.price - b.price;
           });

           // Filter out library mail, if user requested this.
           that._quotes = result.quotes.filter(function (quote) {
               return quote.service != "Library Mail" || include_library_mail;
           })

           ret.resolve(that._quotes);
        });
    }
);

/**
 * Create a package on the specified sale order.
 *
 * @param sale_order
 * @param package
 */
namespace.Model.prototype.createPackage = decorators.deferrable(function (ret, pkg, sale_id, num_packages) {
    var that = this;

    that._api
        .create_package(pkg, sale_id, num_packages)
        .done(function (response) {
           if (response.success) {
               that._pkg_id = response.id;
               ret.resolve(response);
           } else {
               that._pkg_id = null;
               ret.reject(response);
           }
        });
});

namespace.Model.prototype.getPackList = function (picking_id) {
    this._actionAPI.ir_actions_report_xml({
        "report_name": "stock.picking.list.out", "report_type":"pdf",
        "context": {"active_ids": [picking_id]}
    }, { on_close: function () {} });
}

/**
 * Return a quote in our quotes cache, specified by 0-based index.
 *
 * @param index
 * @returns {*}
 */
namespace.Model.prototype.getQuote = function (index) {
    if (!this._quotes) {
        throw "No quotes to pick from!"
    }

    if ((index % 1) != 0 || index >= this._quotes.length) {
        throw "'" + index + "' is not a valid label index.";
    }
    return this._quotes[index];
};

/**
 * Generates a label from a package ID.
 * If no callback is passed in, it runs synchronously and returns the server's response as an object.
 * If a callback is passed in, it runs asynchronously and passes the server's response to the callback,
 * returning nothing.
 *
 * The callback should expect to take the server's response object as its first argument and an error
 * message as an optional second argument.
 *
 * @param package_id
 * @param quote
 * @param callback (optional)
 * @returns undefined || {{*}}
 */
namespace.Model.prototype.getLabelByPackageID = decorators.deferrable(function (ret, package_id, quote, customs) {
    this._api.get_label_by_package_id(package_id, quote, customs)
        .done(function (result) {
            if (!result || !result.label) {
                ret.reject(result, "Unable to generate label!");
            } else {
                ret.resolve(result);
            }
        });
});

/**
 * Generates a label from a package object.
 * If no callback is passed in, it runs synchronously and returns the server's response as an object.
 * If a callback is passed in, it runs asynchronously and passes the server's response to the callback,
 * returning nothing.
 *
 * The callback should expect to take the server's response object as its first argument and an error
 * message as an optional second argument.
 *
 * @param package_id
 * @param quote
 * @param callback (optional)
 * @returns undefined || {{*}}
 */
namespace.Model.prototype.getLabelByPackage = decorators.deferrable(function (ret, pkg, from_address, to_address, quote, customs) {
    this._api.get_label_by_package(pkg, from_address, to_address, quote, customs)
        .done(function (result) {
            if (!result || !result.label) {
                ret.reject(result, "Unable to generate label!");
            } else {
                ret.resolve(result);
            }
        });
});

/**
 * Sends data of the specified format to the printer proxy.
 *
 * @param format
 * @param data
 * @param callback (optional)
 * @returns undefined || {{ weight: *, unit: * }}
 */
namespace.Model.prototype.print = decorators.deferrable(function (ret, format, data) {
    ret.resolve(this._printerAPI.print(format, data));
});

/**
 * Optionally takes a user ID and returns the user's QuickShip ID.
 * If no user ID is passed in, returns the current user's QuickShip ID.
 *
 * @param user_id (optional)
 * @return quickship_id
 */
namespace.Model.prototype.getQuickshipID = decorators.deferrable(function (ret, user_id) {
    this._api.get_quickship_id(user_id)
        .done(function (quickship_id) {
            ret.resolve(quickship_id);
        })
        .fail(function (response) {
            ret.reject(response);
        });
});
<|endoftext|>


<commit_before>const req = require("request")
const semver = require("semver")
const replace = require("replace")
const _ = require("lodash")

const badgeRegex = /\[!\[v\d\.\d\.\d\sprogress\]\(http:\/\/progressed\.io\/bar\/\d{1,3}\?title=v\d\.\d\.\d\)\]\(https:\/\/github.com\/kristerkari\/stylelint-scss\/milestones\/\d\.\d\.\d\)/

const options = {
  url: "https://api.github.com/repos/kristerkari/stylelint-scss/milestones",
  headers: {
    "User-Agent": "request",
  },
}

req.get(options, (err, resp) => {
  if (err) { throw err }
  if (!resp.body) { return }

  const body = JSON.parse(resp.body)

  if (!_.isArray(body)) { return }

  const openMilestones = _.filter(body, (m) => m.open_issues > 0 && m.state !== "closed")

  if (!openMilestones.length) { return }

  const versions = _.map(openMilestones, (m) => m.title)
  const newestVersion = semver.maxSatisfying(versions, "*").replace(/$v/, "")
  const newestMilestone = _.find(body, (m) => m.title === newestVersion)
  const totalIssues = newestMilestone.open_issues + newestMilestone.closed_issues
  const percentage = newestMilestone.closed_issues / totalIssues * 100

  const badge = `[![v${newestVersion} progress](http://progressed.io/bar/${percentage}?title=v${newestVersion})](https://github.com/kristerkari/stylelint-scss/milestones/${newestVersion})`

  replace({
    regex: badgeRegex,
    replacement: badge,
    paths: ["README.md"],
    silent: true,
  })

})
<commit_msg>Fix milestone regex to also support bigger versions<commit_after>const req = require("request")
const semver = require("semver")
const replace = require("replace")
const _ = require("lodash")

const badgeRegex = /\[!\[v\d{1,3}\.\d{1,3}\.\d{1,3}\sprogress\]\(http:\/\/progressed\.io\/bar\/\d{1,3}\?title=v\d{1,3}\.\d{1,3}\.\d{1,3}\)\]\(https:\/\/github.com\/kristerkari\/stylelint-scss\/milestones\/\d{1,3}\.\d{1,3}\.\d{1,3}\)/

const options = {
  url: "https://api.github.com/repos/kristerkari/stylelint-scss/milestones",
  headers: {
    "User-Agent": "request",
  },
}

req.get(options, (err, resp) => {
  if (err) { throw err }
  if (!resp.body) { return }

  const body = JSON.parse(resp.body)

  if (!_.isArray(body)) { return }

  const openMilestones = _.filter(body, (m) => m.open_issues > 0 && m.state !== "closed")

  if (!openMilestones.length) { return }

  const versions = _.map(openMilestones, (m) => m.title)
  const newestVersion = semver.maxSatisfying(versions, "*").replace(/$v/, "")
  const newestMilestone = _.find(body, (m) => m.title === newestVersion)
  const totalIssues = newestMilestone.open_issues + newestMilestone.closed_issues
  const percentage = newestMilestone.closed_issues / totalIssues * 100

  const badge = `[![v${newestVersion} progress](http://progressed.io/bar/${percentage}?title=v${newestVersion})](https://github.com/kristerkari/stylelint-scss/milestones/${newestVersion})`

  replace({
    regex: badgeRegex,
    replacement: badge,
    paths: ["README.md"],
    silent: true,
  })

})
<|endoftext|>