<commit_before>'use strict';

// Load requirements
const path = require('path'),
      fs = require('fs');

// Load modules
const format = require(__base + 'libs/task/format');

// Helper method to check a file or directory exists
function exists(file) {
  return fs.existsSync(file);
}

// Helper method to check for a file
function isFile(file) {
  return ( exists(file) ? fs.lstatSync(file).isFile() : false );
}

const listing = function(directory, seasons) {
  return new Promise((resolve, reject) => {

    // Variables
    let tasks = [],
        files = [],
        promises = [];

    // Reject without a directory
    if ( ! directory ) {
      return reject('No file or directory provided');
    }

    // Normalize the search directory
    directory = path.normalize(directory);

    // Single file
    if ( isFile(directory) ) {

      // Still ensure it matches a format we want
      if ( ! this.format.match(directory) ) {
        return reject('invalid format');
      }

      // Push to tasks and resolve
      tasks.push({season: false, files: [directory]});
      return resolve(tasks);
    }

    // Handle seasons
    if ( seasons !== undefined && Array.isArray(seasons) && seasons.length > 0 ) {

      // Loop through the supplied seasons
      seasons.forEach((season) => {

        // Clean up season
        season = season.toString().trim();

        // Format the season directory path
        let seasonSub = ( parseInt(season) > 0 ? 'Season ' + season : season ),
            seasonDir = path.normalize(path.join(directory + '/' + seasonSub));

        // Push into promise queue
        promises.push(listing(seasonDir, season));
      });

      // Handle the promise resolution
      return Promise.all(promises).then((data) => {
        return resolve(data.map((season) => { return season[0]; }));
      }).catch((err) => {
        return reject(err.message || err);
      });
    }

    // Invalid directory
    if ( ! exists(directory) ) {
      return reject('invalid directory "' + directory + '"');
    }

    // Directory listing
    fs.readdir(directory, (err, result) => {

      // Skip without files or an error
      if ( err !== null || result.length <= 0 ) {
        return resolve(tasks);
      }

      // Loop the available files
      result.forEach((file) => {

        // Update file to include directory
        file = path.join(directory, file);

        // Check it's actually a file and in the format we want
        if ( isFile(file) && format.match(file) ) {
          files.push(file);
        }
      });

      // Push files into array and resolve
      tasks.push({season: seasons || false, files: files});
      return resolve(tasks);
    });
  });
};

module.exports = listing;
<commit_msg>Update empty listing resolution<commit_after>'use strict';

// Load requirements
const path = require('path'),
      fs = require('fs');

// Load modules
const format = require(__base + 'libs/task/format');

// Helper method to check a file or directory exists
function exists(file) {
  return fs.existsSync(file);
}

// Helper method to check for a file
function isFile(file) {
  return ( exists(file) ? fs.lstatSync(file).isFile() : false );
}

const listing = function(directory, seasons) {
  return new Promise((resolve, reject) => {

    // Variables
    let tasks = [],
        files = [],
        promises = [];

    // Reject without a directory
    if ( ! directory ) {
      return reject('No file or directory provided');
    }

    // Normalize the search directory
    directory = path.normalize(directory);

    // Single file
    if ( isFile(directory) ) {

      // Still ensure it matches a format we want
      if ( ! this.format.match(directory) ) {
        return reject('invalid format');
      }

      // Push to tasks and resolve
      tasks.push({season: false, files: [directory]});
      return resolve(tasks);
    }

    // Handle seasons
    if ( seasons !== undefined && Array.isArray(seasons) && seasons.length > 0 ) {

      // Loop through the supplied seasons
      seasons.forEach((season) => {

        // Clean up season
        season = season.toString().trim();

        // Format the season directory path
        let seasonSub = ( parseInt(season) > 0 ? 'Season ' + season : season ),
            seasonDir = path.normalize(path.join(directory + '/' + seasonSub));

        // Push into promise queue
        promises.push(listing(seasonDir, season));
      });

      // Handle the promise resolution
      return Promise.all(promises).then((data) => {
        return resolve(data.map((season) => { return season[0]; }));
      }).catch((err) => {
        return reject(err.message || err);
      });
    }

    // Invalid directory
    if ( ! exists(directory) ) {
      return reject('invalid directory "' + directory + '"');
    }

    // Directory listing
    fs.readdir(directory, (err, result) => {

      // Skip without files or an error
      if ( err !== null || result.length <= 0 ) {
        return resolve([{season: seasons || false, files: []}]);
      }

      // Loop the available files
      result.forEach((file) => {

        // Update file to include directory
        file = path.join(directory, file);

        // Check it's actually a file and in the format we want
        if ( isFile(file) && format.match(file) ) {
          files.push(file);
        }
      });

      // Push files into array and resolve
      tasks.push({season: seasons || false, files: files});
      return resolve(tasks);
    });
  });
};

module.exports = listing;
<|endoftext|>


<commit_before>function LinkView(parent) {
    this.openMode = 'Default';
    this.parent = parent;

    this.viewTemplate = function(){return '';};

    this.dialogWidth;
}

_.extend(LinkView.prototype, {

    setOpenMode: function (mode) {
        if (_.isEmpty(mode)) return;
        this.openMode = mode;
    },

    getOpenMode: function () {
        return this.openMode;
    },

    setContainer: function(containerName){
        this.containerName = containerName;
    },

    setViewTemplate: function(viewTemplate){
        this.viewTemplate = viewTemplate;
    },

    setDialogWidth: function(dialogWidth){
        this.dialogWidth = dialogWidth;
    },

    createView: function (resultCallback) {
        var that = this;

        this.viewTemplate(onViewReady);

        function onViewReady(createdView){
            that.view = createdView;

            that._initViewHandler(createdView);

            resultCallback(createdView);
        }

    },

    _initViewHandler: function(view){
        var that = this;
        var openMode = that.openMode;
        var openStrategy;
        var container;

        if(view.setParent){
            view.setParent(this.parent);
        }
        if(this.parent && this.parent.addChild){
            this.parent.addChild(view);
        }

        switch(openMode){
            case 'Container': {
                container = InfinniUI.global.containers[this.containerName];

                openStrategy = new OpenModeContainerStrategy();
                openStrategy.setView(view);
                openStrategy.setContainer(container);
                view.setOpenStrategy(openStrategy);
            } break;

            case 'Dialog': {
                openStrategy = new OpenModeDialogStrategy();
                openStrategy.setView(view);
                if(this.dialogWidth){
                    openStrategy.setDialogWidth(this.dialogWidth);
                }
                openStrategy.setView(view);
                view.setOpenStrategy(openStrategy);
            } break;
        }
    }
});
<commit_msg>name of dialog size is insensitive now<commit_after>function LinkView(parent) {
    this.openMode = 'Default';
    this.parent = parent;

    this.viewTemplate = function(){return '';};

    this.dialogWidth;
}

_.extend(LinkView.prototype, {

    setOpenMode: function (mode) {
        if (_.isEmpty(mode)) return;
        this.openMode = mode;
    },

    getOpenMode: function () {
        return this.openMode;
    },

    setContainer: function(containerName){
        this.containerName = containerName;
    },

    setViewTemplate: function(viewTemplate){
        this.viewTemplate = viewTemplate;
    },

    setDialogWidth: function(dialogWidth){
        this.dialogWidth = dialogWidth.toLowerCase();
    },

    createView: function (resultCallback) {
        var that = this;

        this.viewTemplate(onViewReady);

        function onViewReady(createdView){
            that.view = createdView;

            that._initViewHandler(createdView);

            resultCallback(createdView);
        }

    },

    _initViewHandler: function(view){
        var that = this;
        var openMode = that.openMode;
        var openStrategy;
        var container;

        if(view.setParent){
            view.setParent(this.parent);
        }
        if(this.parent && this.parent.addChild){
            this.parent.addChild(view);
        }

        switch(openMode){
            case 'Container': {
                container = InfinniUI.global.containers[this.containerName];

                openStrategy = new OpenModeContainerStrategy();
                openStrategy.setView(view);
                openStrategy.setContainer(container);
                view.setOpenStrategy(openStrategy);
            } break;

            case 'Dialog': {
                openStrategy = new OpenModeDialogStrategy();
                openStrategy.setView(view);
                if(this.dialogWidth){
                    openStrategy.setDialogWidth(this.dialogWidth);
                }
                openStrategy.setView(view);
                view.setOpenStrategy(openStrategy);
            } break;
        }
    }
});
<|endoftext|>


<commit_before>require('todo/todo-methods');
require('todo/server/todo-subscriptions');

// Do server-rendering only in proudction mode
if (process.env.NODE_ENV === 'production') {
  // Load Webpack infos for SSR
  ReactRouterSSR.LoadWebpackStats(JSON.parse(Assets.getText('webpack.stats.json')));

  require('../client/routes');
}
<commit_msg>Add missing import<commit_after>import ReactRouterSSR from 'react-router-ssr';

require('todo/todo-methods');
require('todo/server/todo-subscriptions');

// Do server-rendering only in proudction mode
if (process.env.NODE_ENV === 'production') {
  // Load Webpack infos for SSR
  ReactRouterSSR.LoadWebpackStats(JSON.parse(Assets.getText('webpack.stats.json')));

  require('../client/routes');
}
<|endoftext|>


<commit_before>import Ember from 'ember';
import PouchDbMixin from 'hospitalrun/mixins/pouchdb';

const { inject, isEmpty } = Ember;

export default Ember.Mixin.create(PouchDbMixin, {
  idPrefix: null,
  database: inject.service(),
  config: inject.service(),

  /**
  * Override this function to generate an id for a new record
  * @return a generated id;default is null which means that an
  * id will be automatically generated via Ember data.
  */
  generateFriendlyId() {
    const config = this.get('config');
    const database = this.get('database');
    const maxValue = this.get('maxValue');

    const findUnusedId = (sequence) => {
      let next, id;
      return config.getPatientPrefix()
        .then(function(prefix) {
          next = sequence.incrementProperty('value');
          id = sequenceId(prefix, next);
          const query = {
            startkey: [ id, null ],
            endkey: [ id, maxValue ]
          };
          return database.queryMainDB(query, 'patient_by_display_id');
        })
        .then(function(found) {
          if (isEmpty(found.rows)) {
            sequence.set('value', next);
          } else {
            return findUnusedId(sequence);
          }
          return sequence.save().then(function() {
            return id;
          });
        });
    };

    return this.store.find('sequence', 'patient')
      .then(findUnusedId)
      .catch(() => {
        var store = this.get('store');
        var sequence = store.push(store.normalize('sequence', {
          id: 'patient',
          value: 0
        }));
        return findUnusedId(sequence);
      });
  }
});

export function sequenceId(prefix, sequence) {
  if (sequence < 100000) {
    sequence = `00000${sequence}`.slice(-5);
  }
  return `${prefix}${sequence}`;
}
<commit_msg>Keep track of the current `friendlyId` rather than the next available one<commit_after>import Ember from 'ember';
import PouchDbMixin from 'hospitalrun/mixins/pouchdb';

const { inject, isEmpty } = Ember;

