<commit_before>// account.js

var org = {

	// added on script load
	config: {
						endpoint: { hzws: 'http://api.spokanelibrary.org/v2/request/' }
					 }

	// added on authentication
	,user: {}

	// called on script load
	,init: function() {
		_self = this;

		this.setUser();

		// init ui
		this.initRequestItem();

	} // init()

, setUser: function(user) {
		if ( !ORG.user ) {
			ORG.setUser(user);
		}
		this.user = ORG.user;
}

, initRequestItem: function() {

		/*
		$('body').on('change', 'input:radio[name = "spl-form[material]"]', function() {
			var materialTypeDescription = $(this).parent().text();
			console.log(materialTypeDescription);
		});
		*/

		// hide material type selectors and generic request form on select
		$('body').on('show.bs.collapse', '#spl-form-request-panels', function() {
			$('#spl-form-request-panel-choose').collapse('hide');
			//$('#spl-form-panel-request').collapse('hide');
			$('#spl-form-panel-request').collapse('show');

			$('#spl-form-request-submit-item').hide();
			$('#spl-form-request-submit-download').hide();
		});

		// show generic request form when requested
		$('body').on('shown.bs.collapse', '.spl-form-request-generic', function() {
			//$('#spl-form-panel-request').collapse('show');
			$('#spl-form-request-submit-item').fadeIn();
		});

		// hide generic request form when not requested
		$('body').on('shown.bs.collapse', '.spl-form-request-specific', function() {
			$('#spl-form-panel-request').collapse('hide');
		});

		$('body').on('shown.bs.collapse', '.spl-form-request-download', function() {
			$('#spl-form-request-submit-item').hide();
			$('#spl-form-request-submit-download').fadeIn();
		});

  } // initRequestItem()

};
<commit_msg>request<commit_after>// account.js

var org = {

	// added on script load
	config: {
						endpoint: { hzws: 'http://api.spokanelibrary.org/v2/request/' }
					 }

	// added on authentication
	,user: {}

	// called on script load
	,init: function() {
		_self = this;

		this.setUser();

		// init ui
		this.initRequestItem();

	} // init()

, setUser: function(user) {
		if ( !ORG.user ) {
			ORG.setUser(user);
		}
		this.user = ORG.user;
}

, initRequestItem: function() {

		/*
		$('body').on('change', 'input:radio[name = "spl-form[material]"]', function() {
			var materialTypeDescription = $(this).parent().text();
			console.log(materialTypeDescription);
		});
		*/

		// hide material type selectors and generic request form on select
		$('body').on('show.bs.collapse', '#spl-form-request-panels', function() {
			$('#spl-form-request-panel-choose').collapse('hide');
			//$('#spl-form-panel-request').collapse('hide');
			//$('#spl-form-panel-request').collapse('show');

			$('#spl-form-request-submit-item').hide();
			$('#spl-form-request-submit-download').hide();
		});

		// show generic request form when requested
		$('body').on('show.bs.collapse', '.spl-form-request-generic', function() {
			$('#spl-form-panel-request').collapse('show');
		});
		$('body').on('shown.bs.collapse', '.spl-form-request-generic', function() {
			//$('#spl-form-panel-request').collapse('show');
			$('#spl-form-request-submit-item').fadeIn();
		});

		// hide generic request form when not requested
		$('body').on('shown.bs.collapse', '.spl-form-request-specific', function() {
			$('#spl-form-panel-request').collapse('hide');
		});

		$('body').on('shown.bs.collapse', '.spl-form-request-download', function() {
			$('#spl-form-request-submit-item').hide();
			$('#spl-form-request-submit-download').fadeIn();
		});

  } // initRequestItem()

};
<|endoftext|>


<commit_before>import httpErrors from 'http-errors'
import users from '../models/users'
import { isValidUsername } from '../../../app/common/constants'

export default function(router) {
  router
    .get('/:username', checkAvailability)
}

async function checkAvailability(ctx, next) {
  const username = ctx.params.username
  if (!isValidUsername(username)) {
    throw new httpErrors.BadRequest('Invalid username')
  }

  let user
  try {
    user = await users.find(username)
  } catch (err) {
    ctx.log.error({ err }, 'error finding user')
    throw err
  }

  if (user) {
    throw new httpErrors.NotFound('Username not available')
  } else {
    ctx.body = { username, available: true }
  }
}
<commit_msg>Add throttling to usernameAvailability.<commit_after>import httpErrors from 'http-errors'
import createThrottle from '../throttle/create-throttle'
import throttleMiddleware from '../throttle/middleware'
import users from '../models/users'
import { isValidUsername } from '../../../app/common/constants'

const throttle = createThrottle('usernameavailability', {
  rate: 10,
  burst: 300,
  window: 60000,
})

export default function(router) {
  router
    .get('/:username', throttleMiddleware(throttle, ctx => ctx.ip), checkAvailability)
}

async function checkAvailability(ctx, next) {
  const username = ctx.params.username
  if (!isValidUsername(username)) {
    throw new httpErrors.BadRequest('Invalid username')
  }

  let user
  try {
    user = await users.find(username)
  } catch (err) {
    ctx.log.error({ err }, 'error finding user')
    throw err
  }

  if (user) {
    throw new httpErrors.NotFound('Username not available')
  } else {
    ctx.body = { username, available: true }
  }
}
<|endoftext|>


