<commit_before>'use strict';

var _                 = require('mano').i18n.bind('View: Statistics')
  , db                = require('../db')
  , uncapitalize      = require('es5-ext/string/#/uncapitalize')
  , location          = require('mano/lib/client/location')
  , queryHandlerConf  = require('../apps/statistics/flow-query-conf')
  , setupQueryHandler = require('../utils/setup-client-query-handler')
  , copy              = require('es5-ext/object/copy')
  , ObservableValue   = require('observable-value')
  , assign            = require('es5-ext/object/assign')
  , Pagination        = require('./components/pagination')
  , modes             = require('../utils/statistics-flow-group-modes')
  , selectService     = require('./components/filter-bar/select-service')
  , selectCertificate = require('./components/filter-bar/select-certificate')
  , selectPeriodMode  = require('./components/filter-bar/select-period-mode')
  , itemsPerPage      = require('../conf/objects-list-items-per-page')
  , serviceQuery      = require('../apps-common/query-conf/service')
  , certificateQuery  = require('../apps-common/query-conf/certificate')
  , stepStatusQuery   = require('../apps-common/query-conf/processing-step-status')
  , pageQuery         = require('../utils/query/date-constrained-page')
  , copyDbDate        = require('../utils/copy-db-date')
  , queryServer       = require('./utils/statistics-flow-query-server')
  , processingSteps   = require('../processing-steps-meta')
  , getStepLabelByShortPath = require('../utils/get-step-label-by-short-path')
  , incrementDateByTimeUnit = require('../utils/increment-date-by-time-unit')
  , floorToTimeUnit         = require('../utils/floor-to-time-unit')
  , calculateDurationByMode = require('../utils/calculate-duration-by-mode')
  , reduceResult            = require('../utils/statistics-flow-reduce-processing-step')
  , filterData              = require('../utils/statistics-flow-roles-filter-result');

exports._parent        = require('./statistics-flow');
exports._customFilters = Function.prototype;

exports['flow-nav']                = { class: { 'submitted-menu-item-active': true } };
exports['flow-by-role-nav'] = { class: { 'pills-nav-active': true } };

var serviceToCertLegacyMatch = { '': [] };

var getServiceName = function (ServiceType) {
	return uncapitalize.call(
		ServiceType.__id__.slice('BusinessProcess'.length)
	);
};

db.BusinessProcess.extensions.forEach(function (ServiceType) {
	ServiceType.prototype.certificates.map.forEach(function (certificate) {
		if (!serviceToCertLegacyMatch[getServiceName(ServiceType)]) {
			serviceToCertLegacyMatch[getServiceName(ServiceType)] = [];
		}
		serviceToCertLegacyMatch[getServiceName(ServiceType)].push('certificate-' + certificate.key);
		serviceToCertLegacyMatch[''].push('certificate-' + certificate.key);
	});
});

var stepStatuses = {};
['pending', 'approved', 'sentBack', 'rejected', 'paused'].forEach(function (stepName) {
	// sanity check
	if (!db.ProcessingStepStatus.members.has(stepName)) {
		return;
	}
	stepStatuses[stepName] = db.ProcessingStepStatus.meta[stepName];
});

exports['statistics-main'] = function () {
	var queryHandler, data = new ObservableValue({})
	  , pagination = new Pagination('/flow/by-role/'), handlerConf;

	handlerConf = queryHandlerConf.slice(0);
	handlerConf.push(pageQuery, serviceQuery, certificateQuery, stepStatusQuery);
	queryHandler = setupQueryHandler(handlerConf,
		location, '/flow/by-role/');

	queryHandler.on('query', function (query) {
		var serverQuery = copy(query), dateFrom, dateTo, mode
		  , currentDate, offset, timeUnitsCount = 0, durationInTimeUnits, page;
		dateFrom = query.dateFrom;
		dateTo   = query.dateTo || new db.Date();
		mode     = query.mode;
		page     = query.page;

		durationInTimeUnits = calculateDurationByMode(dateFrom, dateTo, mode);
		if (query.pageCount > 1) {
			offset = { from: ((page - 1) * itemsPerPage) };
			offset.to = offset.from;
			if ((durationInTimeUnits - offset.from) < itemsPerPage) {
				offset.to += durationInTimeUnits - offset.from;
			} else {
				offset.to += itemsPerPage;
			}
			offset.to -= 1;

			currentDate = copyDbDate(dateFrom);
			floorToTimeUnit(currentDate, mode);
			while (timeUnitsCount <= offset.to) {
				if (timeUnitsCount === offset.from && query.page > 1) {
					dateFrom = copyDbDate(currentDate);
				}
				if (timeUnitsCount === offset.to && query.page < query.pageCount) {
					dateTo = incrementDateByTimeUnit(copyDbDate(currentDate), mode);
					dateTo.setUTCDate(dateTo.getUTCDate() - 1);
				}
				timeUnitsCount++;
				incrementDateByTimeUnit(currentDate, mode);
			}
		}
		serverQuery.dateFrom = dateFrom.toJSON();
		serverQuery.dateTo = dateTo.toJSON();

		delete serverQuery.service;
		delete serverQuery.page;
		delete serverQuery.certificate;
		delete serverQuery.status;
		delete serverQuery.pageCount;

		queryServer(serverQuery).done(function (responseData) {
			data.value = filterData(reduceResult(responseData),
				assign(query, { dateFrom: dateFrom, dateTo: dateTo }));
			pagination.count.value   = query.pageCount;
			pagination.current.value = query.page;
		});
	});

	section({ class: 'section-primary users-table-filter-bar' },
		form({ action: '/flow/by-role/', autoSubmit: true },
			div({ class: 'users-table-filter-bar-status' },
				selectService({ label: _("All services") })),
			div({ class: 'users-table-filter-bar-status' },
				selectCertificate(),
				legacy('selectMatch', 'service-select', serviceToCertLegacyMatch)),

			div({ class: 'users-table-filter-bar-status' },
				select(
					{ id: 'step-status', name: 'status' },
					list(Object.keys(stepStatuses), function (status) {
						return option({
							id: 'status-' + status,
							value: status,
							selected: location.query.get('status').map(function (value) {
								var selected = (status ? (value === status) : (value == null));
								return selected ? 'selected' : null;
							})
						}, stepStatuses[status].label);
					})
				)),

			div(
				{ class: 'users-table-filter-bar-status' },
				label({ for: 'date-from-input' }, _("Date from"), ":"),
				input({ id: 'date-from-input', type: 'date',
					name: 'dateFrom', value: location.query.get('dateFrom').map(function (dateFrom) {
					var now = new db.Date(), defaultDate;
					defaultDate = new db.Date(now.getUTCFullYear(), now.getUTCMonth(),
								now.getUTCDate() - 6);

					return dateFrom || defaultDate;
				}) })
			),
			div(
				{ class: 'users-table-filter-bar-status' },
				label({ for: 'date-to-input' }, _("Date to"), ":"),
				input({ id: 'date-to-input', type: 'date',
					name: 'dateTo', value: location.query.get('dateTo') })
			),
			selectPeriodMode(),
			p({ class: 'submit' }, input({ type: 'submit' }))));

	section(pagination);
	section({ class: "section-primary statistics-table-scrollable" },
		data.map(function (result) {
			var mode = modes.get(location.query.mode || 'daily');
			return table({ class: 'statistics-table' },
				thead(
					th({ class: 'statistics-table-number' }, mode.labelNoun),
					list(Object.keys(processingSteps), function (shortStepPath) {
						return th({ class: 'statistics-table-number' }, getStepLabelByShortPath(shortStepPath));
					})
				),
				tbody({ onEmpty: tr(td({ class: 'empty', colspan: Object.keys(processingSteps).length },
					_("No data for this criteria"))) }, Object.keys(result), function (key) {
					return tr(
						td(key),
						Object.keys(result[key]).length ?
								list(Object.keys(result[key]), function (step) {
									return td({ class: 'statistics-table-number' },
											result[key][step] == null ? _("N/A") : result[key][step]);
								}) : td({ class: 'statistics-table-info', colspan:
								Object.keys(processingSteps).length },
							_("Nothing to report for this period"))
					);
				}));
		}));
};
<commit_msg>#1767 added default dateTo setup<commit_after>'use strict';

var _                 = require('mano').i18n.bind('View: Statistics')
  , db                = require('../db')
  , uncapitalize      = require('es5-ext/string/#/uncapitalize')
  , location          = require('mano/lib/client/location')
  , queryHandlerConf  = require('../apps/statistics/flow-query-conf')
  , setupQueryHandler = require('../utils/setup-client-query-handler')
  , copy              = require('es5-ext/object/copy')
  , ObservableValue   = require('observable-value')
  , assign            = require('es5-ext/object/assign')
  , Pagination        = require('./components/pagination')
  , modes             = require('../utils/statistics-flow-group-modes')
  , selectService     = require('./components/filter-bar/select-service')
  , selectCertificate = require('./components/filter-bar/select-certificate')
  , selectPeriodMode  = require('./components/filter-bar/select-period-mode')
  , selectDateFrom    = require('./components/filter-bar/select-date-from')
  , selectDateTo      = require('./components/filter-bar/select-date-to')
  , itemsPerPage      = require('../conf/objects-list-items-per-page')
  , serviceQuery      = require('../apps-common/query-conf/service')
  , certificateQuery  = require('../apps-common/query-conf/certificate')
  , stepStatusQuery   = require('../apps-common/query-conf/processing-step-status')
  , pageQuery         = require('../utils/query/date-constrained-page')
  , copyDbDate        = require('../utils/copy-db-date')
  , queryServer       = require('./utils/statistics-flow-query-server')
  , processingSteps   = require('../processing-steps-meta')
  , getStepLabelByShortPath = require('../utils/get-step-label-by-short-path')
  , incrementDateByTimeUnit = require('../utils/increment-date-by-time-unit')
  , floorToTimeUnit         = require('../utils/floor-to-time-unit')
  , calculateDurationByMode = require('../utils/calculate-duration-by-mode')
  , reduceResult            = require('../utils/statistics-flow-reduce-processing-step')
  , filterData              = require('../utils/statistics-flow-roles-filter-result');

exports._parent        = require('./statistics-flow');
exports._customFilters = Function.prototype;

exports['flow-nav']                = { class: { 'submitted-menu-item-active': true } };
exports['flow-by-role-nav'] = { class: { 'pills-nav-active': true } };

var serviceToCertLegacyMatch = { '': [] };

var getServiceName = function (ServiceType) {
	return uncapitalize.call(
		ServiceType.__id__.slice('BusinessProcess'.length)
	);
};

db.BusinessProcess.extensions.forEach(function (ServiceType) {
	ServiceType.prototype.certificates.map.forEach(function (certificate) {
		if (!serviceToCertLegacyMatch[getServiceName(ServiceType)]) {
			serviceToCertLegacyMatch[getServiceName(ServiceType)] = [];
		}
		serviceToCertLegacyMatch[getServiceName(ServiceType)].push('certificate-' + certificate.key);
		serviceToCertLegacyMatch[''].push('certificate-' + certificate.key);
	});
});

var stepStatuses = {};
['pending', 'approved', 'sentBack', 'rejected', 'paused'].forEach(function (stepName) {
	// sanity check
	if (!db.ProcessingStepStatus.members.has(stepName)) {
		return;
	}
	stepStatuses[stepName] = db.ProcessingStepStatus.meta[stepName];
});