export default Ember.Mixin.create(PouchDbMixin, {
  idPrefix: null,
  database: inject.service(),
  config: inject.service(),

  /**
  * Override this function to generate an id for a new record
  * @return a generated id;default is null which means that an
  * id will be automatically generated via Ember data.
  */
  generateFriendlyId() {
    const config = this.get('config');
    const database = this.get('database');
    const maxValue = this.get('maxValue');

    const findUnusedId = (sequence) => {
      let current, id;
      return config.getPatientPrefix()
        .then(function(prefix) {
          current = sequence.get('value');
          id = sequenceId(prefix, current);
          const query = {
            startkey: [ id, null ],
            endkey: [ id, maxValue ]
          };
          return database.queryMainDB(query, 'patient_by_display_id');
        })
        .then(function(found) {
          if (!isEmpty(found.rows)) {
            sequence.incrementProperty('value');
            return findUnusedId(sequence);
          }
          if (sequence.get('hasDirtyAttributes')) {
            return sequence.save().then(function() {
              return id;
            });
          }
          return id;
        });
    };

    return this.store.find('sequence', 'patient')
      .then(findUnusedId)
      .catch(() => {
        var store = this.get('store');
        var sequence = store.push(store.normalize('sequence', {
          id: 'patient',
          value: 1
        }));
        return findUnusedId(sequence);
      });
  }
});

export function sequenceId(prefix, sequence) {
  if (sequence < 100000) {
    sequence = `00000${sequence}`.slice(-5);
  }
  return `${prefix}${sequence}`;
}
<|endoftext|>


<commit_before>var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello Travis!\n') // build should pass now!
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');
<commit_msg>added semicolon<commit_after>var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello Travis!\n'); // build should pass now!
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');
<|endoftext|>


<commit_before>/*global _, window, document, jQuery, Kinetic*/
var MAPJS = MAPJS || {};
if (Kinetic.Stage.prototype.isRectVisible) {
	throw ('isRectVisible already exists, should not mix in our methods');
}
MAPJS.Rectangle = function (x, y, width, height) {
	'use strict';
	this.scale = function (scale) {
		return new MAPJS.Rectangle(x * scale, y * scale, width * scale, height * scale);
	};
	this.translate = function (dx, dy) {
		return new MAPJS.Rectangle(x + dx, y + dy, width, height);
	};
	this.inset = function (margin) {
		return new MAPJS.Rectangle(x + margin, y + margin, width - (margin * 2), height - (margin * 2));
	};
	this.x = x;
	this.y = y;
	this.height = height;
	this.width = width;
};
Kinetic.Stage.prototype.isRectVisible = function (rect, offset) {
	'use strict';
	offset = offset || {x: 0, y: 0, margin: 0};
	var scale = this.getScale().x || 1;
	rect = rect.scale(scale).translate(offset.x, offset.y).inset(offset.margin);
	return !(
		rect.x + this.attrs.x > this.getWidth() ||
		rect.x + rect.width + this.attrs.x < 0  ||
		rect.y + this.attrs.y > this.getHeight() ||
		rect.y + rect.height + this.attrs.y < 0
	);
};

MAPJS.KineticMediator = function (mapModel, stage, imageRendering) {
	'use strict';
	var layer = new Kinetic.Layer(),
		nodeByIdeaId = {},
		connectorByFromIdeaId_ToIdeaId = {},
		connectorKey = function (fromIdeaId, toIdeaId) {
			return fromIdeaId + '_' + toIdeaId;
		},
		atLeastOneVisible = function (list, deltaX, deltaY) {
			var margin = Math.min(stage.getHeight(), stage.getWidth()) * 0.1;
			return _.find(list, function (node) {
				return node.isVisible({x: deltaX, y: deltaY, margin: margin});
			});
		},
		moveStage = function (deltaX, deltaY) {
			var visibleAfterMove, visibleBeforeMove;
			if (!stage) {
				return;
			}
			visibleBeforeMove = atLeastOneVisible(nodeByIdeaId, 0, 0) || atLeastOneVisible(connectorByFromIdeaId_ToIdeaId, 0, 0);
			visibleAfterMove = atLeastOneVisible(nodeByIdeaId, deltaX, deltaY) || atLeastOneVisible(connectorByFromIdeaId_ToIdeaId, deltaX, deltaY);
			if (visibleAfterMove || (!visibleBeforeMove)) {
				if (deltaY !== 0) { stage.attrs.y += deltaY; }
				if (deltaX !== 0) { stage.attrs.x += deltaX; }
				stage.draw();
			}
		},
		resetStage = function () {
			stage.transitionTo({
				x: 0.5 * stage.getWidth(),
				y: 0.5 * stage.getHeight(),
				scale: {
					x: 1,
					y: 1
				},
				duration: 0.5,
				easing: 'ease-in-out',
				callback: function () {
					stage.fire(':scaleChangeComplete');
				}
			});
		};
	stage.add(layer);

	mapModel.addEventListener('nodeEditRequested', function (nodeId, shouldSelectAll) {
		var node = nodeByIdeaId[nodeId];
		if (node) {
			node.editNode(shouldSelectAll);
		}
	});
	mapModel.addEventListener('nodeCreated', function (n) {
		var node = new Kinetic.Idea({
			level: n.level,
			x: n.x,
			y: n.y,
			text: n.title,
			mmStyle: n.style,
			opacity: 1
		}),
			getScale = function () {
				return (stage && stage.attrs && stage.attrs.scale && stage.attrs.scale.x) || 1;
			};

		if (imageRendering) {
			node = Kinetic.IdeaProxy(node, stage, layer);
		}
		/* in kinetic 4.3 cannot use click because click if fired on dragend */
		node.on('click tap', mapModel.selectNode.bind(mapModel, n.id));
		node.on('dblclick dbltap', mapModel.editNode.bind(mapModel, 'mouse', false));
		node.on('dragstart', function () {
			var scale = getScale();

			node.moveToTop();
			node.getNodeAttrs().shadow.offset = {
				x: 8 * scale,
				y: 8 * scale
			};
		});
		node.on('dragmove', function () {
			mapModel.nodeDragMove(
				n.id,
				node.attrs.x,
				node.attrs.y
			);
		});
		node.on('dragend', function () {
			var scale = getScale();
			node.getNodeAttrs().shadow.offset = {
				x: 4 * scale,
				y: 4 * scale
			};
			mapModel.nodeDragEnd(
				n.id,
				node.attrs.x,
				node.attrs.y
			);
			if (n.level > 1) {
				stage.setDraggable(true);
			}
		});
		node.on(':textChanged', function (event) {
			mapModel.updateTitle(n.id, event.text);
			mapModel.setInputEnabled(true);
		});
		node.on(':editing', function () {
			mapModel.setInputEnabled(false);
		});

		if (n.level > 1) {
			node.on('mouseover touchstart', stage.setDraggable.bind(stage, false));
			node.on('mouseout touchend', stage.setDraggable.bind(stage, true));

		}
		layer.add(node);
		node.transitionToAndDontStopCurrentTransitions({
			opacity: 1,
			duration: 0.4
		});
		console.log(':scaleChangeComplete setup', stage);
		stage.on(':scaleChangeComplete', function () {
			console.log(':scaleChangeComplete');
			node.setupShadows();
		});

		nodeByIdeaId[n.id] = node;

	});
	mapModel.addEventListener('nodeSelectionChanged', function (ideaId, isSelected) {
		var node = nodeByIdeaId[ideaId],
			scale = stage.getScale().x || 1,
			offset = 100,
			move = { x: 0, y: 0 };
		node.setIsSelected(isSelected);
		if (!isSelected) {
			return;
		}
		if (node.getAbsolutePosition().x + node.getWidth() * scale + offset > stage.getWidth()) {
			move.x = stage.getWidth() - (node.getAbsolutePosition().x + node.getWidth() * scale + offset);
		} else if (node.getAbsolutePosition().x < offset) {
			move.x  = offset - node.getAbsolutePosition().x;
		}
		if (node.getAbsolutePosition().y + node.getHeight() * scale + offset > stage.getHeight()) {
			move.y = stage.getHeight() - (node.getAbsolutePosition().y + node.getHeight() * scale + offset);
		} else if (node.getAbsolutePosition().y < offset) {
			move.y = offset - node.getAbsolutePosition().y;
		}
		stage.transitionTo({
			x: stage.attrs.x + move.x,
			y: stage.attrs.y + move.y,
			duration: 0.4,
			easing: 'ease-in-out'
		});
	});
	mapModel.addEventListener('nodeStyleChanged', function (n) {
		var node = nodeByIdeaId[n.id];
		node.setMMStyle(n.style);
	});
	mapModel.addEventListener('nodeDroppableChanged', function (ideaId, isDroppable) {
		var node = nodeByIdeaId[ideaId];
		node.setIsDroppable(isDroppable);
	});
	mapModel.addEventListener('nodeRemoved', function (n) {
		var node = nodeByIdeaId[n.id];
		delete nodeByIdeaId[n.id];
		node.transitionTo({
			opacity: 0.25,
			duration: 0.4,
			callback: node.remove.bind(node)
		});
		node.off('click dblclick tap dragstart dragmove dragend mouseover mouseout :textChanged');
	});
	mapModel.addEventListener('nodeMoved', function (n, reason) {
		var node = nodeByIdeaId[n.id];
		node.transitionTo({
			x: n.x,
			y: n.y,
			duration: 0.4,
			easing: reason === 'failed' ? 'bounce-ease-out' : 'ease-in-out'
		});
	});
	mapModel.addEventListener('nodeTitleChanged', function (n) {
		var node = nodeByIdeaId[n.id];
		node.setText(n.title);
		layer.draw();
	});
	mapModel.addEventListener('connectorCreated', function (n) {
		var connector = new Kinetic.Connector({
			shapeFrom: nodeByIdeaId[n.from],
			shapeTo: nodeByIdeaId[n.to],
			stroke: '#888',
			strokeWidth: 1,
			opacity: 0
		});
		connector.opacity = 0;
		connectorByFromIdeaId_ToIdeaId[connectorKey(n.from, n.to)] = connector;
		layer.add(connector);
		connector.moveToBottom();
		connector.transitionTo({
			opacity: 1,
			duration: 0.4
		});
	});
	mapModel.addEventListener('connectorRemoved', function (n) {
		var key = connectorKey(n.from, n.to),
			connector = connectorByFromIdeaId_ToIdeaId[key];
		delete connectorByFromIdeaId_ToIdeaId[key];
		connector.transitionTo({
			opacity: 0,
			duration: 0.1,
			callback: connector.remove.bind(connector)
		});
	});
	mapModel.addEventListener('mapScaleChanged', function (scaleMultiplier, zoomPoint) {
		var currentScale = stage.getScale().x || 1,
			targetScale = Math.max(Math.min(currentScale * scaleMultiplier, 5), 0.2);
		if (currentScale === targetScale) {
			return;
		}
		zoomPoint = zoomPoint || {x:  0.5 * stage.getWidth(), y: 0.5 * stage.getHeight()};
		stage.transitionTo({
			scale: {
				x: targetScale,
				y: targetScale
			},
			x: zoomPoint.x + (stage.attrs.x - zoomPoint.x) * targetScale / currentScale,
			y: zoomPoint.y + (stage.attrs.y - zoomPoint.y) * targetScale / currentScale,
			duration: 0.1,
			easing: 'ease-in-out',
			callback: function () {
				stage.fire(':scaleChangeComplete');
			}
		});
	});
	mapModel.addEventListener('mapViewResetRequested', function () {
		resetStage();
	});
	mapModel.addEventListener('mapMoveRequested', function (deltaX, deltaY) {
		moveStage(deltaX, deltaY);
	});
	(function () {
		var x, y;
		stage.on('dragmove', function () {
			var deltaX = x - stage.attrs.x,
				deltaY = y - stage.attrs.y,
				visibleAfterMove = atLeastOneVisible(nodeByIdeaId, 0, 0) || atLeastOneVisible(connectorByFromIdeaId_ToIdeaId, 0, 0),
				shouldMoveBack = !visibleAfterMove && !(atLeastOneVisible(nodeByIdeaId, deltaX, deltaY) || atLeastOneVisible(connectorByFromIdeaId_ToIdeaId, deltaX, deltaY));
			if (shouldMoveBack) {
				moveStage(deltaX, deltaY);
			} else {
				x = stage.attrs.x;
				y = stage.attrs.y;
			}
		});
	}());
};
MAPJS.KineticMediator.dimensionProvider = _.memoize(function (title) {
	'use strict';
	var text = new Kinetic.Idea({
		text: title
	});
	return {
		width: text.getWidth(),
		height: text.getHeight()
	};
});
MAPJS.KineticMediator.layoutCalculator = function (idea) {
	'use strict';
	return MAPJS.calculateLayout(idea, MAPJS.KineticMediator.dimensionProvider);
};
<commit_msg>change duration so scale to v small number<commit_after>/*global _, window, document, jQuery, Kinetic*/
var MAPJS = MAPJS || {};
if (Kinetic.Stage.prototype.isRectVisible) {
	throw ('isRectVisible already exists, should not mix in our methods');
}
MAPJS.Rectangle = function (x, y, width, height) {
	'use strict';
	this.scale = function (scale) {
		return new MAPJS.Rectangle(x * scale, y * scale, width * scale, height * scale);
	};
	this.translate = function (dx, dy) {
		return new MAPJS.Rectangle(x + dx, y + dy, width, height);
	};
	this.inset = function (margin) {
		return new MAPJS.Rectangle(x + margin, y + margin, width - (margin * 2), height - (margin * 2));
	};
	this.x = x;
	this.y = y;
	this.height = height;
	this.width = width;
};
Kinetic.Stage.prototype.isRectVisible = function (rect, offset) {
	'use strict';
	offset = offset || {x: 0, y: 0, margin: 0};
	var scale = this.getScale().x || 1;
	rect = rect.scale(scale).translate(offset.x, offset.y).inset(offset.margin);
	return !(
		rect.x + this.attrs.x > this.getWidth() ||
		rect.x + rect.width + this.attrs.x < 0  ||
		rect.y + this.attrs.y > this.getHeight() ||
		rect.y + rect.height + this.attrs.y < 0
	);
};