<commit_before>var typeahead_helper = (function () {

var exports = {};

// Returns an array of private message recipients, removing empty elements.
// For example, "a,,b, " => ["a", "b"]
exports.get_cleaned_pm_recipients = function (query_string) {
    var recipients = util.extract_pm_recipients(query_string);
    recipients = _.filter(recipients, function (elem) {
        return elem.match(/\S/);
    });
    return recipients;
};

// Loosely based on Bootstrap's default highlighter, but with escaping added.
exports.highlight_with_escaping = function (query, item) {
    // query: The text currently in the searchbox
    // item: The string we are trying to appropriately highlight
    query = query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
    var regex = new RegExp('(' + query + ')', 'ig');
    // The result of the split will include the query term, because our regex
    // has parens in it.
    // (as per https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/split)
    // However, "not all browsers support this capability", so this is a place to look
    // if we have an issue here in, e.g. IE.
    var pieces = item.split(regex);
    // We need to assemble this manually (as opposed to doing 'join') because we need to
    // (1) escape all the pieces and (2) the regex is case-insensitive, and we need
    // to know the case of the content we're replacing (you can't just use a bolded
    // version of 'query')
    var result = "";
    _.each(pieces, function (piece) {
        if (piece.match(regex)) {
            result += "" + Handlebars.Utils.escapeExpression(piece) + "";
        } else {
            result += Handlebars.Utils.escapeExpression(piece);
        }
    });
    return result;
};

exports.highlight_with_escaping_and_regex = function (regex, item) {
    var pieces = item.split(regex);
    var result = "";
    _.each(pieces, function (piece) {
        if (piece.match(regex)) {
            result += "" + Handlebars.Utils.escapeExpression(piece) + "";
        } else {
            result += Handlebars.Utils.escapeExpression(piece);
        }
    });
    return result;
};

exports.highlight_query_in_phrase = function (query, phrase) {
    var i;
    query = query.toLowerCase();
    query = query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
    var regex = new RegExp('(^' + query + ')', 'ig');

    var result = "";
    var parts = phrase.split(' ');
    for (i = 0; i < parts.length; i += 1) {
        if (i > 0) {
            result += " ";
        }
        result += exports.highlight_with_escaping_and_regex(regex, parts[i]);
    }
    return result;
};

exports.render_person = function (token, person) {
    if (person.special_item_text) {
        return person.special_item_text;
    }

    var full_name = exports.highlight_with_escaping(token, person.full_name);
    var email = exports.highlight_with_escaping(token, person.email);

    return full_name + " <" + email + ">";
};

exports.render_stream = function (token, stream) {
    var desc = stream.description;
    var short_desc = desc.substring(0, 35);

    if (desc === short_desc) {
        desc = exports.highlight_with_escaping(token, desc);
    } else {
        desc = exports.highlight_with_escaping(token, short_desc) + "...";
    }

    var name = exports.highlight_with_escaping(token, stream.name);

    return name + '  ' + desc + '';
};

function split_by_subscribers(people, current_stream) {
    var subscribers = [];
    var non_subscribers = [];

    if (!stream_data.get_sub(current_stream)) {
        // If there is no stream specified, everyone is considered as a subscriber.
        return {subscribers: people, non_subscribers: []};
    }

    _.each(people, function (person) {
        if (person.email === "all" || person.email === "everyone") {
            subscribers.push(person);
        } else if (stream_data.user_is_subscribed(current_stream, person.email)) {
            subscribers.push(person);
        } else {
            non_subscribers.push(person);
        }
    });

    return {subscribers: subscribers, non_subscribers: non_subscribers};
}

exports.sorter = function (query, objs, get_item) {
   var results = util.prefix_sort(query, objs, get_item);
   return results.matches.concat(results.rest);
};

exports.compare_by_pms = function (user_a, user_b) {
    var count_a = people.get_recipient_count(user_a);
    var count_b = people.get_recipient_count(user_b);

    if (count_a > count_b) {
        return -1;
    } else if (count_a < count_b) {
        return 1;
    }

    if (!user_a.is_bot && user_b.is_bot) {
        return -1;
    } else if (user_a.is_bot && !user_b.is_bot) {
        return 1;
    }

    // We use alpha sort as a tiebreaker, which might be helpful for
    // new users.
    if (user_a.full_name < user_b.full_name) {
        return -1;
    } else if (user_a === user_b) {
        return 0;
    }
    return 1;
};

exports.sort_for_at_mentioning = function (objs, current_stream) {
    var objs_split = split_by_subscribers(objs, current_stream);

    var subs_sorted = objs_split.subscribers.sort(exports.compare_by_pms);
    var non_subs_sorted = objs_split.non_subscribers.sort(exports.compare_by_pms);
    return subs_sorted.concat(non_subs_sorted);
};

exports.compare_by_popularity = function (lang_a, lang_b) {
    var diff = pygments_data.langs[lang_b] - pygments_data.langs[lang_a];
    if (diff !== 0) {
        return diff;
    }
    return util.strcmp(lang_a, lang_b);
};

exports.sort_languages = function (matches, query) {
    var results = util.prefix_sort(query, matches, function (x) { return x; });

    // Languages that start with the query
    results.matches = results.matches.sort(exports.compare_by_popularity);
    // Languages that have the query somewhere in their name
    results.rest = results.rest.sort(exports.compare_by_popularity);
    return results.matches.concat(results.rest);
};

exports.sort_recipients = function (matches, query, current_stream) {
    var name_results =  util.prefix_sort(query, matches, function (x) { return x.full_name; });
    var email_results = util.prefix_sort(query, name_results.rest,
        function (x) { return x.email; });

    var matches_sorted = exports.sort_for_at_mentioning(
        name_results.matches.concat(email_results.matches),
        current_stream
    );
    var rest_sorted = exports.sort_for_at_mentioning(
        email_results.rest,
        current_stream
    );
    return matches_sorted.concat(rest_sorted);
};

exports.sort_emojis = function (matches, query) {
    // TODO: sort by category in v2
    var results = util.prefix_sort(query, matches, function (x) { return x.emoji_name; });
    return results.matches.concat(results.rest);
};

// Gives stream a score from 0 to 3 based on its activity
function activity_score(sub) {
    var stream_score = 0;
    if (sub.pin_to_top) {
        stream_score += 2;
    }
    // Note: A pinned stream may accumulate a 3rd point if it is active
    if (stream_data.is_active(sub)) {
        stream_score += 1;
    }
    return stream_score;
}

// Sort streams by ranking them by activity. If activity is equal,
// as defined bv activity_score, decide based on subscriber count.
exports.compare_by_activity = function (stream_a, stream_b) {
    var diff = activity_score(stream_b) - activity_score(stream_a);
    if (diff !== 0) {
        return diff;
    }
    diff = stream_b.subscribers.num_items() - stream_a.subscribers.num_items();
    if (diff !== 0) {
        return diff;
    }
    return util.strcmp(stream_a.name, stream_b.name);
};

exports.sort_streams = function (matches, query) {
    var name_results = util.prefix_sort(query, matches, function (x) { return x.name; });
    var desc_results
        = util.prefix_sort(query, name_results.rest, function (x) { return x.description; });

    // Streams that start with the query.
    name_results.matches = name_results.matches.sort(exports.compare_by_activity);
    // Streams with descriptions that start with the query.
    desc_results.matches = desc_results.matches.sort(exports.compare_by_activity);
    // Streams with names and descriptions that don't start with the query.
    desc_results.rest = desc_results.rest.sort(exports.compare_by_activity);

    return name_results.matches.concat(desc_results.matches.concat(desc_results.rest));
};

exports.sort_recipientbox_typeahead = function (query, matches, current_stream) {
    // input_text may be one or more pm recipients
    var cleaned = exports.get_cleaned_pm_recipients(query);
    query = cleaned[cleaned.length - 1];
    return exports.sort_recipients(matches, query, current_stream);
};

return exports;

}());
if (typeof module !== 'undefined') {
    module.exports = typeahead_helper;
}
<commit_msg>typeahead: Extract out render_secondary and alter style for emails.<commit_after>var typeahead_helper = (function () {

var exports = {};

// Returns an array of private message recipients, removing empty elements.
// For example, "a,,b, " => ["a", "b"]
exports.get_cleaned_pm_recipients = function (query_string) {
    var recipients = util.extract_pm_recipients(query_string);
    recipients = _.filter(recipients, function (elem) {
        return elem.match(/\S/);
    });
    return recipients;
};

// Loosely based on Bootstrap's default highlighter, but with escaping added.
exports.highlight_with_escaping = function (query, item) {
    // query: The text currently in the searchbox
    // item: The string we are trying to appropriately highlight
    query = query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
    var regex = new RegExp('(' + query + ')', 'ig');
    // The result of the split will include the query term, because our regex
    // has parens in it.
    // (as per https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/split)
    // However, "not all browsers support this capability", so this is a place to look
    // if we have an issue here in, e.g. IE.
    var pieces = item.split(regex);
    // We need to assemble this manually (as opposed to doing 'join') because we need to
    // (1) escape all the pieces and (2) the regex is case-insensitive, and we need
    // to know the case of the content we're replacing (you can't just use a bolded
    // version of 'query')
    var result = "";
    _.each(pieces, function (piece) {
        if (piece.match(regex)) {
            result += "" + Handlebars.Utils.escapeExpression(piece) + "";
        } else {
            result += Handlebars.Utils.escapeExpression(piece);
        }
    });
    return result;
};

exports.highlight_with_escaping_and_regex = function (regex, item) {
    var pieces = item.split(regex);
    var result = "";
    _.each(pieces, function (piece) {
        if (piece.match(regex)) {
            result += "" + Handlebars.Utils.escapeExpression(piece) + "";
        } else {
            result += Handlebars.Utils.escapeExpression(piece);
        }
    });
    return result;
};

exports.highlight_query_in_phrase = function (query, phrase) {
    var i;
    query = query.toLowerCase();
    query = query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
    var regex = new RegExp('(^' + query + ')', 'ig');

    var result = "";
    var parts = phrase.split(' ');
    for (i = 0; i < parts.length; i += 1) {
        if (i > 0) {
            result += " ";
        }
        result += exports.highlight_with_escaping_and_regex(regex, parts[i]);
    }
    return result;
};

function render_secondary(item) {
    return '  ' + item + '';
}

exports.render_person = function (token, person) {
    if (person.special_item_text) {
        return person.special_item_text;
    }

    var full_name = exports.highlight_with_escaping(token, person.full_name);
    var email = exports.highlight_with_escaping(token, person.email);

    return full_name + render_secondary(email);
};

exports.render_stream = function (token, stream) {
    var desc = stream.description;
    var short_desc = desc.substring(0, 35);

    if (desc === short_desc) {
        desc = exports.highlight_with_escaping(token, desc);
    } else {
        desc = exports.highlight_with_escaping(token, short_desc) + "...";
    }

    var name = exports.highlight_with_escaping(token, stream.name);

    return name + render_secondary(desc);
};

function split_by_subscribers(people, current_stream) {
    var subscribers = [];
    var non_subscribers = [];

    if (!stream_data.get_sub(current_stream)) {
        // If there is no stream specified, everyone is considered as a subscriber.
        return {subscribers: people, non_subscribers: []};
    }

    _.each(people, function (person) {
        if (person.email === "all" || person.email === "everyone") {
            subscribers.push(person);
        } else if (stream_data.user_is_subscribed(current_stream, person.email)) {
            subscribers.push(person);
        } else {
            non_subscribers.push(person);
        }
    });

    return {subscribers: subscribers, non_subscribers: non_subscribers};
}

exports.sorter = function (query, objs, get_item) {
   var results = util.prefix_sort(query, objs, get_item);
   return results.matches.concat(results.rest);
};

exports.compare_by_pms = function (user_a, user_b) {
    var count_a = people.get_recipient_count(user_a);
    var count_b = people.get_recipient_count(user_b);

    if (count_a > count_b) {
        return -1;
    } else if (count_a < count_b) {
        return 1;
    }

    if (!user_a.is_bot && user_b.is_bot) {
        return -1;
    } else if (user_a.is_bot && !user_b.is_bot) {
        return 1;
    }

    // We use alpha sort as a tiebreaker, which might be helpful for
    // new users.
    if (user_a.full_name < user_b.full_name) {
        return -1;
    } else if (user_a === user_b) {
        return 0;
    }
    return 1;
};

exports.sort_for_at_mentioning = function (objs, current_stream) {
    var objs_split = split_by_subscribers(objs, current_stream);

    var subs_sorted = objs_split.subscribers.sort(exports.compare_by_pms);
    var non_subs_sorted = objs_split.non_subscribers.sort(exports.compare_by_pms);
    return subs_sorted.concat(non_subs_sorted);
};

exports.compare_by_popularity = function (lang_a, lang_b) {
    var diff = pygments_data.langs[lang_b] - pygments_data.langs[lang_a];
    if (diff !== 0) {
        return diff;
    }
    return util.strcmp(lang_a, lang_b);
};

exports.sort_languages = function (matches, query) {
    var results = util.prefix_sort(query, matches, function (x) { return x; });

    // Languages that start with the query
    results.matches = results.matches.sort(exports.compare_by_popularity);
    // Languages that have the query somewhere in their name
    results.rest = results.rest.sort(exports.compare_by_popularity);
    return results.matches.concat(results.rest);
};

exports.sort_recipients = function (matches, query, current_stream) {
    var name_results =  util.prefix_sort(query, matches, function (x) { return x.full_name; });
    var email_results = util.prefix_sort(query, name_results.rest,
        function (x) { return x.email; });

    var matches_sorted = exports.sort_for_at_mentioning(
        name_results.matches.concat(email_results.matches),
        current_stream
    );
    var rest_sorted = exports.sort_for_at_mentioning(
        email_results.rest,
        current_stream
    );
    return matches_sorted.concat(rest_sorted);
};

exports.sort_emojis = function (matches, query) {
    // TODO: sort by category in v2
    var results = util.prefix_sort(query, matches, function (x) { return x.emoji_name; });
    return results.matches.concat(results.rest);
};

// Gives stream a score from 0 to 3 based on its activity
function activity_score(sub) {
    var stream_score = 0;
    if (sub.pin_to_top) {
        stream_score += 2;
    }
    // Note: A pinned stream may accumulate a 3rd point if it is active
    if (stream_data.is_active(sub)) {
        stream_score += 1;
    }
    return stream_score;
}

// Sort streams by ranking them by activity. If activity is equal,
// as defined bv activity_score, decide based on subscriber count.
exports.compare_by_activity = function (stream_a, stream_b) {
    var diff = activity_score(stream_b) - activity_score(stream_a);
    if (diff !== 0) {
        return diff;
    }
    diff = stream_b.subscribers.num_items() - stream_a.subscribers.num_items();
    if (diff !== 0) {
        return diff;
    }
    return util.strcmp(stream_a.name, stream_b.name);
};

exports.sort_streams = function (matches, query) {
    var name_results = util.prefix_sort(query, matches, function (x) { return x.name; });
    var desc_results
        = util.prefix_sort(query, name_results.rest, function (x) { return x.description; });

    // Streams that start with the query.
    name_results.matches = name_results.matches.sort(exports.compare_by_activity);
    // Streams with descriptions that start with the query.
    desc_results.matches = desc_results.matches.sort(exports.compare_by_activity);
    // Streams with names and descriptions that don't start with the query.
    desc_results.rest = desc_results.rest.sort(exports.compare_by_activity);

    return name_results.matches.concat(desc_results.matches.concat(desc_results.rest));
};

exports.sort_recipientbox_typeahead = function (query, matches, current_stream) {
    // input_text may be one or more pm recipients
    var cleaned = exports.get_cleaned_pm_recipients(query);
    query = cleaned[cleaned.length - 1];
    return exports.sort_recipients(matches, query, current_stream);
};

return exports;

}());
if (typeof module !== 'undefined') {
    module.exports = typeahead_helper;
}
<|endoftext|>


<commit_before>'use strict';

var db             = require('mano').db
  , storage        = require('mano').dbDriver.getStorage('object')
  , serializeValue = require('dbjs/_setup/serialize/value')
  , debug          = require('debug-ext')('current-date-update')
  , time           = require('time')
  , key            = 'globalPrimitives/currentDate';

var getNextScheduleTimeout = function (tz) {
	var now                = (new time.Date()).setTimezone(tz)
	  , next_schedule_date = (new time.Date(now.getFullYear(), now.getMonth(),
				now.getDate() + 1, tz));

	return next_schedule_date - now;
};

module.exports = function (tz) {
	var updateCallback = function () {
		var currentDate = db.Date((new time.Date()).setTimezone(tz));

		storage.get(key).then(function (data) {
			if (data.value !== serializeValue(currentDate)) {
				debug('to %s', currentDate.toISOString().slice(0, 10));
				storage.store(key, serializeValue(currentDate)).done();
			}
		});

		setTimeout(updateCallback, getNextScheduleTimeout(tz));
	};

// Update once on start
	updateCallback();
};
<commit_msg>fixed<commit_after>'use strict';

