<commit_before>'use strict';

angular.module('MyApp.controllers')
.value('BASE_URL', 'https://noticeapp.firebaseio.com/')
.controller('DashboardCtrl', function($firebase, $scope, Auth, md5, $ionicModal, User, $http) {
    var noticeRef = new Firebase('https://trynotice.firebaseio.com/notifications');
    $scope.notifications = $firebase(noticeRef);

    $scope.email = Auth.currentUser.email;
    $scope.message = '';
    $scope.activityName = '';
    $scope.isStudent = /([\._a-zA-Z0-9-]+@students.d211.org)/.test($scope.email);

    $http.get(User.getSubscriptions())
    .success(function(data) {
        if(data == null) {
            $scope.subscriptions = [{ id: 1, name: 'Math Team', color: '#43cee6', isChecked: false },
            { id: 2, name: 'Basketball', color: '#4a87ee', isChecked: false },
            { id: 3, name: 'Horticulture Club', color: '#ef4e3a', isChecked: false },
            { id: 4, name: 'Science Olympiad', color: '#8a6de9', isChecked: false }];
        }

        else {
            $scope.subscriptions = data;
        }
    });

    $scope.gravatarURL = 'http://www.gravatar.com/avatar/' + md5.createHash($scope.email);

    $scope.manage = function() {
        User.manageSubscriptions($scope.subscriptions);
    };

    $scope.postNotification = function(message, tag, color) {
        $scope.notifications.$add({message: message, createdBy: $scope.email, gravatarURL: $scope.gravatarURL, dateCreated: Date.now(), tag: tag, color: color});
  	    $scope.message = null;
    };

    $scope.getGravatar = function(md5) {
        return 'http://www.gravatar.com/avatar/' + notifications.md5;
    };

    $ionicModal.fromTemplateUrl('templates/modal.html', {
        scope: $scope
    }).then(function(modal) {
        $scope.modal = modal;
    });

    $scope.filterSubscriptions = function(index) {
        console.log(index);
        console.log($scope.subscriptions[0].tagName)
        console.log($scope.notifications[0].tag)
        if($scope.subscriptions[index].tagName == $scope.notifications[index].tag) {
            return true;
        }
        else {
            return false;
        }
    };
})
.filter('reverse', function() {
      function toArray(list) {
         var k, out = [];
         if( list ) {
            if( angular.isArray(list) ) {
               out = list;
            }
            else if( typeof(list) === 'object' ) {
               for (k in list) {
                  if (list.hasOwnProperty(k)) { out.push(list[k]); }
               }
            }
         }
         return out;
      }
      return function(items) {
         return toArray(items).slice().reverse();
      };
});
<commit_msg>Update dashboard-controller.js<commit_after>'use strict';

angular.module('MyApp.controllers')
.value('BASE_URL', 'https://noticeapp.firebaseio.com/')
.controller('DashboardCtrl', function($firebase, $scope, Auth, md5, $ionicModal, User, $http) {
    var noticeRef = new Firebase('https://trynotice.firebaseio.com/notifications');
    $scope.notifications = $firebase(noticeRef);

    $scope.email = Auth.currentUser.email;
    $scope.message = '';
    $scope.activityName = '';
    $scope.isStudent = /([\._a-zA-Z0-9-]+@students.d211.org)/.test($scope.email);

    $http.get(User.getSubscriptions())
    .success(function(data) {
        if(data == null) {
            $scope.subscriptions = [{ id: 1, name: 'Math Team', color: '#43cee6', isChecked: false },
            { id: 2, name: 'Basketball', color: '#4a87ee', isChecked: false },
            { id: 3, name: 'Horticulture Club', color: '#ef4e3a', isChecked: false },
            { id: 4, name: 'Science Olympiad', color: '#8a6de9', isChecked: false }];
        }

        else {
            $scope.subscriptions = data;
        }
    });

    $scope.gravatarURL = 'http://www.gravatar.com/avatar/' + md5.createHash($scope.email);

    $scope.manage = function() {
        User.manageSubscriptions($scope.subscriptions);
    };

    $scope.postNotification = function(message, tag, color) {
        $scope.notifications.$add({message: message, createdBy: $scope.email, gravatarURL: $scope.gravatarURL, dateCreated: Date.now(), tag: tag, color: color});
  	    $scope.message = null;
    };

    $scope.getGravatar = function(md5) {
        return 'http://www.gravatar.com/avatar/' + notifications.md5;
    };

    $ionicModal.fromTemplateUrl('templates/modal.html', {
        scope: $scope
    }).then(function(modal) {
        $scope.modal = modal;
    });

    $scope.filterSubscriptions = function(index) {
        console.log(User.getSubscriptions())
        if($scope.subscriptions[index].tagName == $scope.notifications[index].tag) {
            return true;
        }
        else {
            return false;
        }
    };
})
.filter('reverse', function() {
      function toArray(list) {
         var k, out = [];
         if( list ) {
            if( angular.isArray(list) ) {
               out = list;
            }
            else if( typeof(list) === 'object' ) {
               for (k in list) {
                  if (list.hasOwnProperty(k)) { out.push(list[k]); }
               }
            }
         }
         return out;
      }
      return function(items) {
         return toArray(items).slice().reverse();
      };
});
<|endoftext|>


<commit_before>
import vec2 from '../vec2'
import Curve from './curve'
import {EPSILON} from '../constants'

class EllipseArc extends Curve {

  /**
   * @param {number[]} center - Center of ellipse
   * @param {number} rx - Radius along X
   * @param {number} ry - Radius along Y
   * @param {number} start - Start angle in radians
   * @param {number} end - End angle in radians
   * @param {boolean} ccw - Counter Clock Wise
   */
  constructor(center, rx, ry, start, end, ccw) {

    super();

    /**
     * @type {number[]}
     */
    this.center = center;
    /**
     * @type {number}
     */
    this.rx = rx;
    /**
     * @type {number}
     */
    this.ry = ry;
    /**
     * @type {number}
     */
    this.start = start;
    /**
     * @type {number}
     */
    this.end = end;
    /**
     * @type {boolean}
     */
    this.ccw = ccw;

  }

  /**
   * Evaluate point on arc at angle t
   * @param {number} t - Angle in radians
   * @returns {number[]}
   */
  evaluate(t) {
    let [cx,cy] = this.center;
    return [
      cx + this.rx * Math.cos(t),
      cy + this.ry * Math.sin(t)
    ];
  }

  toCanvasPathDef() {

  }

  /**
   * Create circular arc that starts from pA, ends at pB and passes through pC
   * @param {number[]} pA
   * @param {number[]} pB
   * @param {number[]} pC
   * @returns {EllipseArc}
   */
  static circularArcFrom3Points(pA,pB,pC) {
    let ax = pA[0], ay = pA[1];
    let bx = pB[0], by = pB[1];
    let cx = pC[0], cy = pC[1];

    // Ref: https://en.wikipedia.org/wiki/Circumscribed_circle#Circumcenter_coordinates
    let D = 2 * (ax * (by-cy) + bx * (cy-ay) + cx * (ay-by));
    if(Math.abs(D) < EPSILON) {
      return {
        center : [Infinity, Infinity],
        radius : Infinity
      };
    }
    let x = ((ax * ax + ay * ay) * (by - cy) +
      (bx * bx + by * by) * (cy - ay) +
      (cx * cx + cy * cy) * (ay - by))/D;
    let y = ((ax * ax + ay * ay) * (cx - bx) +
      (bx * bx + by * by) * (ax - cx) +
      (cx * cx + cy * cy) * (bx - ax))/D;
    let center = [x,y];

    let startAngle = getCircleAngle(center, pA),
      throughAngle = getCircleAngle(center, pB),
      endAngle = getCircleAngle(center, pC);

    let minAngle = Math.min(startAngle, endAngle);
    let maxAngle = Math.max(startAngle, endAngle);

    let ccw = minAngle > throughAngle || throughAngle > maxAngle;

    let reversed = (minAngle !== startAngle);

    let radius = vec2.dist(pA, center);

    return new EllipseArc(center, radius, radius, minAngle, maxAngle, ccw);
  }

  static circularArcFrom2PointsAndRadius(pA, pB, radius, sideflag) {

  }

}

function getCircleAngle(center, pt) {
  let dot = vec2.dot([1,0], vec2.unit(vec2.sub(pt, center)));
  if(pt[1] > center[1]) {
    return wrapAngle(Math.acos(dot));
  } else {
    return wrapAngle(2*Math.PI - Math.acos(dot));
  }
}

function wrapAngle(angle) {
  while(angle < 0) {
    angle = angle + 2*Math.PI;
  }
  while(angle > 2*Math.PI) {
    angle = angle - 2*Math.PI;
  }
  return angle;
}

export default EllipseArc;<commit_msg>Fix the error in documentation of routine<commit_after>
import vec2 from '../vec2'
import Curve from './curve'
import {EPSILON} from '../constants'

class EllipseArc extends Curve {

  /**
   * @param {number[]} center - Center of ellipse
   * @param {number} rx - Radius along X
   * @param {number} ry - Radius along Y
   * @param {number} start - Start angle in radians
   * @param {number} end - End angle in radians
   * @param {boolean} ccw - Counter Clock Wise
   */
  constructor(center, rx, ry, start, end, ccw) {

    super();

    /**
     * @type {number[]}
     */
    this.center = center;
    /**
     * @type {number}
     */
    this.rx = rx;
    /**
     * @type {number}
     */
    this.ry = ry;
    /**
     * @type {number}
     */
    this.start = start;
    /**
     * @type {number}
     */
    this.end = end;
    /**
     * @type {boolean}
     */
    this.ccw = ccw;

  }

  /**
   * Evaluate point on arc at angle t
   * @param {number} t - Angle in radians
   * @returns {number[]}
   */
  evaluate(t) {
    let [cx,cy] = this.center;
    return [
      cx + this.rx * Math.cos(t),
      cy + this.ry * Math.sin(t)
    ];
  }

  toCanvasPathDef() {

  }

  /**
   * Create circular arc that starts from pA, ends at pC and passes through pB
   * @param {number[]} pA Start point
   * @param {number[]} pB Through point
   * @param {number[]} pC End point
   * @returns {EllipseArc|null}
   */
  static circularArcFrom3Points(pA,pB,pC) {
    let ax = pA[0], ay = pA[1];
    let bx = pB[0], by = pB[1];
    let cx = pC[0], cy = pC[1];

    // Ref: https://en.wikipedia.org/wiki/Circumscribed_circle#Circumcenter_coordinates
    let D = 2 * (ax * (by-cy) + bx * (cy-ay) + cx * (ay-by));
    if(Math.abs(D) < EPSILON) {
      return null;
    }
    let x = ((ax * ax + ay * ay) * (by - cy) +
      (bx * bx + by * by) * (cy - ay) +
      (cx * cx + cy * cy) * (ay - by))/D;
    let y = ((ax * ax + ay * ay) * (cx - bx) +
      (bx * bx + by * by) * (ax - cx) +
      (cx * cx + cy * cy) * (bx - ax))/D;
    let center = [x,y];

    let startAngle = getCircleAngle(center, pA),
      throughAngle = getCircleAngle(center, pB),
      endAngle = getCircleAngle(center, pC);

    let minAngle = Math.min(startAngle, endAngle);
    let maxAngle = Math.max(startAngle, endAngle);

    let ccw = minAngle > throughAngle || throughAngle > maxAngle;

    let reversed = (minAngle !== startAngle);

    let radius = vec2.dist(pA, center);

    return new EllipseArc(center, radius, radius, minAngle, maxAngle, ccw);
  }

