<commit_before>var getVegaSpec = function(table,DataViews,resourceIndex) {
  var price = DataViews[resourceIndex].state.series[0];
  var date = DataViews[resourceIndex].state.group;
  var parse = makeParse(date, price);
  // needs to be automate (passed to datapackage.json or smth)
  var template = makeTemplate(date, "annual");
  var spec =
    "actions": false,
    "spec": {
      "width": 1080,
      "height": 500,
      "signals": [
        {
          "name": "tooltip",
          "init": {},
          "streams": [
            {"type": "symbol:mouseover", "expr": "datum"},
            {"type": "symbol:mouseout", "expr": "{}"}
          ]
        }
      ],
      "data": [
        {
          "name": "data",
          "url": table.path,
          "format": {
            "type": "csv",
            "parse": parse
          }
        }
      ],
      "scales": [
        {
          "name": "x",
          "type": "time",
          "range": "width",
          "nice": "day",
          "domain": {"data": "data","field": date}
        },
        {
          "name": "y",
          "type": "linear",
          "range": "height",
          "nice": true,
          "zero": false,
          "domain": {"data": "data","field": price}
        }
      ],
      "axes": [
        {"type": "x","scale": "x","ticks": 12,"grid": true},
        {"type": "y","scale": "y","ticks": 5,"grid": true}
      ],
      "marks": [
        {
          "type": "line",
          "from": {"data": "data"},
          "properties": {
            "enter": {
              "x": {"scale": "x","field": date},
              "y": {"scale": "y","field": price},
              "stroke": {"value": "blue"},
              "strokeWidth": {"value": 2}
            }
          }
        },
        {
          "type": "symbol",
          "from": {"data": "data"},
          "properties": {
            "enter": {
              "x": {"scale": "x","field": date},
              "y": {"scale": "y","field": price},
              "strokeWidth": {"value": 2}
            },
            "update": {
              "fill": {"value": "steelblue"},
              "size": {"value": "40"}
            },
            "hover": {
              "fill": {"value": "red"},
              "size": {"value": "280"}
            }
          }
        },
        {
          "type": "group",
          "from": {"data": "data"},
          "properties": {
            "update": {
              "x": {"scale": "x", "signal": "tooltip."+date, "offset": 15},
              "y": {"scale": "y", "signal": "tooltip."+price, "offset": -10},
              "width": {"value": 120},
              "height": {"value": 30},
              "fill": {"value": "#edf1f7"},
              "fillOpacity": [
                {
                  "test": "!tooltip._id",
                  "value": 0
                },
                  {"value": 0.8}
                ],
              "stroke": {"value": "#aaa"},
              "strokeWidth": [
                {
                  "test": "!tooltip._id",
                  "value": 0
                },
                {"value": 1}
              ]
            }
          },
          "marks": [
            {
              "type": "text",
              "properties": {
                "enter": {
                  "align": {"value": "left"},
                  "fill": {"value": "#333"}
                },
                "update": {
                  "x": {"value": 6},
                  "y": {"value": 13},
                  "text": {"template": template},
                  "fillOpacity": [
                    {
                      "test": "!tooltip._id",
                      "value": 0
                    },
                    {"value": 1}
                  ]
                }
              }
            },
            {
              "type": "text",
              "properties": {
                "enter": {
                  "align": {"value": "left"},
                  "fill": {"value": "#333"}
                },
                "update": {
                  "x": {"value": 6},
                  "y": {"value": 27},
                  "text": {"template": "Price: {{tooltip."+price+"}}"},
                  "fillOpacity": [
                    { "test": "!tooltip._id",
                      "value": 0
                    },
                    {"value": 1}
                  ]
                }
              }
            }
          ]
        }
      ]
    }
  };
  return spec;
};

function makeParse(date, price) {
  var obj = {};
  obj[price] = "number";
  obj[date] = "date";
  return obj;
}

function makeTemplate(field, series) {
  var template;
  switch (series){
    case "daily":
      template = "Date: {{tooltip."+field+"| time: '%Y %b %d'}}";
      break;
    case "monthly":
      template = "Date: {{tooltip."+field+"| time: '%Y %b'}}";
      break;
    case "annual":
      template = "Year: {{tooltip."+field+"| time: '%Y'}}";
      break;
  }
  return template;
}<commit_msg>[graphs][s]: typo fixed<commit_after>var getVegaSpec = function(table,DataViews,resourceIndex) {
  var price = DataViews[resourceIndex].state.series[0];
  var date = DataViews[resourceIndex].state.group;
  var parse = makeParse(date, price);
  // needs to be automate (passed to datapackage.json or smth)
  var template = makeTemplate(date, "annual");
  var spec = {
    "actions": false,
    "spec": {
      "width": 1080,
      "height": 500,
      "signals": [
        {
          "name": "tooltip",
          "init": {},
          "streams": [
            {"type": "symbol:mouseover", "expr": "datum"},
            {"type": "symbol:mouseout", "expr": "{}"}
          ]
        }
      ],
      "data": [
        {
          "name": "data",
          "url": table.path,
          "format": {
            "type": "csv",
            "parse": parse
          }
        }
      ],
      "scales": [
        {
          "name": "x",
          "type": "time",
          "range": "width",
          "nice": "day",
          "domain": {"data": "data","field": date}
        },
        {
          "name": "y",
          "type": "linear",
          "range": "height",
          "nice": true,
          "zero": false,
          "domain": {"data": "data","field": price}
        }
      ],
      "axes": [
        {"type": "x","scale": "x","ticks": 12,"grid": true},
        {"type": "y","scale": "y","ticks": 5,"grid": true}
      ],
      "marks": [
        {
          "type": "line",
          "from": {"data": "data"},
          "properties": {
            "enter": {
              "x": {"scale": "x","field": date},
              "y": {"scale": "y","field": price},
              "stroke": {"value": "blue"},
              "strokeWidth": {"value": 2}
            }
          }
        },
        {
          "type": "symbol",
          "from": {"data": "data"},
          "properties": {
            "enter": {
              "x": {"scale": "x","field": date},
              "y": {"scale": "y","field": price},
              "strokeWidth": {"value": 2}
            },
            "update": {
              "fill": {"value": "steelblue"},
              "size": {"value": "40"}
            },
            "hover": {
              "fill": {"value": "red"},
              "size": {"value": "280"}
            }
          }
        },
        {
          "type": "group",
          "from": {"data": "data"},
          "properties": {
            "update": {
              "x": {"scale": "x", "signal": "tooltip."+date, "offset": 15},
              "y": {"scale": "y", "signal": "tooltip."+price, "offset": -10},
              "width": {"value": 120},
              "height": {"value": 30},
              "fill": {"value": "#edf1f7"},
              "fillOpacity": [
                {
                  "test": "!tooltip._id",
                  "value": 0
                },
                  {"value": 0.8}
                ],
              "stroke": {"value": "#aaa"},
              "strokeWidth": [
                {
                  "test": "!tooltip._id",
                  "value": 0
                },
                {"value": 1}
              ]
            }
          },
          "marks": [
            {
              "type": "text",
              "properties": {
                "enter": {
                  "align": {"value": "left"},
                  "fill": {"value": "#333"}
                },
                "update": {
                  "x": {"value": 6},
                  "y": {"value": 13},
                  "text": {"template": template},
                  "fillOpacity": [
                    {
                      "test": "!tooltip._id",
                      "value": 0
                    },
                    {"value": 1}
                  ]
                }
              }
            },
            {
              "type": "text",
              "properties": {
                "enter": {
                  "align": {"value": "left"},
                  "fill": {"value": "#333"}
                },
                "update": {
                  "x": {"value": 6},
                  "y": {"value": 27},
                  "text": {"template": "Price: {{tooltip."+price+"}}"},
                  "fillOpacity": [
                    { "test": "!tooltip._id",
                      "value": 0
                    },
                    {"value": 1}
                  ]
                }
              }
            }
          ]
        }
      ]
    }
  };
  return spec;
};

function makeParse(date, price) {
  var obj = {};
  obj[price] = "number";
  obj[date] = "date";
  return obj;
}

function makeTemplate(field, series) {
  var template;
  switch (series){
    case "daily":
      template = "Date: {{tooltip."+field+"| time: '%Y %b %d'}}";
      break;
    case "monthly":
      template = "Date: {{tooltip."+field+"| time: '%Y %b'}}";
      break;
    case "annual":
      template = "Year: {{tooltip."+field+"| time: '%Y'}}";
      break;
  }
  return template;
}<|endoftext|>


<commit_before>import { getTimeISO8601, normalizeUrl } from './utils';

export function scrape (elem) {
    const postType = (elem.find('.uiStreamSponsoredLink').length === 1) ?
      'sponsored' : 'feed';
    return scrapePost(postType, elem);
}

var publicTrigger = {
  "english": "Public",
  "deutsch": "Öffentlich",
  "espanol": "Público",
  "italiano": "Tutti",
  "português": "Público"
}

export function scrapePost (postType, elem) {
    // Skip if the post is not top level
    if (elem.parents('.userContentWrapper').length) {
        console.log("Skipping post because nested");
        return null;
    }

    var isPublic = false;

    var sharingLevel = elem
      .find('[data-hover="tooltip"][role][aria-label][data-tooltip-content]')
      .attr('aria-label')
      .split(':')
      .pop()
      .trim();

    for(var lang in publicTrigger) {
        if(publicTrigger[lang] === sharingLevel) {
            console.log("Language detected: ", lang);
            isPublic = true;
        }
    }

    return {
        visibility: isPublic ? 'public' : 'private',
        impressionTime: getTimeISO8601()
    };
}

export function scrapeUserData (elem) {
    const info = elem.find('.fbxWelcomeBoxName');
    const parsedInfo = {
        // even if the id is a number, I feel more comfortable to cast it to a String
        id: String(JSON.parse(info.attr('data-gt')).bmid),
        href: info.attr('href').split('?')[0]
    };

    return parsedInfo;
}
<commit_msg>Fix code style<commit_after>import { getTimeISO8601 } from './utils';

export function scrape (elem) {
    const postType = (elem.find('.uiStreamSponsoredLink').length === 1) ? 'sponsored' : 'feed';
    return scrapePost(postType, elem);
}

var publicTrigger = {
    'english': 'Public',
    'deutsch': 'Öffentlich',
    'espanol': 'Público',
    'italiano': 'Tutti',
    'português': 'Público'
};

export function scrapePost (postType, elem) {
    // Skip if the post is not top level
    if (elem.parents('.userContentWrapper').length) {
        console.log('Skipping post because nested');
        return null;
    }

    var isPublic = false;

    var sharingLevel = elem
      .find('[data-hover="tooltip"][role][aria-label][data-tooltip-content]')
      .attr('aria-label')
      .split(':')
      .pop()
      .trim();

    for (var lang in publicTrigger) {
        console.log('trying', lang, publicTrigger[lang]);
        if (publicTrigger[lang] === sharingLevel) {
            console.log('Language detected: ', lang);
            isPublic = true;
        }
    }

    return {
        visibility: isPublic ? 'public' : 'private',
        impressionTime: getTimeISO8601()
    };
}

export function scrapeUserData (elem) {
    const info = elem.find('.fbxWelcomeBoxName');
    const parsedInfo = {
        // even if the id is a number, I feel more comfortable to cast it to a String
        id: String(JSON.parse(info.attr('data-gt')).bmid),
        href: info.attr('href').split('?')[0]
    };

    return parsedInfo;
}
<|endoftext|>


<commit_before>var templates = require('./modules/templates');
var pkg = require('../package.json');
var storage = require('./modules/storage');
var publicApi = require('./modules/public-api');
var ember = require('./modules/ember-api');
var logger = require('./modules/logger');