var db             = require('mano').db
  , storage        = require('mano').dbDriver.getStorage('object')
  , serializeValue = require('dbjs/_setup/serialize/value')
  , debug          = require('debug-ext')('current-date-update')
  , time           = require('time')
  , key            = 'globalPrimitives/currentDate';

var getNextScheduleTimeout = function (tz) {
	var now                = (new time.Date()).setTimezone(tz)
	  , next_schedule_date = (new time.Date(now.getFullYear(), now.getMonth(),
				now.getDate() + 1, tz));

	return next_schedule_date - now;
};

module.exports = function (tz) {
	var updateCallback = function () {
		var currentDate = db.Date((new time.Date()).setTimezone(tz));

		storage.get(key).then(function (data) {
			if (data.value !== serializeValue(currentDate)) {
				debug('to %s', currentDate.toISOString().slice(0, 10));
				return storage.store(key, serializeValue(currentDate));
			}
		}).done();

		setTimeout(updateCallback, getNextScheduleTimeout(tz));
	};

// Update once on start
	updateCallback();
};
<|endoftext|>


<commit_before>var AWS = require('aws-sdk')
, ENV_CONFIG = require('./config/env_config')
, fs = require('fs')
, crypto = require('crypto');

var License = function(){};

License.prototype.sign = function(data, callback) {
    fs.readFile(ENV_CONFIG.License.PrivateKey, function (err, pem) {
        if (!err) {
            var privateKey = pem.toString('ascii');
            var sign = crypto.createSign(ENV_CONFIG.License.Algorithm);
            sign.update(data);
            var signature = sign.sign(privateKey, ENV_CONFIG.License.SignatureFormat);
            callback(signature);
        } else {
            callback(null);
        }
    });

};

License.prototype.verify = function(data, signature, callback) {
    fs.readFile(ENV_CONFIG.License.PrivateKey, function (err, pem) {
        if (!err) {
            var privateKey = pem.toString('ascii');
            var verifier = crypto.createVerify(ENV_CONFIG.License.Algorithm);
            verifier.update(data);
            var isVerified = verifier.verify(privateKey, signature, ENV_CONFIG.License.SignatureFormat);
            callback(isVerified);
        } else {
            callback(null);
        }
    });
};

module.exports = new License();
<commit_msg>remove env vars in license<commit_after>var AWS = require('aws-sdk')
, fs = require('fs')
, crypto = require('crypto');

var License = function(){};

License.prototype.sign = function(data, callback) {
    fs.readFile(ENV_CONFIG.License.PrivateKey, function (err, pem) {
        if (!err) {
            var privateKey = pem.toString('ascii');
            var sign = crypto.createSign(ENV_CONFIG.License.Algorithm);
            sign.update(data);
            var signature = sign.sign(privateKey, ENV_CONFIG.License.SignatureFormat);
            callback(signature);
        } else {
            callback(null);
        }
    });

};

License.prototype.verify = function(data, signature, callback) {
    fs.readFile(ENV_CONFIG.License.PrivateKey, function (err, pem) {
        if (!err) {
            var privateKey = pem.toString('ascii');
            var verifier = crypto.createVerify(ENV_CONFIG.License.Algorithm);
            verifier.update(data);
            var isVerified = verifier.verify(privateKey, signature, ENV_CONFIG.License.SignatureFormat);
            callback(isVerified);
        } else {
            callback(null);
        }
    });
};

module.exports = new License();
<|endoftext|>


<commit_before>let moment = require('moment-timezone');
require('moment/locale/en-gb');
moment.locale("en-gb");

describe('Advanced Passenger Information Splits exposed to Port Operators', function () {
  const now = moment();
  const schDateString = now.format("YYYY-MM-DD");
  const day = now.date();
  const month = now.month() + 1;
  const year = now.year();
  const header = "IATA,ICAO,Origin,Gate/Stand,Status,Scheduled Date,Scheduled Time,Est Arrival,Act Arrival,Est Chox,Act Chox,Est PCP,Total Pax,PCP Pax,API e-Gates,API EEA,API Non-EEA,API Fast Track,Historical e-Gates,Historical EEA,Historical Non-EEA,Historical Fast Track,Terminal Average e-Gates,Terminal Average EEA,Terminal Average Non-EEA,Terminal Average Fast Track";

  beforeEach(function () {
    cy.deleteData();
    cy.setRoles(["test"]);
  });

  function downloadCsv(terminalName, year, month, day) {
    return cy.request({url: '/export/api/'+terminalName+'/'+year+'/'+month+'/'+day, failOnStatusCode: false})
  }

  function waitForArrivalToAppearInTheSystem() {
    cy.visit('#terminal/T1/current/arrivals/?timeRangeStart=0&timeRangeEnd=24');
    cy.get("#arrivals").contains("TS0123");
  }

  it("Forbidden when user does not have the role `ApiViewPortCsv`", function () {
    downloadCsv("T1", year, month, day).then((response) => {
      expect(response.status).to.eq(401)
    });
  });

  it("Forbidden when user does not have the role to access the port", function () {
    cy.setRoles(["api:view-port-arrivals"]);
    downloadCsv("T1", year, month, day).then((response) => {
      expect(response.status).to.eq(401)
  });
  });

  it("Bad Request when the date is invalid", function () {
    cy.setRoles(["test", "api:view-port-arrivals"]);
    downloadCsv("T1", year, month, 40).then((response) => {
      expect(response.status).to.eq(400)
    });
  });

  it("Bad Request when the terminal is invalid", function () {
    cy.setRoles(["test", "api:view-port-arrivals"]);
    downloadCsv("InvalidTerminalName", year, month, day).then((response) => {
      expect(response.status).to.eq(400)
    });
  });

  it("Not Found when there is no arrivals on the date", function () {
    cy.setRoles(["test", "api:view-port-arrivals"]);
    downloadCsv("T1", year, month, day).then((response) => {
      expect(response.status).to.eq(404)
    });
  });

  it("Ok when there are arrivals on the date and user has the correct role", function () {
    cy.addFlight(schDateString + "T00:55:00Z", schDateString + "T00:55:00Z", schDateString + "T01:01:00Z", schDateString + "T01:05:00Z", schDateString + "T00:15:00Z");
    cy.setRoles(["test", "api:view-port-arrivals"]);
    waitForArrivalToAppearInTheSystem();
    downloadCsv("T1", year, month, day).then((response) => {
      expect(response.status).to.eq(200);
      expect(response.body).to.contain(header);
      expect(response.body).to.contain(schDateString + ',' + '00:15');
      expect(response.headers['content-disposition']).to.eq("attachment; filename=export-splits-TEST-T1-" + year + "-" + month + "-" + day + ".csv")
    });
  })

});
<commit_msg>DRT-5532 remove pointless test<commit_after>let moment = require('moment-timezone');
require('moment/locale/en-gb');
moment.locale("en-gb");

describe('Advanced Passenger Information Splits exposed to Port Operators', function () {
  const now = moment();
  const schDateString = now.format("YYYY-MM-DD");
  const day = now.date();
  const month = now.month() + 1;
  const year = now.year();
  const header = "IATA,ICAO,Origin,Gate/Stand,Status,Scheduled Date,Scheduled Time,Est Arrival,Act Arrival,Est Chox,Act Chox,Est PCP,Total Pax,PCP Pax,API e-Gates,API EEA,API Non-EEA,API Fast Track,Historical e-Gates,Historical EEA,Historical Non-EEA,Historical Fast Track,Terminal Average e-Gates,Terminal Average EEA,Terminal Average Non-EEA,Terminal Average Fast Track";

  beforeEach(function () {
    cy.deleteData();
    cy.setRoles(["test"]);
  });

  function downloadCsv(terminalName, year, month, day) {
    return cy.request({url: '/export/api/'+terminalName+'/'+year+'/'+month+'/'+day, failOnStatusCode: false})
  }

  function waitForArrivalToAppearInTheSystem() {
    cy.visit('#terminal/T1/current/arrivals/?timeRangeStart=0&timeRangeEnd=24');
    cy.get("#arrivals").contains("TS0123");
  }

  it("Forbidden when user does not have the role `ApiViewPortCsv`", function () {
    downloadCsv("T1", year, month, day).then((response) => {
      expect(response.status).to.eq(401)
    });
  });

  it("Forbidden when user does not have the role to access the port", function () {
    cy.setRoles(["api:view-port-arrivals"]);
    downloadCsv("T1", year, month, day).then((response) => {
      expect(response.status).to.eq(401)
  });
  });

  it("Bad Request when the date is invalid", function () {
    cy.setRoles(["test", "api:view-port-arrivals"]);
    downloadCsv("T1", year, month, 40).then((response) => {
      expect(response.status).to.eq(400)
    });
  });

  it("Bad Request when the terminal is invalid", function () {
    cy.setRoles(["test", "api:view-port-arrivals"]);
    downloadCsv("InvalidTerminalName", year, month, day).then((response) => {
      expect(response.status).to.eq(400)
    });
  });

  it("Ok when there are arrivals on the date and user has the correct role", function () {
    cy.addFlight(schDateString + "T00:55:00Z", schDateString + "T00:55:00Z", schDateString + "T01:01:00Z", schDateString + "T01:05:00Z", schDateString + "T00:15:00Z");
    cy.setRoles(["test", "api:view-port-arrivals"]);
    waitForArrivalToAppearInTheSystem();
    downloadCsv("T1", year, month, day).then((response) => {
      expect(response.status).to.eq(200);
      expect(response.body).to.contain(header);
      expect(response.body).to.contain(schDateString + ',' + '00:15');
      expect(response.headers['content-disposition']).to.eq("attachment; filename=export-splits-TEST-T1-" + year + "-" + month + "-" + day + ".csv")
    });
  })

});
<|endoftext|>


<commit_before>import {RouteFilterContainer} from './route-filters';

export class RouterConfiguration{
  constructor() {
    this.instructions = [];
    this.options = {};
    this.pipelineSteps = [];
  }

  addPipelineStep(name, step) {
    this.pipelineSteps.push({name, step});
  }

  map(route) {
    if (Array.isArray(route)) {
      route.forEach(this.map.bind(this));
      return this;
    }

    return this.mapRoute(route);
  }

  mapRoute(config) {
    this.instructions.push(router => {
      let routeConfigs = [];

      if (Array.isArray(config.route)) {
        for (let i = 0, ii = config.route.length; i < ii; ++i) {
          let current = Object.assign({}, config);
          current.route = config.route[i];
          routeConfigs.push(current);
        }
      } else {
        routeConfigs.push(Object.assign({}, config));
      }

      let navModel;
      for (let i = 0, ii = routeConfigs.length; i < ii; ++i) {
        let routeConfig = routeConfigs[i];
        routeConfig.settings = routeConfig.settings || {};
        if (!navModel) {
          navModel = router.createNavModel(routeConfig);
        }

        router.addRoute(routeConfig, navModel);
      }
    });

    return this;
  }

  mapUnknownRoutes(config) {
    this.unknownRouteConfig = config;
    return this;
  }