  static circularArcFrom2PointsAndRadius(pA, pB, radius, sideflag) {

  }

}

function getCircleAngle(center, pt) {
  let dot = vec2.dot([1,0], vec2.unit(vec2.sub(pt, center)));
  if(pt[1] > center[1]) {
    return wrapAngle(Math.acos(dot));
  } else {
    return wrapAngle(2*Math.PI - Math.acos(dot));
  }
}

function wrapAngle(angle) {
  while(angle < 0) {
    angle = angle + 2*Math.PI;
  }
  while(angle > 2*Math.PI) {
    angle = angle - 2*Math.PI;
  }
  return angle;
}

export default EllipseArc;<|endoftext|>


<commit_before>"use strict";

class TopicReplyCounter {
  constructor(topicId, replies) {
    this.topicId = topicId;
    this.replies = replies;
    this.replyCount = this.replies.length;
  }

  addReply(reply) {

  }

  totalReplies() {
    return this.replies.filter(reply => !reply.isAbuse);
  }

  totalCount() {
    return this.replyCount;
  }
}<commit_msg>Add default value for this.replies. Complete addReply<commit_after>"use strict";

class TopicReplyCounter {
  constructor(topicId, replies) {
    this.topicId = topicId;
    this.replies = replies || [];
    this.replyCount = this.replies.length;
  }

  addReply(reply) {
    this.replies.push(reply);
    this.replyCount = this.totalReplies().length;
  }

  totalReplies() {
    return this.replies.filter(reply => !reply.isAbuse);
  }

  totalCount() {
    return this.replyCount;
  }
}<|endoftext|>


<commit_before>var qs = require('querystring');
var iconv = require('iconv-lite');
var vm = require('vm');
var util = require('../util');
var extend = require('util')._extend;
var Transform = require('pipestream').Transform;
var WhistleTransform = util.WhistleTransform;
var MAX_REQ_SIZE = 256 * 1024;
var REQ_TYPE = {
		'urlencoded': 'application/x-www-form-urlencoded',
		'form': 'application/x-www-form-urlencoded',
		'json': 'application/json',
		'text': 'text/plain',
		'upload': 'multipart/form-data',
		'multipart': 'multipart/form-data',
		'default': 'application/octet-stream'
};

/**
 * 处理请求数据
 *
 * @param req：method、body、headers，top，bottom，speed、delay，charset,timeout
 * @param data
 */
function handleReq(req, data) {
	if (data.headers) {
		data.headers = util.lowerCaseify(data.headers);
	}
	req.method = data.method || req.method;
	req.timeout = parseInt(data.timeout, 10);
	extend(req.headers, data.headers);
	var method = req.method = typeof req.method != 'string' ? 'GET' : req.method.toUpperCase();
	if (!util.hasRequestBody(method)) {
		delete data.top;
		delete data.bottom;
		delete data.body;
	} else if (data.top || data.bottom || data.body) {
		delete req.headers['content-length'];
	}

	!util.isEmptyObject(data) && req.add(new WhistleTransform(data));
}

function handleCors(data, cors) {
	if (!cors) {
		return;
	}

	if (cors.origin !== undefined) {
		util.setHeader(data, 'origin', cors.origin);
	}

	if (cors.method !== undefined) {
		util.setHeader(data, 'access-control-request-method', cors.method);
	}

	if (cors.headers !== undefined) {
		util.setHeader(data, 'access-control-request-headers', cors.headers);
	}
}

function handleAuth(data, auth) {
	if (!auth) {
		return;
	}

	var basic = [];
	auth.username != null && basic.push(auth.username);
	auth.password != null && basic.push(auth.password);
	if (basic = basic.join(':')) {
		util.setHeader(data, 'authorization', 'Basic ' + new Buffer(basic).toString('base64'));
	}
}

function handleCookies(data, cookies, curCookies) {
	var list = cookies && Object.keys(cookies);
	if (list && list.length) {
		var result = {};
		if (curCookies && typeof curCookies == 'string') {
			curCookies.split(/;\s*/g)
					.forEach(function(cookie) {
						var index = cookie.indexOf('=');
						if (index == -1) {
							result[cookie] = null;
						} else {
							result[cookie.substring(0, index)] = cookie.substring(index + 1);
						}
					});
		}

		list.forEach(function(name) {
			var value = cookies[name];
			value = value && typeof value == 'object' ? value.value : value;
			result[util.encodeURIComponent(name)] = value ? util.encodeURIComponent(value) : value;
		});

		cookies = Object.keys(result).map(function(name) {
			var value = result[name];
			return name + (value == null ? '' : '=' + value);
		}).join('; ');
		util.setHeader(data, 'cookie', cookies);
	}
}

function handleUrlParams(req, urlParams) {
	if (urlParams) {
		req.fullUrl = util.replaceUrlQueryString(req.fullUrl, urlParams);
	}
}

function handleParams(req, params) {
	if (!(params = params && qs.stringify(params))) {
		return;
	}

	if (!req.method || /^GET$/i.test(req.method)) {
		req.fullUrl = util.replaceUrlQueryString(req.fullUrl, params);
	} else if (util.isUrlEncoded(req)) {
		delete req.headers['content-length'];
		var transform = new Transform();
		var buffer, interrupt;
		transform._transform = function(chunk, encoding, callback) {
			if (chunk) {
				if (!interrupt) {
					buffer = buffer ? Buffer.concat([buffer, chunk]) : chunk;
					chunk = null;
					if (buffer.length > MAX_REQ_SIZE) {
						interrupt = true;
						chunk = buffer;
						buffer = null;
					}
				}
			} else if (buffer) {
				var body = buffer + '';
				var isGBK = body.indexOf('�') == -1;
				if (isGBK) {
					body = iconv.decode(buffer, 'GB18030');
					body = util.replaceQueryString(body, params);
					chunk = iconv.encode(body, 'GB18030');
				} else {
					chunk = new Buffer(body);
				}
				buffer = null;
			} else {
				chunk = new Buffer(params);
			}

			callback(null, chunk);
		};
		req.add(transform);
	}
}

module.exports = function(req, res, next) {
	var reqRules = req.rules;
	util.parseRuleJson([reqRules.req, reqRules.reqHeaders, reqRules.reqCookies,
	                    reqRules.auth, reqRules.urlParams, reqRules.params, reqRules.reqCors],
			function(data, headers, cookies, auth, urlParams, params, cors) {
		if (reqRules.head && reqRules.head.req) {
			data = extend(reqRules.head.req, data);
		}
		data = data || {};
		if (headers) {
			data.headers = headers;
		}

		util.readInjectFiles(data, function(data) {
			util.getRuleValue([reqRules.reqBody, reqRules.reqPrepend, reqRules.reqAppend],
				function(reqBody, reqPrepend, reqAppend) {
					if (reqBody) {
						data.body = reqBody;
					}

					if (reqPrepend) {
						data.top = reqPrepend;
					}

					if (reqAppend) {
						data.append = reqAppend;
					}

					var method = util.getMatcherValue(reqRules.method);
					if (method) {
						data.method = method;
					}

					var type = util.getMatcherValue(reqRules.reqType);
					if (type) {
						type = type.indexOf('/') != -1 ? type : (REQ_TYPE[type] || REQ_TYPE['default']);
						util.setHeader(data, 'content-type', type);
					}

					var referer = util.getMatcherValue(reqRules.referer);
					if (referer) {
						util.setHeader(data, 'referer', referer);
					}

					var ua = util.getMatcherValue(reqRules.ua);
					if (ua) {
						util.setHeader(data, 'user-agent', ua);
					}

					var reqDelay = util.getMatcherValue(reqRules.reqDelay);
					reqDelay = reqDelay && parseInt(reqDelay, 10);
					if (reqDelay > 0) {
						data.delay = reqDelay;
					}

					var reqSpeed = util.getMatcherValue(reqRules.reqSpeed);
					reqSpeed = reqSpeed && parseFloat(reqSpeed);
					if (reqSpeed > 0) {
						data.speed = reqSpeed;
					}

					handleCookies(data, cookies, req.headers.cookie);
					handleAuth(data, auth);
					handleCors(data, cors);
					handleReq(req, data);
					handleUrlParams(req, urlParams);
					handleParams(req, params);
					util.removeUnsupportsHeaders(req.headers);

					next();
				});
		});
	});
};<commit_msg>refine code<commit_after>var qs = require('querystring');
var iconv = require('iconv-lite');
var vm = require('vm');
var util = require('../util');
var extend = require('util')._extend;
var Transform = require('pipestream').Transform;
var WhistleTransform = util.WhistleTransform;
var MAX_REQ_SIZE = 256 * 1024;
var REQ_TYPE = {
		'urlencoded': 'application/x-www-form-urlencoded',
		'form': 'application/x-www-form-urlencoded',
		'json': 'application/json',
		'text': 'text/plain',
		'upload': 'multipart/form-data',
		'multipart': 'multipart/form-data',
		'default': 'application/octet-stream'
};

/**
 * 处理请求数据
 *
 * @param req：method、body、headers，top，bottom，speed、delay，charset,timeout
 * @param data
 */
function handleReq(req, data) {
	if (data.headers) {
		data.headers = util.lowerCaseify(data.headers);
	}
	req.method = data.method || req.method;
	req.timeout = parseInt(data.timeout, 10);
	extend(req.headers, data.headers);
	var method = req.method = typeof req.method != 'string' ? 'GET' : req.method.toUpperCase();
	if (!util.hasRequestBody(method)) {
		delete data.top;
		delete data.bottom;
		delete data.body;
	} else if (data.top || data.bottom || data.body) {
		delete req.headers['content-length'];
	}

	!util.isEmptyObject(data) && req.add(new WhistleTransform(data));
}

function handleCors(data, cors) {
	if (!cors) {
		return;
	}

	if (cors.origin !== undefined) {
		util.setHeader(data, 'origin', cors.origin);
	}

	if (cors.method !== undefined) {
		util.setHeader(data, 'access-control-request-method', cors.method);
	}

	if (cors.headers !== undefined) {
		util.setHeader(data, 'access-control-request-headers', cors.headers);
	}
}

function handleAuth(data, auth) {
	if (!auth) {
		return;
	}

	var basic = [];
	auth.username != null && basic.push(auth.username);
	auth.password != null && basic.push(auth.password);
	if (basic = basic.join(':')) {
		util.setHeader(data, 'authorization', 'Basic ' + new Buffer(basic).toString('base64'));
	}
}

function handleCookies(data, cookies, curCookies) {
	var list = cookies && Object.keys(cookies);
	if (list && list.length) {
		var result = {};
		if (curCookies && typeof curCookies == 'string') {
			curCookies.split(/;\s*/g)
					.forEach(function(cookie) {
						var index = cookie.indexOf('=');
						if (index == -1) {
							result[cookie] = null;
						} else {
							result[cookie.substring(0, index)] = cookie.substring(index + 1);
						}
					});
		}

		list.forEach(function(name) {
			var value = cookies[name];
			value = value && typeof value == 'object' ? value.value : value;
			result[util.encodeURIComponent(name)] = value ? util.encodeURIComponent(value) : value;
		});

		cookies = Object.keys(result).map(function(name) {
			var value = result[name];
			return name + (value == null ? '' : '=' + value);
		}).join('; ');
		util.setHeader(data, 'cookie', cookies);
	}
}