var $ = null;
var jQuery = null;

// Expose public api.
if (typeof window.emoteMenu === 'undefined') {
	window.emoteMenu = publicApi;
}

// Script-wide variables.
//-----------------------
// DOM elements.
var elements = {
	// The button to send a chat message.
	chatButton: null,
	// The area where all chat messages are contained.
	chatContainer: null,
	// The input field for chat messages.
	chatBox: null,
	// The button used to show the menu.
	menuButton: null,
	// The menu that contains all emotes.
	menu: null
};

var helpers = {
	user: {
		/**
		 * Check if user is logged in, and prompts them to if they aren't.
		 * @return {boolean} `true` if logged in, `false` if logged out.
		 */
		login: function () {
			// Check if logged in already.
			if (window.Twitch && window.Twitch.user.isLoggedIn()) {
				logger.debug('User is logged in.');
				return true;
			}
			// Not logged in, call Twitch's login method.
			$.login();
			logger.debug('User is not logged in, show the login screen.');
			return false;
		}
	}
};

logger.log('Initial load on ' + location.href);

// Only enable script if we have the right variables.
//---------------------------------------------------
var initTimer = 0;
(function init(time) {
	if (!time) {
		time = 0;
	}

	$ = jQuery = window.jQuery;
	var objectsLoaded = (
		window.Twitch !== undefined &&
		ember.isLoaded() &&
		jQuery !== undefined &&
		$('.send-chat-button').length
	);
	if (!objectsLoaded) {
		// Stops trying after 10 minutes.
		if (initTimer >= 600000) {
			logger.log('Taking too long to load, stopping. Refresh the page to try again. (' + initTimer + 'ms)');
			return;
		}

		// Give an update every 10 seconds.
		if (initTimer % 10000) {
			logger.debug('Still waiting for objects to load. (' + initTimer + 'ms)');
		}

		// Bump time up after 1s to reduce possible lag.
		time = time >= 1000 ? 1000 : time + 25;
		initTimer += time;

		setTimeout(init, time, time);
		return;
	}

	function deactivate() {
		// Remove menu from screen when redirecting.
		if (elements.menu) {
			elements.menu.hide();
		}
	}
	ember.hook('route:channel', init, deactivate);
	ember.hook('route:chat', init, deactivate);

	setup();
})();

// Start of functions.
//--------------------
/**
 * Runs initial setup of DOM and variables.
 */
function setup() {
	var emotes = require('./modules/emotes');
	logger.debug('Running setup...');
	// Load CSS.
	require('../build/styles');
	// Load jQuery plugins.
	require('./plugins/resizable');
	require('jquery-custom-scrollbar/jquery.custom-scrollbar');

	elements.chatButton = $('.send-chat-button');
	elements.chatBox = $('.chat-interface textarea');
	elements.chatContainer = $('.chat-messages');

	createMenuElements();
	bindListeners();
	emotes.init();
}

/**
 * Creates the initial menu elements
 */
function createMenuElements() {
	// Remove menu button if found.
	elements.menuButton = $('#emote-menu-button');
	if (elements.menuButton.length) {
		elements.menuButton.remove();
	}
	// Create menu button.
	elements.menuButton = $(templates.emoteButton());
	elements.menuButton.insertBefore(elements.chatButton);
	elements.menuButton.hide();
	elements.menuButton.fadeIn();

	// Remove menu if found.
	elements.menu = $('#emote-menu-for-twitch');
	if (elements.menu.length) {
		elements.menu.remove();
	}
	// Create menu.
	elements.menu = $(templates.menu());
	elements.menu.appendTo(document.body);

	logger.debug('Created menu elements.');
}

/**
 * Bind event listeners.
 */
function bindListeners() {

	function toggleMenu() {
		// Menu shown, hide it.
		if (elements.menu.is(':visible')) {
			elements.menu.hide();
			elements.menu.removeClass('pinned');
			elements.menu.removeClass('editing');
			elements.menuButton.removeClass('active');

			logger.debug('Menu hidden.');
		}
		// Menu hidden, show it.
		else if (helpers.user.login()) {
			populateEmotesMenu();
			elements.menu.show();
			elements.menuButton.addClass('active');

			$(document).on('mouseup', checkForClickOutside);

			// Menu moved, move it back.
			if (elements.menu.hasClass('moved')) {
				elements.menu.offset(JSON.parse(elements.menu.attr('data-offset')));
			}
			// Never moved, make it the same size as the chat window.
			else {
				var diff = elements.menu.height() - elements.menu.find('#all-emotes-group').height();
				// Adjust the size and position of the popup.
				elements.menu.height(elements.chatContainer.outerHeight() - (elements.menu.outerHeight() - elements.menu.height()));
				elements.menu.width(elements.chatContainer.outerWidth() - (elements.menu.outerWidth() - elements.menu.width()));
				elements.menu.offset(elements.chatContainer.offset());
				// Fix `.emotes-all` height.
				elements.menu.find('#all-emotes-group').height(elements.menu.height() - diff);
				elements.menu.find('#all-emotes-group').width(elements.menu.width());
			}
			// Recalculate any scroll bars.
			elements.menu.find('.scrollable').customScrollbar('resize');

			logger.debug('Menu visible.');
		}

		function checkForClickOutside(e) {
			// Not outside of the menu, ignore the click.
			if ($(e.target).is('#emote-menu-for-twitch, #emote-menu-for-twitch *')) {
				return;
			}
			// Clicked on the menu button, just remove the listener and let the normal listener handle it.
			if (!elements.menu.is(':visible') || $(e.target).is('#emote-menu-button, #emote-menu-button *')) {
				$(document).off('mouseup', checkForClickOutside);
				return;
			}
			// Clicked outside, make sure the menu isn't pinned.
			if (!elements.menu.hasClass('pinned')) {
				// Menu wasn't pinned, remove listener.
				$(document).off('mouseup', checkForClickOutside);
				toggleMenu();
			}
		}
	}

	// Toggle menu.
	elements.menuButton.on('click', toggleMenu);

	// Make draggable.
	elements.menu.draggable({
		handle: '.draggable',
		start: function () {
			$(this).addClass('pinned');
			$(this).addClass('moved');
		},
		stop: function () {
			elements.menu.attr('data-offset', JSON.stringify(elements.menu.offset()));
		},
		containment: $(document.body)
	});

	elements.menu.resizable({
		handle: '[data-command="resize-handle"]',
		resize: function () {
			// Recalculate any scroll bars.
			elements.menu.find('.scrollable').customScrollbar('resize');
		},
		stop: function () {
			$(this).addClass('pinned');
			$(this).addClass('moved');
		},
		alsoResize: elements.menu.find('.scrollable'),
		containment: $(document.body),
		minHeight: 180,
		minWidth: 200
	});

	// Enable menu pinning.
	elements.menu.find('[data-command="toggle-pinned"]').on('click', function () {
		elements.menu.toggleClass('pinned');
	});

	// Enable menu editing.
	elements.menu.find('[data-command="toggle-editing"]').on('click', function () {
		elements.menu.toggleClass('editing');
		// Recalculate any scroll bars.
		elements.menu.find('.scrollable').customScrollbar('resize');
	});

	// Enable emote clicking (delegated).
	elements.menu.on('click', '.emote', function () {
		if (elements.menu.is('.editing')) {
			return;
		}
		insertEmoteText($(this).attr('data-emote'));
		logger.debug('Clicked emote: ' + $(this).attr('data-emote'));
	});

	// Enable emote hiding (delegated).
	elements.menu.on('click', '[data-command="toggle-visibility"]', function () {
		// Make sure we are in edit mode.
		if (!elements.menu.is('.editing')) {
			return;
		}
		var which = $(this).attr('data-which');
		var isVisible = storage.visibility.get(which, true);
		// Toggle visibility.
		storage.visibility.set(which, !isVisible);
		populateEmotesMenu();

		logger.debug('Set hidden emote.', {
			which: which,
			isVisible: !isVisible
		});
	});

	// Enable emote starring (delegated).
	elements.menu.on('click', '[data-command="toggle-starred"]', function () {
		// Make sure we are in edit mode.
		if (!elements.menu.is('.editing')) {
			return;
		}
		var which = $(this).attr('data-which');
		var isStarred = storage.starred.get(which, false);
		// Toggle star.
		storage.starred.set(which, !isStarred);
		populateEmotesMenu();

		logger.debug('Set starred emote.', {
			which: which,
			isStarred: !isStarred
		});
	});

	elements.menu.find('.scrollable').customScrollbar({
		skin: 'default-skin',
		hScroll: false,
		preventDefaultScroll: true
	});

	logger.debug('Bounded event listeners.');
}

/**
 * Populates the popup menu with current emote data.
 */
function populateEmotesMenu() {
	var emotes = require('./modules/emotes');
	var container = null;

	// Add starred emotes.
	container = elements.menu.find('#starred-emotes-group');
	container.html('');
	emotes.getEmotes(
		function (emote) {
			return emote.isFavorite();
		},
		'default'
	).forEach(function (emote) {
		createEmote(emote, container);
	});

	// Add all emotes.
	container = elements.menu.find('#all-emotes-group');
	if (container.find('.overview').length) {
		container = container.find('.overview');
	}
	container.html('');
	emotes.getEmotes(null, 'channel').forEach(function (emote) {
		createEmote(emote, container, true);
	});
}

/**
 * Inserts an emote into the chat box.
 * @param {string} text The text of the emote (e.g. "Kappa").
 */
function insertEmoteText(text) {
	// Get input.
	var element = document.querySelector('#chat_text_input, .chat-interface textarea');

	// Insert at cursor / replace selection.
	// https://developer.mozilla.org/en-US/docs/Code_snippets/Miscellaneous
	var selectionEnd = element.selectionStart + text.length;
	var currentValue = element.value;
	var beforeText = currentValue.substring(0, element.selectionStart);
	var afterText = currentValue.substring(element.selectionEnd, currentValue.length);
	// Smart padding, only put space at start if needed.
	if (
		beforeText !== '' &&
		beforeText.substr(-1) !== ' '
	) {
		text = ' ' + text;
	}
	// Always put space at end.
	text = beforeText + text + ' ' + afterText;
	// Set the text.
	ember.get('controller:chat', 'currentRoom').set('messageToSend', text);
	element.focus();
	// Put cursor at end.
	selectionEnd = element.selectionStart + text.length;
	element.setSelectionRange(selectionEnd, selectionEnd);

	// Close popup if it hasn't been moved by the user.
	if (!elements.menu.hasClass('pinned')) {
		elements.menuButton.click();
	}
	// Re-populate as it is still open.
	else {
		populateEmotesMenu();
	}
}

/**
 * Creates the emote element and listens for a click event that will add the emote text to the chat.
 * @param {object}  emote      The emote that you want to add. This object should be one coming from `emotes`.
 * @param {element} container  The HTML element that the emote should be appended to.
 * @param {boolean} showHeader Whether a header shouldbe created if found. Only creates the header once.
 */