  exportToRouter(router) {
    let instructions = this.instructions;
    for (let i = 0, ii = instructions.length; i < ii; ++i) {
      instructions[i](router);
    }

    if (this.title) {
      router.title = this.title;
    }

    if (this.unknownRouteConfig) {
      router.handleUnknownRoutes(this.unknownRouteConfig);
    }

    router.options = this.options;

    let pipelineSteps = this.pipelineSteps;
    if (pipelineSteps.length) {
      if (!router.isRoot) {
        throw new Error('Pipeline steps can only be added to the root router');
      }

      let filterContainer = router.container.get(RouteFilterContainer);
      for (let i = 0, ii = pipelineSteps.length; i < ii; ++i) {
        let {name, step} = pipelineSteps[i];
        filterContainer.addStep(name, step);
      }
    }
  }
}
<commit_msg>refactor(RouterConfiguration): list all properties on the class directly<commit_after>import {RouteFilterContainer} from './route-filters';

export class RouterConfiguration{
  instructions = [];
  options = {};
  pipelineSteps = [];
  title;
  unknownRouteConfig;

  addPipelineStep(name, step) {
    this.pipelineSteps.push({name, step});
  }

  map(route) {
    if (Array.isArray(route)) {
      route.forEach(this.map.bind(this));
      return this;
    }

    return this.mapRoute(route);
  }

  mapRoute(config) {
    this.instructions.push(router => {
      let routeConfigs = [];

      if (Array.isArray(config.route)) {
        for (let i = 0, ii = config.route.length; i < ii; ++i) {
          let current = Object.assign({}, config);
          current.route = config.route[i];
          routeConfigs.push(current);
        }
      } else {
        routeConfigs.push(Object.assign({}, config));
      }

      let navModel;
      for (let i = 0, ii = routeConfigs.length; i < ii; ++i) {
        let routeConfig = routeConfigs[i];
        routeConfig.settings = routeConfig.settings || {};
        if (!navModel) {
          navModel = router.createNavModel(routeConfig);
        }

        router.addRoute(routeConfig, navModel);
      }
    });

    return this;
  }

  mapUnknownRoutes(config) {
    this.unknownRouteConfig = config;
    return this;
  }

  exportToRouter(router) {
    let instructions = this.instructions;
    for (let i = 0, ii = instructions.length; i < ii; ++i) {
      instructions[i](router);
    }

    if (this.title) {
      router.title = this.title;
    }

    if (this.unknownRouteConfig) {
      router.handleUnknownRoutes(this.unknownRouteConfig);
    }

    router.options = this.options;

    let pipelineSteps = this.pipelineSteps;
    if (pipelineSteps.length) {
      if (!router.isRoot) {
        throw new Error('Pipeline steps can only be added to the root router');
      }

      let filterContainer = router.container.get(RouteFilterContainer);
      for (let i = 0, ii = pipelineSteps.length; i < ii; ++i) {
        let {name, step} = pipelineSteps[i];
        filterContainer.addStep(name, step);
      }
    }
  }
}
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import Relay from 'react-relay';
import UpdateTeamUserMutation from '../../relay/UpdateTeamUserMutation';
import DeleteTeamUserMutation from '../../relay/DeleteTeamUserMutation';
import Select from 'react-select';
import 'react-select/dist/react-select.css';

class TeamMembersCell extends Component {
  handleDeleteRequest(e) {
     e.preventDefault();
     var that = this
     console.log("on delete handle");

     var onFailure = (transaction) => {
       transaction.getError().json().then(function(json) {
         console.log("on failure");
       });

       this.setState({isEditingNameAndDescription: false});
    };
    var onSuccess = (response) => {
      console.log("on sucess");

    };

    Relay.Store.commitUpdate(
      new DeleteTeamUserMutation({
       id: this.props.team_user.node.id,
     }),
     { onSuccess, onFailure }
   );
  }

  handleApproveRequest(e) {
     e.preventDefault();
     var that = this
     console.log("on approve handle");

     var onFailure = (transaction) => {
       transaction.getError().json().then(function(json) {
         console.log("on failure");
       });

       this.setState({isEditingNameAndDescription: false});
    };
    var onSuccess = (response) => {
      console.log("on sucess");

    };

    Relay.Store.commitUpdate(
      new UpdateTeamUserMutation({
       team_id: this.props.team_user.node.team_id,
       user_id: this.props.team_user.node.user_id,
       id: this.props.team_user.node.id,
       status: "member"
     }),
     { onSuccess, onFailure }
   );
 }

  render() {
    const team_user = this.props.team_user
    var isEditing = this.props.isEditing
    const roles = [
      {value: 'contributor', label: 'Contributor'},
      {value: 'journalist', label: 'Journalist'},
      {value: 'editor', label: 'Editor'}
    ];
    return (

{team_user.node.user.name}

          ({team_user.node.user.name})

        <Select className='team-members__member-role' autosize={true} searchable={false} backspaceRemoves={false} clearable={false} disabled={!isEditing} options={roles} value='contributor'/>
        {isEditing ? (<button className='team-members__delete-member'>×</button>) : null }

    );
  }
}

export default TeamMembersCell;
<commit_msg>handle delete Team User in editing team members<commit_after>import React, { Component } from 'react';
import Relay from 'react-relay';
import UpdateTeamUserMutation from '../../relay/UpdateTeamUserMutation';
import DeleteTeamUserMutation from '../../relay/DeleteTeamUserMutation';
import Select from 'react-select';
import 'react-select/dist/react-select.css';

class TeamMembersCell extends Component {
  handleDeleteTeamUser(e) {
     e.preventDefault();
     var that = this
     console.log("on delete handle");

     var onFailure = (transaction) => {
       transaction.getError().json().then(function(json) {
         console.log("on failure");
       });

       this.setState({isEditingNameAndDescription: false});
    };
    var onSuccess = (response) => {
      console.log("on sucess");

    };

    Relay.Store.commitUpdate(
      new DeleteTeamUserMutation({
       id: this.props.team_user.node.id,
     }),
     { onSuccess, onFailure }
   );
  }

  render() {
    const team_user = this.props.team_user
    var isEditing = this.props.isEditing
    const roles = [
      {value: 'contributor', label: 'Contributor'},
      {value: 'journalist', label: 'Journalist'},
      {value: 'editor', label: 'Editor'}
    ];
    return (

{team_user.node.user.name}

          ({team_user.node.user.name})

        <Select className='team-members__member-role' autosize={true} searchable={false} backspaceRemoves={false} clearable={false} disabled={!isEditing} options={roles} value='contributor'/>
        {isEditing ? (<button onClick={this.handleDeleteTeamUser.bind(this)} className='team-members__delete-member'>×</button>) : null }

    );
  }
}

export default TeamMembersCell;
<|endoftext|>


<commit_before>/*
 * Licensed to the Sakai Foundation (SF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The SF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
define(["config/config"], function(config) {

    // Custom CSS Files to load in
    config.skinCSS = ["/dev/skins/default/skin.css"];

    /**
     * Kaltura Settings
     */
    config.kaltura = {
        serverURL:  "http://www.kaltura.com", //INSERT_KALTURA_INSTALLATION_URL_HERE
        partnerId:  656132, //INSERT_YOUR_PARTNER_ID_HERE
        playerId: 5182932 //INSERT_YOUR_PLAYER_ID_HERE
    };

    return config;
});
<commit_msg>add placeholders for kaltura settings<commit_after>/*
 * Licensed to the Sakai Foundation (SF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The SF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
define(["config/config"], function(config) {

    // Custom CSS Files to load in
    config.skinCSS = ["/dev/skins/default/skin.css"];

    /**
     * Kaltura Settings
     */
    config.kaltura = {
        serverURL:  "http://www.kaltura.com", //INSERT_KALTURA_INSTALLATION_URL_HERE
        partnerId:  100, //INSERT_YOUR_PARTNER_ID_HERE
        playerId: 100 //INSERT_YOUR_PLAYER_ID_HERE
    };

    return config;
});
<|endoftext|>


<commit_before>
app.controller('IndexCtrl', function($scope, $location, Index, $timeout) {

    var IndexCtrl = function(){

        var path = $location.search()['_p'] || '/';

        // bind some methods to scope
        [
            'list'
        ].forEach(function(f){
            $scope[f] = angular.bind(this, this[f]);
        }.bind(this))

        $scope.breadcrumb = [];
        $scope.breadcrumb = path.split('/').slice(1).reduce(function(o, i, k, d){
            if(i == '') return o;
            o.push({
                name: i,
                path: '/' + d.slice(0, k+1).join('/')
            })

            return o;

        }, $scope.breadcrumb);

        this.list(path);
    }

    IndexCtrl.prototype.list = function(path){

        Index.load({path: path}, function(data){

            $scope.folders = [];
            $scope.files = [];

            _.each(data, function(entry){
                entry.name = entry.path.split('/');
                entry.name = entry.name[entry.name.length-1];

                if(entry.is_dir){
                    if(entry.thumbnailPath){
                        entry.thumbnailStyle = {
                            'background-image': "url('image/l?_p=" + entry.thumbnailPath + "')"
                        }
                    }
                    $scope.folders.push(entry);
                } else {
                    entry.thumbnailStyle = {
                        'background-image': "url('image/l?_p=" + entry.path + "')"
                    }
                    $scope.files.push(entry);
                }

            }.bind(this))

            $timeout(function(){
                $('a[rel*=prettyPhoto]').prettyPhoto({
                    overlay_gallery: false,
                    deeplinking: false,
                    social_tools: false,
                    opacity: 0.9
                });
            }, 100)

        }.bind(this), function(err){
            if(err.status == 403){
                $location.replace();
                $location.path('/login');
            }
        })
    }

    return new IndexCtrl;

});

app.controller('LoginCtrl', function($scope, $location, $http) {

    var LoginCtrl = function(){

        var path = $location.search()['_p'] || '/';

        // bind some methods to scope
        [
            'login'
        ].forEach(function(f){
                $scope[f] = angular.bind(this, this[f]);
            }.bind(this))

        $scope.error = false;
    }

    LoginCtrl.prototype.login = function(){
        //console.log($scope.form);

        $http.post('api/login', $scope.form).
            success(function(data, status){
                //console.log(data, status);
                $scope.error = false;
                $location.replace();
                $location.path('/');
            }).
            error(function(data, status){
                $scope.error = true;
                //console.log(data, status);
            });
    }

    return new LoginCtrl;

});
<commit_msg>Hide non-image files<commit_after>
app.controller('IndexCtrl', function($scope, $location, Index, $timeout) {

    var IndexCtrl = function(){

        var path = $location.search()['_p'] || '/';

        // bind some methods to scope
        [
            'list'
        ].forEach(function(f){
            $scope[f] = angular.bind(this, this[f]);
        }.bind(this))

        $scope.breadcrumb = [];
        $scope.breadcrumb = path.split('/').slice(1).reduce(function(o, i, k, d){
            if(i == '') return o;
            o.push({
                name: i,
                path: '/' + d.slice(0, k+1).join('/')
            })

            return o;

        }, $scope.breadcrumb);

        this.list(path);
    }

    IndexCtrl.prototype.list = function(path){

        Index.load({path: path}, function(data){

            $scope.folders = [];
            $scope.files = [];

            _.each(data, function(entry){
                entry.name = entry.path.split('/');
                entry.name = entry.name[entry.name.length-1];

                if(entry.is_dir){
                    if(entry.thumbnailPath){
                        entry.thumbnailStyle = {
                            'background-image': "url('image/l?_p=" + entry.thumbnailPath + "')"
                        }
                    }
                    $scope.folders.push(entry);
                } else if(/\.(jpg|png)$/i.test(entry.path)){
                    entry.thumbnailStyle = {
                        'background-image': "url('image/l?_p=" + entry.path + "')"
                    }
                    $scope.files.push(entry);
                }

            }.bind(this))

            $timeout(function(){
                $('a[rel*=prettyPhoto]').prettyPhoto({
                    overlay_gallery: false,
                    deeplinking: false,
                    social_tools: false,
                    opacity: 0.9
                });
            }, 100)

        }.bind(this), function(err){
            if(err.status == 403){
                $location.replace();
                $location.path('/login');
            }
        })
    }

    return new IndexCtrl;

});