function handleUrlParams(req, urlParams) {
	if (urlParams) {
		req.fullUrl = util.replaceUrlQueryString(req.fullUrl, urlParams);
	}
}

function handleParams(req, params) {
	if (!(params = params && qs.stringify(params))) {
		return;
	}

	if (!req.method || /^GET$/i.test(req.method)) {
		req.fullUrl = util.replaceUrlQueryString(req.fullUrl, params);
	} else if (util.isUrlEncoded(req)) {
		delete req.headers['content-length'];
		var transform = new Transform();
		var buffer, interrupt;
		transform._transform = function(chunk, encoding, callback) {
			if (chunk) {
				if (!interrupt) {
					buffer = buffer ? Buffer.concat([buffer, chunk]) : chunk;
					chunk = null;
					if (buffer.length > MAX_REQ_SIZE) {
						interrupt = true;
						chunk = buffer;
						buffer = null;
					}
				}
			} else if (buffer) {
				var body = buffer + '';
				var isGBK = body.indexOf('�') == -1;
				if (isGBK) {
					body = iconv.decode(buffer, 'GB18030');
					body = util.replaceQueryString(body, params);
					chunk = iconv.encode(body, 'GB18030');
				} else {
					chunk = new Buffer(body);
				}
				buffer = null;
			} else {
				chunk = new Buffer(params);
			}

			callback(null, chunk);
		};
		req.add(transform);
	}
}

module.exports = function(req, res, next) {
	var reqRules = req.rules;
	util.parseRuleJson([reqRules.req, reqRules.reqHeaders, reqRules.reqCookies,
	                    reqRules.auth, reqRules.urlParams, reqRules.params, reqRules.reqCors],
			function(data, headers, cookies, auth, urlParams, params, cors) {
		if (reqRules.head && reqRules.head.req) {
			data = extend(reqRules.head.req, data);
		}
		data = data || {};
		if (headers) {
			data.headers = headers;
		}

		var method = util.getMatcherValue(reqRules.method);
		if (method) {
			data.method = method;
		}

		var type = util.getMatcherValue(reqRules.reqType);
		if (type) {
			type = type.indexOf('/') != -1 ? type : (REQ_TYPE[type] || REQ_TYPE['default']);
			util.setHeader(data, 'content-type', type);
		}

		var referer = util.getMatcherValue(reqRules.referer);
		if (referer) {
			util.setHeader(data, 'referer', referer);
		}

		var ua = util.getMatcherValue(reqRules.ua);
		if (ua) {
			util.setHeader(data, 'user-agent', ua);
		}

		var reqDelay = util.getMatcherValue(reqRules.reqDelay);
		reqDelay = reqDelay && parseInt(reqDelay, 10);
		if (reqDelay > 0) {
			data.delay = reqDelay;
		}

		var reqSpeed = util.getMatcherValue(reqRules.reqSpeed);
		reqSpeed = reqSpeed && parseFloat(reqSpeed);
		if (reqSpeed > 0) {
			data.speed = reqSpeed;
		}

		handleCookies(data, cookies, req.headers.cookie);
		handleAuth(data, auth);
		handleCors(data, cors);

		util.readInjectFiles(data, function(data) {
			util.getRuleValue([reqRules.reqBody, reqRules.reqPrepend, reqRules.reqAppend],
				function(reqBody, reqPrepend, reqAppend) {
					if (reqBody) {
						data.body = reqBody;
					}

					if (reqPrepend) {
						data.top = reqPrepend;
					}

					if (reqAppend) {
						data.append = reqAppend;
					}

					handleReq(req, data);
					handleUrlParams(req, urlParams);
					handleParams(req, params);
					util.removeUnsupportsHeaders(req.headers);

					next();
				});
		});
	});
};<|endoftext|>


<commit_before>

angular.module('starter.controllers')
.controller('CarteCtrl', ['$scope', '$http','$rootScope', '$ionicPopup', 'etablissementsService', 'artisansService', 'programmesService',
    function($scope, $http, $rootScope, $ionicPopup, etablissementsService, artisansService, programmesService) {

    var southWest = L.latLng(47.369743926768784, 7.174824539917747),
    northEast = L.latLng(47.360589810163582, 7.1379860116837257),
    bounds = L.latLngBounds(southWest, northEast);

    var map = L.map('mapid', {
        center: [47.364965, 7.154498],
        zoom: 18,
        minZoom: 15,
        maxNativeZoom: 20,
        maxBounds: bounds,
        zoomControl:false,
        tap: false
    });

    $scope.artisansMarkers = [];
    $scope.programmesMarkers = [];
    $scope.etablissementMarkers = [];

    var pageID = $('#page_carte');
    $scope.EvenementLayer = L.layerGroup([]);
    $scope.ArtisanLayer = L.layerGroup([]);
    $scope.EtablissementLayer = L.layerGroup([]);

    // Callback de succès sur la fonction de localisation, si la localisation a fonctionné on affiche la position de l'utilisateur
    var onSuccess = function(position) {

        userLat = position.coords.latitude;
        userLng =  position.coords.longitude;
        userLatLng = L.latLng(userLat, userLng);

        if (userLat < 47.369743926768784 && userLat > 47.360589810163582 && userLng > 7.174824539917747 && userLng < 7.1379860116837257){

          L.marker(userLatLng).addTo(map).bindPopup('Vous êtes ici').openPopup();
          map.panTo(userLatLng);

        } else {

          var alertPopup = $ionicPopup.alert({
            title: 'Erreur de localisation',
            template: 'La localisation ne fonctionne pas en dehors de la ville de St-Ursanne.'
          });

          map.panTo([47.364965, 7.154498]);

        }

    };

    // onError Callback receives a PositionError object
    //
    function onError(error) {
      var alertPopup = $ionicPopup.alert({
        title: 'Erreur de localisation',
        template: 'La localisation ne fonctionne pas. Vérifiez que le GPS soit correctement activé puis réessayez.'
      });

    }

    var ourCustomControl = L.Control.extend({

      options: {
        position: 'topright'
      },

      onAdd: function (map) {
        var container = L.DomUtil.create('div', 'leaflet-bar leaflet-control leaflet-control-custom');

        container.onclick = function(){
          navigator.geolocation.getCurrentPosition(onSuccess, onError);
        }

        return container;
      },

    });

	  L.tileLayer('data/img/MapQuest/{z}/{x}/{y}.png', {
		  attribution: '© OpenStreetMap contributors'
	  }).addTo(map);

    map.addControl(new ourCustomControl());

    var restaurant = L.icon({
      iconUrl: 'data/img/icons/restaurantIcon.png',
      iconAnchor: [17, 36]
    });

    var artisans = L.icon({
      iconUrl: 'data/img/icons/artisanIcon.png',
      iconAnchor: [17, 36]
    });

    var events = L.icon({
      iconUrl: 'data/img/icons/eventIcon.png',
      iconAnchor: [17, 36]
    });

    // Affiche tous les marqueurs des établissements
    etablissementsService.get(function (data) {
			$scope.etablissementsRow = data;
			$scope.etablissements = [];
			for (var index = 0; index < $scope.etablissementsRow.length; index++) {
				$scope.etablissements[index] = {
					id: index,
					name: $scope.etablissementsRow[index].name,
					description: $scope.etablissementsRow[index].description,
         	type: $scope.etablissementsRow[index].type,
          latitude: $scope.etablissementsRow[index].latitude,
          longitude: $scope.etablissementsRow[index].longitude
			  };

        function setMarker(i){
          markerEtablissement = new L.marker([$scope.etablissements[i].latitude, $scope.etablissements[i].longitude], {icon: restaurant});
          $scope.EtablissementLayer.addLayer(markerEtablissement);
          $scope.etablissementMarkers.push(markerEtablissement);
        }

        setMarker(index);
			}
		});

    // Affiche tous les marqueurs des artisans
    artisansService.get(function (data) {
			$scope.artisansRow = data;
			$scope.artisans = [];
			for (var index = 0; index < $scope.artisansRow.length; index++) {
				$scope.artisans[index] = {
					id: index,
					name: $scope.artisansRow[index].name,
					latitude: $scope.artisansRow[index].latitude,
					longitude: $scope.artisansRow[index].longitude
				};

        function setMarker(i){
          markerArtisan = new L.marker([$scope.artisans[i].latitude, $scope.artisans[i].longitude], {icon: artisans}).on('click', function(){setMapPopup(pageID, $scope.artisans[i].name, "")});
          $scope.ArtisanLayer.addLayer(markerArtisan);
          $scope.artisansMarkers.push(markerArtisan);
        }

        setMarker(index);
			}
		});

    // Affiche tous les marqueurs du programme (événements)
    programmesService.get(function (data) {
			$scope.programmesRow = data;
			$scope.programmes = [];
			for (var index = 0; index < $scope.programmesRow.length; index++) {
				$scope.programmes[index] = {
					id: index,
					name: $scope.programmesRow[index].name,
          description: $scope.programmesRow[index].description,
					start: $scope.programmesRow[index].start,
					end: $scope.programmesRow[index].end,
					latitude: $scope.programmesRow[index].latitude,
					longitude: $scope.programmesRow[index].longitude

				};

        function setMarker(i){
          markerEvenement = new L.marker([$scope.programmes[i].latitude, $scope.programmes[i].longitude], {icon: events}).on('click', function(){setMapPopup(pageID, $scope.programmes[i].name, $scope.programmes[i].start + " - " + $scope.programmes[i].end)});
          $scope.EvenementLayer.addLayer(markerEvenement);
          $scope.programmesMarkers.push(markerEvenement);
        }

        setMarker(index);
      }
		});

    map.on('click', function(){closeMapPopup(pageID)});

    $scope.showArtisan = true;
    $scope.showRestaurant = true;
    $scope.showEvenement = true;

    $scope.EvenementLayer.addTo(map);
    $scope.ArtisanLayer.addTo(map);
    $scope.EtablissementLayer.addTo(map);

    $('#restaurant-filter').click(function() {
      if($( this ).hasClass("selected")){
        $( this ).removeClass("selected");
        $( this ).find(".img").removeClass("selected");
        $scope.showRestaurant = false;
        map.removeLayer($scope.EtablissementLayer);

      } else {
        $( this ).addClass("selected");
        $( this ).find(".img").addClass("selected");
        $scope.showRestaurant = true;
        map.addLayer($scope.EtablissementLayer);
      }
    });

    $('#events-filter').click(function() {
      if($( this ).hasClass("selected")){
        $( this ).removeClass("selected");
        $( this ).find(".img").removeClass("selected");
        $scope.showEvenement = false;
        map.removeLayer($scope.EvenementLayer);

      } else {
        $( this ).addClass("selected");
        $( this ).find(".img").addClass("selected");
        $scope.showEvenement = true;
        map.addLayer($scope.EvenementLayer);
      }

    });

    $('#artisans-filter').click(function() {
      if($( this ).hasClass("selected")){
        $( this ).removeClass("selected");
        $( this ).find(".img").removeClass("selected");
        $scope.showArtisan = false;
        map.removeLayer($scope.ArtisanLayer);

      } else {
        $( this ).addClass("selected");
        $( this ).find(".img").addClass("selected");
        $scope.showArtisan = true;
        map.addLayer($scope.ArtisanLayer);
      }
    });

  }
]);
<commit_msg>Nouveau niveau de zoom<commit_after>