function createEmote(emote, container, showHeader) {
	// No container, can't add.
	if (!container.length) {
		return;
	}
	if (showHeader) {
		if (emote.getChannelName() && !emote.isSmiley()) {
			if (!elements.menu.find('.group-header[data-emote-channel="' + emote.getChannelName() + '"]').length) {
				container.append(
					$(templates.emoteGroupHeader({
						badge: emote.getChannelBadge(),
						channel: emote.getChannelName(),
						channelDisplayName: emote.getChannelDisplayName(),
						isVisible: storage.visibility.get('channel-' + emote.getChannelName(), true)
					}))
				);
			}
		}
	}

	var channelContainer = container.find('.group-header[data-emote-channel="' + emote.getChannelName() + '"]');
	if (channelContainer.length) {
		container = channelContainer;
	}
	container.append(
		$(templates.emote({
			url: emote.getUrl(),
			text: emote.getText(),
			thirdParty: emote.isThirdParty(),
			isVisible: emote.isVisible(),
			isStarred: emote.isFavorite()
		}))
	);
}
<commit_msg>Don't run in an iframe<commit_after>var templates = require('./modules/templates');
var pkg = require('../package.json');
var storage = require('./modules/storage');
var publicApi = require('./modules/public-api');
var ember = require('./modules/ember-api');
var logger = require('./modules/logger');

var $ = null;
var jQuery = null;

// Expose public api.
if (typeof window.emoteMenu === 'undefined') {
	window.emoteMenu = publicApi;
}

// Script-wide variables.
//-----------------------
// DOM elements.
var elements = {
	// The button to send a chat message.
	chatButton: null,
	// The area where all chat messages are contained.
	chatContainer: null,
	// The input field for chat messages.
	chatBox: null,
	// The button used to show the menu.
	menuButton: null,
	// The menu that contains all emotes.
	menu: null
};

var helpers = {
	user: {
		/**
		 * Check if user is logged in, and prompts them to if they aren't.
		 * @return {boolean} `true` if logged in, `false` if logged out.
		 */
		login: function () {
			// Check if logged in already.
			if (window.Twitch && window.Twitch.user.isLoggedIn()) {
				logger.debug('User is logged in.');
				return true;
			}
			// Not logged in, call Twitch's login method.
			$.login();
			logger.debug('User is not logged in, show the login screen.');
			return false;
		}
	}
};

logger.log('Initial load on ' + location.href);

// Only enable script if we have the right variables.
//---------------------------------------------------
var initTimer = 0;
(function init(time) {
	// Don't run in an iframe.
	if (window.frameElement) {
		return;
	}

	if (!time) {
		time = 0;
	}

	$ = jQuery = window.jQuery;
	var objectsLoaded = (
		window.Twitch !== undefined &&
		ember.isLoaded() &&
		jQuery !== undefined &&
		$('.send-chat-button').length
	);
	if (!objectsLoaded) {
		// Stops trying after 10 minutes.
		if (initTimer >= 600000) {
			logger.log('Taking too long to load, stopping. Refresh the page to try again. (' + initTimer + 'ms)');
			return;
		}

		// Give an update every 10 seconds.
		if (initTimer % 10000) {
			logger.debug('Still waiting for objects to load. (' + initTimer + 'ms)');
		}

		// Bump time up after 1s to reduce possible lag.
		time = time >= 1000 ? 1000 : time + 25;
		initTimer += time;

		setTimeout(init, time, time);
		return;
	}

	function deactivate() {
		// Remove menu from screen when redirecting.
		if (elements.menu) {
			elements.menu.hide();
		}
	}
	ember.hook('route:channel', init, deactivate);
	ember.hook('route:chat', init, deactivate);

	setup();
})();

// Start of functions.
//--------------------
/**
 * Runs initial setup of DOM and variables.
 */
function setup() {
	var emotes = require('./modules/emotes');
	logger.debug('Running setup...');
	// Load CSS.
	require('../build/styles');
	// Load jQuery plugins.
	require('./plugins/resizable');
	require('jquery-custom-scrollbar/jquery.custom-scrollbar');

	elements.chatButton = $('.send-chat-button');
	elements.chatBox = $('.chat-interface textarea');
	elements.chatContainer = $('.chat-messages');

	createMenuElements();
	bindListeners();
	emotes.init();
}

/**
 * Creates the initial menu elements
 */
function createMenuElements() {
	// Remove menu button if found.
	elements.menuButton = $('#emote-menu-button');
	if (elements.menuButton.length) {
		elements.menuButton.remove();
	}
	// Create menu button.
	elements.menuButton = $(templates.emoteButton());
	elements.menuButton.insertBefore(elements.chatButton);
	elements.menuButton.hide();
	elements.menuButton.fadeIn();

	// Remove menu if found.
	elements.menu = $('#emote-menu-for-twitch');
	if (elements.menu.length) {
		elements.menu.remove();
	}
	// Create menu.
	elements.menu = $(templates.menu());
	elements.menu.appendTo(document.body);

	logger.debug('Created menu elements.');
}

/**
 * Bind event listeners.
 */
function bindListeners() {

	function toggleMenu() {
		// Menu shown, hide it.
		if (elements.menu.is(':visible')) {
			elements.menu.hide();
			elements.menu.removeClass('pinned');
			elements.menu.removeClass('editing');
			elements.menuButton.removeClass('active');

			logger.debug('Menu hidden.');
		}
		// Menu hidden, show it.
		else if (helpers.user.login()) {
			populateEmotesMenu();
			elements.menu.show();
			elements.menuButton.addClass('active');

			$(document).on('mouseup', checkForClickOutside);

			// Menu moved, move it back.
			if (elements.menu.hasClass('moved')) {
				elements.menu.offset(JSON.parse(elements.menu.attr('data-offset')));
			}
			// Never moved, make it the same size as the chat window.
			else {
				var diff = elements.menu.height() - elements.menu.find('#all-emotes-group').height();
				// Adjust the size and position of the popup.
				elements.menu.height(elements.chatContainer.outerHeight() - (elements.menu.outerHeight() - elements.menu.height()));
				elements.menu.width(elements.chatContainer.outerWidth() - (elements.menu.outerWidth() - elements.menu.width()));
				elements.menu.offset(elements.chatContainer.offset());
				// Fix `.emotes-all` height.
				elements.menu.find('#all-emotes-group').height(elements.menu.height() - diff);
				elements.menu.find('#all-emotes-group').width(elements.menu.width());
			}
			// Recalculate any scroll bars.
			elements.menu.find('.scrollable').customScrollbar('resize');

			logger.debug('Menu visible.');
		}

		function checkForClickOutside(e) {
			// Not outside of the menu, ignore the click.
			if ($(e.target).is('#emote-menu-for-twitch, #emote-menu-for-twitch *')) {
				return;
			}
			// Clicked on the menu button, just remove the listener and let the normal listener handle it.
			if (!elements.menu.is(':visible') || $(e.target).is('#emote-menu-button, #emote-menu-button *')) {
				$(document).off('mouseup', checkForClickOutside);
				return;
			}
			// Clicked outside, make sure the menu isn't pinned.
			if (!elements.menu.hasClass('pinned')) {
				// Menu wasn't pinned, remove listener.
				$(document).off('mouseup', checkForClickOutside);
				toggleMenu();
			}
		}
	}

	// Toggle menu.
	elements.menuButton.on('click', toggleMenu);

	// Make draggable.
	elements.menu.draggable({
		handle: '.draggable',
		start: function () {
			$(this).addClass('pinned');
			$(this).addClass('moved');
		},
		stop: function () {
			elements.menu.attr('data-offset', JSON.stringify(elements.menu.offset()));
		},
		containment: $(document.body)
	});

	elements.menu.resizable({
		handle: '[data-command="resize-handle"]',
		resize: function () {
			// Recalculate any scroll bars.
			elements.menu.find('.scrollable').customScrollbar('resize');
		},
		stop: function () {
			$(this).addClass('pinned');
			$(this).addClass('moved');
		},
		alsoResize: elements.menu.find('.scrollable'),
		containment: $(document.body),
		minHeight: 180,
		minWidth: 200
	});

	// Enable menu pinning.
	elements.menu.find('[data-command="toggle-pinned"]').on('click', function () {
		elements.menu.toggleClass('pinned');
	});

	// Enable menu editing.
	elements.menu.find('[data-command="toggle-editing"]').on('click', function () {
		elements.menu.toggleClass('editing');
		// Recalculate any scroll bars.
		elements.menu.find('.scrollable').customScrollbar('resize');
	});

	// Enable emote clicking (delegated).
	elements.menu.on('click', '.emote', function () {
		if (elements.menu.is('.editing')) {
			return;
		}
		insertEmoteText($(this).attr('data-emote'));
		logger.debug('Clicked emote: ' + $(this).attr('data-emote'));
	});

	// Enable emote hiding (delegated).
	elements.menu.on('click', '[data-command="toggle-visibility"]', function () {
		// Make sure we are in edit mode.
		if (!elements.menu.is('.editing')) {
			return;
		}
		var which = $(this).attr('data-which');
		var isVisible = storage.visibility.get(which, true);
		// Toggle visibility.
		storage.visibility.set(which, !isVisible);
		populateEmotesMenu();

		logger.debug('Set hidden emote.', {
			which: which,
			isVisible: !isVisible
		});
	});

	// Enable emote starring (delegated).
	elements.menu.on('click', '[data-command="toggle-starred"]', function () {
		// Make sure we are in edit mode.
		if (!elements.menu.is('.editing')) {
			return;
		}
		var which = $(this).attr('data-which');
		var isStarred = storage.starred.get(which, false);
		// Toggle star.
		storage.starred.set(which, !isStarred);
		populateEmotesMenu();

		logger.debug('Set starred emote.', {
			which: which,
			isStarred: !isStarred
		});
	});

	elements.menu.find('.scrollable').customScrollbar({
		skin: 'default-skin',
		hScroll: false,
		preventDefaultScroll: true
	});

	logger.debug('Bounded event listeners.');
}

/**
 * Populates the popup menu with current emote data.
 */
function populateEmotesMenu() {
	var emotes = require('./modules/emotes');
	var container = null;

	// Add starred emotes.
	container = elements.menu.find('#starred-emotes-group');
	container.html('');
	emotes.getEmotes(
		function (emote) {
			return emote.isFavorite();
		},
		'default'
	).forEach(function (emote) {
		createEmote(emote, container);
	});

	// Add all emotes.
	container = elements.menu.find('#all-emotes-group');
	if (container.find('.overview').length) {
		container = container.find('.overview');
	}
	container.html('');
	emotes.getEmotes(null, 'channel').forEach(function (emote) {
		createEmote(emote, container, true);
	});
}

/**
 * Inserts an emote into the chat box.
 * @param {string} text The text of the emote (e.g. "Kappa").
 */
function insertEmoteText(text) {
	// Get input.
	var element = document.querySelector('#chat_text_input, .chat-interface textarea');

	// Insert at cursor / replace selection.
	// https://developer.mozilla.org/en-US/docs/Code_snippets/Miscellaneous
	var selectionEnd = element.selectionStart + text.length;
	var currentValue = element.value;
	var beforeText = currentValue.substring(0, element.selectionStart);
	var afterText = currentValue.substring(element.selectionEnd, currentValue.length);
	// Smart padding, only put space at start if needed.
	if (
		beforeText !== '' &&
		beforeText.substr(-1) !== ' '
	) {
		text = ' ' + text;
	}
	// Always put space at end.
	text = beforeText + text + ' ' + afterText;
	// Set the text.
	ember.get('controller:chat', 'currentRoom').set('messageToSend', text);
	element.focus();
	// Put cursor at end.
	selectionEnd = element.selectionStart + text.length;
	element.setSelectionRange(selectionEnd, selectionEnd);

	// Close popup if it hasn't been moved by the user.
	if (!elements.menu.hasClass('pinned')) {
		elements.menuButton.click();
	}
	// Re-populate as it is still open.
	else {
		populateEmotesMenu();
	}
}

/**
 * Creates the emote element and listens for a click event that will add the emote text to the chat.
 * @param {object}  emote      The emote that you want to add. This object should be one coming from `emotes`.
 * @param {element} container  The HTML element that the emote should be appended to.
 * @param {boolean} showHeader Whether a header shouldbe created if found. Only creates the header once.
 */