exports['statistics-main'] = function () {
	var queryHandler, data = new ObservableValue({})
	  , pagination = new Pagination('/flow/by-role/'), handlerConf;

	handlerConf = queryHandlerConf.slice(0);
	handlerConf.push(pageQuery, serviceQuery, certificateQuery, stepStatusQuery);
	queryHandler = setupQueryHandler(handlerConf,
		location, '/flow/by-role/');

	queryHandler.on('query', function (query) {
		var serverQuery = copy(query), dateFrom, dateTo, mode
		  , currentDate, offset, timeUnitsCount = 0, durationInTimeUnits, page;
		dateFrom = query.dateFrom;
		dateTo   = query.dateTo || new db.Date();
		mode     = query.mode;
		page     = query.page;

		durationInTimeUnits = calculateDurationByMode(dateFrom, dateTo, mode);
		if (query.pageCount > 1) {
			offset = { from: ((page - 1) * itemsPerPage) };
			offset.to = offset.from;
			if ((durationInTimeUnits - offset.from) < itemsPerPage) {
				offset.to += durationInTimeUnits - offset.from;
			} else {
				offset.to += itemsPerPage;
			}
			offset.to -= 1;

			currentDate = copyDbDate(dateFrom);
			floorToTimeUnit(currentDate, mode);
			while (timeUnitsCount <= offset.to) {
				if (timeUnitsCount === offset.from && query.page > 1) {
					dateFrom = copyDbDate(currentDate);
				}
				if (timeUnitsCount === offset.to && query.page < query.pageCount) {
					dateTo = incrementDateByTimeUnit(copyDbDate(currentDate), mode);
					dateTo.setUTCDate(dateTo.getUTCDate() - 1);
				}
				timeUnitsCount++;
				incrementDateByTimeUnit(currentDate, mode);
			}
		}
		serverQuery.dateFrom = dateFrom.toJSON();
		serverQuery.dateTo = dateTo.toJSON();

		delete serverQuery.service;
		delete serverQuery.page;
		delete serverQuery.certificate;
		delete serverQuery.status;
		delete serverQuery.pageCount;

		queryServer(serverQuery).done(function (responseData) {
			data.value = filterData(reduceResult(responseData),
				assign(query, { dateFrom: dateFrom, dateTo: dateTo }));
			pagination.count.value   = query.pageCount;
			pagination.current.value = query.page;
		});
	});

	section({ class: 'section-primary users-table-filter-bar' },
		form({ action: '/flow/by-role/', autoSubmit: true },
			div({ class: 'users-table-filter-bar-status' },
				selectService({ label: _("All services") })),
			div({ class: 'users-table-filter-bar-status' },
				selectCertificate(),
				legacy('selectMatch', 'service-select', serviceToCertLegacyMatch)),

			div({ class: 'users-table-filter-bar-status' },
				select(
					{ id: 'step-status', name: 'status' },
					list(Object.keys(stepStatuses), function (status) {
						return option({
							id: 'status-' + status,
							value: status,
							selected: location.query.get('status').map(function (value) {
								var selected = (status ? (value === status) : (value == null));
								return selected ? 'selected' : null;
							})
						}, stepStatuses[status].label);
					})
				)),

			div(
				{ class: 'users-table-filter-bar-status' },
				label({ for: 'date-from-input' }, _("Date from"), ":"),
				selectDateFrom()
			),
			div(
				{ class: 'users-table-filter-bar-status' },
				label({ for: 'date-to-input' }, _("Date to"), ":"),
				selectDateTo()
			),
			selectPeriodMode(),
			p({ class: 'submit' }, input({ type: 'submit' }))));

	section(pagination);
	section({ class: "section-primary statistics-table-scrollable" },
		data.map(function (result) {
			var mode = modes.get(location.query.mode || 'daily');
			return table({ class: 'statistics-table' },
				thead(
					th({ class: 'statistics-table-number' }, mode.labelNoun),
					list(Object.keys(processingSteps), function (shortStepPath) {
						return th({ class: 'statistics-table-number' }, getStepLabelByShortPath(shortStepPath));
					})
				),
				tbody({ onEmpty: tr(td({ class: 'empty', colspan: Object.keys(processingSteps).length },
					_("No data for this criteria"))) }, Object.keys(result), function (key) {
					return tr(
						td(key),
						Object.keys(result[key]).length ?
								list(Object.keys(result[key]), function (step) {
									return td({ class: 'statistics-table-number' },
											result[key][step] == null ? _("N/A") : result[key][step]);
								}) : td({ class: 'statistics-table-info', colspan:
								Object.keys(processingSteps).length },
							_("Nothing to report for this period"))
					);
				}));
		}));
};
<|endoftext|>


<commit_before>/*globals slate: true*/
"use strict";

// more examples here https://github.com/jigish/dotfiles/blob/master/slate.js
//
// App object: https://github.com/jigish/slate/wiki/Application-Object

// Monitors
var monitorXL = "2560x1440"
var monitorL = "1920x1080"
var monitorM = "1440x900"

var positions = {}
positions.full = slate.operation("move", {
  x: "screenOriginX",
  y: "screenOriginY",
  width: "screenSizeX",
  height: "screenSizeY"
})
positions.top__half = positions.full.dup({
  height: "screenSizeY/2"
})
positions.left__half = positions.full.dup({
  height: "screenSizeY",
  width: "screenSizeX/2"
})
positions.left_top__half = positions.left__half.dup({
  height: "screenSizeY/2"
})
positions.left_bottom__half = positions.left_top__half.dup({
  y: "screenOriginY+screenSizeY/2"
})
positions.left__3of4 = positions.full.dup({
  width: "screenSizeX/4*3"
})
positions.left__2of3 = positions.full.dup({
  width: "screenSizeX/3*2"
})

positions.center_1of2 = positions.left__half.dup({
  x: "screenOriginX+screenSizeX/4"
})

positions.right__half = positions.full.dup({
  height: "screenSizeY",
  width: "screenSizeX/2",
  x: "screenOriginX+screenSizeX/2"
})
positions.right_top__half = positions.right__half.dup({
  height: "screenSizeY/2"
})
positions.right_bottom__half = positions.right_top__half.dup({
  y: "screenOriginY+screenSizeY/2"
})
positions.right__1of3 = positions.full.dup({
  height: "screenSizeY",
  width: "screenSizeX/3",
  x: "screenOriginX+screenSizeX/3*2"
})
positions.right__1of3__top__half = positions.right__1of3.dup({
  height: "screenSizeY/2"
})
positions.right__1of3__bottom__half = positions.right__1of3__top__half.dup({
  y: "screenOriginY+screenSizeY/2"
})
positions.right__2of3 = positions.full.dup({
  height: "screenSizeY",
  width: "2*screenSizeX/3",
  x: "screenOriginX+screenSizeX/3"
})
positions.right__1of4 = positions.full.dup({
  width: "screenSizeX/4",
  x: "screenOriginX+screenSizeX-screenSizeX/4"
})
positions.right__1of4__top__1of3 = positions.right__1of4.dup({
  height: "screenSizeY/3"
})
positions.right__1of4__top__2of3 = positions.right__1of4__top__1of3.dup({
  y: "screenOriginY+screenSizeY/3"
})
positions.right__1of4__top__3of3 = positions.right__1of4__top__1of3.dup({
  y: "screenOriginY+(screenSizeY/3*2)"
})

var tweetbotWidth = 600;
positions.tweetbot = slate.operation("move", {
  screen: 0,
  x: "screenOriginX+screenSizeX-" + tweetbotWidth,
  y: "screenOriginY",
  width: tweetbotWidth,
  height: "screenSizeY"
})

slate.log("❯ Positions defined")

var hashes = {}
Array({screen: 0, key: "main"}, {screen: 1, key: "secondary"}).forEach(function(hashOpts) {
  hashes[hashOpts.key] = {
    full: {operations: [positions.full.dup({screen: hashOpts.screen})]},
    left__half: {operations: [positions.left__half.dup({screen: hashOpts.screen})]},
    left__3of4: {operations: [positions.left__3of4.dup({screen: hashOpts.screen})]},
    left__2of3: {operations: [positions.left__2of3.dup({screen: hashOpts.screen})]},
    center_1of2: {operations: [positions.center_1of2.dup({screen: hashOpts.screen})]},
    right__half: {operations: [positions.right__half.dup({screen: hashOpts.screen})]},
    right_top__half: {operations: [positions.right_top__half.dup({screen: hashOpts.screen})]},
    right_bottom__half: {operations: [positions.right_bottom__half.dup({screen: hashOpts.screen})]},
    right__1of4: {operations: [positions.right__1of4.dup({screen: hashOpts.screen})]},
    right__1of3: {operations: [positions.right__1of3.dup({screen: hashOpts.screen})]},
    right__1of3__top__half: {operations: [positions.right__1of3__top__half.dup({screen: hashOpts.screen})]},
    right__1of3__bottom__half: {operations: [positions.right__1of3__bottom__half.dup({screen: hashOpts.screen})]},
    right__2of3: {operations: [positions.right__2of3.dup({screen: hashOpts.screen})]},
    right__1of4__top__1of3: {operations: [positions.right__1of4__top__1of3.dup({screen: hashOpts.screen})]},
    right__1of4__top__2of3: {operations: [positions.right__1of4__top__2of3.dup({screen: hashOpts.screen})]},
    right__1of4__top__3of3: {operations: [positions.right__1of4__top__3of3.dup({screen: hashOpts.screen})]}
  }
})

// default to ignore-fail & repeat
Object.keys(hashes).forEach(function(type) {
  Object.keys(hashes[type]).forEach(function(hashName) {
    if (hashes[type][hashName]["ignore-fail"] === undefined) {
      hashes[type][hashName]["ignore-fail"] = true
    }
    if (hashes[type][hashName].repeat === undefined) {
      hashes[type][hashName].repeat = true
    }
  })
})

slate.log("❯ Hashes defined", hashes)

var layouts = {}

layouts.XL = slate.layout("layout:XL", {
  Calendar: hashes.main.left__half,
  Wunderlist: hashes.main.right__half,

  Firefox: hashes.main.full,
  FirefoxDeveloperEdition: hashes.main.full, // Firefox
  Nightly: hashes.main.full, // Firefox
  GoogleChrome: hashes.main.full,
  Safari: hashes.main.full,

  Atom: hashes.main.right__2of3,
  SublimeText: hashes.main.right__2of3,

  Tweetbot: {
    operations: [positions.tweetbot],
    ignorefail: true,
    repeat: true
  },

  iTerm: hashes.secondary.left__half,
  Terminal: hashes.secondary.left__half,

  Messages: hashes.secondary.right_top__half,
  Skype: hashes.secondary.right_top__half,
  HipChat: hashes.secondary.right_top__half,
  Slack: hashes.secondary.right_top__half,
  Gitter: hashes.secondary.right_top__half,

  LimeChat: hashes.secondary.right_bottom__half
})

layouts.XM = layouts.XL

Array({key: "L", hashKey: "main"}, {key: "L_alt", hashKey: "secondary"}).forEach(function(layoutOpts) {
  var h = hashes[layoutOpts.hashKey]
  layouts[layoutOpts.key] = slate.layout("layout:" + layoutOpts.key, {
    Calendar: h.left__half,
    Wunderlist: h.right__half,

    Firefox: h.left__3of4,
    FirefoxDeveloperEdition: h.left__3of4, // Firefox
    Nightly: h.left__3of4, // Firefox
    GoogleChrome: h.left__3of4,
    Safari: h.left__3of4,

    Atom: h.center_1of2,
    SublimeText: h.center_1of2,

    Tweetbot: {
      operations: [positions.tweetbot.dup({
        screen: layoutOpts.key === "main" ? 0 : 1,
        x: "screenOriginX+screenSizeX-screenSizeX/4-" + tweetbotWidth,
      })],
      ignorefail: true,
      repeat: true
    },

    iTerm: h.right__1of4__top__1of3,
    Terminal: h.right__1of4__top__1of3,

    LimeChat: h.right__1of4__top__2of3,

    Messages: h.right__1of4__top__3of3,
    Skype: h.right__1of4__top__3of3,
    HipChat: h.right__1of4__top__3of3,
    Slack: h.right__1of4__top__3of3,
    Gitter: h.right__1of4__top__3of3,

    VLC: h.right__1of4__top__3of3,
    MPlayerX: h.right__1of4__top__3of3
  })
})

Array({key: "M", hashKey: "main"}, {key: "M_alt", hashKey: "secondary"}).forEach(function(layoutOpts) {
  var h = hashes[layoutOpts.hashKey]
  layouts[layoutOpts.key] = slate.layout("layout:" + layoutOpts.key, {
    Calendar: h.full,
    Wunderlist: h.right__half,

    Firefox: h.left__2of3,
    FirefoxDeveloperEdition: h.left__2of3, // Firefox
    Nightly: h.left__2of3, // Firefox
    GoogleChrome: h.left__2of3,
    Safari: h.left__2of3,

    Atom: h.left__2of3,
    SublimeText: h.left__2of3,

    Tweetbot: {
      operations: [positions.tweetbot.dup({
        screen: layoutOpts.key === "main" ? 0 : 1,
        x: "screenOriginX+screenSizeX-" + tweetbotWidth,
      })],
      ignorefail: true,
      repeat: true
    },

    iTerm: h.right__1of3__top__half,
    Terminal: h.right__1of3__top__half,

    LimeChat: h.right__1of3__bottom__half,

    Messages: h.right__1of3__bottom__half,
    Skype: h.right__1of3__bottom__half,
    HipChat: h.right__1of3__bottom__half,
    Slack: h.right__1of3__bottom__half,
    Gitter: h.right__1of3__bottom__half,

    VLC: h.right__1of3__bottom__half,
    MPlayerX: h.right__1of3__bottom__half
  })
})

slate.log("❯ Layouts defined")

var ifApp = function(apps, callback) {
  apps = typeof apps === "string" ? [apps] : apps;

  slate.eachApp(function(app) {
    if (apps.indexOf(app.name()) > -1) {
      callback(app)
    }
  })
}

// If a player is running a video, just make it take a quarter of the M screen,
// & make terminals take the rest of the left half
var adaptWhenVideoIsRunning = function() {
  ifApp(["VLC", "MPlayerX"], function(app) {
    app.eachWindow(function(window) {
      if (
          (
            // if VLC is playing
            app.name() === "VLC" ||
            // or if it"s MPlayer
            app.name() === "MPlayerX"
          ) &&
          // and if it"s visible (not an hidden window (eg. pause + minimized))
          !window.isMinimizedOrHidden()
      ) {
        slate.log("Video is running")

        // if two screens, move in the small screen on the top, using half of the height
        if (slate.screenCount() === 2) {
          window.doOperation(positions.left_top__half)

          // make terminals smaller
          slate.eachApp(function(app) {
            if (app.name() === "iTerm" || app.name() === "Terminal") {
              app.eachWindow(function(window) {
                if (window.isMain()) {
                  window.doOperation(positions.left_bottom__half)
                }
              })
            }
          })
        }
        // if one screen, move in the small screen on the top, using half of the height
        // else if (slate.screenCount() === 1) {
          // window.doOperation(positions.right__1of3)
        // }
      }
    })
  })
}