angular.module('starter.controllers')
.controller('CarteCtrl', ['$scope', '$http','$rootScope', '$ionicPopup', 'etablissementsService', 'artisansService', 'programmesService',
    function($scope, $http, $rootScope, $ionicPopup, etablissementsService, artisansService, programmesService) {

    var southWest = L.latLng(47.369743926768784, 7.174824539917747),
    northEast = L.latLng(47.360589810163582, 7.1379860116837257),
    bounds = L.latLngBounds(southWest, northEast);

    var map = L.map('mapid', {
        center: [47.364965, 7.154498],
        zoom: 19,
        minZoom: 15,
        maxZoom: 20,
        maxBounds: bounds,
        zoomControl:false,
        tap: false
    });

    $scope.artisansMarkers = [];
    $scope.programmesMarkers = [];
    $scope.etablissementMarkers = [];

    var pageID = $('#page_carte');
    $scope.EvenementLayer = L.layerGroup([]);
    $scope.ArtisanLayer = L.layerGroup([]);
    $scope.EtablissementLayer = L.layerGroup([]);

    // Callback de succès sur la fonction de localisation, si la localisation a fonctionné on affiche la position de l'utilisateur
    var onSuccess = function(position) {

        userLat = position.coords.latitude;
        userLng =  position.coords.longitude;
        userLatLng = L.latLng(userLat, userLng);

        if (userLat < 47.369743926768784 && userLat > 47.360589810163582 && userLng > 7.174824539917747 && userLng < 7.1379860116837257){

          L.marker(userLatLng).addTo(map).bindPopup('Vous êtes ici').openPopup();
          map.panTo(userLatLng);

        } else {

          var alertPopup = $ionicPopup.alert({
            title: 'Erreur de localisation',
            template: 'La localisation ne fonctionne pas en dehors de la ville de St-Ursanne.'
          });

          map.panTo([47.364965, 7.154498]);

        }

    };

    // onError Callback receives a PositionError object
    //
    function onError(error) {
      var alertPopup = $ionicPopup.alert({
        title: 'Erreur de localisation',
        template: 'La localisation ne fonctionne pas. Vérifiez que le GPS soit correctement activé puis réessayez.'
      });

    }

    var ourCustomControl = L.Control.extend({

      options: {
        position: 'topright'
      },

      onAdd: function (map) {
        var container = L.DomUtil.create('div', 'leaflet-bar leaflet-control leaflet-control-custom');

        container.onclick = function(){
          navigator.geolocation.getCurrentPosition(onSuccess, onError);
        }

        return container;
      },

    });

    var tileLayer = L.tileLayer(
      'data/img/MapQuest/{z}/{x}/{y}.png', {
        maxZoom: 19,
        minZoom: 15,
        attribution: '© OpenStreetMap contributors'
      }).addTo(map);

    map.addControl(new ourCustomControl());

    var restaurant = L.icon({
      iconUrl: 'data/img/icons/restaurantIcon.png',
      iconAnchor: [17, 36]
    });

    var artisans = L.icon({
      iconUrl: 'data/img/icons/artisanIcon.png',
      iconAnchor: [17, 36]
    });

    var events = L.icon({
      iconUrl: 'data/img/icons/eventIcon.png',
      iconAnchor: [17, 36]
    });

    // Affiche tous les marqueurs des établissements
    etablissementsService.get(function (data) {
			$scope.etablissementsRow = data;
			$scope.etablissements = [];
			for (var index = 0; index < $scope.etablissementsRow.length; index++) {
				$scope.etablissements[index] = {
					id: index,
					name: $scope.etablissementsRow[index].name,
					description: $scope.etablissementsRow[index].description,
         	type: $scope.etablissementsRow[index].type,
          latitude: $scope.etablissementsRow[index].latitude,
          longitude: $scope.etablissementsRow[index].longitude
			  };

        function setMarker(i){
          markerEtablissement = new L.marker([$scope.etablissements[i].latitude, $scope.etablissements[i].longitude], {icon: restaurant});
          $scope.EtablissementLayer.addLayer(markerEtablissement);
          $scope.etablissementMarkers.push(markerEtablissement);
        }

        setMarker(index);
			}
		});

    // Affiche tous les marqueurs des artisans
    artisansService.get(function (data) {
			$scope.artisansRow = data;
			$scope.artisans = [];
			for (var index = 0; index < $scope.artisansRow.length; index++) {
				$scope.artisans[index] = {
					id: index,
					name: $scope.artisansRow[index].name,
					latitude: $scope.artisansRow[index].latitude,
					longitude: $scope.artisansRow[index].longitude
				};

        function setMarker(i){
          markerArtisan = new L.marker([$scope.artisans[i].latitude, $scope.artisans[i].longitude], {icon: artisans}).on('click', function(){setMapPopup(pageID, $scope.artisans[i].name, "")});
          $scope.ArtisanLayer.addLayer(markerArtisan);
          $scope.artisansMarkers.push(markerArtisan);
        }

        setMarker(index);
			}
		});

    // Affiche tous les marqueurs du programme (événements)
    programmesService.get(function (data) {
			$scope.programmesRow = data;
			$scope.programmes = [];
			for (var index = 0; index < $scope.programmesRow.length; index++) {
				$scope.programmes[index] = {
					id: index,
					name: $scope.programmesRow[index].name,
          description: $scope.programmesRow[index].description,
					start: $scope.programmesRow[index].start,
					end: $scope.programmesRow[index].end,
					latitude: $scope.programmesRow[index].latitude,
					longitude: $scope.programmesRow[index].longitude

				};

        function setMarker(i){
          markerEvenement = new L.marker([$scope.programmes[i].latitude, $scope.programmes[i].longitude], {icon: events}).on('click', function(){setMapPopup(pageID, $scope.programmes[i].name, $scope.programmes[i].start + " - " + $scope.programmes[i].end)});
          $scope.EvenementLayer.addLayer(markerEvenement);
          $scope.programmesMarkers.push(markerEvenement);
        }

        setMarker(index);
      }
		});

    map.on('click', function(){closeMapPopup(pageID)});

    $scope.showArtisan = true;
    $scope.showRestaurant = true;
    $scope.showEvenement = true;

    $scope.EvenementLayer.addTo(map);
    $scope.ArtisanLayer.addTo(map);
    $scope.EtablissementLayer.addTo(map);

    $('#restaurant-filter').click(function() {
      if($( this ).hasClass("selected")){
        $( this ).removeClass("selected");
        $( this ).find(".img").removeClass("selected");
        $scope.showRestaurant = false;
        map.removeLayer($scope.EtablissementLayer);

      } else {
        $( this ).addClass("selected");
        $( this ).find(".img").addClass("selected");
        $scope.showRestaurant = true;
        map.addLayer($scope.EtablissementLayer);
      }
    });

    $('#events-filter').click(function() {
      if($( this ).hasClass("selected")){
        $( this ).removeClass("selected");
        $( this ).find(".img").removeClass("selected");
        $scope.showEvenement = false;
        map.removeLayer($scope.EvenementLayer);

      } else {
        $( this ).addClass("selected");
        $( this ).find(".img").addClass("selected");
        $scope.showEvenement = true;
        map.addLayer($scope.EvenementLayer);
      }

    });

    $('#artisans-filter').click(function() {
      if($( this ).hasClass("selected")){
        $( this ).removeClass("selected");
        $( this ).find(".img").removeClass("selected");
        $scope.showArtisan = false;
        map.removeLayer($scope.ArtisanLayer);

      } else {
        $( this ).addClass("selected");
        $( this ).find(".img").addClass("selected");
        $scope.showArtisan = true;
        map.addLayer($scope.ArtisanLayer);
      }
    });

  }
]);
<|endoftext|>


<commit_before>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2014, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * 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 License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */

module.exports = {
  fixFloatingPoint: function(n, precision) {
    return parseFloat((n).toFixed(precision));
  }
};<commit_msg>switch to @kentquirk's preferred method of fixing floating-point weirdness<commit_after>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2014, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * 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 License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */

module.exports = {
  fixFloatingPoint: function(n) {
    return Math.floor(n * 100 + 0.5) / 100;
  }
};<|endoftext|>