MAPJS.KineticMediator = function (mapModel, stage, imageRendering) {
	'use strict';
	var layer = new Kinetic.Layer(),
		nodeByIdeaId = {},
		connectorByFromIdeaId_ToIdeaId = {},
		connectorKey = function (fromIdeaId, toIdeaId) {
			return fromIdeaId + '_' + toIdeaId;
		},
		atLeastOneVisible = function (list, deltaX, deltaY) {
			var margin = Math.min(stage.getHeight(), stage.getWidth()) * 0.1;
			return _.find(list, function (node) {
				return node.isVisible({x: deltaX, y: deltaY, margin: margin});
			});
		},
		moveStage = function (deltaX, deltaY) {
			var visibleAfterMove, visibleBeforeMove;
			if (!stage) {
				return;
			}
			visibleBeforeMove = atLeastOneVisible(nodeByIdeaId, 0, 0) || atLeastOneVisible(connectorByFromIdeaId_ToIdeaId, 0, 0);
			visibleAfterMove = atLeastOneVisible(nodeByIdeaId, deltaX, deltaY) || atLeastOneVisible(connectorByFromIdeaId_ToIdeaId, deltaX, deltaY);
			if (visibleAfterMove || (!visibleBeforeMove)) {
				if (deltaY !== 0) { stage.attrs.y += deltaY; }
				if (deltaX !== 0) { stage.attrs.x += deltaX; }
				stage.draw();
			}
		},
		resetStage = function () {
			stage.transitionTo({
				x: 0.5 * stage.getWidth(),
				y: 0.5 * stage.getHeight(),
				scale: {
					x: 1,
					y: 1
				},
				duration: 0.5,
				easing: 'ease-in-out',
				callback: function () {
					stage.fire(':scaleChangeComplete');
				}
			});
		};
	stage.add(layer);

	mapModel.addEventListener('nodeEditRequested', function (nodeId, shouldSelectAll) {
		var node = nodeByIdeaId[nodeId];
		if (node) {
			node.editNode(shouldSelectAll);
		}
	});
	mapModel.addEventListener('nodeCreated', function (n) {
		var node = new Kinetic.Idea({
			level: n.level,
			x: n.x,
			y: n.y,
			text: n.title,
			mmStyle: n.style,
			opacity: 1
		}),
			getScale = function () {
				return (stage && stage.attrs && stage.attrs.scale && stage.attrs.scale.x) || 1;
			};

		if (imageRendering) {
			node = Kinetic.IdeaProxy(node, stage, layer);
		}
		/* in kinetic 4.3 cannot use click because click if fired on dragend */
		node.on('click tap', mapModel.selectNode.bind(mapModel, n.id));
		node.on('dblclick dbltap', mapModel.editNode.bind(mapModel, 'mouse', false));
		node.on('dragstart', function () {
			var scale = getScale();

			node.moveToTop();
			node.getNodeAttrs().shadow.offset = {
				x: 8 * scale,
				y: 8 * scale
			};
		});
		node.on('dragmove', function () {
			mapModel.nodeDragMove(
				n.id,
				node.attrs.x,
				node.attrs.y
			);
		});
		node.on('dragend', function () {
			var scale = getScale();
			node.getNodeAttrs().shadow.offset = {
				x: 4 * scale,
				y: 4 * scale
			};
			mapModel.nodeDragEnd(
				n.id,
				node.attrs.x,
				node.attrs.y
			);
			if (n.level > 1) {
				stage.setDraggable(true);
			}
		});
		node.on(':textChanged', function (event) {
			mapModel.updateTitle(n.id, event.text);
			mapModel.setInputEnabled(true);
		});
		node.on(':editing', function () {
			mapModel.setInputEnabled(false);
		});

		if (n.level > 1) {
			node.on('mouseover touchstart', stage.setDraggable.bind(stage, false));
			node.on('mouseout touchend', stage.setDraggable.bind(stage, true));

		}
		layer.add(node);
		node.transitionToAndDontStopCurrentTransitions({
			opacity: 1,
			duration: 0.4
		});
		stage.on(':scaleChangeComplete', function () {
			node.setupShadows();
		});
		nodeByIdeaId[n.id] = node;
	});
	mapModel.addEventListener('nodeSelectionChanged', function (ideaId, isSelected) {
		var node = nodeByIdeaId[ideaId],
			scale = stage.getScale().x || 1,
			offset = 100,
			move = { x: 0, y: 0 };
		node.setIsSelected(isSelected);
		if (!isSelected) {
			return;
		}
		if (node.getAbsolutePosition().x + node.getWidth() * scale + offset > stage.getWidth()) {
			move.x = stage.getWidth() - (node.getAbsolutePosition().x + node.getWidth() * scale + offset);
		} else if (node.getAbsolutePosition().x < offset) {
			move.x  = offset - node.getAbsolutePosition().x;
		}
		if (node.getAbsolutePosition().y + node.getHeight() * scale + offset > stage.getHeight()) {
			move.y = stage.getHeight() - (node.getAbsolutePosition().y + node.getHeight() * scale + offset);
		} else if (node.getAbsolutePosition().y < offset) {
			move.y = offset - node.getAbsolutePosition().y;
		}
		stage.transitionTo({
			x: stage.attrs.x + move.x,
			y: stage.attrs.y + move.y,
			duration: 0.4,
			easing: 'ease-in-out'
		});
	});
	mapModel.addEventListener('nodeStyleChanged', function (n) {
		var node = nodeByIdeaId[n.id];
		node.setMMStyle(n.style);
	});
	mapModel.addEventListener('nodeDroppableChanged', function (ideaId, isDroppable) {
		var node = nodeByIdeaId[ideaId];
		node.setIsDroppable(isDroppable);
	});
	mapModel.addEventListener('nodeRemoved', function (n) {
		var node = nodeByIdeaId[n.id];
		delete nodeByIdeaId[n.id];
		node.transitionTo({
			opacity: 0.25,
			duration: 0.4,
			callback: node.remove.bind(node)
		});
		node.off('click dblclick tap dragstart dragmove dragend mouseover mouseout :textChanged');
	});
	mapModel.addEventListener('nodeMoved', function (n, reason) {
		var node = nodeByIdeaId[n.id];
		node.transitionTo({
			x: n.x,
			y: n.y,
			duration: 0.4,
			easing: reason === 'failed' ? 'bounce-ease-out' : 'ease-in-out'
		});
	});
	mapModel.addEventListener('nodeTitleChanged', function (n) {
		var node = nodeByIdeaId[n.id];
		node.setText(n.title);
		layer.draw();
	});
	mapModel.addEventListener('connectorCreated', function (n) {
		var connector = new Kinetic.Connector({
			shapeFrom: nodeByIdeaId[n.from],
			shapeTo: nodeByIdeaId[n.to],
			stroke: '#888',
			strokeWidth: 1,
			opacity: 0
		});
		connector.opacity = 0;
		connectorByFromIdeaId_ToIdeaId[connectorKey(n.from, n.to)] = connector;
		layer.add(connector);
		connector.moveToBottom();
		connector.transitionTo({
			opacity: 1,
			duration: 0.4
		});
	});
	mapModel.addEventListener('connectorRemoved', function (n) {
		var key = connectorKey(n.from, n.to),
			connector = connectorByFromIdeaId_ToIdeaId[key];
		delete connectorByFromIdeaId_ToIdeaId[key];
		connector.transitionTo({
			opacity: 0,
			duration: 0.1,
			callback: connector.remove.bind(connector)
		});
	});
	mapModel.addEventListener('mapScaleChanged', function (scaleMultiplier, zoomPoint) {
		var currentScale = stage.getScale().x || 1,
			targetScale = Math.max(Math.min(currentScale * scaleMultiplier, 5), 0.2);
		if (currentScale === targetScale) {
			return;
		}
		zoomPoint = zoomPoint || {x:  0.5 * stage.getWidth(), y: 0.5 * stage.getHeight()};
		stage.transitionTo({
			scale: {
				x: targetScale,
				y: targetScale
			},
			x: zoomPoint.x + (stage.attrs.x - zoomPoint.x) * targetScale / currentScale,
			y: zoomPoint.y + (stage.attrs.y - zoomPoint.y) * targetScale / currentScale,
			duration: 0.01,
			easing: 'ease-in-out',
			callback: function () {
				stage.fire(':scaleChangeComplete');
			}
		});
	});
	mapModel.addEventListener('mapViewResetRequested', function () {
		resetStage();
	});
	mapModel.addEventListener('mapMoveRequested', function (deltaX, deltaY) {
		moveStage(deltaX, deltaY);
	});
	(function () {
		var x, y;
		stage.on('dragmove', function () {
			var deltaX = x - stage.attrs.x,
				deltaY = y - stage.attrs.y,
				visibleAfterMove = atLeastOneVisible(nodeByIdeaId, 0, 0) || atLeastOneVisible(connectorByFromIdeaId_ToIdeaId, 0, 0),
				shouldMoveBack = !visibleAfterMove && !(atLeastOneVisible(nodeByIdeaId, deltaX, deltaY) || atLeastOneVisible(connectorByFromIdeaId_ToIdeaId, deltaX, deltaY));
			if (shouldMoveBack) {
				moveStage(deltaX, deltaY);
			} else {
				x = stage.attrs.x;
				y = stage.attrs.y;
			}
		});
	}());
};
MAPJS.KineticMediator.dimensionProvider = _.memoize(function (title) {
	'use strict';
	var text = new Kinetic.Idea({
		text: title
	});
	return {
		width: text.getWidth(),
		height: text.getHeight()
	};
});
MAPJS.KineticMediator.layoutCalculator = function (idea) {
	'use strict';
	return MAPJS.calculateLayout(idea, MAPJS.KineticMediator.dimensionProvider);
};
<|endoftext|>