function createEmote(emote, container, showHeader) {
	// No container, can't add.
	if (!container.length) {
		return;
	}
	if (showHeader) {
		if (emote.getChannelName() && !emote.isSmiley()) {
			if (!elements.menu.find('.group-header[data-emote-channel="' + emote.getChannelName() + '"]').length) {
				container.append(
					$(templates.emoteGroupHeader({
						badge: emote.getChannelBadge(),
						channel: emote.getChannelName(),
						channelDisplayName: emote.getChannelDisplayName(),
						isVisible: storage.visibility.get('channel-' + emote.getChannelName(), true)
					}))
				);
			}
		}
	}

	var channelContainer = container.find('.group-header[data-emote-channel="' + emote.getChannelName() + '"]');
	if (channelContainer.length) {
		container = channelContainer;
	}
	container.append(
		$(templates.emote({
			url: emote.getUrl(),
			text: emote.getText(),
			thirdParty: emote.isThirdParty(),
			isVisible: emote.isVisible(),
			isStarred: emote.isFavorite()
		}))
	);
}
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import Header from './components/Header';
import MainSection from './components/MainSection';
import * as TodoActions from './actions/TodoActions';

@connect(state => ({
  todos: state.todos
}))
export default class TodoApp extends Component {

  static propTypes = {
    todos: PropTypes.array.isRequired,
    dispatch: PropTypes.func.isRequired
  };

  render() {
    const { todos, dispatch } = this.props;
    const actions = bindActionCreators(TodoActions, dispatch);

    return (

        <MainSection todos={todos} actions={actions} />

    );
  }
}<commit_msg>Revert "set min height"<commit_after>import React, { Component, PropTypes } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import Header from './components/Header';
import MainSection from './components/MainSection';
import * as TodoActions from './actions/TodoActions';

@connect(state => ({
  todos: state.todos
}))
export default class TodoApp extends Component {

  static propTypes = {
    todos: PropTypes.array.isRequired,
    dispatch: PropTypes.func.isRequired
  };

  render() {
    const { todos, dispatch } = this.props;
    const actions = bindActionCreators(TodoActions, dispatch);

    return (

        <MainSection todos={todos} actions={actions} />

    );
  }
}<|endoftext|>


<commit_before>//urls
if(!$){
	function $(){
		return document.getElementById.apply(document,arguments)
	}
}
// datastructures
/*
	 smils a dict of the smils with key of the url
	 and value as indexDict and smilLists
	 */
smils={};
/* smilList:
	 Audio Element
			list with index:
				0 - "audio"
				1 - url of file
				2 - start of clip
				3 - end of clip
	Text Element:
			List with index:
				0 - "text"
				1 - the text
	indexDict:
		key id in the paired smile valus are indexes in the smil List for that tags content
 */
/*
	 htmls a dict of the html documents with key of the url
	 and value as id->text mapping
	 */
htmls={};
smil=[{},[]];//fixme: refactor to a better name, this is the current smil.
index=0;
if(!window.basePath)basePath="media/";//sets but dossent over write
// Constants

function loadConstants (){
	TEXTDISPLAY=document.getElementById("textDisplay");
	TOCDISPLAY=document.getElementById("tocDisplay")
	PROGRESSDISPLAY=document.getElementById("progressDisplay");
	PROGRESS=document.getElementById("progress");
	AUDIOPLAYER=document.getElementById("audioPlayer");
}
//functions