// Layout Operations
var layoutsOperations = {
  XL: slate.operation("layout", {name: "layout:XL"}),
  XM: slate.operation("layout", {name: "layout:XM"}),
  L: slate.operation("layout", {name: "layout:L"}),
  L_alt: slate.operation("layout", {name: "layout:L_alt"}),
  M: slate.operation("layout", {name: "layout:M"}),
  M_alt: slate.operation("layout", {name: "layout:M_alt"})
}

var universalLayout = function() {
  slate.log("❯ Universal layout")

  var screenModifier = slate.screenCount() === 2 ? "X" : ""
  var screenSize = slate.screenForRef(0).rect().width > 1440 ? "L" : "M"

  // if there is app(s) that require fullscreen (video games ?)
  // we just use the secondary screen as a main screen for other apps
  ifApp([
    "insurgency_osx"
  ], function() {
    screenModifier = ""
    screenSize += "_alt"
  })

  // slate.log("❯ Universal layout ", screenSize, screenModifier, layoutsOperations[screenModifier + screenSize])
  layoutsOperations[screenModifier + screenSize].run()

  // slate.log("❯ Universal layout: adapt video player")
  adaptWhenVideoIsRunning()
}

// Defaults when screens are detected
slate.default([monitorXL, monitorL], "layout:XL")
slate.default([monitorXL], "layout:L")
slate.default([monitorL, monitorM], "layout:XM")
slate.default([monitorM], "layout:M")

slate.log("❯ Defaults done")

slate.bindAll({
    // Layout Bindings
  "space:ctrl,alt": universalLayout,

  // Window Hints
  "esc:cmd": slate.operation("hint"),

  // Switch currently doesn"t work well so I"m commenting it out until I fix it.
  // "tab:cmd": slate.operation("switch"),

  // Grid
  "esc:ctrl": slate.operation("grid"),

  "1:cmd,alt,shift": function(win) {
    win.doOperation(positions.full)
  }
})

slate.log("❯ Binds done")
<commit_msg>tmux/vim in fullscreen => simplification of my layout<commit_after>/*globals slate: true*/
"use strict";

// more examples here https://github.com/jigish/dotfiles/blob/master/slate.js
//
// App object: https://github.com/jigish/slate/wiki/Application-Object

// Monitors
var monitorXL = "2560x1440"
var monitorL = "1920x1080"
var monitorM = "1440x900"

var positions = {}
positions.full = slate.operation("move", {
  x: "screenOriginX",
  y: "screenOriginY",
  width: "screenSizeX",
  height: "screenSizeY"
})
positions.top__half = positions.full.dup({height: "screenSizeY/2"})
positions.left__half = positions.full.dup({
  height: "screenSizeY",
  width: "screenSizeX/2"
})
positions.left_top__half = positions.left__half.dup({height: "screenSizeY/2"})
positions.left_bottom__half = positions.left_top__half.dup({y: "screenOriginY+screenSizeY/2"})
positions.left__3of4 = positions.full.dup({width: "screenSizeX/4*3"})
positions.left__2of3 = positions.full.dup({width: "screenSizeX/3*2"})
positions.center_1of2 = positions.left__half.dup({x: "screenOriginX+screenSizeX/4"})
positions.right__half = positions.full.dup({
  height: "screenSizeY",
  width: "screenSizeX/2",
  x: "screenOriginX+screenSizeX/2"
})
positions.right_top__half = positions.right__half.dup({height: "screenSizeY/2"})
positions.right_bottom__half = positions.right_top__half.dup({y: "screenOriginY+screenSizeY/2"})
positions.right__1of3 = positions.full.dup({
  height: "screenSizeY",
  width: "screenSizeX/3",
  x: "screenOriginX+screenSizeX/3*2"
})
positions.right__1of3__top__half = positions.right__1of3.dup({height: "screenSizeY/2"})
positions.right__1of3__bottom__half = positions.right__1of3__top__half.dup({y: "screenOriginY+screenSizeY/2"})
positions.right__2of3 = positions.full.dup({
  height: "screenSizeY",
  width: "2*screenSizeX/3",
  x: "screenOriginX+screenSizeX/3"
})
positions.right__1of4 = positions.full.dup({
  width: "screenSizeX/4",
  x: "screenOriginX+screenSizeX-screenSizeX/4"
})
positions.right__1of4__top__1of3 = positions.right__1of4.dup({height: "screenSizeY/3"})
positions.right__1of4__top__2of3 = positions.right__1of4__top__1of3.dup({y: "screenOriginY+screenSizeY/3"})
positions.right__1of4__top__3of3 = positions.right__1of4__top__1of3.dup({y: "screenOriginY+(screenSizeY/3*2)"})

var tweetbotWidth = 600;
positions.tweetbot = slate.operation("move", {
  screen: 0,
  x: "screenOriginX+screenSizeX-" + tweetbotWidth,
  y: "screenOriginY",
  width: tweetbotWidth,
  height: "screenSizeY"
})

slate.log("❯ Positions defined")

var hashes = {}
Array({screen: 0, key: "main"}, {screen: 1, key: "secondary"}).forEach(function(hashOpts) {
  hashes[hashOpts.key] = {
    full: {operations: [positions.full.dup({screen: hashOpts.screen})]},
    left__half: {operations: [positions.left__half.dup({screen: hashOpts.screen})]},
    right__half: {operations: [positions.right__half.dup({screen: hashOpts.screen})]},
    right_top__half: {operations: [positions.right_top__half.dup({screen: hashOpts.screen})]},
    right_bottom__half: {operations: [positions.right_bottom__half.dup({screen: hashOpts.screen})]},
    // below looks unused
    left__3of4: {operations: [positions.left__3of4.dup({screen: hashOpts.screen})]},
    left__2of3: {operations: [positions.left__2of3.dup({screen: hashOpts.screen})]},
    center_1of2: {operations: [positions.center_1of2.dup({screen: hashOpts.screen})]},
    right__1of4: {operations: [positions.right__1of4.dup({screen: hashOpts.screen})]},
    right__1of3: {operations: [positions.right__1of3.dup({screen: hashOpts.screen})]},
    right__1of3__top__half: {operations: [positions.right__1of3__top__half.dup({screen: hashOpts.screen})]},
    right__1of3__bottom__half: {operations: [positions.right__1of3__bottom__half.dup({screen: hashOpts.screen})]},
    right__2of3: {operations: [positions.right__2of3.dup({screen: hashOpts.screen})]},
    right__1of4__top__1of3: {operations: [positions.right__1of4__top__1of3.dup({screen: hashOpts.screen})]},
    right__1of4__top__2of3: {operations: [positions.right__1of4__top__2of3.dup({screen: hashOpts.screen})]},
    right__1of4__top__3of3: {operations: [positions.right__1of4__top__3of3.dup({screen: hashOpts.screen})]}
  }
})

// default to ignore-fail & repeat
Object.keys(hashes).forEach(function(type) {
  Object.keys(hashes[type]).forEach(function(hashName) {
    if (hashes[type][hashName]["ignore-fail"] === undefined) {
      hashes[type][hashName]["ignore-fail"] = true
    }
    if (hashes[type][hashName].repeat === undefined) {
      hashes[type][hashName].repeat = true
    }
  })
})

slate.log("❯ Hashes defined", hashes)

var layouts = {}

layouts.XL = slate.layout("layout:XL", {
  Firefox: hashes.main.full,
  FirefoxDeveloperEdition: hashes.main.full, // Firefox
  Nightly: hashes.main.full, // Firefox
  Safari: hashes.main.full,
  GoogleChrome: hashes.main.full,

  iTerm: hashes.main.full,
  Terminal: hashes.main.full,

  LimeChat: hashes.secondary.left__half,
  Messages: hashes.secondary.left__half,
  Skype: hashes.secondary.left__half,
  Slack: hashes.secondary.left__half,

  Calendar: hashes.secondary.right__half,
  Wunderlist: hashes.secondary.right__half,
  Tweetbot: hashes.secondary.right__half
})

layouts.XM = layouts.XL

Array(
  {key: "L", hashKey: "main"},
  {key: "L_alt", hashKey: "secondary"},
  {key: "M", hashKey: "main"},
  {key: "M_alt", hashKey: "secondary"}
).forEach(function(layoutOpts) {
  var h = hashes[layoutOpts.hashKey]
  layouts[layoutOpts.key] = slate.layout("layout:" + layoutOpts.key, {
    Firefox: h.full,
    FirefoxDeveloperEdition: h.full, // Firefox
    Nightly: h.full, // Firefox
    GoogleChrome: h.full,
    Safari: h.full,

    iTerm: h.full,
    Terminal: h.full,

    LimeChat: h.left__half,
    Messages: h.left__half,
    Skype: h.left__half,
    Slack: h.left__half,

    Calendar: h.right__half,
    Wunderlist: h.right__half,
    Tweetbot: h.right__half,

    VLC: h.right__1of4__top__3of3,
    MPlayerX: h.right__1of4__top__3of3
  })
})

slate.log("❯ Layouts defined")

var ifApp = function(apps, callback) {
  apps = typeof apps === "string" ? [apps] : apps;

  slate.eachApp(function(app) {
    if (apps.indexOf(app.name()) > -1) {
      callback(app)
    }
  })
}

// If a player is running a video, just make it take a quarter of the M screen,
// & make terminals take the rest of the left half
var adaptWhenVideoIsRunning = function() {
  ifApp(["VLC", "MPlayerX"], function(app) {
    app.eachWindow(function(window) {
      if (
          (
            // if VLC is playing
            app.name() === "VLC" ||
            // or if it"s MPlayer
            app.name() === "MPlayerX"
          ) &&
          // and if it"s visible (not an hidden window (eg. pause + minimized))
          !window.isMinimizedOrHidden()
      ) {
        slate.log("Video is running")

        // if two screens, move in the small screen on the top, using half of the height
        if (slate.screenCount() === 2) {
          window.doOperation(positions.left_top__half)

          // make terminals smaller
          slate.eachApp(function(app) {
            if (app.name() === "LimeChat" ||
                app.name() === "Message" ||
                app.name() === "Skype" ||
                app.name() === "Slack" ) {
              app.eachWindow(function(window) {
                if (window.isMain()) {
                  window.doOperation(positions.left_bottom__half)
                }
              })
            }
          })
        }
        // if one screen, move in the small screen on the top, using half of the height
        // else if (slate.screenCount() === 1) {
          // window.doOperation(positions.right__1of3)
        // }
      }
    })
  })
}

// Layout Operations
var layoutsOperations = {
  XL: slate.operation("layout", {name: "layout:XL"}),
  XM: slate.operation("layout", {name: "layout:XM"}),
  L: slate.operation("layout", {name: "layout:L"}),
  L_alt: slate.operation("layout", {name: "layout:L_alt"}),
  M: slate.operation("layout", {name: "layout:M"}),
  M_alt: slate.operation("layout", {name: "layout:M_alt"})
}

var universalLayout = function() {
  slate.log("❯ Universal layout")

  var screenModifier = slate.screenCount() === 2 ? "X" : ""
  var screenSize = slate.screenForRef(0).rect().width > 1440 ? "L" : "M"

  // if there is app(s) that require fullscreen (video games ?)
  // we just use the secondary screen as a main screen for other apps
  ifApp([
    "insurgency_osx"
  ], function() {
    screenModifier = ""
    screenSize += "_alt"
  })

  // slate.log("❯ Universal layout ", screenSize, screenModifier, layoutsOperations[screenModifier + screenSize])
  layoutsOperations[screenModifier + screenSize].run()

  // slate.log("❯ Universal layout: adapt video player")
  adaptWhenVideoIsRunning()
}

// Defaults when screens are detected
slate.default([monitorXL, monitorL], "layout:XL")
slate.default([monitorXL], "layout:L")
slate.default([monitorL, monitorM], "layout:XM")
slate.default([monitorM], "layout:M")

slate.log("❯ Defaults done")

slate.bindAll({
    // Layout Bindings
  "space:ctrl,alt": universalLayout,

  // Window Hints
  "esc:cmd": slate.operation("hint"),

  // Switch currently doesn"t work well so I"m commenting it out until I fix it.
  // "tab:cmd": slate.operation("switch"),

  // Grid
  "esc:ctrl": slate.operation("grid"),

  "1:cmd,alt,shift": function(win) {
    win.doOperation(positions.full)
  }
})

slate.log("❯ Binds done")
<|endoftext|>


<commit_before>import * as rrb from "rrb-vector";

import { error } from "./error";

import { seq, first, isSeq, isEmpty } from "./seq";

import { into, transform, compose, filter, forEach, foldLeft, cat } from "./transducers";

var List = rrb.empty.constructor;

List.prototype.__is_List = true;