app.controller('LoginCtrl', function($scope, $location, $http) {

    var LoginCtrl = function(){

        var path = $location.search()['_p'] || '/';

        // bind some methods to scope
        [
            'login'
        ].forEach(function(f){
                $scope[f] = angular.bind(this, this[f]);
            }.bind(this))

        $scope.error = false;
    }

    LoginCtrl.prototype.login = function(){
        //console.log($scope.form);

        $http.post('api/login', $scope.form).
            success(function(data, status){
                //console.log(data, status);
                $scope.error = false;
                $location.replace();
                $location.path('/');
            }).
            error(function(data, status){
                $scope.error = true;
                //console.log(data, status);
            });
    }

    return new LoginCtrl;

});
<|endoftext|>


<commit_before>var Orbits = (function ()
{
    var nodes = null
    var central_node = null

    var by_node = {}
    var sizes = []
    var belt_sizes = []

    var config = {
        stroke: 2.2,
        spacing: 5, // the distance between orbits
        first_ring_scale: 1.5 // `first_ring_scale * central_node.radius` define radius of the first ring
    }

    function configure(new_config)
    {
        if(!new_config) return

        // Automatical configuration update:
        for(var key in new_config)
        {
            if(new_config.hasOwnProperty(key))
            {
                config[key] = new_config[key]
            }
        }
    }

    function perimeter(R)
    {
        return 2 * Math.PI * R
    }

    function compareRadius(a, b)
    {
        if (a.r < b.r)
          return -1
        if (a.r > b.r)
            return 1
          return 0
    }

    function addOrbit(R, length_extend)
    {
        sizes.push(R - length_extend)
        belt_sizes.push(length_extend)
    }

    function calculateOrbits()
    {

        var base_length = central_node.r * config.first_ring_scale   // radius of the first orbit, depends of the size of central protein

        var orbit = 0
        var length_extend = 0  // how much the radius will extend on the current orbit

        var R = base_length + length_extend * 2
        var outer_belt_perimeter = perimeter(R)
        var available_space_on_outer_belt = outer_belt_perimeter

        for(var i = 0; i < nodes.length; i++)
        {
            var node = nodes[i]

            if(node.r > length_extend)
            {
                // the outer belt will be larger - let's rescale the outer belt
                length_extend = node.r + config.stroke
                R = base_length + length_extend * 2

                var new_outer_belt_perimeter = perimeter(R)
                percent_available = available_space_on_outer_belt / outer_belt_perimeter
                available_space_on_outer_belt = new_outer_belt_perimeter * percent_available
                outer_belt_perimeter = new_outer_belt_perimeter

            }
            var angle = 2 * Math.asin(length_extend / R)
            var l = R * angle
            // if it does not fit, lets move the next orbit, reset values
            if(available_space_on_outer_belt < l)
            {
                // save the orbit which is full
                addOrbit(R, length_extend)
                // create new orbit
                base_length = R + length_extend + config.spacing
                R = base_length + length_extend * 2
                outer_belt_perimeter = perimeter(R)
                available_space_on_outer_belt = outer_belt_perimeter
                length_extend = node.r + config.stroke
                angle = 2 * Math.asin(length_extend / R)
                l = R * angle
                // move to the new orbit
                orbit += 1
            }

            // finaly since it has to fit to the orbit right now, place it on the current orbit
            by_node[node.name] = orbit
            available_space_on_outer_belt -= l
            if(available_space_on_outer_belt < 0) available_space_on_outer_belt = 0

        }
        addOrbit(R, length_extend)
    }

    function _getRadiusByNode(node)
    {
        return sizes[by_node[node.name]]
    }

    var publicSpace = {
        init: function(orbiting_nodes, the_central_node, config)
        {
            nodes = orbiting_nodes
            central_node = the_central_node
            configure(config)
            // sort nodes by radius from the smallest
            nodes.sort(compareRadius)
            calculateOrbits()
        },
        getRadiusByNode: function(node)
        {
            return _getRadiusByNode(node)
        },
        getMaximalRadius: function()
        {
            return sizes[sizes.length - 1] + belt_sizes[belt_sizes.length - 1]
        },
        placeNodes: function()
        {
            for(var i = 0; i < nodes.length; i++)
            {
                var node = nodes[i]
                angle = Math.random() * Math.PI * 2
                R = _getRadiusByNode(node)
                node.x = R * Math.cos(angle) + central_node.x
                node.y = R * Math.sin(angle) + central_node.y
            }
        }
    }

    return publicSpace

} ())
<commit_msg>Precalculate positions on orbits completly<commit_after>var Orbits = (function ()
{
    var nodes = null
    var central_node = null

    var by_node = {}
    var orbits = []

    var config = {
        stroke: 2.2,
        spacing: 5, // the distance between orbits
        first_ring_scale: 1.5 // `first_ring_scale * central_node.radius` define radius of the first ring
    }

    function configure(new_config)
    {
        if(!new_config) return

        // Automatical configuration update:
        for(var key in new_config)
        {
            if(new_config.hasOwnProperty(key))
            {
                config[key] = new_config[key]
            }
        }
    }

    function perimeter(R)
    {
        return 2 * Math.PI * R
    }

    function compareRadius(a, b)
    {
        if (a.r < b.r)
          return -1
        if (a.r > b.r)
            return 1
          return 0
    }

    // warning: using constructor pattern, not module
    function Orbit(number)
    {
        this.number = number
        this.nodes_count = 0

        this.radius = null
        this.width = null   // how much space takes the biggest node on this orbit

        this.addNode = function(node)
        {
            by_node[node.name] = this.number
            this.nodes_count += 1
        }

        this.setDimensions = function(R, length_extend)
        {
            this.radius = R - length_extend
            this.width = length_extend
        }
    }

    function calculateOrbits()
    {
        // radius of the first orbit, depends of the size of central protein
        var base_length = central_node.r * config.first_ring_scale

        orbits.push(new Orbit(0))
        var length_extend = 0  // how much the radius will extend on the current orbit

        var R = base_length + length_extend * 2
        var outer_belt_perimeter = perimeter(R)
        var available_space_on_outer_belt = outer_belt_perimeter

        for(var i = 0; i < nodes.length; i++)
        {
            var node = nodes[i]

            if(node.r > length_extend)
            {
                // the outer belt will be larger - let's rescale the outer belt
                length_extend = node.r + config.stroke
                R = base_length + length_extend * 2

                var new_outer_belt_perimeter = perimeter(R)
                percent_available = available_space_on_outer_belt / outer_belt_perimeter
                available_space_on_outer_belt = new_outer_belt_perimeter * percent_available
                outer_belt_perimeter = new_outer_belt_perimeter

            }
            var angle = 2 * Math.asin(length_extend / R)
            var l = R * angle
            // if it does not fit, lets move the next orbit, reset values
            if(available_space_on_outer_belt < l)
            {
                // save the orbit which is full
                orbits[orbits.length - 1].setDimensions(R, length_extend)
                // create new orbit
                base_length = R + length_extend + config.spacing
                R = base_length + length_extend * 2
                outer_belt_perimeter = perimeter(R)
                available_space_on_outer_belt = outer_belt_perimeter
                length_extend = node.r + config.stroke
                angle = 2 * Math.asin(length_extend / R)
                l = R * angle
                // move to the new orbit
                orbits.push(new Orbit(orbits.length))
            }

            // finaly since it has to fit to the orbit right now, place it on the current orbit
            orbits[orbits.length - 1].addNode(node)
            available_space_on_outer_belt -= l
            if(available_space_on_outer_belt < 0) available_space_on_outer_belt = 0

        }
        orbits[orbits.length - 1].setDimensions(R, length_extend)
    }

    function getSlots()
    {
        // how many nodes should be placed on each of the available orbits
        var slots = new Array(orbits.length)
        for(var i = 0; i < orbits.length; i++)
            slots[i] = orbits[i].nodes_count
        return slots
    }

    var publicSpace = {
        init: function(orbiting_nodes, the_central_node, config)
        {
            nodes = orbiting_nodes
            central_node = the_central_node
            configure(config)
            // sort nodes by radius from the smallest
            nodes.sort(compareRadius)
            calculateOrbits()
        },
        getRadiusByNode: function(node)
        {
            return orbits[by_node[node.name]].radius
        },
        getMaximalRadius: function()
        {
            var orbit = orbits[orbits.length - 1]
            return orbit.radius + orbit.width
        },
        placeNodes: function()
        {
            var slots = getSlots()

            for(var i = 0; i < nodes.length; i++)
            {
                var node = nodes[i]

                var orbit_id = by_node[node.name]
                var orbit = orbits[orbit_id]

                var full_circle = Math.PI * 2

                var fraction_occupied = slots[orbit_id] / orbit.nodes_count
                var angle = full_circle * fraction_occupied

                node.x = orbit.radius * Math.cos(angle) + central_node.x
                node.y = orbit.radius * Math.sin(angle) + central_node.y

                slots[orbit_id] -= 1
            }
        }
    }

    return publicSpace

} ())
<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';
import classNames from 'classnames';
import { get } from 'lodash';

import PTButton from '../../ui-elements/PTButton/PTButton';
import UserPanelItem from './UserPanelItem';
import NotificationContent from '../../presentational/temprorary/NotificationContent'
import UserAccountPanel from './UserAccountPanel'
import { themeConfigs } from '../../../themes.config';

import TopHeaderButtons from '../../theme/components/TopHeaderButtons';

const USER_ACCOUNT_PANEL = 'userAccountPanel';
const NOTIFICATION_CONTENT = 'notificationContent';

export default class UserPanel extends PureComponent {

  static defaultProps = {
    addUserPanels: [],
    pageUrl: '',
    userId: '',
  };

  state = {
    openedPanel: '',
  };

  /* istanbul ignore next */
  componentWillMount() {
    document.addEventListener('click', this.handleClick, false);
  }

  /* istanbul ignore next */
  componentWillUnmount() {
    document.removeEventListener('click', this.handleClick, false);
  }

  handleClick = /* istanbul ignore next */ (e) => {
    if (!this.node.contains(e.target)) {
      this.setState({ openedPanel: '' });
    }
  };