<commit_before>var WageService = function() {
    this.initialize = function() {
        // No Initialization required
        var deferred = $.Deferred();
        deferred.resolve();
        return deferred.promise();
    }

    this.findByAnswers = function(answers) {
      var deferred = $.Deferred();

      console.log("Answers: " + JSON.stringify(answers));

      var result = {};

      var schedule;

      if(answers["work-seattle"] == "yes") {
        if(answers["number-employees"] == ">500") {
          if(answers["medical-benefits"] == "no") {
            schedule = "A";
          } else {
            schedule = "B";
          }
        } else {
          if(answers["health-insurance"] == "yes" || answers["tips"] == "yes") {
            schedule = "C";
          } else {
            schedule = "D";
          }
        }
      } else {
        schedule = "Washington State";
        result.state = true;
      }

      var intervals = [];
      var current;

      for (wageInterval in wageSchedules[schedule]){
          current = wageSchedules[schedule][wageInterval];

          if(schedule == "D") {
            var compensation = wageSchedules["C"][wageInterval]

            if( typeof compensation != "undefined" ) {
              current.compensation = compensation.wage
            }
          }

          if(!current.time_range.isPast()){
            intervals.push(current);
          }

      }

      result.intervals = intervals

      deferred.resolve(result);
      return deferred.promise();
    }

    // A = Schedule 1 employers (more than 500 employees in the U.S.)
    // B = Schedule 1 employers (more than 500 emp1loyees in the U.S.) with medical benefits
    // C = Schedule 2 employers (500 or fewer employees in the U.S.) with minimum compensation
    // D = Schedule 2 employers (500 or fewer employees in the U.S.)
    var wageSchedules = {
      "A": [
        {"wage": 9.54, "time_range": moment("2014-01-01").twix("2015-03-27", {allDay: true})},
        {"wage": 11.0, "time_range": moment("2015-03-28").twix("2015-12-31", {allDay: true})},
        {"wage": 13.0, "time_range": moment("2016-01-01").twix("2016-12-31", {allDay: true})},
        {"wage": 15.0, "time_range": moment("2017-01-01").twix("2018-12-31", {allDay: true})}
      ],
      "B": [
        {"wage": 9.54, "time_range": moment("2014-01-01").twix("2015-03-27", {allDay: true})},
        {"wage": 11.0, "time_range": moment("2015-03-28").twix("2015-12-31", {allDay: true})},
        {"wage": 12.5, "time_range": moment("2016-01-01").twix("2016-12-31", {allDay: true})},
        {"wage": 13.5, "time_range": moment("2017-01-01").twix("2017-12-31", {allDay: true})},
        {"wage": 15.0, "time_range": moment("2018-01-01").twix("2018-12-31", {allDay: true})}
      ],
      "C": [
        {"wage": 9.54, "time_range": moment("2014-01-01").twix("2015-03-27", {allDay: true})},
        {"wage": 11.0, "time_range": moment("2015-03-28").twix("2015-12-31", {allDay: true})},
        {"wage": 12.0, "time_range": moment("2016-01-01").twix("2016-12-31", {allDay: true})},
        {"wage": 13.0, "time_range": moment("2017-01-01").twix("2017-12-31", {allDay: true})},
        {"wage": 14.0, "time_range": moment("2018-01-01").twix("2018-12-31", {allDay: true})},
        {"wage": 15.0, "time_range": moment("2019-01-01").twix("2019-12-31", {allDay: true})}
      ],
      "D": [
        {"wage": 9.54, "time_range": moment("2014-01-01").twix("2015-03-27", {allDay: true})},
        {"wage": 10.0, "time_range": moment("2015-03-28").twix("2015-12-31", {allDay: true})},
        {"wage": 10.5, "time_range": moment("2016-01-01").twix("2016-12-31", {allDay: true})},
        {"wage": 11.0, "time_range": moment("2017-01-01").twix("2017-12-31", {allDay: true})},
        {"wage": 11.5, "time_range": moment("2018-01-01").twix("2018-12-31", {allDay: true})},
        {"wage": 12.0, "time_range": moment("2019-01-01").twix("2019-12-31", {allDay: true})},
        {"wage": 13.5, "time_range": moment("2020-01-01").twix("2020-12-31", {allDay: true})},
        {"wage": 15.0, "time_range": moment("2021-01-01").twix("2021-12-31", {allDay: true})}
      ],
      "Washington State": [
        {"wage":9.47,"time_range": moment("2015-01-01").twix("2115-12-31", {allDay: true})}
      ]
    };
}
<commit_msg>Invert logic<commit_after>var WageService = function() {
    this.initialize = function() {
        // No Initialization required
        var deferred = $.Deferred();
        deferred.resolve();
        return deferred.promise();
    }

    this.findByAnswers = function(answers) {
      var deferred = $.Deferred();

      console.log("Answers: " + JSON.stringify(answers));

      var result = {};

      var schedule;

      if(answers["work-seattle"] == "yes") {
        if(answers["number-employees"] == ">500") {
          if(answers["medical-benefits"] == "no") {
            schedule = "A";
          } else {
            schedule = "B";
          }
        } else {
          if(answers["health-insurance"] == "no" && answers["tips"] == "no") {
            schedule = "C";
          } else {
            schedule = "D";
          }
        }
      } else {
        schedule = "Washington State";
        result.state = true;
      }

      var intervals = [];
      var current;

      for (wageInterval in wageSchedules[schedule]){
          current = wageSchedules[schedule][wageInterval];

          if(schedule == "D") {
            var compensation = wageSchedules["C"][wageInterval]

            if( typeof compensation != "undefined" ) {
              current.compensation = compensation.wage
            }
          }

          if(!current.time_range.isPast()){
            intervals.push(current);
          }

      }

      result.intervals = intervals

      deferred.resolve(result);
      return deferred.promise();
    }

    // A = Schedule 1 employers (more than 500 employees in the U.S.)
    // B = Schedule 1 employers (more than 500 emp1loyees in the U.S.) with medical benefits
    // C = Schedule 2 employers (500 or fewer employees in the U.S.) with minimum compensation
    // D = Schedule 2 employers (500 or fewer employees in the U.S.)
    var wageSchedules = {
      "A": [
        {"wage": 9.54, "time_range": moment("2014-01-01").twix("2015-03-27", {allDay: true})},
        {"wage": 11.0, "time_range": moment("2015-03-28").twix("2015-12-31", {allDay: true})},
        {"wage": 13.0, "time_range": moment("2016-01-01").twix("2016-12-31", {allDay: true})},
        {"wage": 15.0, "time_range": moment("2017-01-01").twix("2018-12-31", {allDay: true})}
      ],
      "B": [
        {"wage": 9.54, "time_range": moment("2014-01-01").twix("2015-03-27", {allDay: true})},
        {"wage": 11.0, "time_range": moment("2015-03-28").twix("2015-12-31", {allDay: true})},
        {"wage": 12.5, "time_range": moment("2016-01-01").twix("2016-12-31", {allDay: true})},
        {"wage": 13.5, "time_range": moment("2017-01-01").twix("2017-12-31", {allDay: true})},
        {"wage": 15.0, "time_range": moment("2018-01-01").twix("2018-12-31", {allDay: true})}
      ],
      "C": [
        {"wage": 9.54, "time_range": moment("2014-01-01").twix("2015-03-27", {allDay: true})},
        {"wage": 11.0, "time_range": moment("2015-03-28").twix("2015-12-31", {allDay: true})},
        {"wage": 12.0, "time_range": moment("2016-01-01").twix("2016-12-31", {allDay: true})},
        {"wage": 13.0, "time_range": moment("2017-01-01").twix("2017-12-31", {allDay: true})},
        {"wage": 14.0, "time_range": moment("2018-01-01").twix("2018-12-31", {allDay: true})},
        {"wage": 15.0, "time_range": moment("2019-01-01").twix("2019-12-31", {allDay: true})}
      ],
      "D": [
        {"wage": 9.54, "time_range": moment("2014-01-01").twix("2015-03-27", {allDay: true})},
        {"wage": 10.0, "time_range": moment("2015-03-28").twix("2015-12-31", {allDay: true})},
        {"wage": 10.5, "time_range": moment("2016-01-01").twix("2016-12-31", {allDay: true})},
        {"wage": 11.0, "time_range": moment("2017-01-01").twix("2017-12-31", {allDay: true})},
        {"wage": 11.5, "time_range": moment("2018-01-01").twix("2018-12-31", {allDay: true})},
        {"wage": 12.0, "time_range": moment("2019-01-01").twix("2019-12-31", {allDay: true})},
        {"wage": 13.5, "time_range": moment("2020-01-01").twix("2020-12-31", {allDay: true})},
        {"wage": 15.0, "time_range": moment("2021-01-01").twix("2021-12-31", {allDay: true})}
      ],
      "Washington State": [
        {"wage":9.47,"time_range": moment("2015-01-01").twix("2115-12-31", {allDay: true})}
      ]
    };
}
<|endoftext|>


<commit_before>/*eslint no-invalid-this: 0*/
/*
 * Maintains a lookup of connected IRC clients. These connections are transient
 * and may be closed for a variety of reasons.
 */
"use strict";
var stats = require("../config/stats");
var log = require("../logging").get("ClientPool");
var Promise = require("bluebird");

const RECONNECT_TIME_MS = 1000;

function ClientPool(ircBridge) {
    this._ircBridge = ircBridge;
    // The list of bot clients on servers (not specific users)
    this._botClients = {
        // server_domain: BridgedClient
    };

    // list of virtual users on servers
    this._virtualClients = {
        // server_domain: {
        //    nicks: {
        //      <nickname>: BridgedClient
        //    },
        //    userIds: {
        //      <user_id>: BridgedClient
        //    }
        // }
    }
}

ClientPool.prototype.killAllClients = function() {
    let domainList = Object.keys(this._virtualClients);
    let clients = [];
    domainList.forEach((domain) => {
        clients = clients.concat(
            Object.keys(this._virtualClients[domain].nicks).map(
                (nick) => this._virtualClients[domain].nicks[nick]
            )
        );

        clients = clients.concat(
            Object.keys(this._virtualClients[domain].userIds).map(
                (userId) => this._virtualClients[domain].userIds[userId]
            )
        );

        clients.push(this._botClients[domain]);
    });

    clients = clients.filter((c) => Boolean(c));

    return Promise.all(
        clients.map(
            (client) => client.kill()
        )
    );
}

ClientPool.prototype.setBot = function(server, client) {
    this._botClients[server.domain] = client;
};

ClientPool.prototype.getBot = function(server) {
    return this._botClients[server.domain];
};

ClientPool.prototype.createIrcClient = function(ircClientConfig, matrixUser, isBot) {
    var bridgedClient = this._ircBridge.createBridgedClient(
        ircClientConfig, matrixUser, isBot
    );
    var server = bridgedClient.server;

    if (this._virtualClients[server.domain] === undefined) {
        this._virtualClients[server.domain] = {
            nicks: Object.create(null),
            userIds: Object.create(null)
        };
    }
    if (isBot) {
        this._botClients[server.domain] = bridgedClient;
    }

    // add event listeners
    bridgedClient.on("client-connected", this._onClientConnected.bind(this));
    bridgedClient.on("client-disconnected", this._onClientDisconnected.bind(this));
    bridgedClient.on("nick-change", this._onNickChange.bind(this));
    bridgedClient.on("join-error", this._onJoinError.bind(this));
    bridgedClient.on("irc-names", this._onNames.bind(this));

    // store the bridged client immediately in the pool even though it isn't
    // connected yet, else we could spawn 2 clients for a single user if this
    // function is called quickly.
    this._virtualClients[server.domain].userIds[bridgedClient.userId] = bridgedClient;

    // Does this server have a max clients limit? If so, check if the limit is
    // reached and start cycling based on oldest time.
    this._checkClientLimit(server);
    return bridgedClient;
};

ClientPool.prototype.getBridgedClientByUserId = function(server, userId) {
    if (!this._virtualClients[server.domain]) {
        return undefined;
    }
    var cli = this._virtualClients[server.domain].userIds[userId];
    if (!cli || cli.isDead()) {
        return undefined;
    }
    return cli;
};

ClientPool.prototype.getBridgedClientByNick = function(server, nick) {
    var bot = this.getBot(server);
    if (bot && bot.nick === nick) {
        return bot;
    }

    if (!this._virtualClients[server.domain]) {
        return undefined;
    }
    var cli = this._virtualClients[server.domain].nicks[nick];
    if (!cli || cli.isDead()) {
        return undefined;
    }
    return cli;
};

ClientPool.prototype.getBridgedClientsForUserId = function(userId) {
    var domainList = Object.keys(this._virtualClients);
    var clientList = [];
    domainList.forEach((domain) => {
        var cli = this._virtualClients[domain].userIds[userId];
        if (cli && !cli.isDead()) {
            clientList.push(cli);
        }
    });
    return clientList;
};

ClientPool.prototype._checkClientLimit = function(server) {
    if (server.getMaxClients() === 0) {
        return;
    }

    var numConnections = this._getNumberOfConnections(server);
    this._sendConnectionMetric(server);

    if (numConnections < server.getMaxClients()) {
        // under the limit, we're good for now.
        log.debug(
            "%s active connections on %s",
            numConnections, server.domain
        );
        return;
    }

    log.debug(
        "%s active connections on %s (limit %s)",
        numConnections, server.domain, server.getMaxClients()
    );

    // find the oldest client to kill.
    var oldest = null;
    Object.keys(this._virtualClients[server.domain].nicks).forEach((nick) => {
        var client = this._virtualClients[server.domain].nicks[nick];
        if (!client) {
            // possible since undefined/null values can be present from culled entries
            return;
        }
        if (client.isBot) {
            return; // don't ever kick the bot off.
        }
        if (oldest === null) {
            oldest = client;
            return;
        }
        if (client.getLastActionTs() < oldest.getLastActionTs()) {
            oldest = client;
        }
    });
    if (!oldest) {
        return;
    }
    // disconnect and remove mappings.
    this._removeBridgedClient(oldest);
    oldest.disconnect("Client limit exceeded: " + server.getMaxClients()).then(
    function() {
        log.info("Client limit exceeded: Disconnected %s on %s.",
            oldest.nick, oldest.server.domain);
    },
    function(e) {
        log.error("Error when disconnecting %s on server %s: %s",
            oldest.nick, oldest.server.domain, JSON.stringify(e));
    });
};