<commit_before>/*
Language: Apache
Author: Ruslan Keba <rukeba@gmail.com>
Website: http://rukeba.com/
Description: language definition for Apache configuration files (httpd.conf & .htaccess)
Version: 1.1
Date: 2008-12-27
*/

function(hljs) {
  var NUMBER = {className: 'number', begin: '[\\$%]\\d+'};
  return {
    case_insensitive: true,
    contains: [
      hljs.HASH_COMMENT_MODE,
      {className: 'tag', begin: '</?', end: '>'},
      {
        className: 'keyword',
        begin: /\w+/,
        relevance: 0,
        // keywords aren’t needed for highlighting per se, they only boost relevance
        // for a very generally defined mode (starts with a word, ends with line-end
        keywords: {
          common:
            'order deny allow setenv rewriterule rewriteengine rewritecond documentroot ' +
            'sethandler errordocument loadmodule options header listen serverroot ' +
            'servername'
        },
        starts: {
          end: /$/,
          relevance: 0,
          keywords: {
            literal: 'on off all'
          },
          contains: [
            {
              className: 'sqbracket',
              begin: '\\s\\[', end: '\\]$'
            },
            {
              className: 'cbracket',
              begin: '[\\$%]\\{', end: '\\}',
              contains: ['self', NUMBER]
            },
            NUMBER,
            hljs.QUOTE_STRING_MODE
          ]
        }
      }
    ],
    illegal: /\S/
  };
}
<commit_msg>Dropping obsolete date and version from Apache header. dding Ivan Sagalaev to contributors.<commit_after>/*
Language: Apache
Author: Ruslan Keba <rukeba@gmail.com>
Contributors: Ivan Sagalaev <maniac@softwaremaniacs.org>
Website: http://rukeba.com/
Description: language definition for Apache configuration files (httpd.conf & .htaccess)
*/

function(hljs) {
  var NUMBER = {className: 'number', begin: '[\\$%]\\d+'};
  return {
    case_insensitive: true,
    contains: [
      hljs.HASH_COMMENT_MODE,
      {className: 'tag', begin: '</?', end: '>'},
      {
        className: 'keyword',
        begin: /\w+/,
        relevance: 0,
        // keywords aren’t needed for highlighting per se, they only boost relevance
        // for a very generally defined mode (starts with a word, ends with line-end
        keywords: {
          common:
            'order deny allow setenv rewriterule rewriteengine rewritecond documentroot ' +
            'sethandler errordocument loadmodule options header listen serverroot ' +
            'servername'
        },
        starts: {
          end: /$/,
          relevance: 0,
          keywords: {
            literal: 'on off all'
          },
          contains: [
            {
              className: 'sqbracket',
              begin: '\\s\\[', end: '\\]$'
            },
            {
              className: 'cbracket',
              begin: '[\\$%]\\{', end: '\\}',
              contains: ['self', NUMBER]
            },
            NUMBER,
            hljs.QUOTE_STRING_MODE
          ]
        }
      }
    ],
    illegal: /\S/
  };
}
<|endoftext|>


<commit_before>/*
 Language: Kotlin
 Author: Sergey Mashkov <cy6erGn0m@gmail.com>
 Category: misc
 */