  handleMouseDown = (name) => {
    /* istanbul ignore next */
    this.setState((prevState) => {
      if (prevState.openedPanel !== name) {
        return ({ openedPanel: name })
      }
      return ({ openedPanel: '' })
    })
  };

  closePanel = () => {
    this.setState({ openedPanel: '' });
  };

  getUserPanelsItems = (addUserPanels) => {
    if (addUserPanels.length) {
      return addUserPanels.map((el) => {
        return (
          <UserPanelItem className="user-panel-item">
            { el }
          </UserPanelItem>
        );
      });
    }
    return null;
  };

  render() {
    const { openedPanel } = this.state;
    const { addUserPanels, pageUrl, homepageLink } = this.props;

    const isSearch = get(themeConfigs, 'topHeader.showSearch', true);
    const isNotifications = get(themeConfigs, 'topHeader.showNotifications', true);
    const isUserPanel = get(themeConfigs, 'topHeader.showUserPanel', true);

    const additionalUserPanels = this.getUserPanelsItems(addUserPanels);

    return (

 this.node = node}>
        { additionalUserPanels }

        <TopHeaderButtons pageUrl={pageUrl} homepageLink={homepageLink} />

        {isNotifications ? <UserPanelItem className={classNames('user-panel-item dropdown', { 'open': openedPanel === NOTIFICATION_CONTENT })}>
          <NotificationContent />
          <PTButton className="btn-header btn-notification" onClick={() => this.handleMouseDown(NOTIFICATION_CONTENT)}>

              2

          </PTButton>
        </UserPanelItem> : null}

        {isUserPanel ? <UserPanelItem className={classNames('user-panel-item dropdown', { 'open': openedPanel === USER_ACCOUNT_PANEL })}>
          <UserAccountPanel onClick={this.handleMouseDown} onClose={this.closePanel} />
          <PTButton id="icon-profile" className="btn-header btn-user" onClick={() => this.handleMouseDown(USER_ACCOUNT_PANEL)}>

          </PTButton>
        </UserPanelItem> : null}

    )
  }
}
<commit_msg>Accessitility Issue 1: Toolbar Inactivity<commit_after>import React, { PureComponent } from 'react';
import classNames from 'classnames';
import { get } from 'lodash';

import PTButton from '../../ui-elements/PTButton/PTButton';
import UserPanelItem from './UserPanelItem';
import NotificationContent from '../../presentational/temprorary/NotificationContent'
import UserAccountPanel from './UserAccountPanel'
import { themeConfigs } from '../../../themes.config';

import TopHeaderButtons from '../../theme/components/TopHeaderButtons';

const USER_ACCOUNT_PANEL = 'userAccountPanel';
const NOTIFICATION_CONTENT = 'notificationContent';

export default class UserPanel extends PureComponent {

  static defaultProps = {
    addUserPanels: [],
    pageUrl: '',
    userId: '',
  };

  state = {
    openedPanel: '',
  };

  /* istanbul ignore next */
  componentWillMount() {
    document.addEventListener('click', this.handleClick, false);
  }

  /* istanbul ignore next */
  componentWillUnmount() {
    document.removeEventListener('click', this.handleClick, false);
  }

  handleClick = /* istanbul ignore next */ (e) => {
    if (!this.node.contains(e.target)) {
      this.setState({ openedPanel: '' });
    }
  };

  handleMouseDown = (name) => {
    /* istanbul ignore next */
    this.setState((prevState) => {
      if (prevState.openedPanel !== name) {
        return ({ openedPanel: name })
      }
      return ({ openedPanel: '' })
    })
  };

  closePanel = () => {
    this.setState({ openedPanel: '' });
  };

  getUserPanelsItems = (addUserPanels) => {
    if (addUserPanels.length) {
      return addUserPanels.map((el) => {
        return (
          <UserPanelItem className="user-panel-item">
            { el }
          </UserPanelItem>
        );
      });
    }
    return null;
  };

  render() {
    const { openedPanel } = this.state;
    const { addUserPanels, pageUrl, homepageLink } = this.props;

    const isSearch = get(themeConfigs, 'topHeader.showSearch', true);
    const isNotifications = get(themeConfigs, 'topHeader.showNotifications', true);
    const isUserPanel = get(themeConfigs, 'topHeader.showUserPanel', true);

    const additionalUserPanels = this.getUserPanelsItems(addUserPanels);

    return (

 this.node = node}>
        { additionalUserPanels }

        <TopHeaderButtons pageUrl={pageUrl} homepageLink={homepageLink} />

        {isNotifications ? <UserPanelItem role="tab" className={classNames('user-panel-item dropdown', { 'open': openedPanel === NOTIFICATION_CONTENT })}>
          <NotificationContent />
          <PTButton className="btn-header btn-notification" onClick={() => this.handleMouseDown(NOTIFICATION_CONTENT)}>

              2

          </PTButton>
        </UserPanelItem> : null}

        {isUserPanel ? <UserPanelItem role="tab" className={classNames('user-panel-item dropdown', { 'open': openedPanel === USER_ACCOUNT_PANEL })}>
          <UserAccountPanel onClick={this.handleMouseDown} onClose={this.closePanel} />
          <PTButton id="icon-profile" className="btn-header btn-user" onClick={() => this.handleMouseDown(USER_ACCOUNT_PANEL)}>

          </PTButton>
        </UserPanelItem> : null}

    )
  }
}
<|endoftext|>


<commit_before>/*global html */

var findProprietaryStyle;

if(html){
	findProprietaryStyle = function (style) {
		if ('string' != typeof html.style[style]) {
			style = style.charAt(0).toUpperCase() + style.substring(1);
			var prefixes = ['Moz', 'O', 'Khtml', 'Webkit', 'ms'];
			for (var i = prefixes.length; i--; ) {
				if ('undefined' != typeof html.style[prefixes[i] + style]) {
					return prefixes[i] + style;
				}
			}
			return null;
		}
		return style;
	};
}
<commit_msg>Fixed typo and added style capable check<commit_after>/*global html */

var findProprietaryStyle;

if(html && isHostObjectProperty(html, "style")){
	findProprietaryStyle = function (style, el) {
		if ('string' != typeof el.style[style]) {
			style = style.charAt(0).toUpperCase() + style.substring(1);
			var prefixes = ['Moz', 'O', 'Khtml', 'Webkit', 'Ms'];
			for (var i = prefixes.length; i--; ) {
				if ('undefined' != typeof el.style[prefixes[i] + style]) {
					return prefixes[i] + style;
				}
			}
			return null;
		}
		return style;
	};
}
<|endoftext|>


<commit_before>/* eslint-disable react/no-unused-state */
/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import React from 'react';
import PropTypes from 'prop-types';

import { GenericPage } from '../GenericPage';
import { expansionPageStyles } from '../../globalStyles';

/**
 * Renders page to be displayed in StocktakeEditPage -> expansion.
 *
 * @prop  {Realm}         database       App wide database.
 * @prop  {Realm.object}  stocktakeItem  The stocktakeItem, a parent of
 *                                       StocktakeBatches in this expansion
 */
export class RequisitionRegimenModalTable extends React.Component {
  constructor(props) {
    super(props);
    this.state = { forceUpdate: [] };
  }

  onEndEditing = (key, rowData, newValue) => {
    const { database, requisition } = this.props;
    const { parsedCustomData } = requisition;
    const { regimenData } = parsedCustomData;

    const rowIndex = regimenData.findIndex(row => row.code === rowData.code);
    regimenData[rowIndex][key] = newValue;

    database.write(() => {
      requisition.saveCustomData(parsedCustomData);
      database.save('Requisition', requisition);
    });

    this.setState({ forceUpdate: [...regimenData] });
  };

  renderCell = (key, regimenRow) => {
    const { requisition } = this.props;
    const isEditable = !requisition.isFinalised;

    switch (key) {
      default:
        return {
          cellContents: regimenRow[key],
        };
      case 'value': {
        return {
          type: isEditable ? 'editable' : 'text',
          cellContents: regimenRow.value || '',
          keyboardType: regimenRow.type === 'string' ? 'default' : null,
        };
      }
      case 'comment': {
        return {
          type: isEditable ? 'editable' : 'text',
          cellContents: regimenRow.comment || '',
          keyboardType: 'default',
        };
      }
    }
  };

  getData = () => {
    const { requisition } = this.props;
    const { parsedCustomData } = requisition;
    const { regimenData } = parsedCustomData;
    return regimenData;
  };

  render() {
    const { database, genericTablePageStyles } = this.props;

    return (
      <GenericPage
        data={this.getData()}
        renderCell={this.renderCell}
        hideSearchBar={true}
        dontRenderSearchBar={true}
        renderDataTableFooter={null} // Overrides default generic pages footer.
        onEndEditing={this.onEndEditing}
        database={database}
        pageStyles={expansionPageStyles}
        {...genericTablePageStyles}
        columns={[
          {
            key: 'name',
            width: 4,
            title: 'Question',
            alignText: 'left',
          },
          {
            key: 'value',
            width: 1,
            title: 'Value',
            alignText: 'right',
          },
          {
            key: 'comment',
            width: 5,
            title: 'Comment',
            alignText: 'right',
          },
        ]}
      />
    );
  }
}

export default RequisitionRegimenModalTable;

/* eslint-disable react/require-default-props, react/forbid-prop-types */
RequisitionRegimenModalTable.propTypes = {
  database: PropTypes.object,
  genericTablePageStyles: PropTypes.object,
  requisition: PropTypes.object.isRequired,
};
<commit_msg>Add removal of old regimen modal<commit_after><|endoftext|>


<commit_before>// var should = require('should');
var webdriverio = require('webdriverio');
var selenium = require('selenium-standalone');

describe('Form session storage', function() {

  var client = webdriverio.remote({
    logLevel: 'command',
    desiredCapabilities: {
      browserName: 'phantomjs'
    }
  });

  this.timeout(30000);

  before(function(done){
    selenium.install(
      function (err) {
        if (err) return done(err);

        selenium.start(function() {
          client.init().then(function() {
            done();
          });
        });
      }
    );

  });

  it('should prevent people clicking more than once on input submits', function(done) {

    client
      .url('http://localhost:3000/components/elements/land-registry/double-click-prevention/demo/')
      .waitForExist('.phantom-js-test-rendering', 5000)
      .setValue('#foo', 'WebdriverIO')
      .click('#button-1')
      .getAttribute('#button-2', 'disabled')
      .then(function(attr) {
        attr.should.be.equal('true')
      })
      .call(done);
  });

  it('should prevent people clicking more than once on buttons', function(done) {

    client
      .url('http://localhost:3000/components/elements/land-registry/double-click-prevention/demo/')
      .waitForExist('.phantom-js-test-rendering', 5000)
      .click('#button-2')
      .getAttribute('#button-2', 'disabled')
      .then(function(attr) {
        attr.should.be.equal('true')
      })
      .call(done);
  });

  after(function(done) {
    done();
  });

});
<commit_msg>Remove tests as it's not possible to test this in it's current form<commit_after><|endoftext|>


<commit_before>/*
 * PiCard
 * Copyright (c) 2013 Tim De Pauw <http://timdp.github.com/>
 * Released under the MIT License
 */