ClientPool.prototype._getNumberOfConnections = function(server) {
    if (!server || !this._virtualClients[server.domain]) { return 0; }

    var connectedNickMap = this._virtualClients[server.domain].nicks;

    var numConnectedNicks = Object.keys(connectedNickMap).filter(function(nick) {
        return Boolean(connectedNickMap[nick]); // remove 'undefined' values
    }).length;

    return numConnectedNicks;
};

ClientPool.prototype.countTotalConnections = function() {
    var count = 0;

    Object.keys(this._virtualClients).forEach((domain) => {
        let server = this._ircBridge.getServer(domain);
        count += this._getNumberOfConnections(server);
    });

    return count;
};

ClientPool.prototype._sendConnectionMetric = function(server) {
    stats.ircClients(server.domain, this._getNumberOfConnections(server));
};

ClientPool.prototype._removeBridgedClient = function(bridgedClient) {
    var server = bridgedClient.server;
    this._virtualClients[server.domain].userIds[bridgedClient.userId] = undefined;
    this._virtualClients[server.domain].nicks[bridgedClient.nick] = undefined;

    if (bridgedClient.isBot) {
        this._botClients[server.domain] = undefined;
    }
};

ClientPool.prototype._onClientConnected = function(bridgedClient) {
    var server = bridgedClient.server;
    var oldNick = bridgedClient.nick;
    var actualNick = bridgedClient.unsafeClient.nick;

    // assign a nick to this client
    this._virtualClients[server.domain].nicks[actualNick] = bridgedClient;

    // informative logging
    if (oldNick !== actualNick) {
        log.debug("Connected with nick '%s' instead of desired nick '%s'",
            actualNick, oldNick);
    }
};

ClientPool.prototype._onClientDisconnected = function(bridgedClient) {
    this._removeBridgedClient(bridgedClient);
    this._sendConnectionMetric(bridgedClient.server);

    if (bridgedClient.explicitDisconnect) {
        // don't reconnect users which explicitly disconnected e.g. client
        // cycling, idle timeouts, leaving rooms, etc.
        return;
    }
    // Reconnect this user
    log.debug(
        "onClientDisconnected: <%s> Reconnecting %s@%s in %sms",
        bridgedClient._id, bridgedClient.nick, bridgedClient.server.domain, RECONNECT_TIME_MS
    );
    // change the client config to use the current nick rather than the desired nick. This
    // makes sure that the client attempts to reconnect with the *SAME* nick, and also draws
    // from the latest !nick change, as the client config here may be very very old.
    var cliConfig = bridgedClient.getClientConfig();
    cliConfig.setDesiredNick(bridgedClient.nick);

    var cli = this.createIrcClient(
        cliConfig, bridgedClient.matrixUser, bridgedClient.isBot
    );
    var chanList = bridgedClient.chanList;
    var self = this;
    // remove ref to the disconnected client so it can be GC'd. If we don't do this,
    // the timeout below holds it in a closure, preventing it from being GC'd.
    bridgedClient = undefined;
    setTimeout(function() {
        cli.connect().then(function() {
            log.info(
                "<%s> Reconnected %s@%s", cli._id, cli.nick, cli.server.domain
            );
            if (chanList.length > 0) {
                log.info("<%s> Rejoining %s channels", cli._id, chanList.length);
                chanList.forEach(function(c) {
                    cli.joinChannel(c);
                });
            }
            self._sendConnectionMetric(cli.server);
        }, function(e) {
            log.error(
                "<%s> Failed to reconnect %s@%s", cli._id, cli.nick, cli.server.domain
            );
        });
    }, RECONNECT_TIME_MS);
};

ClientPool.prototype._onNickChange = function(bridgedClient, oldNick, newNick) {
    this._virtualClients[bridgedClient.server.domain].nicks[oldNick] = undefined;
    this._virtualClients[bridgedClient.server.domain].nicks[newNick] = bridgedClient;
};

ClientPool.prototype._onJoinError = Promise.coroutine(function*(bridgedClient, chan, err) {
    var errorsThatShouldKick = [
        "err_bannedfromchan", // they aren't allowed in channels they are banned on.
        "err_inviteonlychan", // they aren't allowed in invite only channels
        "err_channelisfull", // they aren't allowed in if the channel is full
        "err_badchannelkey", // they aren't allowed in channels with a bad key
        "err_needreggednick", // they aren't allowed in +r channels if they haven't authed
    ];
    if (errorsThatShouldKick.indexOf(err) === -1) {
        return;
    }
    if (!bridgedClient.userId || bridgedClient.isBot) {
        return; // the bot itself can get these join errors
    }
    // TODO: this is a bit evil, no one in their right mind would expect
    // the client pool to be kicking matrix users from a room :(
    log.info(`Kicking ${bridgedClient.userId} from room due to ${err}`);
    let matrixRooms = yield this._ircBridge.getStore().getMatrixRoomsForChannel(
        bridgedClient.server, chan
    );
    let promises = matrixRooms.map((room) => {
        return this._ircBridge.getAppServiceBridge().getIntent().kick(
            room.getId(), bridgedClient.userId, `IRC error on ${chan}: ${err}`
        );
    });
    yield Promise.all(promises);
});

ClientPool.prototype._onNames = Promise.coroutine(function*(bridgedClient, chan, names) {
    let mls = this._ircBridge.memberListSyncers[bridgedClient.server.domain];
    if (!mls) {
        return;
    }
    yield mls.updateIrcMemberList(chan, names);
});

module.exports = ClientPool;
<commit_msg>Keep track of number of connections in an integer<commit_after>/*eslint no-invalid-this: 0*/
/*
 * Maintains a lookup of connected IRC clients. These connections are transient
 * and may be closed for a variety of reasons.
 */
"use strict";
var stats = require("../config/stats");
var log = require("../logging").get("ClientPool");
var Promise = require("bluebird");

const RECONNECT_TIME_MS = 1000;

function ClientPool(ircBridge) {
    this._ircBridge = ircBridge;
    // The list of bot clients on servers (not specific users)
    this._botClients = {
        // server_domain: BridgedClient
    };

    // list of virtual users on servers
    this._virtualClients = {
        // server_domain: {
        //    nicks: {
        //      <nickname>: BridgedClient
        //    },
        //    userIds: {
        //      <user_id>: BridgedClient
        //    }
        // }
    }
    // map of numbers of connected clients on each server
    this._virtualClientCounts = {
        // server_domain: number
    };
}

ClientPool.prototype.killAllClients = function() {
    let domainList = Object.keys(this._virtualClients);
    let clients = [];
    domainList.forEach((domain) => {
        clients = clients.concat(
            Object.keys(this._virtualClients[domain].nicks).map(
                (nick) => this._virtualClients[domain].nicks[nick]
            )
        );

        clients = clients.concat(
            Object.keys(this._virtualClients[domain].userIds).map(
                (userId) => this._virtualClients[domain].userIds[userId]
            )
        );

        clients.push(this._botClients[domain]);
    });

    clients = clients.filter((c) => Boolean(c));

    return Promise.all(
        clients.map(
            (client) => client.kill()
        )
    );
}

ClientPool.prototype.setBot = function(server, client) {
    this._botClients[server.domain] = client;
};

ClientPool.prototype.getBot = function(server) {
    return this._botClients[server.domain];
};

ClientPool.prototype.createIrcClient = function(ircClientConfig, matrixUser, isBot) {
    var bridgedClient = this._ircBridge.createBridgedClient(
        ircClientConfig, matrixUser, isBot
    );
    var server = bridgedClient.server;

    if (this._virtualClients[server.domain] === undefined) {
        this._virtualClients[server.domain] = {
            nicks: Object.create(null),
            userIds: Object.create(null)
        };
        this._virtualClientCounts[server.domain] = 0;
    }
    if (isBot) {
        this._botClients[server.domain] = bridgedClient;
    }

    // add event listeners
    bridgedClient.on("client-connected", this._onClientConnected.bind(this));
    bridgedClient.on("client-disconnected", this._onClientDisconnected.bind(this));
    bridgedClient.on("nick-change", this._onNickChange.bind(this));
    bridgedClient.on("join-error", this._onJoinError.bind(this));
    bridgedClient.on("irc-names", this._onNames.bind(this));

    // store the bridged client immediately in the pool even though it isn't
    // connected yet, else we could spawn 2 clients for a single user if this
    // function is called quickly.
    this._virtualClients[server.domain].userIds[bridgedClient.userId] = bridgedClient;
    this._virtualClientCounts[server.domain] = this._virtualClientCounts[server.domain] + 1;

    // Does this server have a max clients limit? If so, check if the limit is
    // reached and start cycling based on oldest time.
    this._checkClientLimit(server);
    return bridgedClient;
};

ClientPool.prototype.getBridgedClientByUserId = function(server, userId) {
    if (!this._virtualClients[server.domain]) {
        return undefined;
    }
    var cli = this._virtualClients[server.domain].userIds[userId];
    if (!cli || cli.isDead()) {
        return undefined;
    }
    return cli;
};

ClientPool.prototype.getBridgedClientByNick = function(server, nick) {
    var bot = this.getBot(server);
    if (bot && bot.nick === nick) {
        return bot;
    }

    if (!this._virtualClients[server.domain]) {
        return undefined;
    }
    var cli = this._virtualClients[server.domain].nicks[nick];
    if (!cli || cli.isDead()) {
        return undefined;
    }
    return cli;
};

ClientPool.prototype.getBridgedClientsForUserId = function(userId) {
    var domainList = Object.keys(this._virtualClients);
    var clientList = [];
    domainList.forEach((domain) => {
        var cli = this._virtualClients[domain].userIds[userId];
        if (cli && !cli.isDead()) {
            clientList.push(cli);
        }
    });
    return clientList;
};

ClientPool.prototype._checkClientLimit = function(server) {
    if (server.getMaxClients() === 0) {
        return;
    }

    var numConnections = this._getNumberOfConnections(server);
    this._sendConnectionMetric(server);

    if (numConnections < server.getMaxClients()) {
        // under the limit, we're good for now.
        log.debug(
            "%s active connections on %s",
            numConnections, server.domain
        );
        return;
    }

    log.debug(
        "%s active connections on %s (limit %s)",
        numConnections, server.domain, server.getMaxClients()
    );

    // find the oldest client to kill.
    var oldest = null;
    Object.keys(this._virtualClients[server.domain].nicks).forEach((nick) => {
        var client = this._virtualClients[server.domain].nicks[nick];
        if (!client) {
            // possible since undefined/null values can be present from culled entries
            return;
        }
        if (client.isBot) {
            return; // don't ever kick the bot off.
        }
        if (oldest === null) {
            oldest = client;
            return;
        }
        if (client.getLastActionTs() < oldest.getLastActionTs()) {
            oldest = client;
        }
    });
    if (!oldest) {
        return;
    }
    // disconnect and remove mappings.
    this._removeBridgedClient(oldest);
    oldest.disconnect("Client limit exceeded: " + server.getMaxClients()).then(
    function() {
        log.info("Client limit exceeded: Disconnected %s on %s.",
            oldest.nick, oldest.server.domain);
    },
    function(e) {
        log.error("Error when disconnecting %s on server %s: %s",
            oldest.nick, oldest.server.domain, JSON.stringify(e));
    });
};