function (hljs) {
  var KEYWORDS = {
    keyword:
      'abstract as val var vararg get set class object open private protected public noinline ' +
      'crossinline dynamic final enum if else do while for when throw try catch finally ' +
      'import package is in fun override companion reified inline ' +
      'interface annotation data sealed internal infix operator out by constructor super ' +
      // to be deleted soon
      'trait volatile transient native default',
    built_in:
      'Byte Short Char Int Long Boolean Float Double Void Unit Nothing',
    literal:
      'true false null'
  };
  var KEYWORDS_WITH_LABEL = {
    className: 'keyword',
    begin: /\b(?:break|continue|return|this)\b/,
    starts: {
      className: 'symbol',
      end: /[^\w@]/, excludeEnd: true
    }
  };
  var LABEL = {
    className: 'symbol', begin: hljs.UNDERSCORE_IDENT_RE + '@'
  };

  // for string templates
  var SUBST = {
    className: 'subst',
    variants: [
      {begin: '\\$' + hljs.UNDERSCORE_IDENT_RE},
      {begin: '\\${', end: '}', contains: [hljs.APOS_STRING_MODE, hljs.C_NUMBER_MODE]}
    ]
  };
  var STRING = {
    variants: [
      {
        className: 'string',
        begin: '"""', end: '"""',
        contains: [SUBST]
      },
      hljs.APOS_STRING_MODE,
      hljs.inherit(
        hljs.QUOTE_STRING_MODE,
        {contains: [hljs.BACKSLASH_ESCAPE, SUBST]}
      )
    ]
  };

  var ANNOTATION_USE_SITE = {
    className: 'meta', begin: '@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*' + hljs.UNDERSCORE_IDENT_RE + ')?'
  };
  var ANNOTATION = {
    className: 'meta', begin: '@' + hljs.UNDERSCORE_IDENT_RE
  };

  return {
    keywords: KEYWORDS,
    contains : [
      hljs.COMMENT(
        '/\\*\\*',
        '\\*/',
        {
          relevance : 0,
          contains : [{
            className : 'doctag',
            begin : '@[A-Za-z]+'
          }]
        }
      ),
      hljs.C_LINE_COMMENT_MODE,
      hljs.C_BLOCK_COMMENT_MODE,
      KEYWORDS_WITH_LABEL,
      LABEL,
      ANNOTATION_USE_SITE,
      ANNOTATION,
      {
        className: 'function',
        beginKeywords: 'fun', end: '[(]|$',
        returnBegin: true,
        excludeEnd: true,
        keywords: KEYWORDS,
        illegal: /fun\s+(<.*>)?[^\s\(]+(\s+[^\s\(]+)\s*=/,
        relevance: 5,
        contains: [
          {
            begin: hljs.UNDERSCORE_IDENT_RE + '\\s*\\(', returnBegin: true,
            relevance: 0,
            contains: [hljs.UNDERSCORE_TITLE_MODE]
          },
          {
            className: 'type',
            begin: /</, end: />/, keywords: 'reified',
            relevance: 0
          },
          {
            className: 'params',
            begin: /\(/, end: /\)(?=\s*[=:{\/]|\s*$)/,
            endsParent: true,
            keywords: KEYWORDS,
            relevance: 0,
            illegal: /\([^\(,\s:]+,/,
            contains: [
              {
                className: 'type',
                begin: /:\s*/, end: /\s*[=\),\/]/, excludeBegin: true, returnEnd: true,
                relevance: 0
              },
              hljs.C_LINE_COMMENT_MODE,
              hljs.C_BLOCK_COMMENT_MODE,
              ANNOTATION_USE_SITE,
              ANNOTATION,
              STRING,
              hljs.C_NUMBER_MODE
            ]
          },
          hljs.C_BLOCK_COMMENT_MODE
        ]
      },
      {
        className: 'class',
        beginKeywords: 'class interface trait', end: /[:\{(]|$/, // remove 'trait' when removed from KEYWORDS
        excludeEnd: true,
        illegal: 'extends implements',
        contains: [
          {beginKeywords: 'public protected internal private constructor'},
          hljs.UNDERSCORE_TITLE_MODE,
          {
            className: 'type',
            begin: /</, end: />/, excludeBegin: true, excludeEnd: true,
            relevance: 0
          },
          {
            className: 'type',
            begin: /[,:]\s*/, end: /[<\(,]|$/, excludeBegin: true, returnEnd: true
          },
          ANNOTATION_USE_SITE,
          ANNOTATION
        ]
      },
      STRING,
      {
        className: 'meta',
        begin: "^#!/usr/bin/env", end: '$',
        illegal: '\n'
      },
      hljs.C_NUMBER_MODE
    ]
  };
}
<commit_msg>Optional labels after keywords in Kotlin<commit_after>/*
 Language: Kotlin
 Author: Sergey Mashkov <cy6erGn0m@gmail.com>
 Category: misc
 */

function (hljs) {
  var KEYWORDS = {
    keyword:
      'abstract as val var vararg get set class object open private protected public noinline ' +
      'crossinline dynamic final enum if else do while for when throw try catch finally ' +
      'import package is in fun override companion reified inline ' +
      'interface annotation data sealed internal infix operator out by constructor super ' +
      // to be deleted soon
      'trait volatile transient native default',
    built_in:
      'Byte Short Char Int Long Boolean Float Double Void Unit Nothing',
    literal:
      'true false null'
  };
  var KEYWORDS_WITH_LABEL = {
    className: 'keyword',
    begin: /\b(break|continue|return|this)\b/,
    starts: {
      contains: [
        {
          className: 'symbol',
          begin: /@\w+/
        }
      ]
    }
  };
  var LABEL = {
    className: 'symbol', begin: hljs.UNDERSCORE_IDENT_RE + '@'
  };

  // for string templates
  var SUBST = {
    className: 'subst',
    variants: [
      {begin: '\\$' + hljs.UNDERSCORE_IDENT_RE},
      {begin: '\\${', end: '}', contains: [hljs.APOS_STRING_MODE, hljs.C_NUMBER_MODE]}
    ]
  };
  var STRING = {
    variants: [
      {
        className: 'string',
        begin: '"""', end: '"""',
        contains: [SUBST]
      },
      hljs.APOS_STRING_MODE,
      hljs.inherit(
        hljs.QUOTE_STRING_MODE,
        {contains: [hljs.BACKSLASH_ESCAPE, SUBST]}
      )
    ]
  };

  var ANNOTATION_USE_SITE = {
    className: 'meta', begin: '@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*' + hljs.UNDERSCORE_IDENT_RE + ')?'
  };
  var ANNOTATION = {
    className: 'meta', begin: '@' + hljs.UNDERSCORE_IDENT_RE
  };

  return {
    keywords: KEYWORDS,
    contains : [
      hljs.COMMENT(
        '/\\*\\*',
        '\\*/',
        {
          relevance : 0,
          contains : [{
            className : 'doctag',
            begin : '@[A-Za-z]+'
          }]
        }
      ),
      hljs.C_LINE_COMMENT_MODE,
      hljs.C_BLOCK_COMMENT_MODE,
      KEYWORDS_WITH_LABEL,
      LABEL,
      ANNOTATION_USE_SITE,
      ANNOTATION,
      {
        className: 'function',
        beginKeywords: 'fun', end: '[(]|$',
        returnBegin: true,
        excludeEnd: true,
        keywords: KEYWORDS,
        illegal: /fun\s+(<.*>)?[^\s\(]+(\s+[^\s\(]+)\s*=/,
        relevance: 5,
        contains: [
          {
            begin: hljs.UNDERSCORE_IDENT_RE + '\\s*\\(', returnBegin: true,
            relevance: 0,
            contains: [hljs.UNDERSCORE_TITLE_MODE]
          },
          {
            className: 'type',
            begin: /</, end: />/, keywords: 'reified',
            relevance: 0
          },
          {
            className: 'params',
            begin: /\(/, end: /\)(?=\s*[=:{\/]|\s*$)/,
            endsParent: true,
            keywords: KEYWORDS,
            relevance: 0,
            illegal: /\([^\(,\s:]+,/,
            contains: [
              {
                className: 'type',
                begin: /:\s*/, end: /\s*[=\),\/]/, excludeBegin: true, returnEnd: true,
                relevance: 0
              },
              hljs.C_LINE_COMMENT_MODE,
              hljs.C_BLOCK_COMMENT_MODE,
              ANNOTATION_USE_SITE,
              ANNOTATION,
              STRING,
              hljs.C_NUMBER_MODE
            ]
          },
          hljs.C_BLOCK_COMMENT_MODE
        ]
      },
      {
        className: 'class',
        beginKeywords: 'class interface trait', end: /[:\{(]|$/, // remove 'trait' when removed from KEYWORDS
        excludeEnd: true,
        illegal: 'extends implements',
        contains: [
          {beginKeywords: 'public protected internal private constructor'},
          hljs.UNDERSCORE_TITLE_MODE,
          {
            className: 'type',
            begin: /</, end: />/, excludeBegin: true, excludeEnd: true,
            relevance: 0
          },
          {
            className: 'type',
            begin: /[,:]\s*/, end: /[<\(,]|$/, excludeBegin: true, returnEnd: true
          },
          ANNOTATION_USE_SITE,
          ANNOTATION
        ]
      },
      STRING,
      {
        className: 'meta',
        begin: "^#!/usr/bin/env", end: '$',
        illegal: '\n'
      },
      hljs.C_NUMBER_MODE
    ]
  };
}
<|endoftext|>


<commit_before>import _ from 'lodash';

import defaultUserpicPath from '../../assets/images/default-userpic.svg';

import config from '../config';
import { initialAsyncState } from '../redux/reducers/helpers';

const frontendPrefsConfig = config.frontendPreferences;

export function getCookie(name) {
  const begin = document.cookie.indexOf(name);
  if (begin === -1) {
    return '';
  }
  const fromBegin = document.cookie.substr(begin);
  const tokenWithName = fromBegin.split(';');
  const tokenWithNameSplit = tokenWithName[0].split('=');
  const [, token] = tokenWithNameSplit;
  return token.trim();
}

export function setCookie(name, value = '', expireDays, path) {
  const expiresDate = Date.now() + (expireDays * 24 * 60 * 60 * 1000);
  const expiresTime = new Date(expiresDate).toUTCString();
  //http://stackoverflow.com/questions/1134290/cookies-on-localhost-with-explicit-domain
  const cookie = `${name}=${value}; expires=${expiresTime}; path=${path}`;
  return document.cookie = cookie;
}

const userDefaults = {
  profilePictureMediumUrl: defaultUserpicPath,
  profilePictureLargeUrl:  defaultUserpicPath,
  frontendPreferences:     frontendPrefsConfig.defaultValues
};

/**
 * Fill missing user fields with default values
 *
 * @param {object} user user data from API response or cache
 * @returns {object}
 */
export function userParser(user) {
  const newUser = { ...user };

  // Profile pictures
  newUser.profilePictureMediumUrl = user.profilePictureMediumUrl || userDefaults.profilePictureMediumUrl;
  newUser.profilePictureLargeUrl = user.profilePictureLargeUrl || userDefaults.profilePictureLargeUrl;

  // Frontend preferences (only use this client's subtree).
  // Do not fill them if no 'frontendPreferences' in 'user'.
  if (user.frontendPreferences) {
    const prefs = user.frontendPreferences;
    if (Object.keys(prefs).some((k) => !_.isObjectLike(prefs[k]))) {
      // Looks like frontendPreferences is already parsed, keep them untouch.
      // This is for the backward compatibility with old whoamiCache strategy.
    } else {
      const prefSubTree = prefs[frontendPrefsConfig.clientId] || {};
      newUser.frontendPreferences = { ...userDefaults.frontendPreferences, ...prefSubTree };
    }
  }

  return newUser;
}

export function postParser(post) {
  post.commentsDisabled = (post.commentsDisabled === '1');
  return {
    ...post,
    commentsDisabled: post.commentsDisabled === '1',
    savePostStatus:   initialAsyncState,
  };
}

export function preventDefault(realFunction) {
  return (event) => {
    event.preventDefault();
    return realFunction && realFunction();
  };
}

export function confirmFirst(realFunction) {
  return () => {
    if (confirm('Are you sure?')) {
      return realFunction && realFunction();
    }
  };
}

export function getCurrentRouteName(router) {
  return router && router.routes && router.routes[router.routes.length - 1].name;
}

export function pluralForm(n, singular, plural = null, format = 'n w') {
  let w;

  if (n == 1) {
    w = singular;
  } else if (plural) {
    w = plural;
  } else {
    w = `${singular}s`;
  }

  return format.replace('n', n).replace('w', w);
}

export function delay(timeout = 0) {
  return new Promise((resolve) => setTimeout(resolve, timeout));
}

// detect if localStorage is supported by attempting to set and delete an item
// if it throws, then no localStorage for us (and we are most probably a Safari
// in private browsing mode)
let localStorageSupported = true;
try {
  const lskey = `ff${new Date().getTime()}`;
  window.localStorage.setItem(lskey, 'test');
  window.localStorage.removeItem(lskey);
} catch (err) {
  localStorageSupported = false;
}

const localStorageShim = {
  _data: {},
  setItem(id, val) { return this._data[id] = String(val); },
  getItem(id) { return this._data.hasOwnProperty(id) ? this._data[id] : null; },
  removeItem(id) { return delete this._data[id]; },
  clear() { return this._data = {}; }
};

export const localStorage = localStorageSupported ? window.localStorage : localStorageShim;

export function getSummaryPeriod(days) {
  switch (+days) {
    case 1: return 'day';
    case 7: return 'week';
    case 30: return 'month';
    default: return `${days} days`;
  }
}
<commit_msg>Fix of invalid commentsDisabled processing<commit_after>import _ from 'lodash';

import defaultUserpicPath from '../../assets/images/default-userpic.svg';

import config from '../config';
import { initialAsyncState } from '../redux/reducers/helpers';

const frontendPrefsConfig = config.frontendPreferences;

export function getCookie(name) {
  const begin = document.cookie.indexOf(name);
  if (begin === -1) {
    return '';
  }
  const fromBegin = document.cookie.substr(begin);
  const tokenWithName = fromBegin.split(';');
  const tokenWithNameSplit = tokenWithName[0].split('=');
  const [, token] = tokenWithNameSplit;
  return token.trim();
}

export function setCookie(name, value = '', expireDays, path) {
  const expiresDate = Date.now() + (expireDays * 24 * 60 * 60 * 1000);
  const expiresTime = new Date(expiresDate).toUTCString();
  //http://stackoverflow.com/questions/1134290/cookies-on-localhost-with-explicit-domain
  const cookie = `${name}=${value}; expires=${expiresTime}; path=${path}`;
  return document.cookie = cookie;
}

const userDefaults = {
  profilePictureMediumUrl: defaultUserpicPath,
  profilePictureLargeUrl:  defaultUserpicPath,
  frontendPreferences:     frontendPrefsConfig.defaultValues
};

/**
 * Fill missing user fields with default values
 *
 * @param {object} user user data from API response or cache
 * @returns {object}
 */
export function userParser(user) {
  const newUser = { ...user };

  // Profile pictures
  newUser.profilePictureMediumUrl = user.profilePictureMediumUrl || userDefaults.profilePictureMediumUrl;
  newUser.profilePictureLargeUrl = user.profilePictureLargeUrl || userDefaults.profilePictureLargeUrl;

  // Frontend preferences (only use this client's subtree).
  // Do not fill them if no 'frontendPreferences' in 'user'.
  if (user.frontendPreferences) {
    const prefs = user.frontendPreferences;
    if (Object.keys(prefs).some((k) => !_.isObjectLike(prefs[k]))) {
      // Looks like frontendPreferences is already parsed, keep them untouch.
      // This is for the backward compatibility with old whoamiCache strategy.
    } else {
      const prefSubTree = prefs[frontendPrefsConfig.clientId] || {};
      newUser.frontendPreferences = { ...userDefaults.frontendPreferences, ...prefSubTree };
    }
  }

  return newUser;
}

export function postParser(post) {
  return {
    ...post,
    commentsDisabled: post.commentsDisabled === '1',
    savePostStatus:   initialAsyncState,
  };
}

export function preventDefault(realFunction) {
  return (event) => {
    event.preventDefault();
    return realFunction && realFunction();
  };
}

export function confirmFirst(realFunction) {
  return () => {
    if (confirm('Are you sure?')) {
      return realFunction && realFunction();
    }
  };
}

export function getCurrentRouteName(router) {
  return router && router.routes && router.routes[router.routes.length - 1].name;
}

export function pluralForm(n, singular, plural = null, format = 'n w') {
  let w;

  if (n == 1) {
    w = singular;
  } else if (plural) {
    w = plural;
  } else {
    w = `${singular}s`;
  }

  return format.replace('n', n).replace('w', w);
}

export function delay(timeout = 0) {
  return new Promise((resolve) => setTimeout(resolve, timeout));
}

// detect if localStorage is supported by attempting to set and delete an item
// if it throws, then no localStorage for us (and we are most probably a Safari
// in private browsing mode)
let localStorageSupported = true;
try {
  const lskey = `ff${new Date().getTime()}`;
  window.localStorage.setItem(lskey, 'test');
  window.localStorage.removeItem(lskey);
} catch (err) {
  localStorageSupported = false;
}

const localStorageShim = {
  _data: {},
  setItem(id, val) { return this._data[id] = String(val); },
  getItem(id) { return this._data.hasOwnProperty(id) ? this._data[id] : null; },
  removeItem(id) { return delete this._data[id]; },
  clear() { return this._data = {}; }
};

export const localStorage = localStorageSupported ? window.localStorage : localStorageShim;

export function getSummaryPeriod(days) {
  switch (+days) {
    case 1: return 'day';
    case 7: return 'week';
    case 30: return 'month';
    default: return `${days} days`;
  }
}
<|endoftext|>


<commit_before>let testElem = document.createElement('div')
let prefix = null
let eventPrefix = null
let reUnit = /width|height|top|left|right|bottom|margin|padding/i
let reBool = /true|false/i

export function noop(){}

export function getCoords(el){
    if(el === undefined) el = this
    if(!isDOM(el)) return

    let box = el.getBoundingClientRect(),
    self= window,
    doc = el.ownerDocument,
    body = doc.body,
    html = doc.documentElement,
    clientTop = html.clientTop || body.clientTop || 0,
    clientLeft = html.clientLeft || body.clientLeft || 0

    return {
        top: (box.top + (self.pageYOffset || html.scrollTop || body.scrollTop ) - clientTop),
        left: (box.left + (self.pageXOffset || html.scrollLeft || body.scrollLeft) - clientLeft)
    }
}

export function getStyle(el, name, removeUnit = ""){
    if(typeof el === "string") [el, name, removeUnit] = [this, el, name === undefined ? "" : name]
    if(!isDOM(el)) return

    var style = window.getComputedStyle ? window.getComputedStyle(el, null)[name] : el.currentStyle[name]

    if((name === 'width' || name === 'height') && style === 'auto'){
        if(name == 'width') style = el.offsetWidth
        else if(name == 'height') style = el.offsetHeight
    }

    if(removeUnit !== "" && getType(style) === 'String') {
        style = ~~style.replace(new RegExp(removeUnit), "")
    }

    return style
}

export function escapeHTML(str){
    return str.replace(/&/g,"&")
              .replace(/</g,"<")
              .replace(/>/g,">")
              .replace(/"/g,""")
              .replace(/'/g,"'")
}

export function getDOMState(el, key){
    if(typeof el === 'string') [el, key] = [this, el]

    let attr = null
    if(el instanceof angular.element) {
        attr = ::el.attr
    } else if(isDOM(el)) {
        attr = ::el.getAttribute
    } else {
        throw new Error("Element was not specified.")
    }

    let ret = attr(key)

    if(ret == undefined){
        return false
    } else if(ret === ""){
        return true
    } else if(reBool.test(ret)){
        return !!ret
    } else if(/^\d{1,}$/.test(ret)){
        return ~~ret
    }

    return ret
}

export function addClass(el, cls){
    if(typeof el === 'string') [el, cls] = [this, el]
    if(!isDOM(el)) return

    let clsList = cls.split(' ')

    while(cls = clsList.pop()){
        if (el.classList) {
            el.classList.add(cls)
        } else {
            let cur = ' ' + (el.getAttribute('class') || '') + ' '
            if (cur.indexOf(' ' + cls + ' ') < 0) {
                el.setAttribute('class', (cur + cls).trim())
            }
        }
    }
    return el
}

export function removeClass(el, cls){
    if(typeof el === 'string') [el, cls] = [this, el]
    if(!isDOM(el)) return

    let clsList = cls.split(' ')
    while(cls = clsList.pop()){
        if (el.classList) {
            el.classList.remove(cls)
        } else {
            let cur = ' ' + (el.getAttribute('class') || '') + ' '
            let tar = ' ' + cls + ' '
            while (cur.indexOf(tar) >= 0) {
                cur = cur.replace(tar, ' ')
            }

            el.setAttribute('class', cur.trim())
        }

        if (!el.className) {
            el.removeAttribute('class')
        }
    }
    return el
}

export function replaceClass(el, orig, mdi){
    if(typeof el === 'string') [el, orig, mdi] = [this, el, orig]
    if(!isDOM(el)) return
    el::removeClass(orig)
    el::addClass(mdi)
    return el
}

export function on (el, event, cb) {
    if(typeof el === 'string') [el, event, cb] = [this, el, event]
    if(!isDOM(el)) return
    let evts = event.split(' ')
    while (evts.length){
        el.addEventListener(evts.pop(), cb)
    }
    return el
}

export function off(el, event, cb){
    if(typeof el === 'string') [el, event, cb] = [this, el, event]
    if(!isDOM(el)) return
    let evts = event.split(' ')
    while (evts.length){
        el.removeEventListener(evts.pop(), cb)
    }
    return el
}

export function before(el, target) {
    if(arguments.length === 1) [el, target] = [this, el]
    el = toDOM(el)
    target.parentNode.insertBefore(el, target)
    return el
}

export function after(el, target) {
    if(arguments.length === 1) [el, target] = [this, el]
    el = toDOM(el)
    return el.nextSibling ? before(target,el.nextSibling) : el.parentNode.appendChild(target), target
}

export function prepend(target, el){
    if(arguments.length === 1) [target, el] = [this, target]
    el = toDOM(el)
    return target.firstChild ? el::before(target.firstChild) : target.appendChild(el), el
}

export function last(target, el){
    if(arguments.length === 1) [target, el] = [this, target]
    el = toDOM(el)
    return target.length > 0 ? el::after(target.lastChild) : target.appendChild(el), el
}

export function remove(el){
    if(arguments.length === 0) [el] = [this]
    el.parentNode.removeChild(el)
}

export function replace(target, el){
    if(arguments.length === 1) [target, el] = [this, target]
    el = toDOM(el)

    let parent = target.parentNode
    if(parent){
        parent.replaceChild(el, target)
    }
    return el
}

export function isDOM(el){
    if (el.nodeType && el.nodeName) return true
    return false
}

export function toDOM(el){ //remark 支持多个元素 类似123
321
  用fragment?
    if(arguments.length === 0) el = this
    if(typeof el === 'string'){
        let dom = createElem('div')
        dom.innerHTML = el
        el = dom.firstChild
    }

    return el
}

/*
function fragmentFromString(strHTML) {
    var temp = document.createElement('template');
    temp.innerHTML = strHTML;
    return temp.content;
}
*/

export function detechPrefix(){
    if(prefix !== null && eventPrefix !== null) return { prefix, eventPrefix }

    let vendor = { Webkit: 'webkit', Moz: '', O: 'o' }

    for(var i in vendor){
        if (testElem.style[i + 'TransitionProperty'] !== undefined) {
            prefix = '-' + i.toLowerCase() + '-'
            eventPrefix = vendor[i]
            return { prefix, eventPrefix }
        }
    }

    prefix = eventPrefix = ""
    return { prefix, eventPrefix }
}

export function onMotionEnd(el, cb){
    if(typeof el === 'function') [el, cb] = [this, el]
    if(!isDOM(el) && !(el instanceof angular.element)) return
    if(el instanceof angular.element) el = el[0]

    let {prefix, eventPrefix} = detechPrefix()

    let handler = e => { //remark
        if(e && e.target === el){
            el::off(eventPrefix + 'TransitionEnd', handler)
            el::off('animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd', handler)
            cb()
        }
    }
    el::on(eventPrefix + 'TransitionEnd', handler)
    el::on('animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd', handler)
    return el
}

export function debounce(func, wait){
    let timeout, args, context, timestamp, result
    let later = () => {
        let last = Date.now() - timestamp
        if (last < wait && last >= 0) {
            timeout = setTimeout(later, wait - last)
        } else {
            timeout = null
            result = func.apply(context, args)
            if (!timeout) context = args = null
        }
    }

    return function() {
        context = this
        args = arguments
        timestamp = Date.now()
        if (!timeout)  timeout = setTimeout(later, wait)
        return result
    }
}

export function query(el){
    let base = this
        ? this.__esModule ? document : this
        : document
    if (typeof el === 'string') {
        let selector = el
        el = base.querySelector(selector)
    }
    return el
}

export function queryAll(el){
    let base = this
        ? this.__esModule ? document : this
        : document
    if (typeof el === 'string') {
        let selector = el
        el = base.querySelectorAll(selector)
    }
    return el
}

export function createElem(tag){
    return document.createElement(tag)
}

export function getType(obj){
    if(arguments.length === 0) obj = this
    return Object.prototype.toString.call(obj).replace(/^\[object (\w+)\]$/,'$1')
}

export function is(v1, v2){
    if(this !== undefined){
        [v1, v2] = [this, v1]
    }

    if(!Object.is){
        if (v1 === 0 && v2 === 0) {
            return 1 / v1 === 1 / v2
        }

        if (v1 !== v1) {
            return v2 !== v2
        }

        return v1 === v2
    } else {
        return Object.is(v1, v2)
    }
}

let _FMId = 1
export function generateFermiId(){
    let id = _FMId.toString().split('')
    let len = id.length
    for(let i = 0; i < (5 - len); i++){
        id.unshift("0")
    }
    _FMId++
    return id.join('.')
}

export function nextId(){
    return _FMId++
}

export function clamp(val, min, max){
    return val < min ? min : (val > max ? max : val)
}

export function def(obj, key, option){
    Object.defineProperty(obj, key, option)
}

/*
export function setStyle(el, obj){
    if(arguments.length === 1) [el, obj] = [this, el]
    for(let i in obj){
        if(obj.hasOwnProperty(i)){
            el.style[i] = obj[i]
        }
    }
}
*/

export function inDoc(el) {
    if(arguments.length === 0) el = this
    let doc = document.documentElement
    let parent = el && el.parentNode
    return doc === el || doc === parent || !!(parent && parent.nodeType === 1 && (doc.contains(parent)))
}

export function range(size, start = 0){
    let arr = []
    for(let i = start; i <= size; i++) arr.push(i)
    return arr
}

export function generateUID(){
   return '_F' + ("0000" + (Math.random() * Math.pow(36,6) << 0).toString(36)).slice(-6) + nextId()
}

export function queue(isAsync = false, interval = 0){
    let waiting = []

    let next = () => {
        let fn = waiting.shift()
        if(fn){
            isAsync
            ? setTimeout(() => fn(next), interval)
            : fn(next)
        }
    }

    let entry = fn => {
        waiting.push(fn)
        if (waiting.length === 1) next()
    }

    entry.count = () => waiting.length
    return entry
}

export function isHidden(el){
  return !(el.offsetWidth || el.offsetHeight || el.getClientRects().length)
}

export function forceReflow(el) {
    el.offsetHeight
}

export function setStyle(el, styles){
    if(arguments.length === 1) [el, styles] = [this, el]
    let hasCSSText = (typeof el.style.cssText) !== 'undefined'
    let oldStyleText
    let oldStyle = {}
    oldStyleText = hasCSSText ? el.style.cssText : el.getAttribute('style')
    oldStyleText.split(';').forEach(css => {
        if(css.indexOf(':') !== -1){
            let [key, value] = css.split(':')
            originStyle[key.trim()] = value.trim()
        }
    })

    let newStyle = {}
    Object.keys(styles).forEach(key => {
        let value = styles[key]
        if(reUnit.test(styles[key])) value += 'px'
        newStyle[key] = value
    })

    let mergedStyle = Object.assign({}, oldStyle, newStyle)
    let styleText = Object.keys(mergedStyle).map(key => key + ': ' + mergedStyle[key] + ';').join(' ')
    if(hasCSSText){
        el.style.cssText = styleText
    } else {
        el.setAttribute('style', styleText)
    }
}

/*export function extend(target){
    if(!this.$new) throw new Error("caller was not a angular scope variable.")
    let dest = this
    let ignore = []
    if(target.constructor){
        let re = /(?:this\.)(\w+)/gm
        let source = target.constructor.toString()
        source.match(re).forEach(e => ignore.push(e.substr(5)))
    }

    for (let key in target) {
        if (!dest[key] && ignore.indexOf(key) ===-1 && target.hasOwnProperty(key)) {
            dest[key] = target[key]
        }
    }

    export function toggleClass(el, namespace, state, suffix){
        if(arguments.length === 3) [el, namespace, state, suffix] = [this, el, namespace, state]

        return function(){

            state
            ? el::replaceClass('hide', namespace + '-' + suffix['true'])
            : el::replaceClass(namespace + '-' + suffix['true'], namespace + '-' + suffix['false'])::onMotionEnd(() => {
                //debugger
                el::replaceClass(namespace + '-' + suffix['false'], 'hide')
            })

            state = !state
        }
    }
}*/
<commit_msg>update<commit_after>let testElem = document.createElement('div')
let prefix = null
let eventPrefix = null
let reUnit = /width|height|top|left|right|bottom|margin|padding/i
let reBool = /true|false/i

export function noop(){}

export function getCoords(el){
    if(el === undefined) el = this
    if(!isDOM(el)) return

    let box = el.getBoundingClientRect(),
    self = window,
    doc = el.ownerDocument,
    body = doc.body,
    html = doc.documentElement,
    clientTop = html.clientTop || body.clientTop || 0,
    clientLeft = html.clientLeft || body.clientLeft || 0

    return {
        top: (box.top + (self.pageYOffset || html.scrollTop || body.scrollTop ) - clientTop),
        left: (box.left + (self.pageXOffset || html.scrollLeft || body.scrollLeft) - clientLeft)
    }
}

export function getStyle(el, name, removedUnit = ""){
    if(typeof el === "string") [el, name, removedUnit] = [this, el, name === undefined ? "" : name]
    if(!isDOM(el)) return

    var style = window.getComputedStyle ? window.getComputedStyle(el, null)[name] : el.currentStyle[name]

    if((name === 'width' || name === 'height') && style === 'auto'){
        if(name == 'width') style = el.offsetWidth
        else if(name == 'height') style = el.offsetHeight
    }

    if(removedUnit !== "" && getType(style) === 'String') {
        style = ~~style.replace(new RegExp(removedUnit), "")
    }

    return style
}

export function escapeHTML(str){
    return str.replace(/&/g,"&")
              .replace(/</g,"<")
              .replace(/>/g,">")
              .replace(/"/g,""")
              .replace(/'/g,"'")
}

export function getDOMState(el, key){
    if(typeof el === 'string') [el, key] = [this, el]

    let attr = null
    if(el instanceof angular.element) {
        attr = ::el.attr
    } else if(isDOM(el)) {
        attr = ::el.getAttribute
    } else {
        throw new Error("Element was not specified.")
    }

    let ret = attr(key)

    if(ret == undefined){
        return false
    } else if(ret === ""){
        return true
    } else if(reBool.test(ret)){
        return !!ret
    } else if(/^\d{1,}$/.test(ret)){
        return ~~ret
    }

    return ret
}

export function addClass(el, cls){
    if(typeof el === 'string') [el, cls] = [this, el]
    if(!isDOM(el)) return

    let clsList = cls.split(' ')

    while(cls = clsList.pop()){
        if (el.classList) {
            el.classList.add(cls)
        } else {
            let cur = ' ' + (el.getAttribute('class') || '') + ' '
            if (cur.indexOf(' ' + cls + ' ') < 0) {
                el.setAttribute('class', (cur + cls).trim())
            }
        }
    }
    return el
}

export function removeClass(el, cls){
    if(typeof el === 'string') [el, cls] = [this, el]
    if(!isDOM(el)) return

    let clsList = cls.split(' ')
    while(cls = clsList.pop()){
        if (el.classList) {
            el.classList.remove(cls)
        } else {
            let cur = ' ' + (el.getAttribute('class') || '') + ' '
            let tar = ' ' + cls + ' '
            while (cur.indexOf(tar) >= 0) {
                cur = cur.replace(tar, ' ')
            }

            el.setAttribute('class', cur.trim())
        }

        if (!el.className) {
            el.removeAttribute('class')
        }
    }
    return el
}

export function replaceClass(el, orig, mdi){
    if(typeof el === 'string') [el, orig, mdi] = [this, el, orig]
    if(!isDOM(el)) return
    el::removeClass(orig)
    el::addClass(mdi)
    return el
}

export function on (el, event, cb) {
    if(typeof el === 'string') [el, event, cb] = [this, el, event]
    if(!isDOM(el)) return
    let evts = event.split(' ')
    while (evts.length){
        el.addEventListener(evts.pop(), cb)
    }
    return el
}

export function off(el, event, cb){
    if(typeof el === 'string') [el, event, cb] = [this, el, event]
    if(!isDOM(el)) return
    let evts = event.split(' ')
    while (evts.length){
        el.removeEventListener(evts.pop(), cb)
    }
    return el
}

export function before(el, target) {
    if(arguments.length === 1) [el, target] = [this, el]
    el = toDOM(el)
    target.parentNode.insertBefore(el, target)
    return el
}

export function after(el, target) {
    if(arguments.length === 1) [el, target] = [this, el]
    el = toDOM(el)
    return el.nextSibling ? before(target,el.nextSibling) : el.parentNode.appendChild(target), target
}

export function prepend(target, el){
    if(arguments.length === 1) [target, el] = [this, target]
    el = toDOM(el)
    return target.firstChild ? el::before(target.firstChild) : target.appendChild(el), el
}

export function last(target, el){
    if(arguments.length === 1) [target, el] = [this, target]
    el = toDOM(el)
    return target.length > 0 ? el::after(target.lastChild) : target.appendChild(el), el
}

export function remove(el){
    if(arguments.length === 0) [el] = [this]
    el.parentNode.removeChild(el)
}

export function replace(target, el){
    if(arguments.length === 1) [target, el] = [this, target]
    el = toDOM(el)

    let parent = target.parentNode
    if(parent){
        parent.replaceChild(el, target)
    }
    return el
}

export function isDOM(el){
    if (el.nodeType && el.nodeName) return true
    return false
}

export function toDOM(el){ //remark 支持多个元素 类似123
321
  用fragment?
    if(arguments.length === 0) el = this
    if(typeof el === 'string'){
        let dom = createElem('div')
        dom.innerHTML = el
        el = dom.firstChild
    }

    return el
}

/*
function fragmentFromString(strHTML) {
    var temp = document.createElement('template');
    temp.innerHTML = strHTML;
    return temp.content;
}
*/

export function detechPrefix(){
    if(prefix !== null && eventPrefix !== null) return { prefix, eventPrefix }

    let vendor = { Webkit: 'webkit', Moz: '', O: 'o' }

    for(var i in vendor){
        if (testElem.style[i + 'TransitionProperty'] !== undefined) {
            prefix = '-' + i.toLowerCase() + '-'
            eventPrefix = vendor[i]
            return { prefix, eventPrefix }
        }
    }

    prefix = eventPrefix = ""
    return { prefix, eventPrefix }
}

export function onMotionEnd(el, cb){
    if(typeof el === 'function') [el, cb] = [this, el]
    if(!isDOM(el) && !(el instanceof angular.element)) return
    if(el instanceof angular.element) el = el[0]

    let {prefix, eventPrefix} = detechPrefix()

    let handler = e => { //remark
        if(e && e.target === el){
            el::off(eventPrefix + 'TransitionEnd', handler)
            el::off('animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd', handler)
            cb()
        }
    }
    el::on(eventPrefix + 'TransitionEnd', handler)
    el::on('animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd', handler)
    return el
}

export function debounce(func, wait){
    let timeout, args, ctx, timestamp, ret
    let later = () => {
        let last = Date.now() - timestamp
        if (last < wait && last >= 0) {
            timeout = setTimeout(later, wait - last)
        } else {
            timeout = null
            ret = func.apply(ctx, args)
            if (!timeout) ctx = args = null
        }
    }

    return function() {
        ctx = this
        args = arguments
        timestamp = Date.now()
        if (!timeout)  timeout = setTimeout(later, wait)
        return ret
    }
}

export function query(el){
    let base = this
        ? this.__esModule ? document : this
        : document
    if (typeof el === 'string') {
        let selector = el
        el = base.querySelector(selector)
    }
    return el
}

export function queryAll(el){
    let base = this
        ? this.__esModule ? document : this
        : document
    if (typeof el === 'string') {
        let selector = el
        el = base.querySelectorAll(selector)
    }
    return el
}

export function createElem(tag){
    return document.createElement(tag)
}

export function getType(obj){
    if(arguments.length === 0) obj = this
    return Object.prototype.toString.call(obj).replace(/^\[object (\w+)\]$/,'$1')
}

export function is(v1, v2){
    if(this !== undefined){
        [v1, v2] = [this, v1]
    }

    if(!Object.is){
        if (v1 === 0 && v2 === 0) {
            return 1 / v1 === 1 / v2
        }

        if (v1 !== v1) {
            return v2 !== v2
        }

        return v1 === v2
    } else {
        return Object.is(v1, v2)
    }
}

let _FMId = 1
export function generateFermiId(){
    let id = _FMId.toString().split('')
    let len = id.length
    for(let i = 0; i < (5 - len); i++) id.unshift("0")
    _FMId++
    return id.join('.')
}

export function nextId(){
    return _FMId++
}

export function clamp(val, min, max){
    return val < min ? min : (val > max ? max : val)
}

export function def(obj, key, option){
    Object.defineProperty(obj, key, option)
}

export function inDoc(el) {
    if(arguments.length === 0) el = this
    let doc = document.documentElement
    let parent = el && el.parentNode
    return doc === el || doc === parent || !!(parent && parent.nodeType === 1 && (doc.contains(parent)))
}

export function range(size, start = 0){
    let arr = []
    for(let i = start; i <= size; i++) arr.push(i)
    return arr
}

export function generateUID(){
   return '_F' + ("0000" + (Math.random() * Math.pow(36,6) << 0).toString(36)).slice(-6) + nextId()
}

export function queue(isAsync = false, interval = 0){
    let waiting = []

    let next = () => {
        let fn = waiting.shift()
        if(fn){
            isAsync
            ? setTimeout(() => fn(next), interval)
            : fn(next)
        }
    }

    let entry = fn => {
        waiting.push(fn)
        if (waiting.length === 1) next()
    }

    entry.count = () => waiting.length
    return entry
}

export function isHidden(el){
  return !(el.offsetWidth || el.offsetHeight || el.getClientRects().length)
}

export function forceReflow(el) {
    if(arguments.length === 0) el = this
    el.offsetHeight
}

export function setStyle(el, styles){
    if(arguments.length === 1) [el, styles] = [this, el]
    let hasCSSText = (typeof el.style.cssText) !== 'undefined'
    let oldStyleText
    let oldStyle = {}
    oldStyleText = hasCSSText ? el.style.cssText : el.getAttribute('style')
    oldStyleText.split(';').forEach(css => {
        if(css.indexOf(':') !== -1){
            let [key, value] = css.split(':')
            originStyle[key.trim()] = value.trim()
        }
    })

    let newStyle = {}
    Object.keys(styles).forEach(key => {
        let value = styles[key]
        if(reUnit.test(styles[key])) value += 'px'
        newStyle[key] = value
    })

    let mergedStyle = Object.assign({}, oldStyle, newStyle)
    let styleText = Object.keys(mergedStyle).map(key => key + ': ' + mergedStyle[key] + ';').join(' ')
    if(hasCSSText){
        el.style.cssText = styleText
    } else {
        el.setAttribute('style', styleText)
    }
}

/*export function extend(target){
    if(!this.$new) throw new Error("caller was not a angular scope variable.")
    let dest = this
    let ignore = []
    if(target.constructor){
        let re = /(?:this\.)(\w+)/gm
        let source = target.constructor.toString()
        source.match(re).forEach(e => ignore.push(e.substr(5)))
    }

    for (let key in target) {
        if (!dest[key] && ignore.indexOf(key) ===-1 && target.hasOwnProperty(key)) {
            dest[key] = target[key]
        }
    }

    export function toggleClass(el, namespace, state, suffix){
        if(arguments.length === 3) [el, namespace, state, suffix] = [this, el, namespace, state]

        return function(){

            state
            ? el::replaceClass('hide', namespace + '-' + suffix['true'])
            : el::replaceClass(namespace + '-' + suffix['true'], namespace + '-' + suffix['false'])::onMotionEnd(() => {
                //debugger
                el::replaceClass(namespace + '-' + suffix['false'], 'hide')
            })

            state = !state
        }
    }
}*/
<|endoftext|>


<commit_before>'use strict';

/**
 * Here is the problem: http://bugs.jquery.com/ticket/7292
 * basically jQuery treats change event on some browsers (IE) as a
 * special event and changes it form 'change' to 'click/keydown' and
 * few others. This horrible hack removes the special treatment
 */
_jQuery.event.special.change = undefined;

bindJQuery();
beforeEach(function() {
  publishExternalAPI(angular);

  // workaround for IE bug https://plus.google.com/104744871076396904202/posts/Kqjuj6RSbbT
  // IE overwrite window.jQuery with undefined because of empty jQuery var statement, so we have to
  // correct this, but only if we are not running in jqLite mode
  if (!_jqLiteMode && _jQuery !== jQuery) {
    jQuery = _jQuery;
  }

  // This resets global id counter;
  uid = ['0', '0', '0'];

  // reset to jQuery or default to us.
  bindJQuery();
  jqLite(document.body).html('');
});

afterEach(function() {
  if (this.$injector) {
    var $rootScope = this.$injector.get('$rootScope');
    var $log = this.$injector.get('$log');
    // release the injector
    dealoc($rootScope);

    // check $log mock
    $log.assertEmpty && $log.assertEmpty();
  }

  // complain about uncleared jqCache references
  var count = 0;
  forEachSorted(jqCache, function(value, key){
    count ++;
    delete jqCache[key];
    forEach(value, function(value, key){
      if (value.$element) {
        dump('LEAK', key, value.$id, sortedHtml(value.$element));
      } else {
        dump('LEAK', key, toJson(value));
      }
    });
  });
  if (count) {
    throw new Error('Found jqCache references that were not deallocated!');
  }
});

function dealoc(obj) {
  if (obj) {
    if (isElement(obj)) {
      var element = obj;
      if (element.nodeName) element = jqLite(element);
      if (element.dealoc) element.dealoc();
    } else {
      for(var key in jqCache) {
        var value = jqCache[key];
        if (value.$scope == obj) {
          delete jqCache[key];
        }
      }
    }

  }
}

/**
 * @param {DOMElement} element
 * @param {boolean=} showNgClass
 */
function sortedHtml(element, showNgClass) {
  var html = "";
  forEach(jqLite(element), function toString(node) {
    if (node.nodeName == "#text") {
      html += node.nodeValue.
        replace(/&(\w+[&;\W])?/g, function(match, entity){return entity?match:'&';}).
        replace(/</g, '<').
        replace(/>/g, '>');
    } else {
      html += '<' + (node.nodeName || '?NOT_A_NODE?').toLowerCase();
      var attributes = node.attributes || [];
      var attrs = [];
      var className = node.className || '';
      if (!showNgClass) {
        className = className.replace(/ng-[\w-]+\s*/g, '');
      }
      className = trim(className);
      if (className) {
        attrs.push(' class="' + className + '"');
      }
      for(var i=0; i<attributes.length; i++) {
        if (i>0 && attributes[i] == attributes[i-1])
          continue; //IE9 creates dupes. Ignore them!

        var attr = attributes[i];
        if(attr.name.match(/^ng[\:\-]/) ||
            attr.value &&
            attr.value !='null' &&
            attr.value !='auto' &&
            attr.value !='false' &&
            attr.value !='inherit' &&
            (attr.value !='0' || attr.name =='value') &&
            attr.name !='loop' &&
            attr.name !='complete' &&
            attr.name !='maxLength' &&
            attr.name !='size' &&
            attr.name !='class' &&
            attr.name !='start' &&
            attr.name !='tabIndex' &&
            attr.name !='style' &&
            attr.name.substr(0, 6) != 'jQuery') {
          // in IE we need to check for all of these.
          if (!/ng-\d+/.exec(attr.name) &&
              attr.name != 'getElementById' &&
              // IE7 has `selected` in attributes
              attr.name !='selected' &&
              // IE7 adds `value` attribute to all LI tags
              (node.nodeName != 'LI' || attr.name != 'value'))
            attrs.push(' ' + attr.name + '="' + attr.value + '"');
        }
      }
      attrs.sort();
      html += attrs.join('');
      if (node.style) {
        var style = [];
        if (node.style.cssText) {
          forEach(node.style.cssText.split(';'), function(value){
            value = trim(value);
            if (value) {
              style.push(lowercase(value));
            }
          });
        }
        for(var css in node.style){
          var value = node.style[css];
          if (isString(value) && isString(css) && css != 'cssText' && value && (1*css != css)) {
            var text = lowercase(css + ': ' + value);
            if (value != 'false' && indexOf(style, text) == -1) {
              style.push(text);
            }
          }
        }
        style.sort();
        var tmp = style;
        style = [];
        forEach(tmp, function(value){
          if (!value.match(/^max[^\-]/))
            style.push(value);
        });
        if (style.length) {
          html += ' style="' + style.join('; ') + ';"';
        }
      }
      html += '>';
      var children = node.childNodes;
      for(var j=0; j<children.length; j++) {
        toString(children[j]);
      }
      html += '</' + node.nodeName.toLowerCase() + '>';
    }
  });
  return html;
}

// TODO(vojta): migrate these helpers into jasmine matchers
/**a
 * This method is a cheap way of testing if css for a given node is not set to 'none'. It doesn't
 * actually test if an element is displayed by the browser. Be aware!!!
 */
function isCssVisible(node) {
  var display = node.css('display');
  return display != 'none';
}

function assertHidden(node) {
  if (isCssVisible(node)) {
    throw new Error('Node should be hidden but was visible: ' + angular.module.ngMock.dump(node));
  }
}

function assertVisible(node) {
  if (!isCssVisible(node)) {
    throw new Error('Node should be visible but was hidden: ' + angular.module.ngMock.dump(node));
  }
}

function provideLog($provide) {
  $provide.factory('log', function() {
      var messages = [];

      function log(msg) {
        messages.push(msg);
        return msg;
      }

      log.toString = function() {
        return messages.join('; ');
      }

      log.toArray = function() {
        return messages;
      }

      log.reset = function() {
        messages = [];
      }

      log.fn = function(msg) {
        return function() {
          log(msg);
        }
      }

      log.$$log = true;

      return log;
    });
}

function pending() {
  dump('PENDING');
};
<commit_msg>chore(trace): add helper method trace<commit_after>'use strict';

/**
 * Here is the problem: http://bugs.jquery.com/ticket/7292
 * basically jQuery treats change event on some browsers (IE) as a
 * special event and changes it form 'change' to 'click/keydown' and
 * few others. This horrible hack removes the special treatment
 */
_jQuery.event.special.change = undefined;

bindJQuery();
beforeEach(function() {
  publishExternalAPI(angular);

  // workaround for IE bug https://plus.google.com/104744871076396904202/posts/Kqjuj6RSbbT
  // IE overwrite window.jQuery with undefined because of empty jQuery var statement, so we have to
  // correct this, but only if we are not running in jqLite mode
  if (!_jqLiteMode && _jQuery !== jQuery) {
    jQuery = _jQuery;
  }

  // This resets global id counter;
  uid = ['0', '0', '0'];

  // reset to jQuery or default to us.
  bindJQuery();
  jqLite(document.body).html('');
});

afterEach(function() {
  if (this.$injector) {
    var $rootScope = this.$injector.get('$rootScope');
    var $log = this.$injector.get('$log');
    // release the injector
    dealoc($rootScope);

    // check $log mock
    $log.assertEmpty && $log.assertEmpty();
  }

  // complain about uncleared jqCache references
  var count = 0;
  forEachSorted(jqCache, function(value, key){
    count ++;
    delete jqCache[key];
    forEach(value, function(value, key){
      if (value.$element) {
        dump('LEAK', key, value.$id, sortedHtml(value.$element));
      } else {
        dump('LEAK', key, toJson(value));
      }
    });
  });
  if (count) {
    throw new Error('Found jqCache references that were not deallocated!');
  }
});

function dealoc(obj) {
  if (obj) {
    if (isElement(obj)) {
      var element = obj;
      if (element.nodeName) element = jqLite(element);
      if (element.dealoc) element.dealoc();
    } else {
      for(var key in jqCache) {
        var value = jqCache[key];
        if (value.$scope == obj) {
          delete jqCache[key];
        }
      }
    }

  }
}

/**
 * @param {DOMElement} element
 * @param {boolean=} showNgClass
 */
function sortedHtml(element, showNgClass) {
  var html = "";
  forEach(jqLite(element), function toString(node) {
    if (node.nodeName == "#text") {
      html += node.nodeValue.
        replace(/&(\w+[&;\W])?/g, function(match, entity){return entity?match:'&';}).
        replace(/</g, '<').
        replace(/>/g, '>');
    } else {
      html += '<' + (node.nodeName || '?NOT_A_NODE?').toLowerCase();
      var attributes = node.attributes || [];
      var attrs = [];
      var className = node.className || '';
      if (!showNgClass) {
        className = className.replace(/ng-[\w-]+\s*/g, '');
      }
      className = trim(className);
      if (className) {
        attrs.push(' class="' + className + '"');
      }
      for(var i=0; i<attributes.length; i++) {
        if (i>0 && attributes[i] == attributes[i-1])
          continue; //IE9 creates dupes. Ignore them!

        var attr = attributes[i];
        if(attr.name.match(/^ng[\:\-]/) ||
            attr.value &&
            attr.value !='null' &&
            attr.value !='auto' &&
            attr.value !='false' &&
            attr.value !='inherit' &&
            (attr.value !='0' || attr.name =='value') &&
            attr.name !='loop' &&
            attr.name !='complete' &&
            attr.name !='maxLength' &&
            attr.name !='size' &&
            attr.name !='class' &&
            attr.name !='start' &&
            attr.name !='tabIndex' &&
            attr.name !='style' &&
            attr.name.substr(0, 6) != 'jQuery') {
          // in IE we need to check for all of these.
          if (!/ng-\d+/.exec(attr.name) &&
              attr.name != 'getElementById' &&
              // IE7 has `selected` in attributes
              attr.name !='selected' &&
              // IE7 adds `value` attribute to all LI tags
              (node.nodeName != 'LI' || attr.name != 'value'))
            attrs.push(' ' + attr.name + '="' + attr.value + '"');
        }
      }
      attrs.sort();
      html += attrs.join('');
      if (node.style) {
        var style = [];
        if (node.style.cssText) {
          forEach(node.style.cssText.split(';'), function(value){
            value = trim(value);
            if (value) {
              style.push(lowercase(value));
            }
          });
        }
        for(var css in node.style){
          var value = node.style[css];
          if (isString(value) && isString(css) && css != 'cssText' && value && (1*css != css)) {
            var text = lowercase(css + ': ' + value);
            if (value != 'false' && indexOf(style, text) == -1) {
              style.push(text);
            }
          }
        }
        style.sort();
        var tmp = style;
        style = [];
        forEach(tmp, function(value){
          if (!value.match(/^max[^\-]/))
            style.push(value);
        });
        if (style.length) {
          html += ' style="' + style.join('; ') + ';"';
        }
      }
      html += '>';
      var children = node.childNodes;
      for(var j=0; j<children.length; j++) {
        toString(children[j]);
      }
      html += '</' + node.nodeName.toLowerCase() + '>';
    }
  });
  return html;
}

// TODO(vojta): migrate these helpers into jasmine matchers
/**a
 * This method is a cheap way of testing if css for a given node is not set to 'none'. It doesn't
 * actually test if an element is displayed by the browser. Be aware!!!
 */
function isCssVisible(node) {
  var display = node.css('display');
  return display != 'none';
}

function assertHidden(node) {
  if (isCssVisible(node)) {
    throw new Error('Node should be hidden but was visible: ' + angular.module.ngMock.dump(node));
  }
}

function assertVisible(node) {
  if (!isCssVisible(node)) {
    throw new Error('Node should be visible but was hidden: ' + angular.module.ngMock.dump(node));
  }
}

function provideLog($provide) {
  $provide.factory('log', function() {
      var messages = [];

      function log(msg) {
        messages.push(msg);
        return msg;
      }

      log.toString = function() {
        return messages.join('; ');
      }

      log.toArray = function() {
        return messages;
      }

      log.reset = function() {
        messages = [];
      }

      log.fn = function(msg) {
        return function() {
          log(msg);
        }
      }

      log.$$log = true;

      return log;
    });
}

function pending() {
  dump('PENDING');
};

function trace(name) {
  dump(new Error(name).stack);
}
<|endoftext|>