var PiCard = (function() {
    var opt = {
        axisWidth:       1,
        plotPadding:     10,
        labelMargin:     10,
        plotMarkerSize:  6,
        plotMarkerWidth: 1,
        maxPieRadius:    20,
        startAngle:      -90,
        clockwise:       true,
        dotScale:        "quad",
        fontFamily:      "Verdana, Arial, Helvetica, sans-serif",
        fontSize:        12,
        axisColor:       "#666",
        plotMarkerColor: "#999",
        axisLabelColor:  "#666",
        pieColors:       [
            "#C90", "#0C9", "#90C", "#9C0", "#09C", "#C09",
            "#C00", "#0C0", "#00C", "#099", "#909", "#990",
            "#C66", "#6C6", "#66C", "#999"
        ]
    };

    var loc = {
        dayNames:     [ "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN" ],
        summaryTitle: "Summary",
        summaryLabel: "Commits:",
        loadingText:  "Loading …"
    };

    var createChart = function(data, target) {
        target.empty();
        var users = [];
        var userTotals = {};
        var grandTotal = 0;
        for (user in data) {
            users.push(user);
            var total = 0;
            for (d in data[user]) {
                for (h in data[user][d]) {
                    total += data[user][d][h];
                }
            }
            userTotals[user] = total;
            grandTotal += total;
        }
        var userColors = getUserColors(users);

        var legend = $("
"
            + ""
            + loc.summaryLabel + " " + grandTotal
            + "
");
        for (var i = 0; i < users.length; i++) {
            legend.append(" ");
            legend.append($("")
                .css({
                    color:       userColors[users[i]],
                    marginRight: "1ex",
                    whiteSpace:  "nowrap"
                })
                .text(users[i] + " (" + userTotals[users[i]] + ")"));
        }
        target.append(legend);

        var containerID = target.attr("id") + "-container";
        var container = $("
").attr("id", containerID);
        target.append(container);

        var measure = getMeasurements();

        var stage = new Kinetic.Stage({
            container: containerID,
            width:     measure.width,
            height:    measure.height
        });
        var plotArea = createPlotArea(measure);
        stage.add(plotArea);
        var plot = createPlot(data, userColors, measure);
        stage.add(plot);
        var axes = createAxes(measure);
        stage.add(axes);
    };

    var createPlotArea = function(measure) {
        var plotArea = new Kinetic.Layer();
        var x0 = measure.yLabelWidth + opt.labelMargin + opt.axisWidth
            + opt.plotPadding + opt.maxPieRadius;
        var y = opt.plotPadding + opt.maxPieRadius;
        var s = opt.plotMarkerSize / 2;
        for (var d = 0; d < 7; d++) {
            var x = x0;
            for (var h = 0; h < 24; h++) {
                plotArea.add(new Kinetic.Line({
                    points:      [ x - s, y, x + s, y ],
                    stroke:      opt.plotMarkerColor,
                    strokeWidth: opt.plotMarkerWidth
                }));
                plotArea.add(new Kinetic.Line({
                    points:      [ x, y - s, x, y + s ],
                    stroke:      opt.plotMarkerColor,
                    strokeWidth: opt.plotMarkerWidth
                }));
                x += opt.maxPieRadius * 2;
            }
            y += opt.maxPieRadius * 2;
        }
        return plotArea;
    };

    var createPlot = function(data, userColors, measure) {
        var totals = calculateTotals(data);
        var max = getMaximum(totals);
        var plot = new Kinetic.Layer();
        var x0 = measure.yLabelWidth + opt.labelMargin + opt.axisWidth
            + opt.plotPadding + opt.maxPieRadius;
        var y = opt.plotPadding + opt.maxPieRadius;
        for (var d = 0; d < 7; d++) {
            var x = x0;
            for (var h = 0; h < 24; h++) {
                if (totals[d] && totals[d][h]) {
                    plotValue(d, h, data, totals, max, plot, x, y, userColors);
                }
                x += opt.maxPieRadius * 2;
            }
            y += opt.maxPieRadius * 2;
        }
        return plot;
    };

    var createAxes = function(measure) {
        var axes = new Kinetic.Layer();
        createXAxis(axes, measure);
        createYAxis(axes, measure);
        return axes;
    }

    var createXAxis = function(axes, measure) {
        axes.add(new Kinetic.Line({
            points:      [
                measure.yLabelWidth + opt.labelMargin,
                measure.plotHeight + opt.axisWidth / 2,
                measure.width,
                measure.plotHeight + opt.axisWidth / 2
            ],
            stroke:      opt.axisColor,
            strokeWidth: opt.axisWidth
        }));
        var x = measure.yLabelWidth + opt.labelMargin + opt.axisWidth
            + opt.plotPadding + opt.maxPieRadius;
        var y = measure.plotHeight + opt.axisWidth + opt.labelMargin;
        for (var h = 0; h < 24; h++) {
            var text = createText((h < 10) ? "0" + h : h,
                x, y, opt.axisLabelColor);
            text.setOffset({
                x: text.getWidth() / 2
            });
            axes.add(text);
            x += opt.maxPieRadius * 2;
        }
    };

    var createYAxis = function(axes, measure) {
        axes.add(new Kinetic.Line({
            points:      [
                measure.yLabelWidth + opt.labelMargin + opt.axisWidth / 2,
                0,
                measure.yLabelWidth + opt.labelMargin + opt.axisWidth / 2,
                measure.plotHeight + opt.axisWidth
            ],
            stroke:      opt.axisColor,
            strokeWidth: opt.axisWidth
        }));
        var x = measure.yLabelWidth;
        var y = opt.plotPadding + opt.maxPieRadius - measure.labelHeight / 2;
        for (var d = 0; d < 7; d++) {
            var text = createText(loc.dayNames[d],
                x, y, opt.axisLabelColor);
            text.setOffset({
                x: text.getWidth()
            });
            axes.add(text);
            y += opt.maxPieRadius * 2;
        }
    };

    var plotValue = function(d, h, data, totals, max, plot, x, y, userColors) {
        var total = totals[d][h];
        var ratio = getRatio(total, max);
        if (ratio <= 0) {
            return;
        }
        var radius = ratio * opt.maxPieRadius;
        var angle = (opt.startAngle === null)
            ? Math.random() * 360 : opt.startAngle;
        for (user in data) {
            if (!data[user][d] || !data[user][d][h]) {
                continue;
            }
            var degrees = 360 * (data[user][d][h] / total);
            if (opt.clockWise) {
                degrees = -degrees;
            }
            var wedge = new Kinetic.Wedge({
                x:           x,
                y:           y,
                radius:      radius,
                rotationDeg: angle,
                angleDeg:    degrees,
                fill:        userColors[user]
            });
            plot.add(wedge);
            angle += degrees;
        }
    };

    var getRatio = function(value, max) {
        if (value <= 0) {
            return 0;
        }
        var transform = (opt.scale == "quad") ? Math.sqrt
            : (opt.scale == "log") ? Math.log
            : function(n) { return n; };
        return transform(value) / transform(max);
    };

    var getUserColors = function(users) {
        var userColors = {};
        for (var i = 0; i < users.length; i++) {
            userColors[users[i]] = opt.pieColors[i % opt.pieColors.length];
        }
        return userColors;
    };

    var calculateTotals = function(data) {
        var totals = [];
        for (var d = 0; d < 7; d++) {
            var dayTotals = [];
            for (var h = 0; h < 24; h++) {
                dayTotals[h] = 0;
                for (user in data) {
                    if (data[user][d] && data[user][d][h]) {
                        dayTotals[h] += data[user][d][h];
                    }
                }
            }
            totals[d] = dayTotals;
        }
        return totals;
    };

    var getMaximum = function(totals) {
        var max = 0;
        for (var d = 0; d < 7; d++) {
            for (var h = 0; h < 24; h++) {
                if (totals[d] && totals[d][h]) {
                    max = Math.max(max, totals[d][h]);
                }
            }
        }
        return max;
    };

    var getMeasurements = function() {
        var yLabelWidth = 0;
        for (var d = 0; d < 7; d++) {
            var text = createText(loc.dayNames[d], 0, 0, "black");
            yLabelWidth = Math.max(yLabelWidth, text.getWidth());
        }
        var labelHeight = createText("X", 0, 0, "black").getHeight();

        var plotWidth = opt.plotPadding + opt.maxPieRadius * 2 * 24
            + opt.plotPadding;
        var plotHeight = opt.plotPadding + opt.maxPieRadius * 2 * 7
            + opt.plotPadding;
        var width = yLabelWidth + opt.labelMargin + opt.axisWidth + plotWidth;
        var height = plotHeight + opt.axisWidth + opt.labelMargin + labelHeight;

        return {
            width:       width,
            height:      height,
            plotWidth:   plotWidth,
            plotHeight:  plotHeight,
            yLabelWidth: yLabelWidth,
            labelHeight: labelHeight
        };
    };

    var createText = function(text, x, y, color) {
        return new Kinetic.Text({
            text:       text,
            fontFamily: opt.fontFamily,
            fontSize:   opt.fontSize,
            fill:       color,
            x:          x,
            y:          y
        });
    };

    var processQueue = function(queue, summaryData) {
        var nextEntry = function(i) {
            if (i < queue.length) {
                $.ajax(queue[i].url)
                    .done(function(data) {
                        createChart(data, queue[i].target);
                        updateSummary(queue[i].name, data, summaryData);
                        nextEntry(i + 1);
                    })
                    .fail(function(xhr, stat, err) {
                        // TODO
                        alert("Failed to load data. Reload to try again.");
                    });
            } else {
                createChart(summaryData, $("#pc-tab-summary"));
            }
        };
        nextEntry(0);
    };

    var updateSummary = function(name, data, summaryData) {
        summaryData[name] = {};
        for (var d = 0; d < 7; d++) {
            var dayData = {};
            for (var h = 0; h < 24; h++) {
                dayData[h] = 0;
            }
            summaryData[name][d] = dayData;
        }
        for (user in data) {
            for (d in data[user]) {
                for (h in data[user][d]) {
                    summaryData[name][d][h] += data[user][d][h];
                }
            }
        }
    };

    var initialize = function(container, sources) {
        var queue = [];
        container.empty();
        var tabList = $("
");
        container.append(tabList);
        var tabID = "pc-tab-summary";
        var tab = addTab(loc.summaryTitle, tabID, tabList, container);
        for (var i = 0; i < sources.length; i++) {
            var tabName = sources[i].name;
            var tabID = "pc-tab-" + i;
            var tab = addTab(tabName, tabID, tabList, container);
            queue.push({
                name: tabName,
                url: sources[i].url,
                target: tab
            });
        }
        container.tabs();
        var summaryData = {};
        processQueue(queue, summaryData);
     };

     var addTab = function(tabName, tabID, tabList, container) {
        tabList.append($("
")
            .append($("")
                .attr("href", "#" + tabID).text(tabName)));
        var tab = $("
").attr("id", tabID).addClass("pc-tab")
            .text(loc.loadingText);
        container.append(tab);
        return tab;
     };

    return {
        options: opt,
        locale: loc,
        initialize: initialize
    };
})();
<commit_msg>Indentation<commit_after>/*
 * PiCard
 * Copyright (c) 2013 Tim De Pauw <http://timdp.github.com/>
 * Released under the MIT License
 */

var PiCard = (function() {
    var opt = {
        axisWidth:       1,
        plotPadding:     10,
        labelMargin:     10,
        plotMarkerSize:  6,
        plotMarkerWidth: 1,
        maxPieRadius:    20,
        startAngle:      -90,
        clockwise:       true,
        dotScale:        "quad",
        fontFamily:      "Verdana, Arial, Helvetica, sans-serif",
        fontSize:        12,
        axisColor:       "#666",
        plotMarkerColor: "#999",
        axisLabelColor:  "#666",
        pieColors:       [
            "#C90", "#0C9", "#90C", "#9C0", "#09C", "#C09",
            "#C00", "#0C0", "#00C", "#099", "#909", "#990",
            "#C66", "#6C6", "#66C", "#999"
        ]
    };

    var loc = {
        dayNames:     [ "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN" ],
        summaryTitle: "Summary",
        summaryLabel: "Commits:",
        loadingText:  "Loading …"
    };

    var createChart = function(data, target) {
        target.empty();
        var users = [];
        var userTotals = {};
        var grandTotal = 0;
        for (user in data) {
            users.push(user);
            var total = 0;
            for (d in data[user]) {
                for (h in data[user][d]) {
                    total += data[user][d][h];
                }
            }
            userTotals[user] = total;
            grandTotal += total;
        }
        var userColors = getUserColors(users);

        var legend = $("
"
            + ""
            + loc.summaryLabel + " " + grandTotal
            + "
");
        for (var i = 0; i < users.length; i++) {
            legend.append(" ");
            legend.append($("")
                .css({
                    color:       userColors[users[i]],
                    marginRight: "1ex",
                    whiteSpace:  "nowrap"
                })
                .text(users[i] + " (" + userTotals[users[i]] + ")"));
        }
        target.append(legend);

        var containerID = target.attr("id") + "-container";
        var container = $("
").attr("id", containerID);
        target.append(container);

        var measure = getMeasurements();

        var stage = new Kinetic.Stage({
            container: containerID,
            width:     measure.width,
            height:    measure.height
        });
        var plotArea = createPlotArea(measure);
        stage.add(plotArea);
        var plot = createPlot(data, userColors, measure);
        stage.add(plot);
        var axes = createAxes(measure);
        stage.add(axes);
    };

    var createPlotArea = function(measure) {
        var plotArea = new Kinetic.Layer();
        var x0 = measure.yLabelWidth + opt.labelMargin + opt.axisWidth
            + opt.plotPadding + opt.maxPieRadius;
        var y = opt.plotPadding + opt.maxPieRadius;
        var s = opt.plotMarkerSize / 2;
        for (var d = 0; d < 7; d++) {
            var x = x0;
            for (var h = 0; h < 24; h++) {
                plotArea.add(new Kinetic.Line({
                    points:      [ x - s, y, x + s, y ],
                    stroke:      opt.plotMarkerColor,
                    strokeWidth: opt.plotMarkerWidth
                }));
                plotArea.add(new Kinetic.Line({
                    points:      [ x, y - s, x, y + s ],
                    stroke:      opt.plotMarkerColor,
                    strokeWidth: opt.plotMarkerWidth
                }));
                x += opt.maxPieRadius * 2;
            }
            y += opt.maxPieRadius * 2;
        }
        return plotArea;
    };

    var createPlot = function(data, userColors, measure) {
        var totals = calculateTotals(data);
        var max = getMaximum(totals);
        var plot = new Kinetic.Layer();
        var x0 = measure.yLabelWidth + opt.labelMargin + opt.axisWidth
            + opt.plotPadding + opt.maxPieRadius;
        var y = opt.plotPadding + opt.maxPieRadius;
        for (var d = 0; d < 7; d++) {
            var x = x0;
            for (var h = 0; h < 24; h++) {
                if (totals[d] && totals[d][h]) {
                    plotValue(d, h, data, totals, max, plot, x, y, userColors);
                }
                x += opt.maxPieRadius * 2;
            }
            y += opt.maxPieRadius * 2;
        }
        return plot;
    };

    var createAxes = function(measure) {
        var axes = new Kinetic.Layer();
        createXAxis(axes, measure);
        createYAxis(axes, measure);
        return axes;
    }

    var createXAxis = function(axes, measure) {
        axes.add(new Kinetic.Line({
            points:      [
                measure.yLabelWidth + opt.labelMargin,
                measure.plotHeight + opt.axisWidth / 2,
                measure.width,
                measure.plotHeight + opt.axisWidth / 2
            ],
            stroke:      opt.axisColor,
            strokeWidth: opt.axisWidth
        }));
        var x = measure.yLabelWidth + opt.labelMargin + opt.axisWidth
            + opt.plotPadding + opt.maxPieRadius;
        var y = measure.plotHeight + opt.axisWidth + opt.labelMargin;
        for (var h = 0; h < 24; h++) {
            var text = createText((h < 10) ? "0" + h : h,
                x, y, opt.axisLabelColor);
            text.setOffset({
                x: text.getWidth() / 2
            });
            axes.add(text);
            x += opt.maxPieRadius * 2;
        }
    };

    var createYAxis = function(axes, measure) {
        axes.add(new Kinetic.Line({
            points:      [
                measure.yLabelWidth + opt.labelMargin + opt.axisWidth / 2,
                0,
                measure.yLabelWidth + opt.labelMargin + opt.axisWidth / 2,
                measure.plotHeight + opt.axisWidth
            ],
            stroke:      opt.axisColor,
            strokeWidth: opt.axisWidth
        }));
        var x = measure.yLabelWidth;
        var y = opt.plotPadding + opt.maxPieRadius - measure.labelHeight / 2;
        for (var d = 0; d < 7; d++) {
            var text = createText(loc.dayNames[d],
                x, y, opt.axisLabelColor);
            text.setOffset({
                x: text.getWidth()
            });
            axes.add(text);
            y += opt.maxPieRadius * 2;
        }
    };

    var plotValue = function(d, h, data, totals, max, plot, x, y, userColors) {
        var total = totals[d][h];
        var ratio = getRatio(total, max);
        if (ratio <= 0) {
            return;
        }
        var radius = ratio * opt.maxPieRadius;
        var angle = (opt.startAngle === null)
            ? Math.random() * 360 : opt.startAngle;
        for (user in data) {
            if (!data[user][d] || !data[user][d][h]) {
                continue;
            }
            var degrees = 360 * (data[user][d][h] / total);
            if (opt.clockWise) {
                degrees = -degrees;
            }
            var wedge = new Kinetic.Wedge({
                x:           x,
                y:           y,
                radius:      radius,
                rotationDeg: angle,
                angleDeg:    degrees,
                fill:        userColors[user]
            });
            plot.add(wedge);
            angle += degrees;
        }
    };

    var getRatio = function(value, max) {
        if (value <= 0) {
            return 0;
        }
        var transform = (opt.scale == "quad") ? Math.sqrt
            : (opt.scale == "log") ? Math.log
            : function(n) { return n; };
        return transform(value) / transform(max);
    };

    var getUserColors = function(users) {
        var userColors = {};
        for (var i = 0; i < users.length; i++) {
            userColors[users[i]] = opt.pieColors[i % opt.pieColors.length];
        }
        return userColors;
    };

    var calculateTotals = function(data) {
        var totals = [];
        for (var d = 0; d < 7; d++) {
            var dayTotals = [];
            for (var h = 0; h < 24; h++) {
                dayTotals[h] = 0;
                for (user in data) {
                    if (data[user][d] && data[user][d][h]) {
                        dayTotals[h] += data[user][d][h];
                    }
                }
            }
            totals[d] = dayTotals;
        }
        return totals;
    };

    var getMaximum = function(totals) {
        var max = 0;
        for (var d = 0; d < 7; d++) {
            for (var h = 0; h < 24; h++) {
                if (totals[d] && totals[d][h]) {
                    max = Math.max(max, totals[d][h]);
                }
            }
        }
        return max;
    };

    var getMeasurements = function() {
        var yLabelWidth = 0;
        for (var d = 0; d < 7; d++) {
            var text = createText(loc.dayNames[d], 0, 0, "black");
            yLabelWidth = Math.max(yLabelWidth, text.getWidth());
        }
        var labelHeight = createText("X", 0, 0, "black").getHeight();

        var plotWidth = opt.plotPadding + opt.maxPieRadius * 2 * 24
            + opt.plotPadding;
        var plotHeight = opt.plotPadding + opt.maxPieRadius * 2 * 7
            + opt.plotPadding;
        var width = yLabelWidth + opt.labelMargin + opt.axisWidth + plotWidth;
        var height = plotHeight + opt.axisWidth + opt.labelMargin + labelHeight;

        return {
            width:       width,
            height:      height,
            plotWidth:   plotWidth,
            plotHeight:  plotHeight,
            yLabelWidth: yLabelWidth,
            labelHeight: labelHeight
        };
    };

    var createText = function(text, x, y, color) {
        return new Kinetic.Text({
            text:       text,
            fontFamily: opt.fontFamily,
            fontSize:   opt.fontSize,
            fill:       color,
            x:          x,
            y:          y
        });
    };

    var processQueue = function(queue, summaryData) {
        var nextEntry = function(i) {
            if (i < queue.length) {
                $.ajax(queue[i].url)
                    .done(function(data) {
                        createChart(data, queue[i].target);
                        updateSummary(queue[i].name, data, summaryData);
                        nextEntry(i + 1);
                    })
                    .fail(function(xhr, stat, err) {
                        // TODO
                        alert("Failed to load data. Reload to try again.");
                    });
            } else {
                createChart(summaryData, $("#pc-tab-summary"));
            }
        };
        nextEntry(0);
    };

    var updateSummary = function(name, data, summaryData) {
        summaryData[name] = {};
        for (var d = 0; d < 7; d++) {
            var dayData = {};
            for (var h = 0; h < 24; h++) {
                dayData[h] = 0;
            }
            summaryData[name][d] = dayData;
        }
        for (user in data) {
            for (d in data[user]) {
                for (h in data[user][d]) {
                    summaryData[name][d][h] += data[user][d][h];
                }
            }
        }
    };

    var initialize = function(container, sources) {
        var queue = [];
        container.empty();
        var tabList = $("
");
        container.append(tabList);
        var tabID = "pc-tab-summary";
        var tab = addTab(loc.summaryTitle, tabID, tabList, container);
        for (var i = 0; i < sources.length; i++) {
            var tabName = sources[i].name;
            var tabID = "pc-tab-" + i;
            var tab = addTab(tabName, tabID, tabList, container);
            queue.push({
                name: tabName,
                url: sources[i].url,
                target: tab
            });
        }
        container.tabs();
        var summaryData = {};
        processQueue(queue, summaryData);
    };

    var addTab = function(tabName, tabID, tabList, container) {
        tabList.append($("
")
            .append($("")
                .attr("href", "#" + tabID).text(tabName)));
        var tab = $("
").attr("id", tabID).addClass("pc-tab")
            .text(loc.loadingText);
        container.append(tab);
        return tab;
    };

    return {
        options: opt,
        locale: loc,
        initialize: initialize
    };
})();
<|endoftext|>