List.prototype["@@empty"] = function(){
	return rrb.empty;
}

List.prototype["@@append"] = List.prototype.push;

rrb.TreeIterator.prototype["@@empty"] = function(){
	return rrb.empty;
}

rrb.TreeIterator.prototype["@@append"] = List.prototype.push;

export function isArray($maybe) {
	let maybe = first($maybe);
	return !!(maybe && maybe.__is_List);
}

export default function(...a) {
	var l = a.length;
	if(l===0){
		return rrb.empty;
	}
	if(l==1 && isSeq(a[0])){
		return rrb.fromArray(a[0].toArray());
	}
	return rrb.fromArray(a);//into(a,compose(filter(_ => !isEmpty(_)), forEach(_ => first(_))), rrb.empty);
}

export function join($a) {
	if ($a === undefined) return error("XPTY0004");
	// assume a sequence of vectors
	return foldLeft(a,rrb.empty,function(pre,cur){
		var v = first(cur);
		if(!isArray(v)) return error("XPTY0004","One of the items for array:join is not an array.");
		return pre.concat(v);
	});
}

function _checked($a, fn, ...args) {
	if ($a === undefined) return error("XPTY0004");
	var a = $a;
	if (isSeq($a)) {
		if ($a.size > 1) return error("XPTY0004");
		a = first($a);
	}
	if (!isArray(a)) return error("XPTY0004");
	args.unshift(a);
	return fn.apply(a, args);
}

export function head($a) {
	return _checked($a, rrb.slice,0,1);
}

export function tail($a) {
	return _checked($a, rrb.slice,1);
}

export function size($a) {
	return _checked($a, List.prototype.count);
}

export function subarray($a,$s,$l) {
	var s =  first($s) || 1, l = first($l);
	var sx = s - 1;
	return _checked($a, rrb.slice, sx,  l ? sx + l : undefined);
}

export function insertBefore($a, $i, $v) {
	var i = first($i) || 1;
	var ix = i.valueOf() - 1;
	// unmarshal Singleton
	var v = isSeq($v) && $v.size > 1 ? $v : first($v);
	return _checked($a, function(a){
		// slice from 0 to i
		// slice form i to end
		// concat s1 + v + s2
		return a.slice(0,ix).push(v).concat(a.slice(ix));
	});
}

export function remove($a,$i) {
	var i = first($i) || 1;
	var ix = i.valueOf() - 1;
	return _checked($a, function(a){
		return a.slice(0,ix).concat(a.slice(i));
	});
}

export function append($a,$v) {
	var v = isSeq($v) && $v.size > 1 ? $v : first($v);
	return _checked($a,rrb.push,v);
}

export function reverse($a) {
	return _checked($a,function(a){
		return rrb.fromArray(rrb.toArray(a).reverse());
	});
}

export function flatten($a) {
	return into($a,cat,seq());
}

export function get($a,$i) {
	var i = first($i) || 1;
	var ix = i.valueOf() - 1;
	return _checked($a,rrb.get,ix);
}
<commit_msg>fix transducer name clash<commit_after>import * as rrb from "rrb-vector";

import { error } from "./error";

import { seq, first, isSeq, isEmpty } from "./seq";

import * as t from "./transducers";

var List = rrb.empty.constructor;

List.prototype.__is_List = true;

List.prototype["@@empty"] = function(){
	return rrb.empty;
}

List.prototype["@@append"] = List.prototype.push;

rrb.TreeIterator.prototype["@@empty"] = function(){
	return rrb.empty;
}

rrb.TreeIterator.prototype["@@append"] = List.prototype.push;

export function isArray($maybe) {
	let maybe = first($maybe);
	return !!(maybe && maybe.__is_List);
}

export default function(...a) {
	var l = a.length;
	if(l===0){
		return rrb.empty;
	}
	if(l==1 && isSeq(a[0])){
		return rrb.fromArray(a[0].toArray());
	}
	return rrb.fromArray(a);//t.into(a,t.compose(t.filter(_ => !isEmpty(_)), t.forEach(_ => first(_))), rrb.empty);
}

export function join($a) {
	if ($a === undefined) return error("XPTY0004");
	// assume a sequence of vectors
	return t.foldLeft($a,rrb.empty,function(pre,cur){
		var v = first(cur);
		if(!isArray(v)) return error("XPTY0004","One of the items for array:join is not an array.");
		return pre.concat(v);
	});
}

function _checked($a, fn, ...args) {
	if ($a === undefined) return error("XPTY0004");
	var a = $a;
	if (isSeq($a)) {
		if ($a.size > 1) return error("XPTY0004");
		a = first($a);
	}
	if (!isArray(a)) return error("XPTY0004");
	args.unshift(a);
	return fn.apply(a, args);
}

export function head($a) {
	return _checked($a, rrb.slice,0,1);
}

export function tail($a) {
	return _checked($a, rrb.slice,1);
}

export function size($a) {
	return _checked($a, List.prototype.count);
}

export function subarray($a,$s,$l) {
	var s =  first($s) || 1, l = first($l);
	var sx = s - 1;
	return _checked($a, rrb.slice, sx,  l ? sx + l : undefined);
}

export function insertBefore($a, $i, $v) {
	var i = first($i) || 1;
	var ix = i.valueOf() - 1;
	// unmarshal Singleton
	var v = isSeq($v) && $v.size > 1 ? $v : first($v);
	return _checked($a, function(a){
		// slice from 0 to i
		// slice form i to end
		// concat s1 + v + s2
		return a.slice(0,ix).push(v).concat(a.slice(ix));
	});
}

export function remove($a,$i) {
	var i = first($i) || 1;
	var ix = i.valueOf() - 1;
	return _checked($a, function(a){
		return a.slice(0,ix).concat(a.slice(i));
	});
}

export function append($a,$v) {
	var v = isSeq($v) && $v.size > 1 ? $v : first($v);
	return _checked($a,rrb.push,v);
}

export function reverse($a) {
	return _checked($a,function(a){
		return rrb.fromArray(rrb.toArray(a).reverse());
	});
}

export function flatten($a) {
	return t.into($a,t.cat,seq());
}

export function get($a,$i) {
	var i = first($i) || 1;
	var ix = i.valueOf() - 1;
	return _checked($a,rrb.get,ix);
}

export function forEach($a,$f){
	return t.forEach(first($a),first($f));
}

export function filter($a,$f){
	return t.filter(first($a),first($f));
}

export function foldLeft($a,$z,$f){
	return t.foldLeft(first($a),$z,first($f));
}
<|endoftext|>


<commit_before>/* jshint browser: true, jquery: true */
/* global Hammer: false */