ClientPool.prototype._getNumberOfConnections = function(server) {
    if (!server || !this._virtualClients[server.domain]) { return 0; }
    return this._virtualClientCounts[server.domain];
};

ClientPool.prototype.countTotalConnections = function() {
    var count = 0;

    Object.keys(this._virtualClients).forEach((domain) => {
        let server = this._ircBridge.getServer(domain);
        count += this._getNumberOfConnections(server);
    });

    return count;
};

ClientPool.prototype._sendConnectionMetric = function(server) {
    stats.ircClients(server.domain, this._getNumberOfConnections(server));
};

ClientPool.prototype._removeBridgedClient = function(bridgedClient) {
    var server = bridgedClient.server;
    this._virtualClients[server.domain].userIds[bridgedClient.userId] = undefined;
    this._virtualClients[server.domain].nicks[bridgedClient.nick] = undefined;
    this._virtualClientCounts[server.domain] = this._virtualClientCounts[server.domain] - 1;

    if (bridgedClient.isBot) {
        this._botClients[server.domain] = undefined;
    }
};

ClientPool.prototype._onClientConnected = function(bridgedClient) {
    var server = bridgedClient.server;
    var oldNick = bridgedClient.nick;
    var actualNick = bridgedClient.unsafeClient.nick;

    // assign a nick to this client
    this._virtualClients[server.domain].nicks[actualNick] = bridgedClient;

    // informative logging
    if (oldNick !== actualNick) {
        log.debug("Connected with nick '%s' instead of desired nick '%s'",
            actualNick, oldNick);
    }
};

ClientPool.prototype._onClientDisconnected = function(bridgedClient) {
    this._removeBridgedClient(bridgedClient);
    this._sendConnectionMetric(bridgedClient.server);

    if (bridgedClient.explicitDisconnect) {
        // don't reconnect users which explicitly disconnected e.g. client
        // cycling, idle timeouts, leaving rooms, etc.
        return;
    }
    // Reconnect this user
    log.debug(
        "onClientDisconnected: <%s> Reconnecting %s@%s in %sms",
        bridgedClient._id, bridgedClient.nick, bridgedClient.server.domain, RECONNECT_TIME_MS
    );
    // change the client config to use the current nick rather than the desired nick. This
    // makes sure that the client attempts to reconnect with the *SAME* nick, and also draws
    // from the latest !nick change, as the client config here may be very very old.
    var cliConfig = bridgedClient.getClientConfig();
    cliConfig.setDesiredNick(bridgedClient.nick);

    var cli = this.createIrcClient(
        cliConfig, bridgedClient.matrixUser, bridgedClient.isBot
    );
    var chanList = bridgedClient.chanList;
    var self = this;
    // remove ref to the disconnected client so it can be GC'd. If we don't do this,
    // the timeout below holds it in a closure, preventing it from being GC'd.
    bridgedClient = undefined;
    setTimeout(function() {
        cli.connect().then(function() {
            log.info(
                "<%s> Reconnected %s@%s", cli._id, cli.nick, cli.server.domain
            );
            if (chanList.length > 0) {
                log.info("<%s> Rejoining %s channels", cli._id, chanList.length);
                chanList.forEach(function(c) {
                    cli.joinChannel(c);
                });
            }
            self._sendConnectionMetric(cli.server);
        }, function(e) {
            log.error(
                "<%s> Failed to reconnect %s@%s", cli._id, cli.nick, cli.server.domain
            );
        });
    }, RECONNECT_TIME_MS);
};

ClientPool.prototype._onNickChange = function(bridgedClient, oldNick, newNick) {
    this._virtualClients[bridgedClient.server.domain].nicks[oldNick] = undefined;
    this._virtualClients[bridgedClient.server.domain].nicks[newNick] = bridgedClient;
};

ClientPool.prototype._onJoinError = Promise.coroutine(function*(bridgedClient, chan, err) {
    var errorsThatShouldKick = [
        "err_bannedfromchan", // they aren't allowed in channels they are banned on.
        "err_inviteonlychan", // they aren't allowed in invite only channels
        "err_channelisfull", // they aren't allowed in if the channel is full
        "err_badchannelkey", // they aren't allowed in channels with a bad key
        "err_needreggednick", // they aren't allowed in +r channels if they haven't authed
    ];
    if (errorsThatShouldKick.indexOf(err) === -1) {
        return;
    }
    if (!bridgedClient.userId || bridgedClient.isBot) {
        return; // the bot itself can get these join errors
    }
    // TODO: this is a bit evil, no one in their right mind would expect
    // the client pool to be kicking matrix users from a room :(
    log.info(`Kicking ${bridgedClient.userId} from room due to ${err}`);
    let matrixRooms = yield this._ircBridge.getStore().getMatrixRoomsForChannel(
        bridgedClient.server, chan
    );
    let promises = matrixRooms.map((room) => {
        return this._ircBridge.getAppServiceBridge().getIntent().kick(
            room.getId(), bridgedClient.userId, `IRC error on ${chan}: ${err}`
        );
    });
    yield Promise.all(promises);
});

ClientPool.prototype._onNames = Promise.coroutine(function*(bridgedClient, chan, names) {
    let mls = this._ircBridge.memberListSyncers[bridgedClient.server.domain];
    if (!mls) {
        return;
    }
    yield mls.updateIrcMemberList(chan, names);
});

module.exports = ClientPool;
<|endoftext|>


<commit_before>import { isExisty } from '../lib/helpers';
import { find } from 'lodash';
import gravity from '../lib/loaders/gravity';
import cached from './fields/cached';
import date from './fields/date';
import markdown from './fields/markdown';
import Artist from './artist';
import Partner from './partner';
import Fair from './fair';
import Artwork from './artwork';
import Location from './location';
import Image, { getDefault } from './image';
import PartnerShowEventType from './partner_show_event';
import {
  GraphQLObjectType,
  GraphQLString,
  GraphQLNonNull,
  GraphQLList,
  GraphQLInt,
  GraphQLBoolean,
} from 'graphql';

const kind = ({ artists, fair }) => {
  if (isExisty(fair)) return 'fair';
  if (artists.length > 1) return 'group';
  if (artists.length === 1) return 'solo';
};

const PartnerShowType = new GraphQLObjectType({
  name: 'PartnerShow',
  fields: () => ({
    cached,
    _id: {
      type: GraphQLString,
    },
    id: {
      type: GraphQLString,
    },
    href: {
      type: GraphQLString,
      resolve: ({ id }) => `/show/${id}`,
    },
    kind: {
      type: GraphQLString,
      resolve: (show) => {
        if (show.artists) return kind(show);
        return gravity(`partner/${show.partner.id}/show/${show.id}`).then(kind);
      },
    },
    name: {
      type: GraphQLString,
      description: 'The exhibition title',
    },
    description: {
      type: GraphQLString,
    },
    displayable: {
      type: GraphQLBoolean,
    },
    press_release: markdown(),
    start_at: date,
    end_at: date,
    artists: {
      type: new GraphQLList(Artist.type),
      resolve: ({ artists }) => artists,
    },
    partner: {
      type: Partner.type,
      resolve: ({ partner }) => partner,
    },
    fair: {
      type: Fair.type,
      resolve: ({ fair }) => fair,
    },
    location: {
      type: Location.type,
      resolve: ({ location, fair_location }) => location || fair_location,
    },
    status: {
      type: GraphQLString,
    },
    events: {
      type: new GraphQLList(PartnerShowEventType),
      resolve: ({ events }) => events,
    },
    artworks: {
      type: new GraphQLList(Artwork.type),
      args: {
        size: {
          type: GraphQLInt,
          description: 'Number of artworks to return',
          defaultValue: 25,
        },
        published: {
          type: GraphQLBoolean,
          defaultValue: true,
        },
        page: {
          type: GraphQLInt,
          defaultValue: 1,
        },
        all: {
          type: GraphQLBoolean,
          default: false,
        },
      },
      resolve: (show, options) => {
        const path = `partner/${show.partner.id}/show/${show.id}/artworks`;

        if (options.all) {
          return gravity.all(path, options);
        }

        return gravity(path, options);
      },
    },
    meta_image: {
      type: Image.type,
      resolve: ({ id, partner, image_versions, image_url }) => {
        if (image_versions && image_versions.length && image_url) {
          return Image.resolve({ image_versions, image_url });
        }

        return gravity(`partner/${partner.id}/show/${id}/artworks`, {
          published: true,
        })
          .then(artworks => {
            Image.resolve(getDefault(find(artworks, { can_share_image: true })));
          });
      },
    },
    cover_image: {
      type: Image.type,
      resolve: ({ id, partner, image_versions, image_url }) => {
        if (image_versions && image_versions.length && image_url) {
          return Image.resolve({ image_versions, image_url });
        }

        return gravity(`partner/${partner.id}/show/${id}/artworks`, {
          size: 1,
          published: true,
        })
          .then(artworks => {
            const { images } = artworks[0];
            return Image.resolve(getDefault(images));
          });
      },
    },
    images: {
      type: new GraphQLList(Image.type),
      args: {
        size: {
          type: GraphQLInt,
          description: 'Number of images to return',
        },
        default: {
          type: GraphQLBoolean,
          description: 'Pass true/false to include cover or not',
        },
        page: {
          type: GraphQLInt,
        },
      },
      resolve: ({ id }, options) => {
        return gravity(`partner_show/${id}/images`, options)
          .then(Image.resolve);
      },
    },
  }),
});

const PartnerShow = {
  type: PartnerShowType,
  description: 'A Partner Show',
  args: {
    id: {
      type: new GraphQLNonNull(GraphQLString),
      description: 'The slug or ID of the PartnerShow',
    },
  },
  resolve: (root, { id }) => {
    return gravity(`show/${id}`)
      .then(show => {
        if (!show.displayable) return new Error('Show Not Found');
        return show;
      });
  },
};

export default PartnerShow;
<commit_msg>Fix events cache bug<commit_after>import { isExisty } from '../lib/helpers';
import { find } from 'lodash';
import gravity from '../lib/loaders/gravity';
import cached from './fields/cached';
import date from './fields/date';
import markdown from './fields/markdown';
import Artist from './artist';
import Partner from './partner';
import Fair from './fair';
import Artwork from './artwork';
import Location from './location';
import Image, { getDefault } from './image';
import PartnerShowEventType from './partner_show_event';
import {
  GraphQLObjectType,
  GraphQLString,
  GraphQLNonNull,
  GraphQLList,
  GraphQLInt,
  GraphQLBoolean,
} from 'graphql';

const kind = ({ artists, fair }) => {
  if (isExisty(fair)) return 'fair';
  if (artists.length > 1) return 'group';
  if (artists.length === 1) return 'solo';
};