function log(){
	//This Function is convinient for loging events to the console in fire bug and the element inspector
	window.console&& window.console.log.apply(window.console,arguments);
}
function getAjax(){
	//this Function is used so that we can extract the Ajax cretion for difernet brower from the app code
	return new XMLHttpRequest();
}
function loadSyncFile(src){
	var ajax=getAjax();
	ajax.open("GET",src,false);
	ajax.send(null);
	return ajax.responseText
}
function loadSyncDoc(src){
	var ajax=getAjax();
	ajax.open("GET",src,false);
	ajax.send(null);
	return ajax.responseXML || (new DOMParser()).parseFromString(ajax.responseText,"text/xml");
}
function loadTOC(){
	var toc = document.createElement("ol");
	toc.setAttribute("data-level","base");
	var current = toc;
	var levels = ["h1","h2","h3","h4","h5","h6","span"];
	var doc = loadSyncDoc(basePath+"ncc.html");
	var walker = document.createTreeWalker(
			doc,
			NodeFilter.SHOW_ELEMENT,
			function (node){
				if(node.tagName=="a"){
					switch(node.parentNode.tagName){
						case "h1":return NodeFilter.FILTER_ACCEPT;break;
						case "h2":return NodeFilter.FILTER_ACCEPT;break;
						case "h3":return NodeFilter.FILTER_ACCEPT;break;
						case "h4":return NodeFilter.FILTER_ACCEPT;break;
						case "h5":return NodeFilter.FILTER_ACCEPT;break;
						case "h6":return NodeFilter.FILTER_ACCEPT;break;
						case "span":return NodeFilter.FILTER_ACCEPT;break;
					}
				}
				return NodeFilter.FILTER_SKIP;
			},
			false
			);
	function playThis(){
		play(this.getAttribute("data-file"),this.getAttribute("data-id"));
	}
	function hideSub(){
			togleHide(this.parentNode.getElementsByTagName("ol")[0]);
			this.src=((this.parentNode.getElementsByTagName("ol")[0].style.display=="none")?this.closed_src:this.open_src);
	}
	while(walker.nextNode()){
		while(levels.indexOf(current.getAttribute("data-level"))>=levels.indexOf(walker.currentNode.parentNode.tagName)){
			current=current.parentNode.parentNode;
		}
		var li=document.createElement("li");
		var ol=document.createElement("ol");
		var a=document.createElement("a");
		var img=document.createElement("img");
		img.onclick=hideSub;
		img.style.width="15px";
		img.style.height="15px";
		img.open_src="Images/open.png";
		img.closed_src="Images/closed.png";
		img.src=img.open_src;
		li.appendChild(img);
		ol.setAttribute("data-level",walker.currentNode.parentNode.tagName);
		a.textContent=walker.currentNode.textContent;
		a.setAttribute("data-file",walker.currentNode.getAttribute("href").split("#")[0])
		a.setAttribute("data-id",walker.currentNode.getAttribute("href").split("#")[1])
		a.onclick=playThis;
		li.appendChild(a);
		li.appendChild(ol);
		img.onclick();
		current.appendChild(li);
		current=ol;
	}
	TOCDISPLAY.innerHTML="";
	TOCDISPLAY.appendChild(toc);
}
function loadSmil(){
	var toc=TOCDISPLAY.childNodes[0];
	walker=document.createTreeWalker(
			toc,
			NodeFilter.SHOW_ALL,
			function (node){
				if(node.hasAttribute && node.hasAttribute("data-file")){
					return NodeFilter.FILTER_ACCEPT;
				}
				return NodeFilter.FILTER_SKIP;
			},
			false
			);
	while(walker.nextNode()){
		log("starting with:"+walker.currentNode.getAttribute("data-file"));
		var doc= loadSyncDoc(basePath+walker.currentNode.getAttribute("data-file"));
		var w=document.createTreeWalker(
				doc,
				NodeFilter.SHOW_ALL,
				function (node){
					if(node.getAttribute && node.getAttribute("id") ||node.tagName=="audio" || node.tagName=="text"){
						return NodeFilter.FILTER_ACCEPT;
					}
					return NodeFilter.FILTER_SKIP;
				},
				false);
		while(w.nextNode() && w.currentNode.getAttribute("id")!=walker.currentNode.getAttribute("data-id")){}
		do{
			if(walker.nextNode()&& w.currentNode.getAttribute("id")!=walker.currentNode.getAttribute("data-id")){
				walker.previousNode();
			}
			switch(w.currentNode.tagName){
				case "audio":{
					var li=document.createElement("li");
					li.setAttribute("data-type",w.currentNode.tagName);
					li.setAttribute("data-src",basePath+w.currentNode.getAttribute("src"));
					li.setAttribute("data-start",w.currentNode.getAttribute("clip-begin").split("npt=")[1].split("s")[0]);
					li.setAttribute("data-stop",w.currentNode.getAttribute("clip-end").split("npt=")[1].split("s")[0]);
					walker.currentNode.nextSibling.appendChild(li);
				};break
				case "text":{
					var li=document.createElement("li");
					li.setAttribute("data-type",w.currentNode.tagName);
					li.setAttribute("data-src",basePath+w.currentNode.getAttribute("src").split("#")[0])
					li.setAttribute("data-id",w.currentNode.getAttribute("src").split("#")[1])
					walker.currentNode.nextSibling.appendChild(li);
				};break
			}
		}while(w.nextNode())
	}
}
function loadNCCTest(){
	var doc= loadSyncDoc(basePath+"ncc.html");
	var a=new Array();
	var walker = document.createTreeWalker(
			doc,
			NodeFilter.SHOW_ALL,
			function (node){
				if(node.tagName=="a"){
					switch(node.parentNode.tagName){
						case "h1":return NodeFilter.FILTER_ACCEPT;break;
						case "h2":return NodeFilter.FILTER_ACCEPT;break;
						case "h3":return NodeFilter.FILTER_ACCEPT;break;
						case "h4":return NodeFilter.FILTER_ACCEPT;break;
						case "h5":return NodeFilter.FILTER_ACCEPT;break;
						case "h6":return NodeFilter.FILTER_ACCEPT;break;
						case "span":return NodeFilter.FILTER_ACCEPT;break;
					}
				}
				return NodeFilter.FILTER_SKIP;
			},
			false
			);
	while(walker.nextNode()){
		//FIXME problem if href is "somthing#somthin#somting"
		var l=walker.currentNode.getAttribute("href").split("#");
		l[l.length]=walker.currentNode.parentNode.tagName;
		l[l.length]=walker.currentNode.textContent;//should it be HTML?
		a[a.length]=l;
	}
	return a;
}
function loadSmileTest(nccList){
	var smilHash={};
	var htmlHash={};
	var smil;
	var index;
	for(i in nccList){
		if(nccList[i][0] in smilHash){
		//=hash[nccList[i][0]];
		}else{
			var doc=loadSyncDoc(basePath+nccList[i][0]);
			var walker=document.createTreeWalker(
					doc,
					NodeFilter.SHOW_ELEMENT,
					function(node){
						if(node.getAttribute("id")){
							return NodeFilter.FILTER_ACCEPT;
						}
						switch(node.tagName.toLowerCase){
							case "text": return NodeFilter.FILTER_ACCEPT;break;
							case "audio":return NodeFilter.FILTER_ACCEPT;break;
						}
						return NodeFilter.FILTER_SKIP;
					},
					false
					);
			smil=[];
			index={};
			while(walker.nextNode()){
				if(walker.currentNode.getAttribute("id")){
					index[walker.currentNode.getAttribute("id")]=smil.length;
				}
				if(walker.currentNode.tagName.toLowerCase()=="audio"){
					smil[smil.length]=[
						"audio",
						basePath+walker.currentNode.getAttribute("src"),
						new Number(walker.currentNode.getAttribute("clip-begin").split("npt=")[1].split("s")[0]),
						new Number(walker.currentNode.getAttribute("clip-end").split("npt=")[1].split("s")[0]),
					];
				}else if(walker.currentNode.tagName.toLowerCase()=="text"){
					var text=basePath+walker.currentNode.getAttribute("src").split("#")[0];
					if(!(text in htmlHash)){
						var html={};
						var doc=loadSyncDoc(text);
						var w=document.createTreeWalker(
								doc,
								NodeFilter.SHOW_ELEMENT,
								function(node){
									if(node.getAttribute("id")){
										return NodeFilter.FILTER_ACCEPT;
									}else{
										return NodeFilter.FILTER_SKIP;
									}
								},
								false
								);
						while(w.nextNode()){
							html[w.currentNode.getAttribute("id")]=w.currentNode.textContent;
						}
						htmlHash[text]=html;
					}
					smil[smil.length]=[
						"text",
						text,
						walker.currentNode.getAttribute("src").split("#")[1],
					];
				}
			}
			smilHash[nccList[i][0]]=[index,smil];
		}
	}
	return [smilHash,htmlHash];
}
function loadTest(){
	var nccList=loadNCCTest();
	var tmp=loadSmileTest(nccList);
	return [nccList,tmp[0],tmp[1]];
}
function setProgress(width){
PROGRESS.style.width=width;
}
function setProgressMsg(s){
	PROGRESSDISPLAY.innerHTML=String(s);
}
function loadNCC(){
	setProgressMsg("Loading Ncc..");
	setProgress("0%");
	var file=loadSyncFile(basePath+"ncc.html")
	setProgress("25%");
	file=file.replace(/(?:.|\n)*((?:.|\n)*)<\/body>(?:.|\n)*/gim,"$1");
	setProgress("50%");
	file=file.replace(
			/(.*)<\/a>/g,
			"$5<\/span>"
			);
	setProgress("75%");
	TOCDISPLAY.innerHTML=file;
	setProgress("100%");
	setProgressMsg("Ncc Loaded");
}
//function bindings
function load(){
	//return loadAll();
	//var a=loadTest();
	//fillTOC(a[0]);
	loadTOC();
	//smils=a[1];
	//htmls=a[2];
	if($("state")){$("state").setAttribute("data-state","on");}
	loadSmil();
}
function play(file,id){
	if($("state")){$("state").setAttribute("data-state","playing");}
	if (id==undefined && file==undefined){
		index-=1;
		skip();
		return;
	}
	loadID(file,id);
}
function skip(){
	if(AUDIOPLAYER.timeOut)clearTimeout(AUDIOPLAYER.timeOut);
	AUDIOPLAYER.pause();
	index=index+1;
	var smilList=smil[1];
	if(smilList[index][0]=="text"){
		loadText(smilList,5);
		index=index+1;
		loadAudio(smilList);
	}else if (smilList[index][0]="audio"){
		loadAudio(smilList);
	}
	AUDIOPLAYER.play();
}
function stop(){
	if(AUDIOPLAYER.timeOut)clearTimeout(AUDIOPLAYER.timeOut);
	AUDIOPLAYER.pause();
	if($("state")){$("state").setAttribute("data-state","on");}
}
function loadText(smilList,width){
		function f(e,i,a){
			return (e[0]=='text')?e.concat(i==index):undefined;
		}
		function m(e,i,a){
				var alpha=1-Math.abs((i/a.length-0.5))*2;//Fix me: wrong opacity in begining and end of smil
				return (e[3])?""+htmls[e[1]][e[2]]+"":""+htmls[e[1]][e[2]]+"";
		}
		var a=smilList.map(f);
		a=a.filter(function (e){return e});
		if(width){
			var I;
			a.forEach(function (e,i,a){if(e[3]==true)I=i});
			a=a.slice(Math.max(new Number(I)-width,0),Math.min(new Number(I)+width+1,a.length));
		}
		var text=a.map(m).join("
");
		TEXTDISPLAY.innerHTML=text;//htmls[smilList[index][1]][smilList[index][2]]
}
function loadAudio(smilList){
			if(AUDIOPLAYER.timeOut)clearTimeout(AUDIOPLAYER.timeOut);
			function wait(){
				AUDIOPLAYER.pause();
				if(AUDIOPLAYER.readyState==4){
					log("readyState==4");
					AUDIOPLAYER.currentTime=smilList[index][2];
					AUDIOPLAYER.play();
					if(AUDIOPLAYER.timeOut)clearTimeout(AUDIOPLAYER.timeOut);
					AUDIOPLAYER.timeOut=setTimeout(skip,(smilList[index][3]-smilList[index][2])*1000);
				}
				else{
					log("readyState=="+AUDIOPLAYER.readyState+" i.e. not 4");
					AUDIOPLAYER.pause();
				}
			}
			AUDIOPLAYER.src=smilList[index][1];
			if(AUDIOPLAYER.src!=AUDIOPLAYER.currentSrc)AUDIOPLAYER.load();
			AUDIOPLAYER.pause();
			AUDIOPLAYER.onload=wait;
			try{
				wait();
			}catch(err){}
}
function loadID(file,id){
	smil=smils[file];
	var indexDict=smil[0];
	var smilList=smil[1];
	index=indexDict[id];
	if(smilList[index][0]=="text"){
		loadText(smilList,5);
		index=index+1;
		loadAudio(smilList);
	}else if (smilList[index][0]="audio"){
		loadAudio(smilList);
	}
	if($("state")){$("state").setAttribute("data-state","playing");}
}
window.addEventListener("keypress",function (e){
			e=e || window.event;
			if(e.altKey || e.ctrlKey || e.shiftKey){
				return;
			}
			switch(String.fromCharCode(e.keyCode || e.charCode)){
				case "l":load();break;
				case "p":play();break;
				case "s":skip();break;
				case "f":forward();break;
				case "b":backward();break;
			}
		},false);

<commit_msg>deleated old code and added a playlist variable to replace the old datastructures in the script file.<commit_after>//urls
if(!$){
	function $(){
		return document.getElementById.apply(document,arguments)
	}
}
if(!window.basePath)basePath="media/";//sets but dossent over write
function loadConstants (){
	TEXTDISPLAY=document.getElementById("textDisplay");
	TOCDISPLAY=document.getElementById("tocDisplay")
	PROGRESSDISPLAY=document.getElementById("progressDisplay");
	PROGRESS=document.getElementById("progress");
	AUDIOPLAYER=document.getElementById("audioPlayer");
}
//functions

function log(){
	//This Function is convinient for loging events to the console in fire bug and the element inspector
	window.console&& window.console.log.apply(window.console,arguments);
}
function getAjax(){
	//this Function is used so that we can extract the Ajax cretion for difernet brower from the app code
	return new XMLHttpRequest();
}
function loadSyncFile(src){
	var ajax=getAjax();
	ajax.open("GET",src,false);
	ajax.send(null);
	return ajax.responseText
}
function loadSyncDoc(src){
	var ajax=getAjax();
	ajax.open("GET",src,false);
	ajax.send(null);
	return ajax.responseXML || (new DOMParser()).parseFromString(ajax.responseText,"text/xml");
}
function loadTOC(){
	var toc = document.createElement("ol");
	toc.setAttribute("data-level","base");
	var current = toc;
	var levels = ["h1","h2","h3","h4","h5","h6","span"];
	var doc = loadSyncDoc(basePath+"ncc.html");
	var walker = document.createTreeWalker(
			doc,
			NodeFilter.SHOW_ELEMENT,
			function (node){
				if(node.tagName=="a"){
					switch(node.parentNode.tagName){
						case "h1":return NodeFilter.FILTER_ACCEPT;break;
						case "h2":return NodeFilter.FILTER_ACCEPT;break;
						case "h3":return NodeFilter.FILTER_ACCEPT;break;
						case "h4":return NodeFilter.FILTER_ACCEPT;break;
						case "h5":return NodeFilter.FILTER_ACCEPT;break;
						case "h6":return NodeFilter.FILTER_ACCEPT;break;
						case "span":return NodeFilter.FILTER_ACCEPT;break;
					}
				}
				return NodeFilter.FILTER_SKIP;
			},
			false
			);
	function playThis(){
		play(this.getAttribute("data-file"),this.getAttribute("data-id"));
	}
	function hideSub(){
			togleHide(this.parentNode.getElementsByTagName("ol")[0]);
			this.src=((this.parentNode.getElementsByTagName("ol")[0].style.display=="none")?this.closed_src:this.open_src);
	}
	while(walker.nextNode()){
		while(levels.indexOf(current.getAttribute("data-level"))>=levels.indexOf(walker.currentNode.parentNode.tagName)){
			current=current.parentNode.parentNode;
		}
		var li=document.createElement("li");
		var ol=document.createElement("ol");
		var a=document.createElement("a");
		var img=document.createElement("img");
		img.onclick=hideSub;
		img.style.width="15px";
		img.style.height="15px";
		img.open_src="Images/open.png";
		img.closed_src="Images/closed.png";
		img.src=img.open_src;
		li.appendChild(img);
		ol.setAttribute("data-level",walker.currentNode.parentNode.tagName);
		a.textContent=walker.currentNode.textContent;
		a.setAttribute("data-file",walker.currentNode.getAttribute("href").split("#")[0])
		a.setAttribute("data-id",walker.currentNode.getAttribute("href").split("#")[1])
		a.onclick=playThis;
		li.appendChild(a);
		li.appendChild(ol);
		img.onclick();
		current.appendChild(li);
		current=ol;
	}
	TOCDISPLAY.innerHTML="";
	TOCDISPLAY.appendChild(toc);
}
function loadSmil(){
	var toc=TOCDISPLAY.childNodes[0];
	walker=document.createTreeWalker(
			toc,
			NodeFilter.SHOW_ALL,
			function (node){
				if(node.hasAttribute && node.hasAttribute("data-file")){
					return NodeFilter.FILTER_ACCEPT;
				}
				return NodeFilter.FILTER_SKIP;
			},
			false
			);
	while(walker.nextNode()){
		log("starting with:"+walker.currentNode.getAttribute("data-file"));
		var doc= loadSyncDoc(basePath+walker.currentNode.getAttribute("data-file"));
		var w=document.createTreeWalker(
				doc,
				NodeFilter.SHOW_ALL,
				function (node){
					if(node.getAttribute && node.getAttribute("id") ||node.tagName=="audio" || node.tagName=="text"){
						return NodeFilter.FILTER_ACCEPT;
					}
					return NodeFilter.FILTER_SKIP;
				},
				false);
		while(w.nextNode() && w.currentNode.getAttribute("id")!=walker.currentNode.getAttribute("data-id")){}
		do{
			if(walker.nextNode()&& w.currentNode.getAttribute("id")!=walker.currentNode.getAttribute("data-id")){
				walker.previousNode();
			}
			switch(w.currentNode.tagName){
				case "audio":{
					var li=document.createElement("li");
					li.setAttribute("data-type",w.currentNode.tagName);
					li.setAttribute("data-src",basePath+w.currentNode.getAttribute("src"));
					li.setAttribute("data-start",w.currentNode.getAttribute("clip-begin").split("npt=")[1].split("s")[0]);
					li.setAttribute("data-stop",w.currentNode.getAttribute("clip-end").split("npt=")[1].split("s")[0]);
					walker.currentNode.nextSibling.appendChild(li);
				};break
				case "text":{
					var li=document.createElement("li");
					li.setAttribute("data-type",w.currentNode.tagName);
					li.setAttribute("data-src",basePath+w.currentNode.getAttribute("src").split("#")[0])
					li.setAttribute("data-id",w.currentNode.getAttribute("src").split("#")[1])
					walker.currentNode.nextSibling.appendChild(li);
				};break
			}
		}while(w.nextNode())
	}
	window.playlist=document.createTreeWalker(TOCDISPLAY,NodeFilter.SHOW_ELEMENT,
			function (node){
				if(node.tagName.toLowerCase()=="li" && node.hasAttribute("data-type")){
					return NodeFilter.FILTER_ACCEPT;
				}
				else{
					return NodeFilter.FILTER_SKIP;
				}
			}
			,false);
	playlist.nextNode();
}
function loadSmileTest(nccList){
	var smilHash={};
	var htmlHash={};
	var smil;
	var index;
	for(i in nccList){
		if(nccList[i][0] in smilHash){
		//=hash[nccList[i][0]];
		}else{
			var doc=loadSyncDoc(basePath+nccList[i][0]);
			var walker=document.createTreeWalker(
					doc,
					NodeFilter.SHOW_ELEMENT,
					function(node){
						if(node.getAttribute("id")){
							return NodeFilter.FILTER_ACCEPT;
						}
						switch(node.tagName.toLowerCase){
							case "text": return NodeFilter.FILTER_ACCEPT;break;
							case "audio":return NodeFilter.FILTER_ACCEPT;break;
						}
						return NodeFilter.FILTER_SKIP;
					},
					false
					);
			smil=[];
			index={};
			while(walker.nextNode()){
				if(walker.currentNode.getAttribute("id")){
					index[walker.currentNode.getAttribute("id")]=smil.length;
				}
				if(walker.currentNode.tagName.toLowerCase()=="audio"){
					smil[smil.length]=[
						"audio",
						basePath+walker.currentNode.getAttribute("src"),
						new Number(walker.currentNode.getAttribute("clip-begin").split("npt=")[1].split("s")[0]),
						new Number(walker.currentNode.getAttribute("clip-end").split("npt=")[1].split("s")[0]),
					];
				}else if(walker.currentNode.tagName.toLowerCase()=="text"){
					var text=basePath+walker.currentNode.getAttribute("src").split("#")[0];
					if(!(text in htmlHash)){
						var html={};
						var doc=loadSyncDoc(text);
						var w=document.createTreeWalker(
								doc,
								NodeFilter.SHOW_ELEMENT,
								function(node){
									if(node.getAttribute("id")){
										return NodeFilter.FILTER_ACCEPT;
									}else{
										return NodeFilter.FILTER_SKIP;
									}
								},
								false
								);
						while(w.nextNode()){
							html[w.currentNode.getAttribute("id")]=w.currentNode.textContent;
						}
						htmlHash[text]=html;
					}
					smil[smil.length]=[
						"text",
						text,
						walker.currentNode.getAttribute("src").split("#")[1],
					];
				}
			}
			smilHash[nccList[i][0]]=[index,smil];
		}
	}
	return [smilHash,htmlHash];
}
function load(){
	loadTOC();
	if($("state")){$("state").setAttribute("data-state","on");}
	loadSmil();
}
function play(file,id){
	if($("state")){$("state").setAttribute("data-state","playing");}
	if (id==undefined && file==undefined){
		index-=1;
		skip();
		return;
	}
	loadID(file,id);
}
function skip(){
	if(AUDIOPLAYER.timeOut)clearTimeout(AUDIOPLAYER.timeOut);
	AUDIOPLAYER.pause();
	index=index+1;
	var smilList=smil[1];
	if(smilList[index][0]=="text"){
		loadText(smilList,5);
		index=index+1;
		loadAudio(smilList);
	}else if (smilList[index][0]="audio"){
		loadAudio(smilList);
	}
	AUDIOPLAYER.play();
}
function stop(){
	if(AUDIOPLAYER.timeOut)clearTimeout(AUDIOPLAYER.timeOut);
	AUDIOPLAYER.pause();
	if($("state")){$("state").setAttribute("data-state","on");}
}
function loadText(smilList,width){
		function f(e,i,a){
			return (e[0]=='text')?e.concat(i==index):undefined;
		}
		function m(e,i,a){
				var alpha=1-Math.abs((i/a.length-0.5))*2;//Fix me: wrong opacity in begining and end of smil
				return (e[3])?""+htmls[e[1]][e[2]]+"":""+htmls[e[1]][e[2]]+"";
		}
		var a=smilList.map(f);
		a=a.filter(function (e){return e});
		if(width){
			var I;
			a.forEach(function (e,i,a){if(e[3]==true)I=i});
			a=a.slice(Math.max(new Number(I)-width,0),Math.min(new Number(I)+width+1,a.length));
		}
		var text=a.map(m).join("
");
		TEXTDISPLAY.innerHTML=text;//htmls[smilList[index][1]][smilList[index][2]]
}
function loadAudio(smilList){
			if(AUDIOPLAYER.timeOut)clearTimeout(AUDIOPLAYER.timeOut);
			function wait(){
				AUDIOPLAYER.pause();
				if(AUDIOPLAYER.readyState==4){
					log("readyState==4");
					AUDIOPLAYER.currentTime=smilList[index][2];
					AUDIOPLAYER.play();
					if(AUDIOPLAYER.timeOut)clearTimeout(AUDIOPLAYER.timeOut);
					AUDIOPLAYER.timeOut=setTimeout(skip,(smilList[index][3]-smilList[index][2])*1000);
				}
				else{
					log("readyState=="+AUDIOPLAYER.readyState+" i.e. not 4");
					AUDIOPLAYER.pause();
				}
			}
			AUDIOPLAYER.src=smilList[index][1];
			if(AUDIOPLAYER.src!=AUDIOPLAYER.currentSrc)AUDIOPLAYER.load();
			AUDIOPLAYER.pause();
			AUDIOPLAYER.onload=wait;
			try{
				wait();
			}catch(err){}
}
function loadID(file,id){
	smil=smils[file];
	var indexDict=smil[0];
	var smilList=smil[1];
	index=indexDict[id];
	if(smilList[index][0]=="text"){
		loadText(smilList,5);
		index=index+1;
		loadAudio(smilList);
	}else if (smilList[index][0]="audio"){
		loadAudio(smilList);
	}
	if($("state")){$("state").setAttribute("data-state","playing");}
}
window.addEventListener("keypress",function (e){
			e=e || window.event;
			if(e.altKey || e.ctrlKey || e.shiftKey){
				return;
			}
			switch(String.fromCharCode(e.keyCode || e.charCode)){
				case "l":load();break;
				case "p":play();break;
				case "s":skip();break;
				case "f":forward();break;
				case "b":backward();break;
			}
		},false);

<|endoftext|>


<commit_before>module.exports = {
  backendRoot: 'https://obscure-woodland-71302.herokuapp.com/',
  graphQLRoot: (process.env.NODE_ENV !== 'production') ? '//localhost:5000/graphql' : '//catappdatabase.herokuapp.com/graphql',
};
// Alternative: //catapp-console.herokuapp.com/graphql
<commit_msg>Changed options to quickly change overall layout style<commit_after>module.exports = {
  backendRoot: 'https://obscure-woodland-71302.herokuapp.com/',
  graphQLRoot: (process.env.NODE_ENV !== 'production') ? '//localhost:5000/graphql' : '//catappdatabase.herokuapp.com/graphql',
  suBranding: true,
  appBar: true,

};
<|endoftext|>


<commit_before>module.exports = {
  backendRoot: 'https://obscure-woodland-71302.herokuapp.com/',
  /* graphQLRoot: (process.env.NODE_ENV !== 'production') ? '//localhost:5000/graphql' : '//catappdatabase.herokuapp.com/graphql', */
  graphQLRoot: '//catappdatabase.herokuapp.com/graphql',
  whiteLabel: false,
  suBranding: false,
  appBar: true,
  version: '0.1.0',
  gaTrackingId: 'UA-109061730-1',
};
<commit_msg>Bumped bugfix version<commit_after>module.exports = {
  backendRoot: 'https://obscure-woodland-71302.herokuapp.com/',
  /* graphQLRoot: (process.env.NODE_ENV !== 'production') ? '//localhost:5000/graphql' : '//catappdatabase.herokuapp.com/graphql', */
  graphQLRoot: '//catappdatabase.herokuapp.com/graphql',
  whiteLabel: false,
  suBranding: false,
  appBar: true,
  version: '0.1.1',
  gaTrackingId: 'UA-109061730-1',
};
<|endoftext|>


<commit_before>'use strict';

angular.module('myApp.runs', ['ngRoute', 'ngMap', 'ngGeolocation', 'ngAnimate', 'toastr'])

    .config(['$routeProvider', function ($routeProvider) {
        $routeProvider.when('/runs/:userid', {
            templateUrl: 'views/runs/runs.html',
            controller: 'RunCtrl as vm'
        });
    }])

    .controller('RunCtrl', function ($scope, $http, $routeParams, $filter,
                                    $mdDialog, toastr, $route, NgMap, $geolocation) {
        $scope.storageuser = JSON.parse(localStorage.getItem("fs_web_userdata"));
        $scope.user=[];
        $scope.run={};
        $scope.centerPos={
            lat: 0,
            long: 0
        };
        var vm = this;
        vm.run={
            name: "polyline",
            path: [[]]
        };
        $scope.selectRun=function(run){
            $http.get(urlapi + "runs/byRunId/" + run._id)
              .then(function (data) {
                  console.log('data success');
                  console.log(data); // for browser console
                  $scope.run=data.data;
                  /* ara pintem al mapa */
                  vm.run={
                      name: "polyline",
                      path: []
                  };
                  for(var i=0; i<run.positions.length; i++)
                  {
                      vm.run.path.push([run.positions[i].lat, run.positions[i].long]);
                  }
                  $scope.centerPos.lat=run.positions[0].lat;
                  $scope.centerPos.long=run.positions[0].long;

              }, function (data, status) {
                  console.log('data error');
                  console.log(status);
                  console.log(data);
              });
        };
        $scope.centerMap = function (pos) {
            $scope.centerPos.lat=pos.lat;
            $scope.centerPos.long=pos.long;
        };

        $scope.myPosition={};
        $scope.geoActivated=false;
        /* primer pillem la localització no exacte a partir de la ip
        per si l'user no accepta activar la geolocalització, almenys
        així tenim la localització basada en la ip */
        var ip = $.getJSON('//freegeoip.net/json/?callback=?', function(data) {
            ip = data;
            console.log(ip);
            $scope.myPosition={
                coords:{
                    latitude: ip.latitude,
                    longitude: ip.longitude
                }
            };
            console.log($scope.myPosition.coords);
        });
        /* geolocation */
        $geolocation.getCurrentPosition({
            timeout: 60000
         }).then(function(position) {
            $scope.geoActivated=true;
            $scope.myPosition = position;
            console.log($scope.myPosition.coords);
        });
        /* end of geolocation */
        /* map */
        NgMap.getMap().then(function(map) {
            console.log(map.getCenter());
            console.log('markers', map.markers);
            console.log('shapes', map.shapes);
          });
        /* end of map */

        $http.get(urlapi + "runs/byUserId/" + $routeParams.userid)
          .then(function (data) {
              console.log('data success');
              console.log(data); // for browser console
              $scope.user=data.data;
              $scope.selectRun($scope.user.runs[$scope.user.runs.length-1]);
          }, function (data, status) {
              console.log('data error');
              console.log(status);
              console.log(data);
          });
    });
<commit_msg>arreglat<commit_after>'use strict';

angular.module('myApp.runs', ['ngRoute', 'ngMap', 'ngGeolocation', 'ngAnimate', 'toastr'])

    .config(['$routeProvider', function ($routeProvider) {
        $routeProvider.when('/runs/:userid', {
            templateUrl: 'views/runs/runs.html',
            controller: 'RunCtrl as vm'
        });
    }])

    .controller('RunCtrl', function ($scope, $http, $routeParams, $filter,
                                    $mdDialog, toastr, $route, NgMap, $geolocation) {
        $scope.storageuser = JSON.parse(localStorage.getItem("fs_web_userdata"));
        $scope.user=[];
        $scope.run={};
        $scope.centerPos={
            lat: 0,
            long: 0
        };
        var vm = this;
        vm.run={
            name: "polyline",
            path: [[]]
        };
        $scope.selectRun=function(run){
            $http.get(urlapi + "runs/byRunId/" + run._id)
              .then(function (data) {
                  console.log('data success');
                  console.log(data); // for browser console
                  $scope.run=data.data;
                  /* ara pintem al mapa */
                  vm.run={
                      name: "polyline",
                      path: []
                  };
                  for(var i=0; i<run.positions.length; i++)
                  {
                      vm.run.path.push([run.positions[i].lat, run.positions[i].long]);
                  }
                  $scope.centerPos.lat=run.positions[0].lat;
                  $scope.centerPos.long=run.positions[0].long;

              }, function (data, status) {
                  console.log('data error');
                  console.log(status);
                  console.log(data);
              });
        };
        $scope.centerMap = function (pos) {
            $scope.centerPos.lat=pos.lat;
            $scope.centerPos.long=pos.long;
        };

        $scope.myPosition={};
        $scope.geoActivated=false;
        /* primer pillem la localització no exacte a partir de la ip
        per si l'user no accepta activar la geolocalització, almenys
        així tenim la localització basada en la ip */
        var ip = $.getJSON('//freegeoip.net/json/?callback=?', function(data) {
            ip = data;
            console.log(ip);
            $scope.myPosition={
                coords:{
                    latitude: ip.latitude,
                    longitude: ip.longitude
                }
            };
            console.log($scope.myPosition.coords);
        });
        /* geolocation */
        $geolocation.getCurrentPosition({
            timeout: 60000
         }).then(function(position) {
            $scope.geoActivated=true;
            $scope.myPosition = position;
            console.log($scope.myPosition.coords);
        });
        /* end of geolocation */
        /* map */
        NgMap.getMap().then(function(map) {
            console.log(map.getCenter());
            console.log('markers', map.markers);
            console.log('shapes', map.shapes);
          });
        /* end of map */

        $http.get(urlapi + "runs/byUserId/" + $routeParams.userid)
          .then(function (data) {
              console.log('data success');
              console.log(data); // for browser console
              $scope.user=data.data;
              if($scope.user.runs)
              {
                  $scope.selectRun($scope.user.runs[$scope.user.runs.length-1]);
              }
          }, function (data, status) {
              console.log('data error');
              console.log(status);
              console.log(data);
          });
    });
<|endoftext|>


<commit_before>// This is mock data for testing purpose
import { totalDaysInYear } from './helper'

const getBoxes = year => {
  const contributeOrNot = (count, at) => (count === 0 ? 'No contributions' : `${count} contributions`)
  const totalDays = totalDaysInYear(year)
  const boxes = []
  for (let i = 0; i <= totalDays; i++) {
    boxes.push({
      id: `b${i}`,
      color: ['#ecf0f1', '#2ecc71', '#f1c40f', '#f39c12', '#e67e22', '#d35400', '#e74c3c'][Math.floor(Math.random() * 7)],
      data: `${contributeOrNot(Math.floor(10 * Math.random()))} on ${new Date(year, 0, i).toDateString()}`
    })
  }

  return boxes
}

export { getBoxes }
<commit_msg>refactor(seeder): Correct colors<commit_after>// This is mock data for testing purpose
import { totalDaysInYear } from './helper'

const getBoxes = year => {
  const colors = ['#eeeeee', '#c6e48b', '#7bc96f', '#239a3b', '#196127']
  const getColorFromContributeTime = contributeTime => {
    const maxContributions = 20
    const total = colors.length - 1
    const time = Math.min(contributeTime, maxContributions) / maxContributions
    console.log(contributeTime, time)
    return colors[Math.floor(time * total)]
  }
  const contributeOrNot = (count, at) => (count === 0 ? 'No contributions' : `${count} contributions`)

  const totalDays = totalDaysInYear(year)
  const boxes = []
  for (let i = 0; i <= totalDays; i++) {
    const contributeTime = Math.floor(20 * Math.random())
    boxes.push({
      id: `b${i}`,
      color: getColorFromContributeTime(contributeTime),
      data: `${contributeOrNot(contributeTime)} on ${new Date(year, 0, i).toDateString()}`
    })
  }

  return boxes
}

export { getBoxes }
<|endoftext|>


<commit_before>/**
 * # Select
 *
 * Construct a unique CSS queryselector to access the selected DOM element(s).
 * Applies different matching and optimization strategies for efficiency.
 */

import adapt from './adapt'
import match from './match'
import optimize from './optimize'
import { getCommonAncestor, getCommonProperties } from './common'

/**
 * Choose action depending on the input (single/multi)
 *
 * @param  {HTMLElement|Array.<HTMLElement>} input   - [description]
 * @param  {Object}                          options - [description]
 * @return {string}                                  - [description]
 */
export default function getQuerySelector (input, options = {}) {
  if (Array.isArray(input)) {
    return getMultiSelector(input, options)
  }
  return getSingleSelector(input, options)
}

/**
 * Get a selector for the provided element
 *
 * @param  {HTMLElement} element - [description]
 * @param  {Object}      options - [description]
 * @return {string}              - [description]
 */
export function getSingleSelector (element, options = {}) {

  if (element.nodeType === 3) {
    element = element.parentNode
  }
  if (element.nodeType !== 1) {
    throw new Error(`Invalid input - only HTMLElements or representations of them are supported! (not "${typeof element}")`)
  }

  const globalModified = adapt(element, options)

  const selector = match(element, options)
  const optimized = optimize(selector, element, options)

  // debug
  // console.log(`
  //   selector:  ${selector}
  //   optimized: ${optimized}
  // `)

  if (globalModified) {
    delete global.document
  }

  return optimized
}

/**
 * Get a selector to match multiple descendants from an ancestor
 *
 * @param  {Array.<HTMLElement>} elements - [description]
 * @param  {Object}              options  - [description]
 * @return {string}                       - [description]
 */
export function getMultiSelector (elements, options = {}) {

  if (elements.some((element) => element.nodeType !== 1)) {
    throw new Error(`Invalid input - only an Array of HTMLElements or representations of them is supported!`)
  }

  const globalModified = adapt(elements[0], options)

  const ancestor = getCommonAncestor(elements, options)
  const ancestorSelector = getSingleSelector(ancestor, options)

  // TODO: consider usage of multiple selectors + parent-child relation
  const commonSelectors = getCommonSelectors(elements)
  const descendantSelector = commonSelectors[0]

  const selector = `${ancestorSelector} ${descendantSelector}`
  const selectorMatches = [...document.querySelectorAll(selector)]

  if (!elements.every((element) => selectorMatches.some((entry) => entry === element) )) {
    // TODO: cluster matches to split into similar groups for sub selections
    return console.warn(`
      The selected elements can\'t be efficiently mapped.
      Its probably best to use multiple single selectors instead!
    `, elements)
  }

  if (globalModified) {
    delete global.document
  }

  return selector
}

/**
 * Get selectors to describe a set of elements
 *
 * @param  {Array.<HTMLElements>} elements - [description]
 * @return {string}                        - [description]
 */
function getCommonSelectors (elements) {

  const { classes, attributes, tag } = getCommonProperties(elements)

  const selectorPath = []

   if (tag) {
     selectorPath.push(tag)
   }

   if (classes) {
     const classSelector = classes.map((name) => `.${name}`).join('')
     selectorPath.push(classSelector)
   }

   if (attributes) {
     const attributeSelector = Object.keys(attributes).reduce((parts, name) => {
       parts.push(`[${name}="${attributes[name]}"]`)
       return parts
     }, []).join('')
     selectorPath.push(attributeSelector)
   }

   if (selectorPath.length) {
     // TODO: check for parent-child relation
   }

   return [
     selectorPath.join('')
   ]
 }
<commit_msg>accept 'NodeList' input<commit_after>/**
 * # Select
 *
 * Construct a unique CSS queryselector to access the selected DOM element(s).
 * Applies different matching and optimization strategies for efficiency.
 */

import adapt from './adapt'
import match from './match'
import optimize from './optimize'
import { getCommonAncestor, getCommonProperties } from './common'

/**
 * Choose action depending on the input (single/multi)
 *
 * @param  {HTMLElement|Array.<HTMLElement>} input   - [description]
 * @param  {Object}                          options - [description]
 * @return {string}                                  - [description]
 */
export default function getQuerySelector (input, options = {}) {
  if (!input.length) {
    return getSingleSelector(input, options)
  }
  return getMultiSelector(input, options)
}

/**
 * Get a selector for the provided element
 *
 * @param  {HTMLElement} element - [description]
 * @param  {Object}      options - [description]
 * @return {string}              - [description]
 */
export function getSingleSelector (element, options = {}) {

  if (element.nodeType === 3) {
    element = element.parentNode
  }
  if (element.nodeType !== 1) {
    throw new Error(`Invalid input - only HTMLElements or representations of them are supported! (not "${typeof element}")`)
  }

  const globalModified = adapt(element, options)

  const selector = match(element, options)
  const optimized = optimize(selector, element, options)

  // debug
  // console.log(`
  //   selector:  ${selector}
  //   optimized: ${optimized}
  // `)

  if (globalModified) {
    delete global.document
  }

  return optimized
}

/**
 * Get a selector to match multiple descendants from an ancestor
 *
 * @param  {Array.<HTMLElement>} elements - [description]
 * @param  {Object}              options  - [description]
 * @return {string}                       - [description]
 */
export function getMultiSelector (elements, options = {}) {

  if (!Array.isArray(elements)) {
    elements = [...elements]
  }

  if (elements.some((element) => element.nodeType !== 1)) {
    throw new Error(`Invalid input - only an Array of HTMLElements or representations of them is supported!`)
  }

  const globalModified = adapt(elements[0], options)

  const ancestor = getCommonAncestor(elements, options)
  const ancestorSelector = getSingleSelector(ancestor, options)

  // TODO: consider usage of multiple selectors + parent-child relation + check for part redundancy
  const commonSelectors = getCommonSelectors(elements)
  const descendantSelector = commonSelectors[0]

  const selector = optimize(`${ancestorSelector} ${descendantSelector}`, elements, options)
  const selectorMatches = [...document.querySelectorAll(selector)]

  if (!elements.every((element) => selectorMatches.some((entry) => entry === element) )) {
    // TODO: cluster matches to split into similar groups for sub selections
    return console.warn(`
      The selected elements can\'t be efficiently mapped.
      Its probably best to use multiple single selectors instead!
    `, elements)
  }

  if (globalModified) {
    delete global.document
  }

  return selector
}

/**
 * Get selectors to describe a set of elements
 *
 * @param  {Array.<HTMLElements>} elements - [description]
 * @return {string}                        - [description]
 */
function getCommonSelectors (elements) {

  const { classes, attributes, tag } = getCommonProperties(elements)

  const selectorPath = []

  if (tag) {
    selectorPath.push(tag)
  }

  if (classes) {
    const classSelector = classes.map((name) => `.${name}`).join('')
    selectorPath.push(classSelector)
  }

  if (attributes) {
    const attributeSelector = Object.keys(attributes).reduce((parts, name) => {
      parts.push(`[${name}="${attributes[name]}"]`)
      return parts
    }, []).join('')
    selectorPath.push(attributeSelector)
  }

  if (selectorPath.length) {
    // TODO: check for parent-child relation
  }

  return [
    selectorPath.join('')
  ]
}
<|endoftext|>


<commit_before>'use strict'

const weighted = require('weighted');

function choose(arr) {
    return arr[Math.floor(Math.random()*arr.length)];
}

function galaxyGenerator() {
    const galaxyName = () => {
        const classificationName = () => {
            let name = '';
            do {
                name += Math.random().toString(36).substr(0,1);
            } while (Math.random() < 0.25);

            return name;
        };
        const standardName = () => {
            return choose(['Andromeda', 'Big Daddy', 'Tencent', 'Fubar', 'Johnny', 'Sixty-O', 'Dfjsktisd', 'Lemonade']);
        }

        return choose([classificationName, standardName])()
    };

    const galaxyId = () => {
        var name = galaxyName();
        var type = choose(['huge', 'giant', 'colossal', 'average', 'medium', 'small', 'tiny', 'miniscule']) + ' ' +
            choose(['grey', 'blue', 'green', 'rainbow', 'puke-colored', 'magenta', 'black as night']) + ' ' +
            choose(['elliptical', 'spherical', 'spiral', 'S0', 'irregular']);
        return `The ${name} galaxy is a ${type} galaxy.`;
    }

    const galaxyCharacteristic = () => {
        return choose(
            ['Its nearest neighbor is ' + choose([galaxyName() + ' galaxy', 'a black hole', 'a dark matter reactor', 'the pocket universe ' + galaxyName()]),
            'Its prominent feature is ' + choose(['a black hole', 'a dyson sphere', 'intelligent life', 'a historic event']),
            'It has ' + Math.random() + choose([' stars', ' planets', ' fast food joints'])
            ]);
    }
    return choose(
        [
            galaxyId,
            galaxyCharacteristic
        ]
    )();
}

export class RandomSensor {
    retrieveData() {
        return galaxyGenerator();
    }
}

export class StaticSensor {
    retrieveData() {
        return 'Earth is roughly a sphere.'
    }
};
<commit_msg>Start playing with a node based architecture.<commit_after>'use strict'

const weighted = require('weighted');

// TODO: Make a class, move
/* node = {
    characteristics: [],
    type: string,
    parent: node
    children: []
    max-children: Number,
    description: string
 }*/

function choose(arr) {
    return arr[Math.floor(Math.random()*arr.length)];
}

function generateGalaxyDescription() {
    const galaxyName = () => {
        const classificationName = () => {
            let name = '';
            do {
                name += Math.random().toString(36).substr(0,5);
            } while (Math.random() > 0.25);

            return name;
        };
        const standardName = () => {
            return choose(['Andromeda', 'Big Daddy', 'Tencent', 'Fubar', 'Johnny', 'Sixty-O', 'Dfjsktisd', 'Lemonade']);
        }

        return choose([classificationName, standardName])()
    };

    return galaxyName();
}

function generateBlackHoleDescription() {
    return 'Black Hole ' + Math.floor(Math.random() * 1000);
}

function generateSolarSystemDescription() {
    return 'Solar System ' + Math.floor(Math.random() * 1000);
}

function galaxyCharacteristicGenerator() {
    const galaxyId = () => {
        var type = choose(['huge', 'giant', 'colossal', 'average', 'medium', 'small', 'tiny', 'miniscule']) + ' ' +
            choose(['grey', 'blue', 'green', 'rainbow', 'puke-colored', 'magenta', 'black as night']) + ' ' +
            choose(['elliptical', 'spherical', 'spiral', 'S0', 'irregular']);
        return `It is a ${type} galaxy.`;
    }

    const galaxyCharacteristic = () => {
        return choose(
            ['Its nearest neighbor is ' + choose([generateGalaxyDescription() + ' galaxy', 'a black hole', 'a dark matter reactor', 'the pocket universe ' + generateGalaxyDescription()]),
            'Its prominent feature is ' + choose(['a black hole', 'a dyson sphere', 'intelligent life', 'a historic event']),
            'It has ' + Math.random() + choose([' stars', ' planets', ' fast food joints'])
            ]);
    }
    return choose(
        [
            galaxyId,
            galaxyCharacteristic
        ]
    )();
}

function blackHoleCharacteristicGenerator() {
    return 'Black holes are really something, huh?';
}

function solarSystemCharacteristicGenerator() {
    return 'Solar systems are really something, huh?';
}

export class RandomSensor {
    constructor() {
        this.currentNode = null;
    }

    retrieveData() {
        if (!this.currentNode) {
            // Let's start a node!
            this.currentNode = this.generateGalaxy();
            return 'Let\'s talk about ' + this.currentNode.description;
        }

        const newNode = this.walk();
        if (this.currentNode != newNode) {
            this.currentNode = newNode;
            return 'Let\'s talk about ' + newNode.description;
        }

        // We now have a current node. Decide if we want to print a characteristic about this node, or make a new child.
        if (Math.random() < 0.25 && this.currentNode.children < this.currentNode.maxChildren) {
            // Make a new child:
            const childNode = this.generateNode(this.currentNode.type);
            childNode.parent = this.currentNode;
            this.currentNode.children.push(childNode);
            this.currentNode = childNode;
            return 'It has a child ' + childNode.description;
        } else if (Math.random() < 0.2) {
            return 'We\'re talking about ' + newNode.description;
        } else {
            const characteristic = this.generateCharacteristic(this.currentNode.type);
            this.currentNode.characteristics.push(characteristic);
            return characteristic;
        }
    }

    walk() {
        let newNode = this.currentNode;
        const numSteps = Math.floor(Math.random()*5) + 1;
        let i = 0;
        for (i = 0; i < numSteps; i++) {
            if (this.currentNode.parent && Math.random() < 0.25) {
                newNode = this.currentNode.parent;
            } else if (this.currentNode.children.length > 0 && Math.random() < 0.25) {
                newNode = choose(this.currentNode.children);
            }
        }

        return newNode;
    }

    generateCharacteristic(nodeType) {
        if (nodeType === 'galaxy') {
            return galaxyCharacteristicGenerator();
        } else if (nodeType === 'black-hole') {
            return blackHoleCharacteristicGenerator();
        } else if (nodeType == 'solar-system') {
            return solarSystemCharacteristicGenerator();
        }
    }

    generateGalaxy() {
        return {
            parent: null,
            children: [],
            characteristics: [],
            description: generateGalaxyDescription(),
            maxChildren: 100,
            type: 'galaxy'
        };
    }

    generateBlackHole() {
        return {
            parent: null,
            children: [],
            characteristics: [],
            description: generateBlackHoleDescription(),
            maxChildren: 0,
            type: 'black-hole'
        }
    }

    generateSolarSystem() {
        return {
            parent: null,
            children: [],
            characteristics: [],
            description: generateSolarSystemDescription(),
            maxChildren: 0,
            type: 'solar-system'
        }
    }

    generateNode(nodeType) {
        let types = null;
        if (nodeType === 'galaxy') {
            types = [this.generateSolarSystem, this.generateBlackHole];
        } else {
            types = [this.generateGalaxy, this.generateBlackHole, this.generateSolarSystem];
        }
        return choose(types)();
    }
}

export class StaticSensor {
    retrieveData() {
        return 'Earth is roughly a sphere.'
    }
};
<|endoftext|>


<commit_before>/*

    -exports.queue = {
        guildId: {
            canPlay,
            textChannel,
            playing,
            dispatcher,
            volume,
            songs: [
                songData {
                    source // Stream URL or File location
                    type // 'URL' or 'File'
                    name // Song name
                    addedBy // Guild member who added song
                },
                ...
            ]
        },
        ...
    }

    -exports.autoPlaylist = {
        guildId: {
            songData {},
            ...
        },
        ...
    }

    -exports.textChannel(channelResolvable)
    -exports.triggerPlay(guild) // Plays the song at start of queue or auto playlist, stops current song if playing (causing it to start the next one)
    -exports.addSong(guild, channel, nameResolvable, position)
    -exports.remSong(guild, channel, positionResolvable)
    -exports.setPosition(guild, channel, oldPositionResolvable, newPositionResolvable, trigger)
    -exports.pause(guild, channel)
    -exports.resume(guild, channel)
    -exports.stop(guild, channel)
    -exports.skip(guild, channel)
    -exports.getTime(guild)
    -exports.setVolume(guild, channel, newVolume, addVolume)
    -exports.join(guild, channel, channelResolvable)
    -exports.leave(guild, channel)
    -exports.addSongAuto(guild, channel, nameResolvable, position)
    -exports.remSongAuto(guild, channel, positionResolvable)
    -exports.setPositionAuto(guild, channel, oldPositionResolvable, newPositionResolvable, trigger)

    -exports.triggerPlay(guild)
        -Check guild queue exists
        -Set textChannel variable to guild queue textChannel or guild default channel
        -Check guild queue has canPlay enabled
        -If no guild voice connection (not in voice channel)
            -[Await] Join voice channel
            -return exports.triggerPlay(guild)
        -If already playing
            -End current dispatcher
            -Return true
        -Set songData to first song in queue or random auto-playlist song
        -Get stream if songData is of type URL
        -Set dispatcher
        -Set playing
        -On dispatcher end
            // Remember that canPlay may be disabled at this point
            -Reset playing & dispatcher
            -exports.triggerPlay(guild)
        -On dispatcher error
            // Remember that canPlay may be disabled at this point
            -Reset playing & dispatcher
            -Output error
            -exports.triggerPlay(guild)
        -Return true

    -Call: exports.triggerPlay(guild)

*/
<commit_msg>Autoplaylist songs don't need position-triggering-new-song<commit_after>/*

    -exports.queue = {
        guildId: {
            canPlay,
            textChannel,
            playing,
            dispatcher,
            volume,
            songs: [
                songData {
                    source // Stream URL or File location
                    type // 'URL' or 'File'
                    name // Song name
                    addedBy // Guild member who added song
                },
                ...
            ]
        },
        ...
    }

    -exports.autoPlaylist = {
        guildId: {
            songData {},
            ...
        },
        ...
    }

    -exports.textChannel(channelResolvable)
    -exports.triggerPlay(guild) // Plays the song at start of queue or auto playlist, stops current song if playing (causing it to start the next one)
    -exports.addSong(guild, channel, nameResolvable, position)
    -exports.remSong(guild, channel, positionResolvable)
    -exports.setPosition(guild, channel, oldPositionResolvable, newPositionResolvable, trigger)
    -exports.pause(guild, channel)
    -exports.resume(guild, channel)
    -exports.stop(guild, channel)
    -exports.skip(guild, channel)
    -exports.getTime(guild)
    -exports.setVolume(guild, channel, newVolume, addVolume)
    -exports.join(guild, channel, channelResolvable)
    -exports.leave(guild, channel)
    -exports.addSongAuto(guild, channel, nameResolvable, position)
    -exports.remSongAuto(guild, channel, positionResolvable)

    -exports.triggerPlay(guild)
        -Check guild queue exists
        -Set textChannel variable to guild queue textChannel or guild default channel
        -Check guild queue has canPlay enabled
        -If no guild voice connection (not in voice channel)
            -[Await] Join voice channel
            -return exports.triggerPlay(guild)
        -If already playing
            -End current dispatcher
            -Return true
        -Set songData to first song in queue or random auto-playlist song
        -Get stream if songData is of type URL
        -Set dispatcher
        -Set playing
        -On dispatcher end
            // Remember that canPlay may be disabled at this point
            -Reset playing & dispatcher
            -exports.triggerPlay(guild)
        -On dispatcher error
            // Remember that canPlay may be disabled at this point
            -Reset playing & dispatcher
            -Output error
            -exports.triggerPlay(guild)
        -Return true

    -Call: exports.triggerPlay(guild)

*/
<|endoftext|>