(function() {
  'use strict';

  var tend_evt = "transitionend webkitTransitionEnd oTransitionEnd msTransitionEnd";

  function transitionTo(selector, url, dir, speed, easing, onend) {
    speed = speed || 800;
    easing = easing || "ease-in";
    dir = dir==="right" ? "right" : "left";

    $.get(url, function(data) {

      var xmldoc = $.parseHTML(data);
      var matches = data.match(/<title>([\s\S]*?)<\/title>/);
      if (matches) {
        var title = $('
').html(decodeURIComponent(matches[1].trim())).text();
        document.title = title;
      }

      var element = $(selector);
      var copy = element.clone().html($(selector, xmldoc).html());
      var pos = element.offset();
      var dist = element.parent().width();
      var hard_width = element.width();

      var preheight = element.height();
      element.hide(); //PRETEND LIKE IT'S NOT THERE SO WE CAN FIGURE HOW HOW BIG THE NEW ONE IS
      element.after(copy);
      var copypos = copy.offset();
      var copywidth = copy.width();
      var copyheight = copy.height();
      element.show();
      var minheight = preheight>copyheight ? preheight : copyheight;

      element.parent().append('

')
      var hfix = $('#sideswipehfix').css('height', minheight); //Used to make sure the parent div is large enough

      copy.css("position","absolute"); //Now they're exactly on top of one another...

      copy.width(copywidth);
      copy.height(copyheight);
      copy.offset(copypos);

      if (dir==="right") {
        dist = dist * -1;
      }
      copy.css("left", "+="+dist);

      var original_left = element.get(0).style.left;
      var original_pos = element.get(0).style.position;
      var original_trans = element.get(0).style.transition;
      var original_top = element.get(0).style.top;
      var original_width = element.get(0).style.width;

      element.css("position", "absolute");
      element.offset(pos);
      element.width(hard_width);

      var cleaned = false;
      var cleanup = function(){
        if (cleaned) { return; }
        hfix.remove();
        element.html(copy.html());
        element.css("transition", original_trans);
        element.css("left", original_left);
        element.css("position", original_pos);
        element.css("width", original_width);
        element.css("top", original_top);
        copy.remove();
        cleaned = true;
        if ($(selector, xmldoc).attr("side-onload")) {
          eval($(selector, xmldoc).attr("side-onload"));
        }
        if (onend) {
          onend();
        }
      };

      element.one(tend_evt, cleanup);

      var trans = "left "+speed+"ms "+easing;
      var cssChanges = {
        left: "-="+dist,
        WebkitTransition : trans,
        MozTransition    : trans,
        MsTransition     : trans,
        OTransition      : trans,
        transition       : trans
      };

      element.css(cssChanges);
      copy.css(cssChanges);

      setTimeout(function() {
        cleanup();
      }, speed + 5);

    });
  }

  function currentPage(linklist) {
    var curpage = linklist.indexOf(window.location.pathname);
    var trimmed = window.location.pathname.replace(/index.html$/, ""); //catch index.html for its eq
    if (curpage<0 && trimmed!="") {
      curpage = linklist.indexOf(trimmed);
    }
    return curpage;
  }

  function activate(selector, linklist) {

    var curpage = currentPage(linklist);
    if (curpage<0) { return; } //we're apparently not on a path we're supposed to be, ignore the request
    if ($(selector).attr("side-onload")) {
      eval($(selector).attr("side-onload"));
    }

    var returns = {
      onStartTransition: function() {},
      onEndTransition: function() {},
      onLeftBound: function() {},
      onRightBound: function() {},
      left: function(duration) {

        var pos = currentPage(linklist);
        if (pos<0) { return; } //we're apparently not on a path we're supposed to be
        if (pos===(linklist.length-1)) { //On the boundary already. Do a bounce animation? Expand a sidebar?
                returns.onRightBound();
                return;
        }

        returns.onStartTransition(selector, linklist[pos+1], "left", duration);
        transitionTo(selector, linklist[pos+1], "left", duration, null, returns.onEndTransition);
        history.pushState({contentarea: selector, link: linklist[pos+1], dir: "left"}, "Swipeleft page", linklist[pos+1]);
      },
      right: function(duration) {
        var pos = currentPage(linklist);
        if (pos<0) { return; } //we're apparently not on a path we're supposed to be
        if (pos===0) { //On the boundary already. Do a bounce animation? Expand a sidebar?
          returns.onLeftBound();
          return;
        }

        returns.onStartTransition(selector, linklist[pos-1], "right", duration);
        transitionTo(selector, linklist[pos-1], "right", duration, null, returns.onEndTransition);
        history.pushState({contentarea: selector, link: linklist[pos-1], dir: "right"}, "Swiperight page", linklist[pos-1]);
      }
    };

    var element = document.querySelector(selector);
    var pos = linklist.indexOf(window.location.pathname);

    history.pushState({contentarea: selector, link: linklist[pos]}, document.title, window.location.pathname);

    (new Hammer.Instance(element, {
      prevent_default: true,
      no_mouseevents: true
    })).on("swipeleft swiperight", function(ev) {

      if (!ev.gesture) { return; }

      var velocity = Math.abs(ev.gesture.distance/ev.gesture.deltaTime);
      var duration = (1/velocity)*800;

      var pos = linklist.indexOf(window.location.pathname);
      if (pos<0) { return; } //we're apparently not on a path we're supposed to be
      if (ev.type === "swipeleft") {
        returns.left(duration);
      } else { //swiperight
        returns.right(duration);
      }
    });

    window.onpopstate = function(data) {
      if (data.state) {
        returns.onStartTransition(data.state.contentarea, data.state.link, data.state.dir, 800);
        transitionTo(data.state.contentarea, data.state.link, data.state.dir, null, null, returns.onEndTransition);
      }
    };

    return returns;
  }

  window.Sideswipe = activate;

})(this);
<commit_msg>fixes breaking scrolling on mobile<commit_after>/* jshint browser: true, jquery: true */
/* global Hammer: false */

(function() {
  'use strict';

  var tend_evt = "transitionend webkitTransitionEnd oTransitionEnd msTransitionEnd";

  function transitionTo(selector, url, dir, speed, easing, onend) {
    speed = speed || 800;
    easing = easing || "ease-in";
    dir = dir==="right" ? "right" : "left";

    $.get(url, function(data) {

      var xmldoc = $.parseHTML(data);
      var matches = data.match(/<title>([\s\S]*?)<\/title>/);
      if (matches) {
        var title = $('
').html(decodeURIComponent(matches[1].trim())).text();
        document.title = title;
      }

      var element = $(selector);
      var copy = element.clone().html($(selector, xmldoc).html());
      var pos = element.offset();
      var dist = element.parent().width();
      var hard_width = element.width();

      var preheight = element.height();
      element.hide(); //PRETEND LIKE IT'S NOT THERE SO WE CAN FIGURE HOW HOW BIG THE NEW ONE IS
      element.after(copy);
      var copypos = copy.offset();
      var copywidth = copy.width();
      var copyheight = copy.height();
      element.show();
      var minheight = preheight>copyheight ? preheight : copyheight;

      element.parent().append('

')
      var hfix = $('#sideswipehfix').css('height', minheight); //Used to make sure the parent div is large enough

      copy.css("position","absolute"); //Now they're exactly on top of one another...

      copy.width(copywidth);
      copy.height(copyheight);
      copy.offset(copypos);

      if (dir==="right") {
        dist = dist * -1;
      }
      copy.css("left", "+="+dist);

      var original_left = element.get(0).style.left;
      var original_pos = element.get(0).style.position;
      var original_trans = element.get(0).style.transition;
      var original_top = element.get(0).style.top;
      var original_width = element.get(0).style.width;

      element.css("position", "absolute");
      element.offset(pos);
      element.width(hard_width);

      var cleaned = false;
      var cleanup = function(){
        if (cleaned) { return; }
        hfix.remove();
        element.html(copy.html());
        element.css("transition", original_trans);
        element.css("left", original_left);
        element.css("position", original_pos);
        element.css("width", original_width);
        element.css("top", original_top);
        copy.remove();
        cleaned = true;
        if ($(selector, xmldoc).attr("side-onload")) {
          eval($(selector, xmldoc).attr("side-onload"));
        }
        if (onend) {
          onend();
        }
      };

      element.one(tend_evt, cleanup);

      var trans = "left "+speed+"ms "+easing;
      var cssChanges = {
        left: "-="+dist,
        WebkitTransition : trans,
        MozTransition    : trans,
        MsTransition     : trans,
        OTransition      : trans,
        transition       : trans
      };

      element.css(cssChanges);
      copy.css(cssChanges);

      setTimeout(function() {
        cleanup();
      }, speed + 5);

    });
  }

  function currentPage(linklist) {
    var curpage = linklist.indexOf(window.location.pathname);
    var trimmed = window.location.pathname.replace(/index.html$/, ""); //catch index.html for its eq
    if (curpage<0 && trimmed!="") {
      curpage = linklist.indexOf(trimmed);
    }
    return curpage;
  }

  function activate(selector, linklist) {

    var curpage = currentPage(linklist);
    if (curpage<0) { return; } //we're apparently not on a path we're supposed to be, ignore the request
    if ($(selector).attr("side-onload")) {
      eval($(selector).attr("side-onload"));
    }

    var returns = {
      onStartTransition: function() {},
      onEndTransition: function() {},
      onLeftBound: function() {},
      onRightBound: function() {},
      left: function(duration) {

        var pos = currentPage(linklist);
        if (pos<0) { return; } //we're apparently not on a path we're supposed to be
        if (pos===(linklist.length-1)) { //On the boundary already. Do a bounce animation? Expand a sidebar?
                returns.onRightBound();
                return;
        }

        returns.onStartTransition(selector, linklist[pos+1], "left", duration);
        transitionTo(selector, linklist[pos+1], "left", duration, null, returns.onEndTransition);
        history.pushState({contentarea: selector, link: linklist[pos+1], dir: "left"}, "Swipeleft page", linklist[pos+1]);
      },
      right: function(duration) {
        var pos = currentPage(linklist);
        if (pos<0) { return; } //we're apparently not on a path we're supposed to be
        if (pos===0) { //On the boundary already. Do a bounce animation? Expand a sidebar?
          returns.onLeftBound();
          return;
        }

        returns.onStartTransition(selector, linklist[pos-1], "right", duration);
        transitionTo(selector, linklist[pos-1], "right", duration, null, returns.onEndTransition);
        history.pushState({contentarea: selector, link: linklist[pos-1], dir: "right"}, "Swiperight page", linklist[pos-1]);
      }
    };

    var element = document.querySelector(selector);
    var pos = linklist.indexOf(window.location.pathname);

    history.pushState({contentarea: selector, link: linklist[pos]}, document.title, window.location.pathname);

    (new Hammer.Instance(element, {
      prevent_default: false,
      no_mouseevents: true
    })).on("swipeleft swiperight", function(ev) {

      if (!ev.gesture) { return; }

      var velocity = Math.abs(ev.gesture.distance/ev.gesture.deltaTime);
      var duration = (1/velocity)*800;

      var pos = linklist.indexOf(window.location.pathname);
      if (pos<0) { return; } //we're apparently not on a path we're supposed to be
      if (ev.type === "swipeleft") {
        returns.left(duration);
      } else { //swiperight
        returns.right(duration);
      }
    });

    window.onpopstate = function(data) {
      if (data.state) {
        returns.onStartTransition(data.state.contentarea, data.state.link, data.state.dir, 800);
        transitionTo(data.state.contentarea, data.state.link, data.state.dir, null, null, returns.onEndTransition);
      }
    };

    return returns;
  }

  window.Sideswipe = activate;

})(this);
<|endoftext|>


<commit_before>/*!
 * ${copyright}
 */

sap.ui.define([
	'./Splitter',
	'./SplitterRenderer',
	"sap/base/Log",
	"sap/ui/layout/SplitterLayoutData"
], function(Splitter, SplitterRenderer, Log, SplitterLayoutData) {
	"use strict";

	/**
	 * Constructor for a new AssociativeSplitter.
	 *
	 * @param {string} [sId] ID for the new control, generated automatically if no ID is given
	 * @param {object} [mSettings] Initial settings for the new control
	 *
	 * @class
	 * AssociativeSplitter is a version of Splitter that uses an association in addition to the contentAreas aggregation.
	 * It is used to visualize controls aggregated in {@link sap.ui.layout.PaneContainer PaneContainer} panes.
	 *
	 * @extends sap.ui.layout.Splitter
	 *
	 * @author SAP SE
	 * @version ${version}
	 *
	 * @constructor
	 * @private
	 * @since 1.38
	 * @alias sap.ui.layout.AssociativeSplitter
	 */
	var AssociativeSplitter = Splitter.extend("sap.ui.layout.AssociativeSplitter", /** @lends sap.ui.layout.AssociativeSplitter.prototype */ {
		metadata : {
			associations : {
				/**
				 * The same as contentAreas, but provided in the form of an association.
				 */
				associatedContentAreas: {type : "sap.ui.core.Control", multiple : true, singularName : "associatedContentArea"}
			}
		},
		renderer: SplitterRenderer
	});

	AssociativeSplitter.prototype.init = function () {
		Splitter.prototype.init.call(this);
		// We need to have different step size than the existing in the Splitter
		this._keyListeners = {
			increase     : this._onKeyboardResize.bind(this, "inc", 1),
			decrease     : this._onKeyboardResize.bind(this, "dec", 1),
			increaseMore : this._onKeyboardResize.bind(this, "incMore", 2),
			decreaseMore : this._onKeyboardResize.bind(this, "decMore", 2),
			max          : this._onKeyboardResize.bind(this, "max", 1),
			min          : this._onKeyboardResize.bind(this, "min", 1)
		};
		this._enableKeyboardListeners();
	};

	AssociativeSplitter.prototype.addAssociatedContentArea = function (oContent) {
		this._ensureLayoutData(oContent);
		return this.addAssociation("associatedContentAreas", oContent);
	};

	/**
	 * Adds shift + arrows keyboard handling to the existing one
	 * @returns {void}
	 * @private
	 * @override
	 */
	AssociativeSplitter.prototype._enableKeyboardListeners = function () {
		Splitter.prototype._enableKeyboardListeners.call(this);
		this.onsaprightmodifiers = this._keyListeners.increase;
		this.onsapleftmodifiers = this._keyListeners.decrease;
		this.onsapupmodifiers = this._keyListeners.decrease;
		this.onsapdownmodifiers = this._keyListeners.increase;
		this.onsapright = this._keyListeners.increaseMore;
		this.onsapdown = this._keyListeners.increaseMore;
		this.onsapleft = this._keyListeners.decreaseMore;
		this.onsapup = this._keyListeners.decreaseMore;
		this.onsapend = this._keyListeners.max;
		this.onsaphome = this._keyListeners.min;

		this._keyboardEnabled = true;
	};

	/**
	 * @override
	 */
	AssociativeSplitter.prototype._getContentAreas = function () {
		var aAssociatedContentAreas = this.getAssociatedContentAreas() || [];
		var aContentAreas = this.getContentAreas();

		var aValidAssContentAreas = aAssociatedContentAreas.map(function (sId) {
			return sap.ui.getCore().byId(sId);
		}).filter(function (oContent) { return oContent; });

		return aContentAreas.concat(aValidAssContentAreas);
	};

	AssociativeSplitter.prototype.ondblclick = function (oEvent) {
		// For some reason dblclick returns the whole Splitter not only the clicked splitbar
		var sId = this.getId(),
			iBar, oContentArea;
		if (!(oEvent.target.contains(this._oLastDOMclicked) && (this._oLastDOMclicked.id.indexOf(sId + "-splitbar") > -1))) {
			// The clicked element was not one of my splitter bars
			return;
		}

		iBar = parseInt(this._oLastDOMclicked.id.substr((sId + "-splitbar-").length));
		oContentArea = this._getContentAreas()[iBar];
		oContentArea._currentPosition = this.getCalculatedSizes()[iBar];
		oContentArea._lastPosition = oContentArea._lastPosition || oContentArea._currentPosition;

		if (oContentArea._currentPosition === oContentArea._lastPosition) {
			this._resizeContents(iBar, (this.getCalculatedSizes()[iBar]) * -1, true);
		} else {
			this._resizeContents(iBar, oContentArea._lastPosition, true);
			oContentArea._lastPosition = null;
		}
	};

	// Overriding sap.ui.layout.Splitter's calculation functions in order to make it responsive

	/**
	 * Resizes the contents after a bar has been moved
	 *
	 * @param {Number} [iLeftContent] Number of the first (left) content that is resized
	 * @param {Number} [iPixels] Number of pixels to increase the first and decrease the second content
	 * @param {boolean} [bFinal] Whether this is the final position (sets the size in the layoutData of the content areas)
	 * @override
	 */
	AssociativeSplitter.prototype._resizeContents = function (iLeftContent, iPixels, bFinal) {
		var aContentAreas, oLd1, oLd2, sSize1,
			sSize2, $Cnt1, $Cnt2, iNewSize1, iNewSize2,
			iMinSize1, iMinSize2, sOrientation, iSplitterSize,
			sFinalSize1, sFinalSize2, iDiff,
			sMoveContentSize1 = parseFloat(this._move.c1Size).toFixed(5),
			sMoveContentSize2 = parseFloat(this._move.c2Size).toFixed(5),
			fMoveC1Size = parseFloat(sMoveContentSize1),
			fMoveC2Size = parseFloat(sMoveContentSize2);

		if (isNaN(iPixels)) {
			Log.warning("Splitter: Received invalid resizing values - resize aborted.");
			return;
		}

		aContentAreas = this._getContentAreas();
		oLd1 = aContentAreas[iLeftContent].getLayoutData();
		oLd2 = aContentAreas[iLeftContent + 1].getLayoutData();

		sSize1 = oLd1.getSize();
		sSize2 = oLd2.getSize();

		$Cnt1 = this.$("content-" + iLeftContent);
		$Cnt2 = this.$("content-" + (iLeftContent + 1));

		iNewSize1 = fMoveC1Size + iPixels;
		iNewSize2 = fMoveC2Size - iPixels;
		iMinSize1 = parseInt(oLd1.getMinSize());
		iMinSize2 = parseInt(oLd2.getMinSize());

		sOrientation = this.getOrientation();
		iSplitterSize = sOrientation === "Horizontal" ? this.$().width() : this.$().height();

		// Adhere to size constraints
		if (iNewSize1 < iMinSize1) {
			iDiff = iMinSize1 - iNewSize1;
			iPixels += iDiff;
			iNewSize1 = iMinSize1;
			iNewSize2 -= iDiff;
		} else if (iNewSize2 < iMinSize2) {
			iDiff = iMinSize2 - iNewSize2;
			iPixels -= iDiff;
			iNewSize2 = iMinSize2;
			iNewSize1 -= iDiff;
		}

		if (bFinal) {
			// Resize finished, set layout data in content areas
			if (sSize1 === "auto" && sSize2 !== "auto") {
				// First pane has auto size - only change size of second pane
				sFinalSize2 = this._pxToPercent(iNewSize2, iSplitterSize);
				oLd2.setSize(sFinalSize2);
			} else if (sSize1 !== "auto" && sSize2 === "auto") {
				// Second pane has auto size - only change size of first pane
				sFinalSize1 = this._pxToPercent(iNewSize1, iSplitterSize);
				oLd1.setSize(sFinalSize1);
			} else {
				sFinalSize1 = this._pxToPercent(iNewSize1, iSplitterSize);
				sFinalSize2 = this._pxToPercent(iNewSize2, iSplitterSize);

				oLd1.setSize(sFinalSize1);
				oLd2.setSize(sFinalSize2);
			}
		} else {
			// Live-Resize, resize contents in Dom
			sFinalSize1 = this._pxToPercent(iNewSize1, iSplitterSize);
			sFinalSize2 = this._pxToPercent(iNewSize2, iSplitterSize);

			$Cnt1.css(this._sizeType, sFinalSize1);
			$Cnt2.css(this._sizeType, sFinalSize2);
		}
	};

	AssociativeSplitter.prototype._pxToPercent = function (iPx, iFullSize) {
		return (iPx * 100) / iFullSize + "%";
	};

	/**
	 * Recalculates the content sizes in three steps:
	 *  1. Searches for all absolute values ("px") and deducts them from the available space.
	 *  2. Searches for all percent values and interprets them as % of the available space after step 1
	 *  3. Divides the rest of the space uniformly between all contents with "auto" size values
	 *
	 * @private
	 * @override
	 */
	AssociativeSplitter.prototype._recalculateSizes = function () {
		// TODO: (?) Use maxSize value from layoutData
		var i, sSize, oLayoutData, iColSize, idx, iSize, iMinSize;

		// Read all content sizes from the layout data
		var aSizes = [];
		var aContentAreas = this._getContentAreas();
		var sOrientation = this.getOrientation();
		var aAutosizeIdx = [];
		var aAutoMinsizeIdx = [];
		var aPercentsizeIdx = [];

		for (i = 0; i < aContentAreas.length; ++i) {
			oLayoutData = aContentAreas[i].getLayoutData();
			sSize = oLayoutData ? oLayoutData.getSize() : "auto";

			aSizes.push(sSize);
		}

		var iAvailableSize = this._calculateAvailableContentSize(aSizes) + 1;
		this._calculatedSizes = [];

		// Remove fixed sizes from available size
		for (i = 0; i < aSizes.length; ++i) {
			sSize = aSizes[i];

			if (sSize.indexOf("px") > -1) {
				// Pixel based Value - deduct it from available size
				iSize = parseInt(sSize);
				iAvailableSize -= iSize;
				this._calculatedSizes[i] = iSize;
			} else if (sSize.indexOf("%") > -1) {
				aPercentsizeIdx.push(i);
			} else if (sSize === "auto") {
				oLayoutData = aContentAreas[i].getLayoutData();
				if (oLayoutData && parseInt(oLayoutData.getMinSize()) !== 0) {
					aAutoMinsizeIdx.push(i);
				} else {
					aAutosizeIdx.push(i);
				}
			} else {
				Log.error("Illegal size value: " + aSizes[i]);
			}
		}

		var bWarnSize = false; // Warn about sizes being too big for the available space

		// If more than the available size if assigned to fixed width content, the rest will get no
		// space at all
		if (iAvailableSize < 0) { bWarnSize = true; iAvailableSize = 0; }

		// Now calculate % of the available space
		var iRest = iAvailableSize;
		iAvailableSize = sOrientation === "Horizontal" ? this.$().width() : this.$().height();

		var iPercentSizes = aPercentsizeIdx.length;
		for (i = 0; i < iPercentSizes; ++i) {
			idx = aPercentsizeIdx[i];
			if (iPercentSizes === 1 && aContentAreas.length === 1) {
				iColSize = iAvailableSize;
			} else {
				// Percent based Value - deduct it from available size
				iColSize = parseFloat(aSizes[idx]) / 100 * iAvailableSize;
				iMinSize = parseInt(aContentAreas[idx].getLayoutData().getMinSize());

				if (iColSize < iMinSize) {
					iColSize = iMinSize;
				}
			}
			this._calculatedSizes[idx] = iColSize;
			iRest -= iColSize;
		}
		iAvailableSize = iRest;

		if (iAvailableSize < 0) { bWarnSize = true; iAvailableSize = 0; }

		// Calculate auto sizes
		iColSize = Math.floor(iAvailableSize / (aAutoMinsizeIdx.length + aAutosizeIdx.length), 0);

		// First calculate auto-sizes with a minSize constraint
		var iAutoMinSizes = aAutoMinsizeIdx.length;
		for (i = 0; i < iAutoMinSizes; ++i) {
			idx = aAutoMinsizeIdx[i];
			iMinSize = parseInt(aContentAreas[idx].getLayoutData().getMinSize());
			if (iMinSize > iColSize) {
				this._calculatedSizes[idx] = iMinSize;
				iAvailableSize -= iMinSize;
			} else {
				this._calculatedSizes[idx] = iColSize;
				iAvailableSize -= iColSize;
			}
		}

		if (iAvailableSize < 0) { bWarnSize = true; iAvailableSize = 0; }

		// Now calculate "auto"-sizes
		iRest = iAvailableSize;
		var iAutoSizes = aAutosizeIdx.length;
		iColSize = Math.floor(iAvailableSize / iAutoSizes, 0);
		for (i = 0; i < iAutoSizes; ++i) {
			idx = aAutosizeIdx[i];
			this._calculatedSizes[idx] = iColSize;
			iRest -= iColSize;
		}

		if (bWarnSize) {
			// TODO: Decide if the warning should be kept - might spam the console but on the other
			//       hand it might make analyzing of splitter bugs easier, since we can just ask
			//       developers if there was a [Splitter] output on the console if the splitter looks
			//       weird in their application.
			Log.info(
				"[Splitter] The set sizes and minimal sizes of the splitter contents are bigger " +
				"than the available space in the UI."
			);
		}
		this._calculatedSizes = this._calculatedSizes;
	};

	AssociativeSplitter.prototype._ensureAllSplittersCollapsed = function (iBar) {
		var aAreas = this._getContentAreas();
		var bAllCollapsed = false;
		for (var i = 0; i < aAreas.length; i++) {
			var sSize = aAreas[i].getLayoutData().getSize().slice(0, -2);

			if (sSize === "0" || sSize === "au") {
				bAllCollapsed = true;
				continue;
			} else if (i === (aAreas.length - 1) && bAllCollapsed) {
				this._getContentAreas()[iBar + 1].setLayoutData(new SplitterLayoutData({ size: "100%" }));
			}
		}
	};

	AssociativeSplitter.prototype.containsControl = function (sControlId) {
		var aContentAreas = this._getContentAreas(),
			oContentArea,
			i;

		for (i = 0; i < aContentAreas.length; i++) {

			oContentArea = aContentAreas[i];

			if (oContentArea.isA("sap.ui.layout.AssociativeSplitter")) {
				if (oContentArea.containsControl(sControlId)) {
					return true;
				}
			} else {
				if (oContentArea.getId() === sControlId) {
					return true;
				}
			}
		}
	};

	return AssociativeSplitter;
});<commit_msg>[INTERNAL] sap.ui.layout.AssociativeSplitter: Delete unused method<commit_after>/*!
 * ${copyright}
 */

sap.ui.define([
	'./Splitter',
	'./SplitterRenderer',
	"sap/base/Log",
	"sap/ui/layout/SplitterLayoutData"
], function(Splitter, SplitterRenderer, Log, SplitterLayoutData) {
	"use strict";

	/**
	 * Constructor for a new AssociativeSplitter.
	 *
	 * @param {string} [sId] ID for the new control, generated automatically if no ID is given
	 * @param {object} [mSettings] Initial settings for the new control
	 *
	 * @class
	 * AssociativeSplitter is a version of Splitter that uses an association in addition to the contentAreas aggregation.
	 * It is used to visualize controls aggregated in {@link sap.ui.layout.PaneContainer PaneContainer} panes.
	 *
	 * @extends sap.ui.layout.Splitter
	 *
	 * @author SAP SE
	 * @version ${version}
	 *
	 * @constructor
	 * @private
	 * @since 1.38
	 * @alias sap.ui.layout.AssociativeSplitter
	 */
	var AssociativeSplitter = Splitter.extend("sap.ui.layout.AssociativeSplitter", /** @lends sap.ui.layout.AssociativeSplitter.prototype */ {
		metadata : {
			associations : {
				/**
				 * The same as contentAreas, but provided in the form of an association.
				 */
				associatedContentAreas: {type : "sap.ui.core.Control", multiple : true, singularName : "associatedContentArea"}
			}
		},
		renderer: SplitterRenderer
	});

	AssociativeSplitter.prototype.init = function () {
		Splitter.prototype.init.call(this);
		// We need to have different step size than the existing in the Splitter
		this._keyListeners = {
			increase     : this._onKeyboardResize.bind(this, "inc", 1),
			decrease     : this._onKeyboardResize.bind(this, "dec", 1),
			increaseMore : this._onKeyboardResize.bind(this, "incMore", 2),
			decreaseMore : this._onKeyboardResize.bind(this, "decMore", 2),
			max          : this._onKeyboardResize.bind(this, "max", 1),
			min          : this._onKeyboardResize.bind(this, "min", 1)
		};
		this._enableKeyboardListeners();
	};

	AssociativeSplitter.prototype.addAssociatedContentArea = function (oContent) {
		this._ensureLayoutData(oContent);
		return this.addAssociation("associatedContentAreas", oContent);
	};

	/**
	 * Adds shift + arrows keyboard handling to the existing one
	 * @returns {void}
	 * @private
	 * @override
	 */
	AssociativeSplitter.prototype._enableKeyboardListeners = function () {
		Splitter.prototype._enableKeyboardListeners.call(this);
		this.onsaprightmodifiers = this._keyListeners.increase;
		this.onsapleftmodifiers = this._keyListeners.decrease;
		this.onsapupmodifiers = this._keyListeners.decrease;
		this.onsapdownmodifiers = this._keyListeners.increase;
		this.onsapright = this._keyListeners.increaseMore;
		this.onsapdown = this._keyListeners.increaseMore;
		this.onsapleft = this._keyListeners.decreaseMore;
		this.onsapup = this._keyListeners.decreaseMore;
		this.onsapend = this._keyListeners.max;
		this.onsaphome = this._keyListeners.min;

		this._keyboardEnabled = true;
	};

	/**
	 * @override
	 */
	AssociativeSplitter.prototype._getContentAreas = function () {
		var aAssociatedContentAreas = this.getAssociatedContentAreas() || [];
		var aContentAreas = this.getContentAreas();

		var aValidAssContentAreas = aAssociatedContentAreas.map(function (sId) {
			return sap.ui.getCore().byId(sId);
		}).filter(function (oContent) { return oContent; });

		return aContentAreas.concat(aValidAssContentAreas);
	};

	AssociativeSplitter.prototype.ondblclick = function (oEvent) {
		// For some reason dblclick returns the whole Splitter not only the clicked splitbar
		var sId = this.getId(),
			iBar, oContentArea;
		if (!(oEvent.target.contains(this._oLastDOMclicked) && (this._oLastDOMclicked.id.indexOf(sId + "-splitbar") > -1))) {
			// The clicked element was not one of my splitter bars
			return;
		}

		iBar = parseInt(this._oLastDOMclicked.id.substr((sId + "-splitbar-").length));
		oContentArea = this._getContentAreas()[iBar];
		oContentArea._currentPosition = this.getCalculatedSizes()[iBar];
		oContentArea._lastPosition = oContentArea._lastPosition || oContentArea._currentPosition;

		if (oContentArea._currentPosition === oContentArea._lastPosition) {
			this._resizeContents(iBar, (this.getCalculatedSizes()[iBar]) * -1, true);
		} else {
			this._resizeContents(iBar, oContentArea._lastPosition, true);
			oContentArea._lastPosition = null;
		}
	};

	// Overriding sap.ui.layout.Splitter's calculation functions in order to make it responsive

	/**
	 * Resizes the contents after a bar has been moved
	 *
	 * @param {Number} [iLeftContent] Number of the first (left) content that is resized
	 * @param {Number} [iPixels] Number of pixels to increase the first and decrease the second content
	 * @param {boolean} [bFinal] Whether this is the final position (sets the size in the layoutData of the content areas)
	 * @override
	 */
	AssociativeSplitter.prototype._resizeContents = function (iLeftContent, iPixels, bFinal) {
		var aContentAreas, oLd1, oLd2, sSize1,
			sSize2, $Cnt1, $Cnt2, iNewSize1, iNewSize2,
			iMinSize1, iMinSize2, sOrientation, iSplitterSize,
			sFinalSize1, sFinalSize2, iDiff,
			sMoveContentSize1 = parseFloat(this._move.c1Size).toFixed(5),
			sMoveContentSize2 = parseFloat(this._move.c2Size).toFixed(5),
			fMoveC1Size = parseFloat(sMoveContentSize1),
			fMoveC2Size = parseFloat(sMoveContentSize2);

		if (isNaN(iPixels)) {
			Log.warning("Splitter: Received invalid resizing values - resize aborted.");
			return;
		}

		aContentAreas = this._getContentAreas();
		oLd1 = aContentAreas[iLeftContent].getLayoutData();
		oLd2 = aContentAreas[iLeftContent + 1].getLayoutData();

		sSize1 = oLd1.getSize();
		sSize2 = oLd2.getSize();

		$Cnt1 = this.$("content-" + iLeftContent);
		$Cnt2 = this.$("content-" + (iLeftContent + 1));

		iNewSize1 = fMoveC1Size + iPixels;
		iNewSize2 = fMoveC2Size - iPixels;
		iMinSize1 = parseInt(oLd1.getMinSize());
		iMinSize2 = parseInt(oLd2.getMinSize());

		sOrientation = this.getOrientation();
		iSplitterSize = sOrientation === "Horizontal" ? this.$().width() : this.$().height();

		// Adhere to size constraints
		if (iNewSize1 < iMinSize1) {
			iDiff = iMinSize1 - iNewSize1;
			iPixels += iDiff;
			iNewSize1 = iMinSize1;
			iNewSize2 -= iDiff;
		} else if (iNewSize2 < iMinSize2) {
			iDiff = iMinSize2 - iNewSize2;
			iPixels -= iDiff;
			iNewSize2 = iMinSize2;
			iNewSize1 -= iDiff;
		}

		if (bFinal) {
			// Resize finished, set layout data in content areas
			if (sSize1 === "auto" && sSize2 !== "auto") {
				// First pane has auto size - only change size of second pane
				sFinalSize2 = this._pxToPercent(iNewSize2, iSplitterSize);
				oLd2.setSize(sFinalSize2);
			} else if (sSize1 !== "auto" && sSize2 === "auto") {
				// Second pane has auto size - only change size of first pane
				sFinalSize1 = this._pxToPercent(iNewSize1, iSplitterSize);
				oLd1.setSize(sFinalSize1);
			} else {
				sFinalSize1 = this._pxToPercent(iNewSize1, iSplitterSize);
				sFinalSize2 = this._pxToPercent(iNewSize2, iSplitterSize);

				oLd1.setSize(sFinalSize1);
				oLd2.setSize(sFinalSize2);
			}
		} else {
			// Live-Resize, resize contents in Dom
			sFinalSize1 = this._pxToPercent(iNewSize1, iSplitterSize);
			sFinalSize2 = this._pxToPercent(iNewSize2, iSplitterSize);

			$Cnt1.css(this._sizeType, sFinalSize1);
			$Cnt2.css(this._sizeType, sFinalSize2);
		}
	};

	AssociativeSplitter.prototype._pxToPercent = function (iPx, iFullSize) {
		return (iPx * 100) / iFullSize + "%";
	};

	/**
	 * Recalculates the content sizes in three steps:
	 *  1. Searches for all absolute values ("px") and deducts them from the available space.
	 *  2. Searches for all percent values and interprets them as % of the available space after step 1
	 *  3. Divides the rest of the space uniformly between all contents with "auto" size values
	 *
	 * @private
	 * @override
	 */
	AssociativeSplitter.prototype._recalculateSizes = function () {
		// TODO: (?) Use maxSize value from layoutData
		var i, sSize, oLayoutData, iColSize, idx, iSize, iMinSize;

		// Read all content sizes from the layout data
		var aSizes = [];
		var aContentAreas = this._getContentAreas();
		var sOrientation = this.getOrientation();
		var aAutosizeIdx = [];
		var aAutoMinsizeIdx = [];
		var aPercentsizeIdx = [];

		for (i = 0; i < aContentAreas.length; ++i) {
			oLayoutData = aContentAreas[i].getLayoutData();
			sSize = oLayoutData ? oLayoutData.getSize() : "auto";

			aSizes.push(sSize);
		}

		var iAvailableSize = this._calculateAvailableContentSize(aSizes) + 1;
		this._calculatedSizes = [];

		// Remove fixed sizes from available size
		for (i = 0; i < aSizes.length; ++i) {
			sSize = aSizes[i];

			if (sSize.indexOf("px") > -1) {
				// Pixel based Value - deduct it from available size
				iSize = parseInt(sSize);
				iAvailableSize -= iSize;
				this._calculatedSizes[i] = iSize;
			} else if (sSize.indexOf("%") > -1) {
				aPercentsizeIdx.push(i);
			} else if (sSize === "auto") {
				oLayoutData = aContentAreas[i].getLayoutData();
				if (oLayoutData && parseInt(oLayoutData.getMinSize()) !== 0) {
					aAutoMinsizeIdx.push(i);
				} else {
					aAutosizeIdx.push(i);
				}
			} else {
				Log.error("Illegal size value: " + aSizes[i]);
			}
		}

		var bWarnSize = false; // Warn about sizes being too big for the available space

		// If more than the available size if assigned to fixed width content, the rest will get no
		// space at all
		if (iAvailableSize < 0) { bWarnSize = true; iAvailableSize = 0; }

		// Now calculate % of the available space
		var iRest = iAvailableSize;
		iAvailableSize = sOrientation === "Horizontal" ? this.$().width() : this.$().height();

		var iPercentSizes = aPercentsizeIdx.length;
		for (i = 0; i < iPercentSizes; ++i) {
			idx = aPercentsizeIdx[i];
			if (iPercentSizes === 1 && aContentAreas.length === 1) {
				iColSize = iAvailableSize;
			} else {
				// Percent based Value - deduct it from available size
				iColSize = parseFloat(aSizes[idx]) / 100 * iAvailableSize;
				iMinSize = parseInt(aContentAreas[idx].getLayoutData().getMinSize());

				if (iColSize < iMinSize) {
					iColSize = iMinSize;
				}
			}
			this._calculatedSizes[idx] = iColSize;
			iRest -= iColSize;
		}
		iAvailableSize = iRest;

		if (iAvailableSize < 0) { bWarnSize = true; iAvailableSize = 0; }

		// Calculate auto sizes
		iColSize = Math.floor(iAvailableSize / (aAutoMinsizeIdx.length + aAutosizeIdx.length), 0);

		// First calculate auto-sizes with a minSize constraint
		var iAutoMinSizes = aAutoMinsizeIdx.length;
		for (i = 0; i < iAutoMinSizes; ++i) {
			idx = aAutoMinsizeIdx[i];
			iMinSize = parseInt(aContentAreas[idx].getLayoutData().getMinSize());
			if (iMinSize > iColSize) {
				this._calculatedSizes[idx] = iMinSize;
				iAvailableSize -= iMinSize;
			} else {
				this._calculatedSizes[idx] = iColSize;
				iAvailableSize -= iColSize;
			}
		}

		if (iAvailableSize < 0) { bWarnSize = true; iAvailableSize = 0; }

		// Now calculate "auto"-sizes
		iRest = iAvailableSize;
		var iAutoSizes = aAutosizeIdx.length;
		iColSize = Math.floor(iAvailableSize / iAutoSizes, 0);
		for (i = 0; i < iAutoSizes; ++i) {
			idx = aAutosizeIdx[i];
			this._calculatedSizes[idx] = iColSize;
			iRest -= iColSize;
		}

		if (bWarnSize) {
			// TODO: Decide if the warning should be kept - might spam the console but on the other
			//       hand it might make analyzing of splitter bugs easier, since we can just ask
			//       developers if there was a [Splitter] output on the console if the splitter looks
			//       weird in their application.
			Log.info(
				"[Splitter] The set sizes and minimal sizes of the splitter contents are bigger " +
				"than the available space in the UI."
			);
		}
		this._calculatedSizes = this._calculatedSizes;
	};

	AssociativeSplitter.prototype.containsControl = function (sControlId) {
		var aContentAreas = this._getContentAreas(),
			oContentArea,
			i;

		for (i = 0; i < aContentAreas.length; i++) {

			oContentArea = aContentAreas[i];

			if (oContentArea.isA("sap.ui.layout.AssociativeSplitter")) {
				if (oContentArea.containsControl(sControlId)) {
					return true;
				}
			} else {
				if (oContentArea.getId() === sControlId) {
					return true;
				}
			}
		}
	};

	return AssociativeSplitter;
});<|endoftext|>


<commit_before>var gulp = require('gulp')
var gutil = require('gulp-util')
var watchify = require('watchify')
var browserify = require('browserify')
var connect = require('gulp-connect')
var duration = require('gulp-duration')
var source = require('vinyl-source-stream')

/**
 * Create a browserify build instance.
 *
 * @param  {Boolean} watch
 * @return {Object}
 */
module.exports = function (watch) {
  var build = browserify({
    entries: ['./app/js/main.js'],
    debug:   gutil.env.type !== 'production',
    // Required for watchify.
    cache:        {},
    packageCache: {},
    fullPaths:    watch
  })

  // Enable `watchify` for rebuilds.
  if (watch) {
    build = watchify(build)

    build.on('update', bundle)
  }

  /**
   * Generate a built browserify bundle.
   */
  function bundle () {
    return build.bundle()
      .on('error', function (err) {
        gutil.log(err.message)
      })
      .pipe(source('bundle.js'))
      .pipe(duration('browserify'))
      .pipe(gulp.dest('./build/js/'))
      .pipe(connect.reload())
  }

  return bundle()
}
<commit_msg>use NODE_ENV variable<commit_after>var gulp = require('gulp')
var gutil = require('gulp-util')
var watchify = require('watchify')
var browserify = require('browserify')
var connect = require('gulp-connect')
var duration = require('gulp-duration')
var source = require('vinyl-source-stream')

/**
 * Create a browserify build instance.
 *
 * @param  {Boolean} watch
 * @return {Object}
 */
module.exports = function (watch) {
  var build = browserify({
    entries: ['./app/js/main.js'],
    debug: process.env.NODE_ENV !== 'production',
    // Required for watchify.
    cache: {},
    packageCache: {},
    fullPaths: watch
  })

  // Enable `watchify` for rebuilds.
  if (watch) {
    build = watchify(build)

    build.on('update', bundle)
  }

  /**
   * Generate a built browserify bundle.
   */
  function bundle () {
    return build.bundle()
      .on('error', function (err) {
        gutil.log(err.message)
      })
      .pipe(source('bundle.js'))
      .pipe(duration('browserify'))
      .pipe(gulp.dest('./build/js/'))
      .pipe(connect.reload())
  }

  return bundle()
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 Titanium I.T. LLC. All rights reserved. See LICENSE.txt for details.

/*global desc, task, jake, fail, complete, directory*/
(function() {
	"use strict";

	if (!process.env.loose) console.log("For more forgiving test settings, use 'loose=true'");

	var lint = require("./build/lint/lint_runner.js");
	var nodeunit = require("nodeunit").reporters["default"];
	var path = require("path");

	var NODE_VERSION = "v0.8.10";
	var SUPPORTED_BROWSERS = [
		"IE 8.0",
		"IE 9.0",
		"Firefox 16.0",
		"Chrome 23.0",
		"Mac Safari 6.0",
		"iOS Safari 6.0"
	];

	var GENERATED_DIR = "generated";
	var TEMP_TESTFILE_DIR = GENERATED_DIR + "/test";

	directory(TEMP_TESTFILE_DIR);

	desc("Delete all generated files");
	task("clean", [], function() {
		jake.rmRf(GENERATED_DIR);
	});

	desc("Build and test");
	task("default", ["lint", "test"], function() {
		console.log("\n\nOK");
	});

	desc("Start Testacular server for testing");
	task("testacular", function() {
		sh("node", ["node_modules/testacular/bin/testacular", "start", "build/testacular.conf.js"],
			"Could not start Testacular server", complete);
	}, {async: true});

	desc("Lint everything");
	task("lint", ["lintNode", "lintClient"]);

	task("lintNode", ["nodeVersion"], function() {
		var passed = lint.validateFileList(nodeFiles(), nodeLintOptions(), {});
		if (!passed) fail("Lint failed");
	});

	task("lintClient", function() {
		var passed = lint.validateFileList(clientFiles(), browserLintOptions(), {});
		if (!passed) fail("Lint failed");
	});

	desc("Test everything");
	task("test", ["testNode", "testClient"]);

	desc("Test server code");
	task("testNode", ["nodeVersion", TEMP_TESTFILE_DIR], function() {
		nodeunit.run(nodeTestFiles(), null, function(failures) {
			if (failures) fail("Tests failed");
			complete();
		});
	}, {async: true});

	desc("Test client code");
	task("testClient", function() {
		var config = {};

		var output = "";
		var oldStdout = process.stdout.write;
		process.stdout.write = function(data) {
			output += data;
			oldStdout.apply(this, arguments);
		};

		require("testacular/lib/runner").run(config, function(exitCode) {
			process.stdout.write = oldStdout;

			if (exitCode) fail("Client tests failed (to start server, run 'jake testacular')");
			var browserMissing = false;
			SUPPORTED_BROWSERS.forEach(function(browser) {
				browserMissing = checkIfBrowserTested(browser, output) || browserMissing;
			});
			if (browserMissing && !process.env.loose) fail("Did not test all supported browsers (use 'loose=true' to suppress error)");
			if (output.indexOf("TOTAL: 0 SUCCESS") !== -1) fail("Client tests did not run!");

			complete();
		});
	}, {async: true});

	function checkIfBrowserTested(browser, output) {
		var missing = output.indexOf(browser + ": Executed") === -1;
		if (missing) console.log(browser + " was not tested!");
		return missing;
	}

	desc("Deploy to Heroku");
	task("deploy", ["default"], function() {
		console.log("1. Make sure 'git status' is clean.");
		console.log("2. 'git push heroku master'");
		console.log("3. 'jake test'");
	});

//	desc("Ensure correct version of Node is present.");
	task("nodeVersion", [], function() {
		function failWithQualifier(qualifier) {
			fail("Incorrect node version. Expected " + qualifier +
				" [" + expectedString + "], but was [" + actualString + "].");
		}

		var expectedString = NODE_VERSION;
		var actualString = process.version;
		var expected = parseNodeVersion("expected Node version", expectedString);
		var actual = parseNodeVersion("Node version", actualString);

		if (!process.env.loose) {
			if (actual[0] !== expected[0] || actual[1] !== expected[1] || actual[2] !== expected[2]) {
				failWithQualifier("exactly");
			}
		}
		else {
			if (actual[0] < expected[0]) failWithQualifier("at least");
			if (actual[0] === expected[0] && actual[1] < expected[1]) failWithQualifier("at least");
			if (actual[0] === expected[0] && actual[1] === expected[1] && actual[2] < expected[2]) failWithQualifier("at least");
		}
	});

	desc("Integration checklist");
	task("integrate", ["default"], function() {
		console.log("1. Make sure 'git status' is clean.");
		console.log("2. Build on the integration box.");
		console.log("   a. Walk over to integration box.");
		console.log("   b. 'git pull'");
		console.log("   c. 'npm rebuild'");
		console.log("   d. Check status for files that need to be .gitignore'd");
		console.log("   e. 'jake'");
		console.log("   f. If jake fails, stop! Try again after fixing the issue.");
		console.log("3. 'git checkout integration'");
		console.log("4. 'git merge master --no-ff --log'");
		console.log("5. 'git checkout master'");
	});

	desc("End-of-episode checklist");
	task("episode", [], function() {
		console.log("1. Save recording.");
		console.log("2. Double-check sound and framing.");
		console.log("3. Commit source code.");
		console.log("4. Check Windows compatibility");
		console.log("   a. Switch to Windows VM");
		console.log("   b. 'git pull'");
		console.log("   c. 'npm rebuild'");
		console.log("   d. Check status for files that need to be .gitignore'd");
		console.log("   e. 'jake'");
		console.log("5. Tag episode: 'git tag -a episodeXX -m \"End of episode XX\"'");
	});

	function parseNodeVersion(description, versionString) {
		var versionMatcher = /^v(\d+)\.(\d+)\.(\d+)$/;    // v[major].[minor].[bugfix]
		var versionInfo = versionString.match(versionMatcher);
		if (versionInfo === null) fail("Could not parse " + description + " (was '" + versionString + "')");

		var major = parseInt(versionInfo[1], 10);
		var minor = parseInt(versionInfo[2], 10);
		var bugfix = parseInt(versionInfo[3], 10);
		return [major, minor, bugfix];
	}

	function sh(command, args, errorMessage, callback) {
		console.log("> " + command + " " + args.join(" "));

		// Not using jake.createExec as it adds extra line-feeds into output as of v0.3.7
		var child = require("child_process").spawn(command, args, { stdio: "pipe" });

		// redirect stdout
		var stdout = "";
		child.stdout.setEncoding("utf8");
		child.stdout.on("data", function(chunk) {
			stdout += chunk;
			process.stdout.write(chunk);
		});

		// redirect stderr
		var stderr = "";
		child.stderr.setEncoding("utf8");
		child.stderr.on("data", function(chunk) {
			stderr += chunk;
			process.stderr.write(chunk);
		});

		// handle process exit
		child.on("exit", function(exitCode) {
			if (exitCode !== 0) fail(errorMessage);
		});
		child.on("close", function() {      // 'close' event can happen after 'exit' event
			callback(stdout, stderr);
		});
	}

	function nodeFiles() {
		var javascriptFiles = new jake.FileList();
		javascriptFiles.include("*.js");
		javascriptFiles.include("src/server/**/*.js");
		javascriptFiles.include("src/_smoke_test.js");
		return javascriptFiles.toArray();
	}

	function nodeTestFiles() {
		var testFiles = new jake.FileList();
		testFiles.include("src/server/**/_*_test.js");
		testFiles.include("src/_*_test.js");
		testFiles = testFiles.toArray();
		return testFiles;
	}

	function clientFiles() {
		var javascriptFiles = new jake.FileList();
		javascriptFiles.include("src/client/**/*.js");
		return javascriptFiles.toArray();
	}

	function nodeLintOptions() {
		var options = globalLintOptions();
		options.node = true;
		return options;
	}

	function browserLintOptions() {
		var options = globalLintOptions();
		options.browser = true;
		return options;
	}

	function globalLintOptions() {
		var options = {
			bitwise: true,
			curly: false,
			eqeqeq: true,
			forin: true,
			immed: true,
			latedef: true,
			newcap: true,
			noarg: true,
			noempty: true,
			nonew: true,
			regexp: true,
			undef: true,
			strict: true,
			trailing: true
		};
		return options;
	}

}());
<commit_msg>Updated Firefox version<commit_after>// Copyright (c) 2012 Titanium I.T. LLC. All rights reserved. See LICENSE.txt for details.

/*global desc, task, jake, fail, complete, directory*/
(function() {
	"use strict";

	if (!process.env.loose) console.log("For more forgiving test settings, use 'loose=true'");

	var lint = require("./build/lint/lint_runner.js");
	var nodeunit = require("nodeunit").reporters["default"];
	var path = require("path");

	var NODE_VERSION = "v0.8.10";
	var SUPPORTED_BROWSERS = [
		"IE 8.0",
		"IE 9.0",
		"Firefox 17.0",
		"Chrome 23.0",
		"Mac Safari 6.0",
		"iOS Safari 6.0"
	];

	var GENERATED_DIR = "generated";
	var TEMP_TESTFILE_DIR = GENERATED_DIR + "/test";

	directory(TEMP_TESTFILE_DIR);

	desc("Delete all generated files");
	task("clean", [], function() {
		jake.rmRf(GENERATED_DIR);
	});

	desc("Build and test");
	task("default", ["lint", "test"], function() {
		console.log("\n\nOK");
	});

	desc("Start Testacular server for testing");
	task("testacular", function() {
		sh("node", ["node_modules/testacular/bin/testacular", "start", "build/testacular.conf.js"],
			"Could not start Testacular server", complete);
	}, {async: true});

	desc("Lint everything");
	task("lint", ["lintNode", "lintClient"]);

	task("lintNode", ["nodeVersion"], function() {
		var passed = lint.validateFileList(nodeFiles(), nodeLintOptions(), {});
		if (!passed) fail("Lint failed");
	});

	task("lintClient", function() {
		var passed = lint.validateFileList(clientFiles(), browserLintOptions(), {});
		if (!passed) fail("Lint failed");
	});

	desc("Test everything");
	task("test", ["testNode", "testClient"]);

	desc("Test server code");
	task("testNode", ["nodeVersion", TEMP_TESTFILE_DIR], function() {
		nodeunit.run(nodeTestFiles(), null, function(failures) {
			if (failures) fail("Tests failed");
			complete();
		});
	}, {async: true});

	desc("Test client code");
	task("testClient", function() {
		var config = {};

		var output = "";
		var oldStdout = process.stdout.write;
		process.stdout.write = function(data) {
			output += data;
			oldStdout.apply(this, arguments);
		};

		require("testacular/lib/runner").run(config, function(exitCode) {
			process.stdout.write = oldStdout;

			if (exitCode) fail("Client tests failed (to start server, run 'jake testacular')");
			var browserMissing = false;
			SUPPORTED_BROWSERS.forEach(function(browser) {
				browserMissing = checkIfBrowserTested(browser, output) || browserMissing;
			});
			if (browserMissing && !process.env.loose) fail("Did not test all supported browsers (use 'loose=true' to suppress error)");
			if (output.indexOf("TOTAL: 0 SUCCESS") !== -1) fail("Client tests did not run!");

			complete();
		});
	}, {async: true});

	function checkIfBrowserTested(browser, output) {
		var missing = output.indexOf(browser + ": Executed") === -1;
		if (missing) console.log(browser + " was not tested!");
		return missing;
	}

	desc("Deploy to Heroku");
	task("deploy", ["default"], function() {
		console.log("1. Make sure 'git status' is clean.");
		console.log("2. 'git push heroku master'");
		console.log("3. 'jake test'");
	});

//	desc("Ensure correct version of Node is present.");
	task("nodeVersion", [], function() {
		function failWithQualifier(qualifier) {
			fail("Incorrect node version. Expected " + qualifier +
				" [" + expectedString + "], but was [" + actualString + "].");
		}

		var expectedString = NODE_VERSION;
		var actualString = process.version;
		var expected = parseNodeVersion("expected Node version", expectedString);
		var actual = parseNodeVersion("Node version", actualString);

		if (!process.env.loose) {
			if (actual[0] !== expected[0] || actual[1] !== expected[1] || actual[2] !== expected[2]) {
				failWithQualifier("exactly");
			}
		}
		else {
			if (actual[0] < expected[0]) failWithQualifier("at least");
			if (actual[0] === expected[0] && actual[1] < expected[1]) failWithQualifier("at least");
			if (actual[0] === expected[0] && actual[1] === expected[1] && actual[2] < expected[2]) failWithQualifier("at least");
		}
	});

	desc("Integration checklist");
	task("integrate", ["default"], function() {
		console.log("1. Make sure 'git status' is clean.");
		console.log("2. Build on the integration box.");
		console.log("   a. Walk over to integration box.");
		console.log("   b. 'git pull'");
		console.log("   c. 'npm rebuild'");
		console.log("   d. Check status for files that need to be .gitignore'd");
		console.log("   e. 'jake'");
		console.log("   f. If jake fails, stop! Try again after fixing the issue.");
		console.log("3. 'git checkout integration'");
		console.log("4. 'git merge master --no-ff --log'");
		console.log("5. 'git checkout master'");
	});

	desc("End-of-episode checklist");
	task("episode", [], function() {
		console.log("1. Save recording.");
		console.log("2. Double-check sound and framing.");
		console.log("3. Commit source code.");
		console.log("4. Check Windows compatibility");
		console.log("   a. Switch to Windows VM");
		console.log("   b. 'git pull'");
		console.log("   c. 'npm rebuild'");
		console.log("   d. Check status for files that need to be .gitignore'd");
		console.log("   e. 'jake'");
		console.log("5. Tag episode: 'git tag -a episodeXX -m \"End of episode XX\"'");
	});

	function parseNodeVersion(description, versionString) {
		var versionMatcher = /^v(\d+)\.(\d+)\.(\d+)$/;    // v[major].[minor].[bugfix]
		var versionInfo = versionString.match(versionMatcher);
		if (versionInfo === null) fail("Could not parse " + description + " (was '" + versionString + "')");

		var major = parseInt(versionInfo[1], 10);
		var minor = parseInt(versionInfo[2], 10);
		var bugfix = parseInt(versionInfo[3], 10);
		return [major, minor, bugfix];
	}

	function sh(command, args, errorMessage, callback) {
		console.log("> " + command + " " + args.join(" "));

		// Not using jake.createExec as it adds extra line-feeds into output as of v0.3.7
		var child = require("child_process").spawn(command, args, { stdio: "pipe" });

		// redirect stdout
		var stdout = "";
		child.stdout.setEncoding("utf8");
		child.stdout.on("data", function(chunk) {
			stdout += chunk;
			process.stdout.write(chunk);
		});

		// redirect stderr
		var stderr = "";
		child.stderr.setEncoding("utf8");
		child.stderr.on("data", function(chunk) {
			stderr += chunk;
			process.stderr.write(chunk);
		});

		// handle process exit
		child.on("exit", function(exitCode) {
			if (exitCode !== 0) fail(errorMessage);
		});
		child.on("close", function() {      // 'close' event can happen after 'exit' event
			callback(stdout, stderr);
		});
	}

	function nodeFiles() {
		var javascriptFiles = new jake.FileList();
		javascriptFiles.include("*.js");
		javascriptFiles.include("src/server/**/*.js");
		javascriptFiles.include("src/_smoke_test.js");
		return javascriptFiles.toArray();
	}

	function nodeTestFiles() {
		var testFiles = new jake.FileList();
		testFiles.include("src/server/**/_*_test.js");
		testFiles.include("src/_*_test.js");
		testFiles = testFiles.toArray();
		return testFiles;
	}

	function clientFiles() {
		var javascriptFiles = new jake.FileList();
		javascriptFiles.include("src/client/**/*.js");
		return javascriptFiles.toArray();
	}

	function nodeLintOptions() {
		var options = globalLintOptions();
		options.node = true;
		return options;
	}

	function browserLintOptions() {
		var options = globalLintOptions();
		options.browser = true;
		return options;
	}

	function globalLintOptions() {
		var options = {
			bitwise: true,
			curly: false,
			eqeqeq: true,
			forin: true,
			immed: true,
			latedef: true,
			newcap: true,
			noarg: true,
			noempty: true,
			nonew: true,
			regexp: true,
			undef: true,
			strict: true,
			trailing: true
		};
		return options;
	}

}());
<|endoftext|>