const PartnerShowType = new GraphQLObjectType({
  name: 'PartnerShow',
  fields: () => ({
    cached,
    _id: {
      type: GraphQLString,
    },
    id: {
      type: GraphQLString,
    },
    href: {
      type: GraphQLString,
      resolve: ({ id }) => `/show/${id}`,
    },
    kind: {
      type: GraphQLString,
      resolve: (show) => {
        if (show.artists) return kind(show);
        return gravity(`partner/${show.partner.id}/show/${show.id}`).then(kind);
      },
    },
    name: {
      type: GraphQLString,
      description: 'The exhibition title',
    },
    description: {
      type: GraphQLString,
    },
    displayable: {
      type: GraphQLBoolean,
    },
    press_release: markdown(),
    start_at: date,
    end_at: date,
    artists: {
      type: new GraphQLList(Artist.type),
      resolve: ({ artists }) => artists,
    },
    partner: {
      type: Partner.type,
      resolve: ({ partner }) => partner,
    },
    fair: {
      type: Fair.type,
      resolve: ({ fair }) => fair,
    },
    location: {
      type: Location.type,
      resolve: ({ location, fair_location }) => location || fair_location,
    },
    status: {
      type: GraphQLString,
    },
    events: {
      type: new GraphQLList(PartnerShowEventType),
      resolve: ({ partner, id }) =>
        // Gravity redirects from /api/v1/show/:id => /api/v1/partner/:partner_id/show/:show_id
        // this creates issues where events will remain cached. Fetch the non-redirected
        // route to circumvent this
        gravity(`partner/${partner.id}/show/${id}`)
          .then(({ events }) => events),
    },
    artworks: {
      type: new GraphQLList(Artwork.type),
      args: {
        size: {
          type: GraphQLInt,
          description: 'Number of artworks to return',
          defaultValue: 25,
        },
        published: {
          type: GraphQLBoolean,
          defaultValue: true,
        },
        page: {
          type: GraphQLInt,
          defaultValue: 1,
        },
        all: {
          type: GraphQLBoolean,
          default: false,
        },
      },
      resolve: (show, options) => {
        const path = `partner/${show.partner.id}/show/${show.id}/artworks`;

        if (options.all) {
          return gravity.all(path, options);
        }

        return gravity(path, options);
      },
    },
    meta_image: {
      type: Image.type,
      resolve: ({ id, partner, image_versions, image_url }) => {
        if (image_versions && image_versions.length && image_url) {
          return Image.resolve({ image_versions, image_url });
        }

        return gravity(`partner/${partner.id}/show/${id}/artworks`, {
          published: true,
        })
          .then(artworks => {
            Image.resolve(getDefault(find(artworks, { can_share_image: true })));
          });
      },
    },
    cover_image: {
      type: Image.type,
      resolve: ({ id, partner, image_versions, image_url }) => {
        if (image_versions && image_versions.length && image_url) {
          return Image.resolve({ image_versions, image_url });
        }

        return gravity(`partner/${partner.id}/show/${id}/artworks`, {
          size: 1,
          published: true,
        })
          .then(artworks => {
            const { images } = artworks[0];
            return Image.resolve(getDefault(images));
          });
      },
    },
    images: {
      type: new GraphQLList(Image.type),
      args: {
        size: {
          type: GraphQLInt,
          description: 'Number of images to return',
        },
        default: {
          type: GraphQLBoolean,
          description: 'Pass true/false to include cover or not',
        },
        page: {
          type: GraphQLInt,
        },
      },
      resolve: ({ id }, options) => {
        return gravity(`partner_show/${id}/images`, options)
          .then(Image.resolve);
      },
    },
  }),
});

const PartnerShow = {
  type: PartnerShowType,
  description: 'A Partner Show',
  args: {
    id: {
      type: new GraphQLNonNull(GraphQLString),
      description: 'The slug or ID of the PartnerShow',
    },
  },
  resolve: (root, { id }) => {
    return gravity(`show/${id}`)
      .then(show => {
        if (!show.displayable) return new Error('Show Not Found');
        return show;
      });
  },
};

export default PartnerShow;
<|endoftext|>


<commit_before>import { isExisty } from '../lib/helpers';
import gravity from '../lib/loaders/gravity';
import cached from './fields/cached';
import date from './fields/date';
import markdown from './fields/markdown';
import Artist from './artist';
import Partner from './partner';
import Fair from './fair';
import Artwork from './artwork';
import Location from './location';
import Image, { getDefault } from './image';
import PartnerShowEventType from './partner_show_event';
import {
  GraphQLObjectType,
  GraphQLString,
  GraphQLNonNull,
  GraphQLList,
  GraphQLInt,
  GraphQLBoolean,
} from 'graphql';

const kind = ({ artists, fair }) => {
  if (isExisty(fair)) return 'fair';
  if (artists.length > 1) return 'group';
  if (artists.length === 1) return 'solo';
};

const PartnerShowType = new GraphQLObjectType({
  name: 'PartnerShow',
  fields: () => ({
    cached,
    _id: {
      type: GraphQLString,
    },
    id: {
      type: GraphQLString,
    },
    href: {
      type: GraphQLString,
      resolve: ({ id }) => `/show/${id}`,
    },
    kind: {
      type: GraphQLString,
      resolve: (show) => {
        if (show.artists) return kind(show);
        return gravity(`partner/${show.partner.id}/show/${show.id}`).then(kind);
      },
    },
    name: {
      type: GraphQLString,
      description: 'The exhibition title',
    },
    description: {
      type: GraphQLString,
    },
    displayable: {
      type: GraphQLBoolean,
    },
    press_release: markdown(),
    start_at: date,
    end_at: date,
    artists: {
      type: new GraphQLList(Artist.type),
      resolve: ({ artists }) => artists,
    },
    partner: {
      type: Partner.type,
      resolve: ({ partner }) => partner,
    },
    fair: {
      type: Fair.type,
      resolve: ({ fair }) => fair,
    },
    location: {
      type: Location.type,
      resolve: ({ location, fair_location }) => location || fair_location,
    },
    status: {
      type: GraphQLString,
    },
    events: {
      type: new GraphQLList(PartnerShowEventType),
      resolve: ({ events }) => events,
    },
    artworks: {
      type: new GraphQLList(Artwork.type),
      args: {
        size: {
          type: GraphQLInt,
          description: 'Number of artworks to return',
        },
        published: {
          type: GraphQLBoolean,
          defaultValue: true,
        },
        page: {
          type: GraphQLInt,
        },
      },
      resolve: (show, options) => {
        return gravity(`partner/${show.partner.id}/show/${show.id}/artworks`, options);
      },
    },
    cover_image: {
      type: Image.type,
      resolve: ({ id, partner, image_versions, image_url }) => {
        if (image_versions && image_versions.length && image_url) {
          return Image.resolve({ image_versions, image_url });
        }

        return gravity(`partner/${partner.id}/show/${id}/artworks`, {
          size: 1,
          published: true,
        })
          .then(artworks => {
            const { images } = artworks[0];
            return Image.resolve(getDefault(images));
          });
      },
    },
    images: {
      type: new GraphQLList(Image.type),
      args: {
        size: {
          type: GraphQLInt,
          description: 'Number of images to return',
        },
        default: {
          type: GraphQLBoolean,
          description: 'Pass true/false to include cover or not',
        },
        page: {
          type: GraphQLInt,
        },
      },
      resolve: ({ id }, options) => {
        return gravity(`partner_show/${id}/images`, options)
          .then(Image.resolve);
      },
    },
  }),
});

const PartnerShow = {
  type: PartnerShowType,
  description: 'A Partner Show',
  args: {
    id: {
      type: new GraphQLNonNull(GraphQLString),
      description: 'The slug or ID of the PartnerShow',
    },
  },
  resolve: (root, { id }) => {
    return gravity(`show/${id}`)
      .then(show => {
        if (!show.displayable) return new Error('Show Not Found');
        return show;
      });
  },
};

export default PartnerShow;
<commit_msg>Adds `all` option to partner_shows/artworks<commit_after>import { isExisty } from '../lib/helpers';
import gravity from '../lib/loaders/gravity';
import cached from './fields/cached';
import date from './fields/date';
import markdown from './fields/markdown';
import Artist from './artist';
import Partner from './partner';
import Fair from './fair';
import Artwork from './artwork';
import Location from './location';
import Image, { getDefault } from './image';
import PartnerShowEventType from './partner_show_event';
import {
  GraphQLObjectType,
  GraphQLString,
  GraphQLNonNull,
  GraphQLList,
  GraphQLInt,
  GraphQLBoolean,
} from 'graphql';

const kind = ({ artists, fair }) => {
  if (isExisty(fair)) return 'fair';
  if (artists.length > 1) return 'group';
  if (artists.length === 1) return 'solo';
};

const PartnerShowType = new GraphQLObjectType({
  name: 'PartnerShow',
  fields: () => ({
    cached,
    _id: {
      type: GraphQLString,
    },
    id: {
      type: GraphQLString,
    },
    href: {
      type: GraphQLString,
      resolve: ({ id }) => `/show/${id}`,
    },
    kind: {
      type: GraphQLString,
      resolve: (show) => {
        if (show.artists) return kind(show);
        return gravity(`partner/${show.partner.id}/show/${show.id}`).then(kind);
      },
    },
    name: {
      type: GraphQLString,
      description: 'The exhibition title',
    },
    description: {
      type: GraphQLString,
    },
    displayable: {
      type: GraphQLBoolean,
    },
    press_release: markdown(),
    start_at: date,
    end_at: date,
    artists: {
      type: new GraphQLList(Artist.type),
      resolve: ({ artists }) => artists,
    },
    partner: {
      type: Partner.type,
      resolve: ({ partner }) => partner,
    },
    fair: {
      type: Fair.type,
      resolve: ({ fair }) => fair,
    },
    location: {
      type: Location.type,
      resolve: ({ location, fair_location }) => location || fair_location,
    },
    status: {
      type: GraphQLString,
    },
    events: {
      type: new GraphQLList(PartnerShowEventType),
      resolve: ({ events }) => events,
    },
    artworks: {
      type: new GraphQLList(Artwork.type),
      args: {
        size: {
          type: GraphQLInt,
          description: 'Number of artworks to return',
          defaultValue: 25,
        },
        published: {
          type: GraphQLBoolean,
          defaultValue: true,
        },
        page: {
          type: GraphQLInt,
          defaultValue: 1,
        },
        all: {
          type: GraphQLBoolean,
          default: false,
        },
      },
      resolve: (show, options) => {
        const path = `partner/${show.partner.id}/show/${show.id}/artworks`;

        if (options.all) {
          return gravity.all(path, options);
        }

        return gravity(path, options);
      },
    },
    cover_image: {
      type: Image.type,
      resolve: ({ id, partner, image_versions, image_url }) => {
        if (image_versions && image_versions.length && image_url) {
          return Image.resolve({ image_versions, image_url });
        }

        return gravity(`partner/${partner.id}/show/${id}/artworks`, {
          size: 1,
          published: true,
        })
          .then(artworks => {
            const { images } = artworks[0];
            return Image.resolve(getDefault(images));
          });
      },
    },
    images: {
      type: new GraphQLList(Image.type),
      args: {
        size: {
          type: GraphQLInt,
          description: 'Number of images to return',
        },
        default: {
          type: GraphQLBoolean,
          description: 'Pass true/false to include cover or not',
        },
        page: {
          type: GraphQLInt,
        },
      },
      resolve: ({ id }, options) => {
        return gravity(`partner_show/${id}/images`, options)
          .then(Image.resolve);
      },
    },
  }),
});

const PartnerShow = {
  type: PartnerShowType,
  description: 'A Partner Show',
  args: {
    id: {
      type: new GraphQLNonNull(GraphQLString),
      description: 'The slug or ID of the PartnerShow',
    },
  },
  resolve: (root, { id }) => {
    return gravity(`show/${id}`)
      .then(show => {
        if (!show.displayable) return new Error('Show Not Found');
        return show;
      });
  },
};

export default PartnerShow;
<|endoftext|>