<commit_before>$(function () {
    $('.header .navbar-nav a').smoothScroll();

    function activate(navbarItem) {
      navbarItem.addClass('active').siblings('li').removeClass('active');
    }

    $('.section').mouseenter(function() {
      var sectionName = $(this).attr('id');
      var navbarItem = $('.navbar-nav a[href="#' + sectionName + '"]').parent();
      activate(navbarItem);
    });

    $('.navbar-nav a').click(function() {
      var navbarItem = $(this).parent();
      activate(navbarItem);
    });

    $('#jump2top').css('bottom', '-100px');
    $(window).scroll(function () {
        var btn = $('#jump2top');
        if ($(this).scrollTop() > 100) {
            btn.stop().animate({ 'bottom': '0' }, 200);
        } else {
            btn.stop().animate({ 'bottom': '-100px' }, 200);
        }
    });

    $('#jump2top').smoothScroll();

    // Countdown
    $('.countdown').downCount({
        date: '09/12/2015 12:00:00',
        offset: null
    });

    $('#wishorderform').ajaxForm(function(returnVal) {
      $('#wishorderform').html($(returnVal).html());
      if ($('#wishorderform input[name="form_status"]').val() != '0') {
        // Save wish id
        var wishId = $('#wishorderform input[name="form_status"]').val();
        $('article[data-wishid="'+wishId+'"]').remove();
        // form was sent with success! => reset status and close all things!
        $('#wishorderform input[name="form_status"]').val('0');
        $('.overlay').remove();
        $('#popup_content').css({'display':'none'});
      }
    });

    $('p.didYouOrdered button').click(function() {
        // only activate, when we don't have the overlay now.
        if ($('.overlay').size() <= 0) {
          var docHeight = $(document).height();
          $('body').append("

");
          $('.overlay').height(docHeight);
          // Warning: in case, they click somewhere else, we cancel!
          $('.overlay').click(function() {
            $(this).remove();
            $('#popup_content').css({'display':'none'});
            // He cancelled. So let us reset the form.
            var resetUrl = $('#wishorderform').data('reset');
            // Obtain the CSRF token
            var token = $('#wishorderform input[name="csrfmiddlewaretoken"]').val();
            $.post(resetUrl, { 'csrfmiddlewaretoken': token, }, function (returnVal) {
              $('#wishorderform').html($(returnVal).html());
            });
          });
          // Now show the form!
          $('#wishorderform input[name="wishid"]').val($(this).data('wishid'));
          $('#wishorderform input[name="form_status"]').val('0');
          $('#popup_content').css({'display':'block'});
        }
    });

    $('#contactform').ajaxForm(function(returnVal) {
      $('#contactform').html($(returnVal).html());
    });
});

function scrollTo(elem) {
    $('body,html').animate({
        scrollTop: elem.offset().top
    }, 500);
}

function valemail(email) {
    var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    return re.test(email);
}
<commit_msg>And wrong time used<commit_after>$(function () {
    $('.header .navbar-nav a').smoothScroll();

    function activate(navbarItem) {
      navbarItem.addClass('active').siblings('li').removeClass('active');
    }

    $('.section').mouseenter(function() {
      var sectionName = $(this).attr('id');
      var navbarItem = $('.navbar-nav a[href="#' + sectionName + '"]').parent();
      activate(navbarItem);
    });

    $('.navbar-nav a').click(function() {
      var navbarItem = $(this).parent();
      activate(navbarItem);
    });

    $('#jump2top').css('bottom', '-100px');
    $(window).scroll(function () {
        var btn = $('#jump2top');
        if ($(this).scrollTop() > 100) {
            btn.stop().animate({ 'bottom': '0' }, 200);
        } else {
            btn.stop().animate({ 'bottom': '-100px' }, 200);
        }
    });

    $('#jump2top').smoothScroll();

    // Countdown
    $('.countdown').downCount({
        date: '09/12/2015 14:00:00',
        offset: null
    });

    $('#wishorderform').ajaxForm(function(returnVal) {
      $('#wishorderform').html($(returnVal).html());
      if ($('#wishorderform input[name="form_status"]').val() != '0') {
        // Save wish id
        var wishId = $('#wishorderform input[name="form_status"]').val();
        $('article[data-wishid="'+wishId+'"]').remove();
        // form was sent with success! => reset status and close all things!
        $('#wishorderform input[name="form_status"]').val('0');
        $('.overlay').remove();
        $('#popup_content').css({'display':'none'});
      }
    });

    $('p.didYouOrdered button').click(function() {
        // only activate, when we don't have the overlay now.
        if ($('.overlay').size() <= 0) {
          var docHeight = $(document).height();
          $('body').append("

");
          $('.overlay').height(docHeight);
          // Warning: in case, they click somewhere else, we cancel!
          $('.overlay').click(function() {
            $(this).remove();
            $('#popup_content').css({'display':'none'});
            // He cancelled. So let us reset the form.
            var resetUrl = $('#wishorderform').data('reset');
            // Obtain the CSRF token
            var token = $('#wishorderform input[name="csrfmiddlewaretoken"]').val();
            $.post(resetUrl, { 'csrfmiddlewaretoken': token, }, function (returnVal) {
              $('#wishorderform').html($(returnVal).html());
            });
          });
          // Now show the form!
          $('#wishorderform input[name="wishid"]').val($(this).data('wishid'));
          $('#wishorderform input[name="form_status"]').val('0');
          $('#popup_content').css({'display':'block'});
        }
    });

    $('#contactform').ajaxForm(function(returnVal) {
      $('#contactform').html($(returnVal).html());
    });
});

function scrollTo(elem) {
    $('body,html').animate({
        scrollTop: elem.offset().top
    }, 500);
}

function valemail(email) {
    var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    return re.test(email);
}
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';

import { hasPreviousSelector, classNamesForComponentSelector, stylesForComponentSelector } from '../selectors/localSelectors';
import { getPrevious } from '../../../actions';

const enhance = OriginalComponent => connect(state => ({
  hasPrevious: hasPreviousSelector,
  className: classNamesForComponentSelector(state, 'PreviousButton'),
  style: stylesForComponentSelector(state, 'PreviousButton'),
}),
  {
    getPrevious
  }
)(props => <OriginalComponent {...props} onClick={props.getPrevious} text="Previous" />);

export default enhance;
<commit_msg>Fix for previous button<commit_after>import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';

import { hasPreviousSelector, classNamesForComponentSelector, stylesForComponentSelector } from '../selectors/localSelectors';
import { getPrevious } from '../../../actions';

const enhance = OriginalComponent => connect(state => ({
  hasPrevious: hasPreviousSelector(state),
  className: classNamesForComponentSelector(state, 'PreviousButton'),
  style: stylesForComponentSelector(state, 'PreviousButton'),
}),
  {
    getPrevious
  }
)(props => <OriginalComponent {...props} onClick={props.getPrevious} text="Previous" />);

export default enhance;
<|endoftext|>


<commit_before>$.Redactor.prototype.WoltLabDropdown = function() {
	"use strict";

	return {
		init: function() {
			// prevent overflow: hidden on body while hovering dropdowns
			this.utils.disableBodyScroll = function() {};
			this.utils.enableBodyScroll = function() {};

			// disable slideUp effect for dropdowns on close
			this.WoltLabDropdown._hideAll();

			// disable slideDown effect for dropdowns on open
			// enforce dropdownMenu-like DOM
			this.WoltLabDropdown._show();

			// the original implementation didn't perform that well (especially with multiple
			// instance being launched at start) and suffered from too many live DOM manipulations
			this.dropdown.build = (function(name, $dropdown, dropdownObject) {
				dropdownObject = this.dropdown.buildFormatting(name, dropdownObject);

				var btnObject, fragment = document.createDocumentFragment();
				for (var btnName in dropdownObject) {
					if (dropdownObject.hasOwnProperty(btnName)) {
						btnObject = dropdownObject[btnName];

						var item = this.dropdown.buildItem(btnName, btnObject);

						this.observe.addDropdown($(item), btnName, btnObject);
						fragment.appendChild(item);
					}
				}

				if (fragment.children.length > 0) {
					$dropdown[0].rel = name;
					$dropdown[0].appendChild(fragment);
				}
			}).bind(this);

			this.dropdown.buildItem = (function(btnName, btnObject) {
				var itemContainer = elCreate('li');
				if (typeof btnObject.classname !== 'undefined') {
					itemContainer.classList.add(btnObject.classname);
				}

				if (btnName.toLowerCase().indexOf('divider') === 0) {
					itemContainer.classList.add('redactor-dropdown-divider');

					return itemContainer;
				}

				itemContainer.innerHTML = '' + btnObject.title + '';
				itemContainer.children[0].addEventListener('mousedown', (function(event) {
					event.preventDefault();

					this.dropdown.buildClick(event, btnName, btnObject);
				}).bind(this));

				return itemContainer;
			}).bind(this);
		},

		_hideAll: function() {
			var hideAll = this.dropdown.hideAll;
			this.dropdown.hideAll = (function(e, key) {
				hideAll.call(this, e, key);

				$('.redactor-dropdown-' + this.uuid).stop(true, true).hide();
			}).bind(this);
		},

		_show: function() {
			var show = this.dropdown.show;
			this.dropdown.show = (function(e, key) {
				var $button = this.button.get(key);
				var $dropdown = $button.data('dropdown');

				if (!elDataBool($dropdown[0], 'woltlab')) {
					var list = elCreate('ul');
					list.className = 'dropdownMenu';

					while ($dropdown[0].childElementCount) {
						list.appendChild($dropdown[0].children[0]);
					}

					$dropdown[0].appendChild(list);

					elData($dropdown[0], 'woltlab', true);
				}

				var isActive = $button.hasClass('dropact');

				show.call(this, e, key);

				if (!isActive) {
					$dropdown.stop(true).show();
				}
			}).bind(this);

		}
	};
};
<commit_msg>IE11 does not expose `DocumentFragment.children`<commit_after>$.Redactor.prototype.WoltLabDropdown = function() {
	"use strict";

	return {
		init: function() {
			// prevent overflow: hidden on body while hovering dropdowns
			this.utils.disableBodyScroll = function() {};
			this.utils.enableBodyScroll = function() {};

			// disable slideUp effect for dropdowns on close
			this.WoltLabDropdown._hideAll();

			// disable slideDown effect for dropdowns on open
			// enforce dropdownMenu-like DOM
			this.WoltLabDropdown._show();

			// the original implementation didn't perform that well (especially with multiple
			// instance being launched at start) and suffered from too many live DOM manipulations
			this.dropdown.build = (function(name, $dropdown, dropdownObject) {
				dropdownObject = this.dropdown.buildFormatting(name, dropdownObject);

				var btnObject, fragment = document.createDocumentFragment();
				for (var btnName in dropdownObject) {
					if (dropdownObject.hasOwnProperty(btnName)) {
						btnObject = dropdownObject[btnName];

						var item = this.dropdown.buildItem(btnName, btnObject);

						this.observe.addDropdown($(item), btnName, btnObject);
						fragment.appendChild(item);
					}
				}

				var hasItems = false;
				for (var i = 0, length = fragment.childNodes.length; i < length; i++) {
					if (fragment.childNodes[i].nodeType === Node.ELEMENT_NODE) {
						hasItems = true;
						break;
					}
				}

				if (hasItems) {
					$dropdown[0].rel = name;
					$dropdown[0].appendChild(fragment);
				}
			}).bind(this);

			this.dropdown.buildItem = (function(btnName, btnObject) {
				var itemContainer = elCreate('li');
				if (typeof btnObject.classname !== 'undefined') {
					itemContainer.classList.add(btnObject.classname);
				}

				if (btnName.toLowerCase().indexOf('divider') === 0) {
					itemContainer.classList.add('redactor-dropdown-divider');

					return itemContainer;
				}

				itemContainer.innerHTML = '' + btnObject.title + '';
				itemContainer.children[0].addEventListener('mousedown', (function(event) {
					event.preventDefault();

					this.dropdown.buildClick(event, btnName, btnObject);
				}).bind(this));

				return itemContainer;
			}).bind(this);
		},

		_hideAll: function() {
			var hideAll = this.dropdown.hideAll;
			this.dropdown.hideAll = (function(e, key) {
				hideAll.call(this, e, key);

				$('.redactor-dropdown-' + this.uuid).stop(true, true).hide();
			}).bind(this);
		},

		_show: function() {
			var show = this.dropdown.show;
			this.dropdown.show = (function(e, key) {
				var $button = this.button.get(key);
				var $dropdown = $button.data('dropdown');

				if (!elDataBool($dropdown[0], 'woltlab')) {
					var list = elCreate('ul');
					list.className = 'dropdownMenu';

					while ($dropdown[0].childElementCount) {
						list.appendChild($dropdown[0].children[0]);
					}

					$dropdown[0].appendChild(list);

					elData($dropdown[0], 'woltlab', true);
				}

				var isActive = $button.hasClass('dropact');

				show.call(this, e, key);

				if (!isActive) {
					$dropdown.stop(true).show();
				}
			}).bind(this);

		}
	};
};
<|endoftext|>


<commit_before>class MCProcessesGraphComponentController {
    /*@ngInject*/
    constructor(experimentsService, templates, $stateParams, toast, $mdDialog) {
        this.experimentsService = experimentsService;
        this.templates = templates;
        this.toast = toast;
        this.cy = null;
        this.displayGraph = 'all_processes';
        this.projectId = $stateParams.project_id;
        this.experimentId = $stateParams.experiment_id;
        this.$mdDialog = $mdDialog;
    }

    $onInit() {
        this.allProcessesGraph();
    }

    addProcess(templateId) {
        this.experimentsService.createProcessFromTemplate(this.projectId, this.experimentId, `global_${templateId}`)
            .then(
                (process) => {
                    let p = this.templates.loadTemplateFromProcess(process.template_name, process);
                    this.$mdDialog.show({
                        templateUrl: 'app/global.components/graph/new-process-dialog.html',
                        controllerAs: '$ctrl',
                        controller: NewProcessDialogController,
                        bindToController: true,
                        locals: {
                            process: p
                        }
                    }).then(
                        () => this.experimentsService.getProcessesForExperiment(this.projectId, this.experimentId)
                            .then(
                                (processes) => {
                                    this.processes = processes;
                                    this.allProcessesGraph();
                                },
                                () => toast.error('Error retrieving processes for experiment')
                            )
                    );
                },
                () => this.toast.error('Unable to add samples')
            );
    }

    allProcessesGraph() {
        let transformingProcesses = this.processes.filter(p => p.does_transform);
        let sample2InputProcess = {};
        let sample2OutputProcess = {};
        transformingProcesses.forEach(p => {
            p.input_samples.forEach(s => {
                let id = `${s.id}/${s.property_set_id}`;
                sample2InputProcess[id] = p;
            });

            p.output_samples.forEach(s => {
                let id = `${s.id}/${s.property_set_id}`;
                sample2OutputProcess[id] = p;
            })
        });
        let elements = this.processes.map(p => {
            //console.log(p.name, p);
            return {
                data: {
                    id: p.id,
                    name: p.name,
                    color: p.does_transform ? 'red' : '#999999'
                }
            }
        });
        this.processes.filter(p => !p.does_transform).forEach(p => {
            p.input_samples.forEach(s => {
                let id = `${s.id}/${s.property_set_id}`;
                let process = sample2OutputProcess[id];
                if (process) {
                    elements.push({
                        data: {
                            id: `${p.id}_${process.id}`,
                            source: process.id,
                            target: p.id
                        }
                    });
                }
                process = sample2InputProcess[id];
                if (process) {
                    elements.push({
                        data: {
                            source: p.id,
                            target: process.id
                        }
                    });
                }
            });
        });

        let sampleName2Sample = {};
        this.processes.forEach(p => {
            p.input_samples.forEach(s => {
                sampleName2Sample[s.name] = s;
            });
            p.output_samples.forEach(s => {
                sampleName2Sample[s.name] = s;
            });
        });
        this.samples = _.values(sampleName2Sample);
        this.cy = cytoscape({
            container: document.getElementById('processesGraph'),
            elements: elements,
            style: [
                {
                    selector: 'node',
                    style: {
                        'label': 'data(name)',
                        'background-color': 'data(color)'
                    }
                },
                {
                    selector: 'edge',
                    style: {
                        'width': 4,
                        'target-arrow-shape': 'triangle',
                        //'target-arrow-color': '#9dbaea',
                        'curve-style': 'bezier'
                    }
                }
            ]
        });
        this.cy.on('click', function(event) {
            console.log('node or edge clicked', event);
            let target = event.cyTarget;
            console.log('node name is', target.data('name'));
        });
        this.cy.layout({name: 'dagre'});
    }

    showSelectedGraph() {
        console.log('selected graph', this.displayGraph);
    }

    onlyTransformationProcessesGraph() {
        console.log('onlyTransformationProcessesGraph');
    }

    sampleTransformationGraph() {
        console.log('sampleTransformationGraph');
    }

    filterOnSample(sample) {
        //console.log('filterOnSample', sample);
        let matches = [];
        this.cy.nodes().forEach(node => {
            console.log(node.data('id'));
        });
        console.log('matches', matches);
    }

}

class NewProcessDialogController {
    /*@ngInject*/
    constructor($mdDialog) {
        console.log('NewSamplesDialogController', this.process.plain());
        this.$mdDialog = $mdDialog;
    }

    done() {
        this.$mdDialog.hide();
    }

    cancel() {
        this.$mdDialog.cancel();
    }
}

angular.module('materialscommons').component('mcProcessesGraph', {
    templateUrl: 'app/global.components/graph/mc-processes-graph.html',
    controller: MCProcessesGraphComponentController,
    bindings: {
        processes: '<'
    }
});
<commit_msg>Remove console statement.<commit_after>class MCProcessesGraphComponentController {
    /*@ngInject*/
    constructor(experimentsService, templates, $stateParams, toast, $mdDialog) {
        this.experimentsService = experimentsService;
        this.templates = templates;
        this.toast = toast;
        this.cy = null;
        this.displayGraph = 'all_processes';
        this.projectId = $stateParams.project_id;
        this.experimentId = $stateParams.experiment_id;
        this.$mdDialog = $mdDialog;
    }

    $onInit() {
        this.allProcessesGraph();
    }

    addProcess(templateId) {
        this.experimentsService.createProcessFromTemplate(this.projectId, this.experimentId, `global_${templateId}`)
            .then(
                (process) => {
                    let p = this.templates.loadTemplateFromProcess(process.template_name, process);
                    this.$mdDialog.show({
                        templateUrl: 'app/global.components/graph/new-process-dialog.html',
                        controllerAs: '$ctrl',
                        controller: NewProcessDialogController,
                        bindToController: true,
                        locals: {
                            process: p
                        }
                    }).then(
                        () => this.experimentsService.getProcessesForExperiment(this.projectId, this.experimentId)
                            .then(
                                (processes) => {
                                    this.processes = processes;
                                    this.allProcessesGraph();
                                },
                                () => toast.error('Error retrieving processes for experiment')
                            )
                    );
                },
                () => this.toast.error('Unable to add samples')
            );
    }

    allProcessesGraph() {
        let transformingProcesses = this.processes.filter(p => p.does_transform);
        let sample2InputProcess = {};
        let sample2OutputProcess = {};
        transformingProcesses.forEach(p => {
            p.input_samples.forEach(s => {
                let id = `${s.id}/${s.property_set_id}`;
                sample2InputProcess[id] = p;
            });

            p.output_samples.forEach(s => {
                let id = `${s.id}/${s.property_set_id}`;
                sample2OutputProcess[id] = p;
            })
        });
        let elements = this.processes.map(p => {
            //console.log(p.name, p);
            return {
                data: {
                    id: p.id,
                    name: p.name,
                    color: p.does_transform ? 'red' : '#999999'
                }
            }
        });
        this.processes.filter(p => !p.does_transform).forEach(p => {
            p.input_samples.forEach(s => {
                let id = `${s.id}/${s.property_set_id}`;
                let process = sample2OutputProcess[id];
                if (process) {
                    elements.push({
                        data: {
                            id: `${p.id}_${process.id}`,
                            source: process.id,
                            target: p.id
                        }
                    });
                }
                process = sample2InputProcess[id];
                if (process) {
                    elements.push({
                        data: {
                            source: p.id,
                            target: process.id
                        }
                    });
                }
            });
        });

        let sampleName2Sample = {};
        this.processes.forEach(p => {
            p.input_samples.forEach(s => {
                sampleName2Sample[s.name] = s;
            });
            p.output_samples.forEach(s => {
                sampleName2Sample[s.name] = s;
            });
        });
        this.samples = _.values(sampleName2Sample);
        this.cy = cytoscape({
            container: document.getElementById('processesGraph'),
            elements: elements,
            style: [
                {
                    selector: 'node',
                    style: {
                        'label': 'data(name)',
                        'background-color': 'data(color)'
                    }
                },
                {
                    selector: 'edge',
                    style: {
                        'width': 4,
                        'target-arrow-shape': 'triangle',
                        //'target-arrow-color': '#9dbaea',
                        'curve-style': 'bezier'
                    }
                }
            ]
        });
        this.cy.on('click', function(event) {
            console.log('node or edge clicked', event);
            let target = event.cyTarget;
            console.log('node name is', target.data('name'));
        });
        this.cy.layout({name: 'dagre'});
    }

    showSelectedGraph() {
        console.log('selected graph', this.displayGraph);
    }

    onlyTransformationProcessesGraph() {
        console.log('onlyTransformationProcessesGraph');
    }

    sampleTransformationGraph() {
        console.log('sampleTransformationGraph');
    }

    filterOnSample(sample) {
        //console.log('filterOnSample', sample);
        let matches = [];
        this.cy.nodes().forEach(node => {
            console.log(node.data('id'));
        });
        console.log('matches', matches);
    }

}

class NewProcessDialogController {
    /*@ngInject*/
    constructor($mdDialog) {
        this.$mdDialog = $mdDialog;
    }

    done() {
        this.$mdDialog.hide();
    }

    cancel() {
        this.$mdDialog.cancel();
    }
}

angular.module('materialscommons').component('mcProcessesGraph', {
    templateUrl: 'app/global.components/graph/mc-processes-graph.html',
    controller: MCProcessesGraphComponentController,
    bindings: {
        processes: '<'
    }
});
<|endoftext|>


<commit_before>import { parsePath, createPath } from 'history/PathUtils'
export { locationsAreEqual } from 'history/LocationUtils'

export const createRouterLocation = (input, parseQueryString, stringifyQuery) => {
  if (typeof input === 'string') {
    const location = parsePath(input)
    location.query = location.search !== '' ?
      parseQueryString(location.search) : null
    return location
  } else {
    // got a location descriptor
    return {
      pathname: input.pathname || '',
      search: input.search || (
        input.query ? `?${stringifyQuery(input.query)}` : ''
      ),
      hash: input.hash || '',
      state: input.state || null,
      query: input.query || (
        input.search ? parseQueryString(input.search) : null
      )
    }
  }
}

export const createRouterPath = (input, stringifyQuery) => {
  return typeof input === 'string' ? input : createPath({
    ...input,
    search: input.search || (
      input.query ? `?${stringifyQuery(input.query)}` : ''
    )
  })
}
<commit_msg>add location.key<commit_after>import { parsePath, createPath } from 'history/PathUtils'
export { locationsAreEqual } from 'history/LocationUtils'

export const createRouterLocation = (input, parseQueryString, stringifyQuery) => {
  if (typeof input === 'string') {
    const location = parsePath(input)
    location.query = location.search !== '' ?
      parseQueryString(location.search) : null
    return location
  } else {
    // got a location descriptor
    return {
      pathname: input.pathname || '',
      search: input.search || (
        input.query ? `?${stringifyQuery(input.query)}` : ''
      ),
      hash: input.hash || '',
      state: input.state || null,
      query: input.query || (
        input.search ? parseQueryString(input.search) : null
      ),
      key: input.key
    }
  }
}

export const createRouterPath = (input, stringifyQuery) => {
  return typeof input === 'string' ? input : createPath({
    ...input,
    search: input.search || (
      input.query ? `?${stringifyQuery(input.query)}` : ''
    )
  })
}
<|endoftext|>


<commit_before>/*    Copyright 2016 Firewalla LLC / Firewalla LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

'use strict'

const log = require('../net2/logger.js')(__filename);

const util = require('util');
const minimatch = require("minimatch");
const cronParser = require('cron-parser');

const _ = require('lodash');
const flat = require('flat');

const POLICY_MIN_EXPIRE_TIME = 60 // if policy is going to expire in 60 seconds, don't bother to enforce it.

function arraysEqual(a, b) {
  if (a === b) return true;
  if (a == null || b == null) return false;
  if (a.length != b.length) return false;

  // If you don't care about the order of the elements inside
  // the array, you should sort both arrays here.

  for (var i = 0; i < a.length; ++i) {
    if (a[i] !== b[i]) return false;
  }
  return true;
}

class Policy {
  constructor(raw) {
    if (!raw) throw new Error("Empty policy payload");
    if (!raw.type && !raw['i.type']) throw new Error("Invalid policy payload");

    Object.assign(this, raw);

    if (raw.scope) {
      if (_.isString(raw.scope)) {
        try {
          this.scope = JSON.parse(raw.scope)
        } catch (e) {
          log.error("Failed to parse policy scope string:", raw.scope, e)
        }
      } else if (_.isArray(raw.scope)) {
        this.scope = raw.scope.slice(0) // clone array to avoide side effects
      } else {
        log.error("Unsupported scope", raw.scope)
      }

      if (!_.isArray(this.scope) || _.isEmpty(this.scope))
        delete this.scope;
    }

    if (raw.tag) {
      if (_.isString(raw.tag)) {
        try {
          this.tag = JSON.parse(raw.tag)
        } catch (e) {
          log.error("Failed to parse policy tag string:", raw.tag, e)
        }
      } else if (_.isArray(raw.tag)) {
        this.tag = Array.from(raw.tag); // clone array to avoide side effects
      } else {
        log.error("Unsupported tag", raw.tag)
      }

      if (!_.isArray(this.tag) || _.isEmpty(this.tag))
        delete this.tag;
    }
    this.upnp = false;
    if (raw.upnp)
      this.upnp = JSON.parse(raw.upnp);

    if (raw.expire === "") {
      delete this.expire;
    } else if (raw.expire && _.isString(raw.expire)) {
      try {
        this.expire = parseInt(raw.expire)
      } catch (e) {
        log.error("Failed to parse policy expire time:", raw.expire, e);
        delete this.expire;
      }
    }

    if (raw.cronTime === "") {
      delete this.cronTime;
    }

    // backward compatibilities
    if (this['i.type']) {
      this.type = this['i.type'];
      delete this['i.type'];
    }
    if (this['i.target']) {
      this.target = this['i.target'];
      delete this['i.target'];
    }

    if (this.target && this.type) {
      switch (this.type) {
        case "mac":
          this.target = this.target.toUpperCase(); // always upper case for mac address
          break;
        case "dns":
        case "domain":
          this.target = this.target.toLowerCase(); // always lower case for domain block
          break;
        default:
        // do nothing;
      }
    }

    this.timestamp = this.timestamp || new Date() / 1000;

  }

  isEqualToPolicy(policy) {
    if (!policy) {
      return false
    }
    if (!policy instanceof Policy)
      policy = new Policy(policy) // leverage the constructor for compatibilities conversion

    if (
      this.type === policy.type &&
      this.target === policy.target &&
      this.expire === policy.expire &&
      this.cronTime === policy.cronTime &&
      this.remotePort === policy.remotePort &&
      this.localPort === policy.localPort &&
      this.protocol === policy.protocol &&
      this.direction === policy.direction &&
      this.action === policy.action &&
      this.upnp === policy.upnp
    ) {
      return arraysEqual(this.scope, policy.scope) && arraysEqual(this.tag, policy.tag);
    } else {
      return false
    }
  }

  isExpired() {
    const expire = this.expire || NaN
    const activatedTime = this.activatedTime || this.timestamp
    return parseFloat(activatedTime) + parseFloat(expire) < new Date() / 1000
  }

  willExpireSoon() {
    const expire = this.expire || NaN
    const activatedTime = this.activatedTime || this.timestamp
    return parseFloat(activatedTime) + parseFloat(expire) < new Date() / 1000 + POLICY_MIN_EXPIRE_TIME
  }

  getWhenExpired() {
    const expire = this.expire || NaN
    const activatedTime = this.activatedTime || this.timestamp
    return parseFloat(activatedTime) + parseFloat(expire)
  }

  getExpireDiffFromNow() {
    return this.getWhenExpired() - new Date() / 1000
  }

  isDisabled() {
    return this.disabled && this.disabled == '1'
  }
  inSchedule(alarmTimestamp) {
    const cronTime = this.cronTime;
    const duration = parseFloat(this.duration); // in seconds
    const interval = cronParser.parseExpression(cronTime);
    const lastDate = interval.prev().getTime() / 1000;
    log.info(`lastDate: ${lastDate}, duration: ${duration}, alarmTimestamp:${alarmTimestamp}`);

    if (alarmTimestamp > lastDate && alarmTimestamp < lastDate + duration) {
      return true
    } else {
      return false
    }
  }

  match(alarm) {

    if (this.isExpired()) {
      return false // always return unmatched if policy is already expired
    }
    if (this.cronTime && this.duration && !this.inSchedule(alarm.alarmTimestamp)) {
      return false;
    }

    if (
      this.scope &&
      _.isArray(this.scope) &&
      !_.isEmpty(this.scope) &&
      alarm['p.device.mac'] &&
      !this.scope.includes(alarm['p.device.mac'])
    ) {
      return false; // scope not match
    }

    if (
      this.tag &&
      _.isArray(this.tag) &&
      !_.isEmpty(this.tag) &&
      alarm['p.intf.id'] &&
      !this.tag.includes(Policy.INTF_PREFIX + alarm['p.intf.id'])
    ) {
      return false; // tag not match
    }

    if (
      this.tag &&
      _.isArray(this.tag) &&
      !_.isEmpty(this.tag) &&
      _.has(alarm, 'p.tag.ids') &&
      !_.isEmpty(alarm['p.tag.ids'])
    ) {
      let found = false;
      for (let index = 0; index < alarm['p.tag.ids'].length; index++) {
        const tag = alarm['p.tag.ids'][index];
        if (this.tag.includes(Policy.TAG_PREFIX + tag)) {
          found = true;
        }
      }

      if (!found) {
        return false;
      }
    }

    // for each policy type
    switch (this.type) {
      case "ip":
        if (alarm['p.dest.ip']) {
          return this.target === alarm['p.dest.ip']
        } else {
          return false
        }
        break

      case "dns":
      case "domain":
        if (alarm['p.dest.name']) {
          return minimatch(alarm['p.dest.name'], `*.${this.target}`) ||
            alarm['p.dest.name'] === this.target
        } else {
          return false
        }
        break

      case "mac":
        if (alarm['p.device.mac']) {
          return alarm['p.device.mac'] === this.target
        } else {
          return false
        }
        break

      case "category":
        if (alarm['p.dest.category']) {
          return alarm['p.dest.category'] === this.target;
        } else {
          return false;
        }
        break

      case "devicePort":
        if (!alarm['p.device.mac']) return false;

        if (alarm["p.device.port"] &&
          alarm["p.protocol"]
        ) {
          let alarmTarget = util.format("%s:%s:%s",
            alarm["p.device.mac"],
            alarm["p.device.port"],
            alarm["p.protocol"]
          )
          return alarmTarget === this.target;
        }

        if (alarm["p.upnp.private.port"] &&
          alarm["p.upnp.protocol"]
        ) {
          let alarmTarget = util.format("%s:%s:%s",
            alarm["p.device.mac"],
            alarm["p.upnp.private.port"],
            alarm["p.upnp.protocol"]
          )
          return alarmTarget === this.target;
        }

        return false;
        break
      default:
        return false
        break
    }
  }

  // return a new object ready for redis writing
  redisfy() {
    let p = JSON.parse(JSON.stringify(this))

    // convert array to string so that redis can store it as value
    if (p.scope) {
      if (p.scope.length > 0)
        p.scope = JSON.stringify(p.scope);
      else
        delete p.scope;
    }

    if (p.tag) {
      if (p.tag.length > 0)
        p.tag = JSON.stringify(p.tag);
      else
        delete p.tag;
    }

    if (p.expire === "") {
      delete p.expire;
    }

    if (p.cronTime === "") {
      delete p.cronTime;
    }

    return flat.flatten(p);
  }
}

Policy.INTF_PREFIX = "intf:";
Policy.TAG_PREFIX = "tag:";

module.exports = Policy
<commit_msg>Enhancement: Should not create internet type policy (#2226)<commit_after>/*    Copyright 2016 Firewalla LLC / Firewalla LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

'use strict'

const log = require('../net2/logger.js')(__filename);

const util = require('util');
const minimatch = require("minimatch");
const cronParser = require('cron-parser');

const _ = require('lodash');
const flat = require('flat');

const POLICY_MIN_EXPIRE_TIME = 60 // if policy is going to expire in 60 seconds, don't bother to enforce it.

function arraysEqual(a, b) {
  if (a === b) return true;
  if (a == null || b == null) return false;
  if (a.length != b.length) return false;

  // If you don't care about the order of the elements inside
  // the array, you should sort both arrays here.

  for (var i = 0; i < a.length; ++i) {
    if (a[i] !== b[i]) return false;
  }
  return true;
}

class Policy {
  constructor(raw) {
    if (!raw) throw new Error("Empty policy payload");
    if (!raw.type && !raw['i.type']) throw new Error("Invalid policy payload");
    if (raw.type == 'internet') throw new Error(`Invalid policy type ${raw.type}`);

    Object.assign(this, raw);

    if (raw.scope) {
      if (_.isString(raw.scope)) {
        try {
          this.scope = JSON.parse(raw.scope)
        } catch (e) {
          log.error("Failed to parse policy scope string:", raw.scope, e)
        }
      } else if (_.isArray(raw.scope)) {
        this.scope = raw.scope.slice(0) // clone array to avoide side effects
      } else {
        log.error("Unsupported scope", raw.scope)
      }

      if (!_.isArray(this.scope) || _.isEmpty(this.scope))
        delete this.scope;
    }

    if (raw.tag) {
      if (_.isString(raw.tag)) {
        try {
          this.tag = JSON.parse(raw.tag)
        } catch (e) {
          log.error("Failed to parse policy tag string:", raw.tag, e)
        }
      } else if (_.isArray(raw.tag)) {
        this.tag = Array.from(raw.tag); // clone array to avoide side effects
      } else {
        log.error("Unsupported tag", raw.tag)
      }

      if (!_.isArray(this.tag) || _.isEmpty(this.tag))
        delete this.tag;
    }
    this.upnp = false;
    if (raw.upnp)
      this.upnp = JSON.parse(raw.upnp);

    if (raw.expire === "") {
      delete this.expire;
    } else if (raw.expire && _.isString(raw.expire)) {
      try {
        this.expire = parseInt(raw.expire)
      } catch (e) {
        log.error("Failed to parse policy expire time:", raw.expire, e);
        delete this.expire;
      }
    }

    if (raw.cronTime === "") {
      delete this.cronTime;
    }

    // backward compatibilities
    if (this['i.type']) {
      this.type = this['i.type'];
      delete this['i.type'];
    }
    if (this['i.target']) {
      this.target = this['i.target'];
      delete this['i.target'];
    }

    if (this.target && this.type) {
      switch (this.type) {
        case "mac":
          this.target = this.target.toUpperCase(); // always upper case for mac address
          break;
        case "dns":
        case "domain":
          this.target = this.target.toLowerCase(); // always lower case for domain block
          break;
        default:
        // do nothing;
      }
    }

    this.timestamp = this.timestamp || new Date() / 1000;

  }

  isEqualToPolicy(policy) {
    if (!policy) {
      return false
    }
    if (!policy instanceof Policy)
      policy = new Policy(policy) // leverage the constructor for compatibilities conversion

    if (
      this.type === policy.type &&
      this.target === policy.target &&
      this.expire === policy.expire &&
      this.cronTime === policy.cronTime &&
      this.remotePort === policy.remotePort &&
      this.localPort === policy.localPort &&
      this.protocol === policy.protocol &&
      this.direction === policy.direction &&
      this.action === policy.action &&
      this.upnp === policy.upnp
    ) {
      return arraysEqual(this.scope, policy.scope) && arraysEqual(this.tag, policy.tag);
    } else {
      return false
    }
  }

  isExpired() {
    const expire = this.expire || NaN
    const activatedTime = this.activatedTime || this.timestamp
    return parseFloat(activatedTime) + parseFloat(expire) < new Date() / 1000
  }

  willExpireSoon() {
    const expire = this.expire || NaN
    const activatedTime = this.activatedTime || this.timestamp
    return parseFloat(activatedTime) + parseFloat(expire) < new Date() / 1000 + POLICY_MIN_EXPIRE_TIME
  }

  getWhenExpired() {
    const expire = this.expire || NaN
    const activatedTime = this.activatedTime || this.timestamp
    return parseFloat(activatedTime) + parseFloat(expire)
  }

  getExpireDiffFromNow() {
    return this.getWhenExpired() - new Date() / 1000
  }

  isDisabled() {
    return this.disabled && this.disabled == '1'
  }
  inSchedule(alarmTimestamp) {
    const cronTime = this.cronTime;
    const duration = parseFloat(this.duration); // in seconds
    const interval = cronParser.parseExpression(cronTime);
    const lastDate = interval.prev().getTime() / 1000;
    log.info(`lastDate: ${lastDate}, duration: ${duration}, alarmTimestamp:${alarmTimestamp}`);

    if (alarmTimestamp > lastDate && alarmTimestamp < lastDate + duration) {
      return true
    } else {
      return false
    }
  }

  match(alarm) {

    if (this.isExpired()) {
      return false // always return unmatched if policy is already expired
    }
    if (this.cronTime && this.duration && !this.inSchedule(alarm.alarmTimestamp)) {
      return false;
    }

    if (
      this.scope &&
      _.isArray(this.scope) &&
      !_.isEmpty(this.scope) &&
      alarm['p.device.mac'] &&
      !this.scope.includes(alarm['p.device.mac'])
    ) {
      return false; // scope not match
    }

    if (
      this.tag &&
      _.isArray(this.tag) &&
      !_.isEmpty(this.tag) &&
      alarm['p.intf.id'] &&
      !this.tag.includes(Policy.INTF_PREFIX + alarm['p.intf.id'])
    ) {
      return false; // tag not match
    }

    if (
      this.tag &&
      _.isArray(this.tag) &&
      !_.isEmpty(this.tag) &&
      _.has(alarm, 'p.tag.ids') &&
      !_.isEmpty(alarm['p.tag.ids'])
    ) {
      let found = false;
      for (let index = 0; index < alarm['p.tag.ids'].length; index++) {
        const tag = alarm['p.tag.ids'][index];
        if (this.tag.includes(Policy.TAG_PREFIX + tag)) {
          found = true;
        }
      }

      if (!found) {
        return false;
      }
    }

    // for each policy type
    switch (this.type) {
      case "ip":
        if (alarm['p.dest.ip']) {
          return this.target === alarm['p.dest.ip']
        } else {
          return false
        }
        break

      case "dns":
      case "domain":
        if (alarm['p.dest.name']) {
          return minimatch(alarm['p.dest.name'], `*.${this.target}`) ||
            alarm['p.dest.name'] === this.target
        } else {
          return false
        }
        break

      case "mac":
        if (alarm['p.device.mac']) {
          return alarm['p.device.mac'] === this.target
        } else {
          return false
        }
        break

      case "category":
        if (alarm['p.dest.category']) {
          return alarm['p.dest.category'] === this.target;
        } else {
          return false;
        }
        break

      case "devicePort":
        if (!alarm['p.device.mac']) return false;

        if (alarm["p.device.port"] &&
          alarm["p.protocol"]
        ) {
          let alarmTarget = util.format("%s:%s:%s",
            alarm["p.device.mac"],
            alarm["p.device.port"],
            alarm["p.protocol"]
          )
          return alarmTarget === this.target;
        }

        if (alarm["p.upnp.private.port"] &&
          alarm["p.upnp.protocol"]
        ) {
          let alarmTarget = util.format("%s:%s:%s",
            alarm["p.device.mac"],
            alarm["p.upnp.private.port"],
            alarm["p.upnp.protocol"]
          )
          return alarmTarget === this.target;
        }

        return false;
        break
      default:
        return false
        break
    }
  }

  // return a new object ready for redis writing
  redisfy() {
    let p = JSON.parse(JSON.stringify(this))

    // convert array to string so that redis can store it as value
    if (p.scope) {
      if (p.scope.length > 0)
        p.scope = JSON.stringify(p.scope);
      else
        delete p.scope;
    }

    if (p.tag) {
      if (p.tag.length > 0)
        p.tag = JSON.stringify(p.tag);
      else
        delete p.tag;
    }

    if (p.expire === "") {
      delete p.expire;
    }

    if (p.cronTime === "") {
      delete p.cronTime;
    }

    return flat.flatten(p);
  }
}

Policy.INTF_PREFIX = "intf:";
Policy.TAG_PREFIX = "tag:";

module.exports = Policy
<|endoftext|>


<commit_before>import invariant from 'invariant';
import deepEqual from 'deep-equal';
import { PUSH, REPLACE } from './Actions';
import createLocation from './createLocation';

function createRandomKey(length) {
  return Math.random().toString(36).substr(2, length);
}

function locationsAreEqual(a, b) {
  return a.pathname === b.pathname &&
    a.search === b.search &&
    //a.action === b.action && // Different action !== location change.
    a.key === b.key &&
    deepEqual(a.state, b.state);
}

var DefaultKeyLength = 6;

function createHistory(options={}) {
  var { getCurrentLocation, finishTransition, cancelTransition, go, keyLength, getUserConfirmation } = options;

  if (typeof keyLength !== 'number')
    keyLength = DefaultKeyLength;

  var transitionHooks = [];
  var transitionMiddlewareHandlers = [];
  var changeListeners = [];
  var pendingLocation;
  var location;

  function updateLocation(newLocation) {
    location = newLocation;

    changeListeners.forEach(function (listener) {
      listener(location);
    });
  }

  function addChangeListener(listener) {
    changeListeners.push(listener);
  }

  function removeChangeListener(listener) {
    changeListeners = changeListeners.filter(item => item !== listener);
  }

  function listen(listener) {
    addChangeListener(listener);

    if (location) {
      listener(location);
    } else {
      var currentLocation = getCurrentLocation();
      pendingLocation = currentLocation;
      processMiddleware(function(ok) {
        if (pendingLocation !== currentLocation) {
          return; // An intercepting transition has occured.
        }
        pendingLocation = null;
        if (ok) {
          updateLocation(currentLocation);
        } else {
          invariant(false, 'The initial route location transition was aborted by middleware.');
        }
      });
    }

    return function () {
      removeChangeListener(listener);
    };
  }

  function registerTransitionHook(hook) {
    if (transitionHooks.indexOf(hook) === -1)
      transitionHooks.push(hook);
  }

  function unregisterTransitionHook(hook) {
    transitionHooks = transitionHooks.filter(item => item !== hook);
  }

  function registerTransitionMiddleware(handler) {
    if (transitionMiddlewareHandlers.indexOf(handler) === -1)
      transitionMiddlewareHandlers.push(handler);
    return function() {
      unregisterTransitionMiddleware(handler);
    }
  }

  function unregisterTransitionMiddleware(handler) {
    transitionMiddlewareHandlers = transitionMiddlewareHandlers.filter(item => item !== handler);
  }

  function processMiddleware(callback, optionalMiddleware) {
    let handlers = optionalMiddleware || transitionMiddlewareHandlers;

    // No hanldlers to process? We're done.
    if (handlers.length === 0) {
      callback(true);
      return;
    }

    // Run middleware.
    let pendingLocationCache = pendingLocation;
    handlers[0](pendingLocation, location, function (value) {
        if (pendingLocationCache === pendingLocation) {
          if (arguments.length === 0) {
            // No value? Continue.
            processMiddleware(callback, handlers.slice(1));
          } else if (value === false) {
            // Abort on a value of false.
            callback(false);
          } else if (typeof value.pathname === 'string') {
            // Redirect if the value is a location.
            transitionTo(value);
          } else {
            invariant(false, 'Unexpected middleware value "%s"', value);
          }
        }
      }
    );
  }

  function getTransitionConfirmationMessage() {
    var message = null;

    for (var i = 0, len = transitionHooks.length; i < len && message == null; ++i)
      message = transitionHooks[i].call(this);

    return message;
  }

  function confirmTransition(callback) {
    var message = getTransitionConfirmationMessage();

    if (getUserConfirmation && typeof message === 'string') {
      getUserConfirmation(message, function (ok) {
        callback(ok !== false);
      });
    } else {
      callback(message !== false);
    }
  }

  function transitionTo(nextLocation) {
    if (location && locationsAreEqual(location, nextLocation))
      return; // Nothing to do.

    pendingLocation = nextLocation;

    processMiddleware(function(ok) {
      if (pendingLocation !== nextLocation) {
        return; // An interecepting transition has occurred.
      }
      if (ok) {
        confirmTransition(function (ok) {
          if (pendingLocation !== nextLocation) {
            return; // An interecepting transition has occurred.
          }
          pendingLocation = null;
          if (ok) {
            finishTransition(nextLocation);
            updateLocation(nextLocation);
          } else if (cancelTransition) {
            cancelTransition(nextLocation);
          }
        });
      } else if (cancelTransition) {
        pendingLocation = null;
        cancelTransition(nextLocation);
      }
    });
  }

  function pushState(state, path) {
    transitionTo(
      createLocation(path, state, PUSH, createKey())
    );
  }

  function replaceState(state, path) {
    transitionTo(
      createLocation(path, state, REPLACE, createKey())
    );
  }

  function goBack() {
    go(-1);
  }

  function goForward() {
    go(1);
  }

  function createKey() {
    return createRandomKey(keyLength);
  }

  function createHref(path) {
    return path;
  }

  return {
    listen,
    registerTransitionHook,
    unregisterTransitionHook,
    registerTransitionMiddleware,
    unregisterTransitionMiddleware,
    getTransitionConfirmationMessage,
    transitionTo,
    pushState,
    replaceState,
    go,
    goBack,
    goForward,
    createKey,
    createHref
  };
}

export default createHistory;
<commit_msg>Continue on a value of true.<commit_after>import invariant from 'invariant';
import deepEqual from 'deep-equal';
import { PUSH, REPLACE } from './Actions';
import createLocation from './createLocation';

function createRandomKey(length) {
  return Math.random().toString(36).substr(2, length);
}

function locationsAreEqual(a, b) {
  return a.pathname === b.pathname &&
    a.search === b.search &&
    //a.action === b.action && // Different action !== location change.
    a.key === b.key &&
    deepEqual(a.state, b.state);
}

var DefaultKeyLength = 6;

function createHistory(options={}) {
  var { getCurrentLocation, finishTransition, cancelTransition, go, keyLength, getUserConfirmation } = options;

  if (typeof keyLength !== 'number')
    keyLength = DefaultKeyLength;

  var transitionHooks = [];
  var transitionMiddlewareHandlers = [];
  var changeListeners = [];
  var pendingLocation;
  var location;

  function updateLocation(newLocation) {
    location = newLocation;

    changeListeners.forEach(function (listener) {
      listener(location);
    });
  }

  function addChangeListener(listener) {
    changeListeners.push(listener);
  }

  function removeChangeListener(listener) {
    changeListeners = changeListeners.filter(item => item !== listener);
  }

  function listen(listener) {
    addChangeListener(listener);

    if (location) {
      listener(location);
    } else {
      var currentLocation = getCurrentLocation();
      pendingLocation = currentLocation;
      processMiddleware(function(ok) {
        if (pendingLocation !== currentLocation) {
          return; // An intercepting transition has occured.
        }
        pendingLocation = null;
        if (ok) {
          updateLocation(currentLocation);
        } else {
          invariant(false, 'The initial route location transition was aborted by middleware.');
        }
      });
    }

    return function () {
      removeChangeListener(listener);
    };
  }

  function registerTransitionHook(hook) {
    if (transitionHooks.indexOf(hook) === -1)
      transitionHooks.push(hook);
  }

  function unregisterTransitionHook(hook) {
    transitionHooks = transitionHooks.filter(item => item !== hook);
  }

  function registerTransitionMiddleware(handler) {
    if (transitionMiddlewareHandlers.indexOf(handler) === -1)
      transitionMiddlewareHandlers.push(handler);
    return function() {
      unregisterTransitionMiddleware(handler);
    }
  }

  function unregisterTransitionMiddleware(handler) {
    transitionMiddlewareHandlers = transitionMiddlewareHandlers.filter(item => item !== handler);
  }

  function processMiddleware(callback, optionalMiddleware) {
    let handlers = optionalMiddleware || transitionMiddlewareHandlers;

    // No hanldlers to process? We're done.
    if (handlers.length === 0) {
      callback(true);
      return;
    }

    // Run middleware.
    let pendingLocationCache = pendingLocation;
    handlers[0](pendingLocation, location, function (value) {
        if (pendingLocationCache === pendingLocation) {
          if (arguments.length === 0 || value === true) {
            // No value? Continue.
            processMiddleware(callback, handlers.slice(1));
          } else if (value === false) {
            // Abort on a value of false.
            callback(false);
          } else if (typeof value.pathname === 'string') {
            // Redirect if the value is a location.
            transitionTo(value);
          } else {
            invariant(false, 'Unexpected middleware value "%s"', value);
          }
        }
      }
    );
  }

  function getTransitionConfirmationMessage() {
    var message = null;

    for (var i = 0, len = transitionHooks.length; i < len && message == null; ++i)
      message = transitionHooks[i].call(this);

    return message;
  }

  function confirmTransition(callback) {
    var message = getTransitionConfirmationMessage();

    if (getUserConfirmation && typeof message === 'string') {
      getUserConfirmation(message, function (ok) {
        callback(ok !== false);
      });
    } else {
      callback(message !== false);
    }
  }

  function transitionTo(nextLocation) {
    if (location && locationsAreEqual(location, nextLocation))
      return; // Nothing to do.

    pendingLocation = nextLocation;

    processMiddleware(function(ok) {
      if (pendingLocation !== nextLocation) {
        return; // An interecepting transition has occurred.
      }
      if (ok) {
        confirmTransition(function (ok) {
          if (pendingLocation !== nextLocation) {
            return; // An interecepting transition has occurred.
          }
          pendingLocation = null;
          if (ok) {
            finishTransition(nextLocation);
            updateLocation(nextLocation);
          } else if (cancelTransition) {
            cancelTransition(nextLocation);
          }
        });
      } else if (cancelTransition) {
        pendingLocation = null;
        cancelTransition(nextLocation);
      }
    });
  }

  function pushState(state, path) {
    transitionTo(
      createLocation(path, state, PUSH, createKey())
    );
  }

  function replaceState(state, path) {
    transitionTo(
      createLocation(path, state, REPLACE, createKey())
    );
  }

  function goBack() {
    go(-1);
  }

  function goForward() {
    go(1);
  }

  function createKey() {
    return createRandomKey(keyLength);
  }

  function createHref(path) {
    return path;
  }

  return {
    listen,
    registerTransitionHook,
    unregisterTransitionHook,
    registerTransitionMiddleware,
    unregisterTransitionMiddleware,
    getTransitionConfirmationMessage,
    transitionTo,
    pushState,
    replaceState,
    go,
    goBack,
    goForward,
    createKey,
    createHref
  };
}

export default createHistory;
<|endoftext|>


<commit_before>define([
        'config',
        'mustache',
		'text!views/FindAChurch/Search.html'
        ],
        function(config, Mustache, template){

    return Backbone.View.extend({
        initialize: function(){
            _.bindAll(this, 'location_keyup', 'geocode', 'set_distance_unit_preference',
                'is_distance_unit_preference_set', 'get_distance_units', 'location_keyup')
            window.app.geocoder = new google.maps.Geocoder();
        },
        render: function(){
            this.$el.html(Mustache.render(template))

            // Attach search event handler to search button and text box
            this.listenTo(this.$('.search'), 'click', this.geocode)
            this.listenTo(this.$('.location'), 'keyup', this.location_keyup)
            this.listenTo(this.$('.radius'), 'change', this.geocode)
            this.listenTo(this.$('.units'), 'change', this.set_distance_unit_preference)

            // TODO: Improve User Interface:
            // TODO: - Try to be able to guess which unit of distance (Mi or KM) they prefer based on
            //  some input from the user.
            // TODO:   * Event Handler: On page load

            //If the distance unit preference is set,
			// set the distance units in the form based on what is in the preference.
			if ( this.is_distance_unit_preference_set() ){
				this.$('.units').val(localStorage['units_of_measurement']);
			}
            // TODO:     * Else, on page load, before the person searches,
			else {
				// TODO: guess what units they want based on one of the following:
                //            * First try the users' browser's geolocation information. If
                //                  the user is in one of the countries that use miles, select "miles" in the form
                //                  and save it to the preference.

                var thiz=this

                if (navigator.geolocation){
                    // Center the map on the viewer's country by default
                    navigator.geolocation.getCurrentPosition(function(position){
                        window.app.geocoder = new google.maps.Geocoder();
                        window.app.geocoder.geocode( { 'address': position.coords.latitude + "," + position.coords.longitude}, function(results, status) {
                        //	Underscore.js _.filter() method) for results[0].address_components[x].types.short_name == 'US'
                            if (status == google.maps.GeocoderStatus.OK){
                                // Set the user's location's country's distance units in the form
                                thiz.$('.units').val(thiz.get_distance_units(results))
                            }
                        })
                    })
                }else{
                    console.log("Geolocation is not supported by this browser.");
                    // TODO:   * Next try figuring it based on the country in which they are searching.
                    //              Look at the results Google's geocode API returns from the user's search for an address,
                    //              and extract the country name from those results. Then use the other code we've already
                    //              written to determine whether that country uses miles or kilometers.
                    // TODO:   * Next, try the browser country or language setting.
                    // TODO:   * Maybe try their IP address (but this might be hard to do from JavaScript in the browser).

                    this.create_map({coords:this.default_map_center})
                }

			}
        },
		is_distance_unit_preference_set:function(){
			// Get preference here
			localStorage['units_of_measurement']
			if (typeof localStorage['units_of_measurement'] === 'undefined'){
				return false;
			}else{
				return true
			}
		},
		set_distance_unit_preference:function(){
			//  Set preference here
			localStorage['units_of_measurement'] = this.$('.units').val();

		},
        location_keyup:function(event){
            if (event.which == 13){
                this.geocode(event)
            }
        },
		get_distance_units:function(results){
            var country_names_objects = _.filter(results[0].address_components, function(item){
            	//See if it contains countries that use miles (GB, LR, MM, US)
                return ["United Kingdom", "Liberia", "Myanmar", "United States"].indexOf(item.long_name) !== -1
			});
            country_names = _.chain(country_names_objects)
                .pluck('long_name')
                .filter(function(item){ return typeof item !== 'undefined'; })
                .value()
            if (country_names.length >0){
                output = 'miles'
            }else{
                output = 'km'
            }
            return output;
		},
        geocode: function (event){
            event.preventDefault()
            // If user submitted an address, put that address into this.model
            // Use location user entered

            // Convert radius*units to meters
            var radius = $('.radius').val();
            var units = $('.units').val();
            var distance;
            if (units == 'miles'){
                distance = radius * 1609.344;
            } else if (units == 'km') {
                distance = radius * 1000;
            }

            //  TODO: Start here.
            // TODO: Event handler: On search form submission, record the currently-selected distance unit
            //  in a preference, and record there whether they selected it manually or not (NOTE: this second task
            //  is not done yet).
            // Geocode location
        	var thiz=this
            var location = $('.location').val()
            if (location == ''){
                location = thiz.model.get('location')
            }
            window.app.geocoder.geocode( { 'address': location}, function(results, status) {
                if (status == google.maps.GeocoderStatus.OK) {
                    // Put the above variables into this.model in one action so there's only one change event
                    thiz.model.set({
                        location:location,
                        radius:radius,
                        distance:distance,
                        units:units,
                        results:results
                    })
					if (!thiz.is_distance_unit_preference_set()){
    				    // Try figuring the user's distance_unit preference based on the country in which they are searching.
						var distance_units = thiz.get_distance_units(results)
    					// Set the preference to contain 'miles' or 'km'
						var distance_units = thiz.get_distance_units(results)
						localStorage['units_of_measurement'] = distance_units
                        // Set form to display the distance units of the country in which the user searched
                        thiz.$('.units').val(distance_units)
					}

                    // TODO: Send the request to Google; if Google says the location is ambiguous,
                    //  then use one of the location methods above (geolocation, etc.) to send Google
                    //  a hint about in which country the user is attempting to search.
             		// TODO: Event handler: On search results being returned to the browser from the
                    //  Google Maps API, Google's geocode responses state in which country the searched-for
                    //  location is found, so after they search, you can set their distance units for them
                    //  (in a preference and in the form) based on the country, unless (in a preference you can see)
                    //  they have already selected a distance unit manually.
                } else {
                    alert("Geocode was not successful for the following reason: " + status);
                }
            });
		}
    });
});<commit_msg>Improved comments<commit_after>define([
        'config',
        'mustache',
		'text!views/FindAChurch/Search.html'
        ],
        function(config, Mustache, template){

    return Backbone.View.extend({
        initialize: function(){
            _.bindAll(this, 'location_keyup', 'geocode', 'set_distance_unit_preference',
                'is_distance_unit_preference_set', 'get_distance_units', 'location_keyup')
            window.app.geocoder = new google.maps.Geocoder();
        },
        render: function(){
            this.$el.html(Mustache.render(template))

            // Attach search event handler to search button and text box
            this.listenTo(this.$('.search'), 'click', this.geocode)
            this.listenTo(this.$('.location'), 'keyup', this.location_keyup)
            this.listenTo(this.$('.radius'), 'change', this.geocode)
            this.listenTo(this.$('.units'), 'change', this.set_distance_unit_preference)

            // TODO: Improve User Interface:
            // TODO: - Try to be able to guess which unit of distance (Mi or KM) they prefer based on
            //  some input from the user.
            // TODO:   * Event Handler: On page load

            //If the distance unit preference is set,
			// set the distance units in the form based on what is in the preference.
			if ( this.is_distance_unit_preference_set() ){
				this.$('.units').val(localStorage['units_of_measurement']);
			}
            // TODO:     * Else, on page load, before the person searches,
			else {
				// TODO: guess what units they want based on one of the following:
                //            * First try the users' browser's geolocation information. If
                //                  the user is in one of the countries that use miles, select "miles" in the form
                //                  and save it to the preference.

                var thiz=this

                if (navigator.geolocation){
                    // Center the map on the viewer's country by default
                    navigator.geolocation.getCurrentPosition(function(position){
                        window.app.geocoder = new google.maps.Geocoder();
                        window.app.geocoder.geocode( { 'address': position.coords.latitude + "," + position.coords.longitude}, function(results, status) {
                        //	Underscore.js _.filter() method) for results[0].address_components[x].types.short_name == 'US'
                            if (status == google.maps.GeocoderStatus.OK){
                                // Set the user's location's country's distance units in the form
                                thiz.$('.units').val(thiz.get_distance_units(results))
                            }
                        })
                    })
                }else{
                    console.log("Geolocation is not supported by this browser.");
                    // TODO:   * Next, try the browser country or language setting.

                    // TODO:   * Maybe try their IP address (but this might be hard to do from JavaScript in the browser).

                    this.create_map({coords:this.default_map_center})
                }

			}
        },
		is_distance_unit_preference_set:function(){
			// Get preference here
			localStorage['units_of_measurement']
			if (typeof localStorage['units_of_measurement'] === 'undefined'){
				return false;
			}else{
				return true
			}
		},
		set_distance_unit_preference:function(){
			//  Set preference here
			localStorage['units_of_measurement'] = this.$('.units').val();

		},
        location_keyup:function(event){
            if (event.which == 13){
                this.geocode(event)
            }
        },
		get_distance_units:function(results){
            var country_names_objects = _.filter(results[0].address_components, function(item){
            	//See if it contains countries that use miles (GB, LR, MM, US)
                return ["United Kingdom", "Liberia", "Myanmar", "United States"].indexOf(item.long_name) !== -1
			});
            country_names = _.chain(country_names_objects)
                .pluck('long_name')
                .filter(function(item){ return typeof item !== 'undefined'; })
                .value()
            if (country_names.length >0){
                output = 'miles'
            }else{
                output = 'km'
            }
            return output;
		},
        geocode: function (event){
            event.preventDefault()
            // If user submitted an address, put that address into this.model
            // Use location user entered

            // Convert radius*units to meters
            var radius = $('.radius').val();
            var units = $('.units').val();
            var distance;
            if (units == 'miles'){
                distance = radius * 1609.344;
            } else if (units == 'km') {
                distance = radius * 1000;
            }

            //  TODO: Start here.
            // TODO: Event handler: On search form submission, record the currently-selected distance unit
            //  in a preference, and record there whether they selected it manually or not (NOTE: this second task
            //  is not done yet).
            // Geocode location
        	var thiz=this
            var location = $('.location').val()
            if (location == ''){
                location = thiz.model.get('location')
            }
            window.app.geocoder.geocode( { 'address': location}, function(results, status) {
                if (status == google.maps.GeocoderStatus.OK) {
                    // Put the above variables into this.model in one action so there's only one change event
                    thiz.model.set({
                        location:location,
                        radius:radius,
                        distance:distance,
                        units:units,
                        results:results
                    })
					if (!thiz.is_distance_unit_preference_set()){
    				    // Try figuring the user's distance_unit preference based on the country in which they are searching.
						var distance_units = thiz.get_distance_units(results)
    					// Set the preference to contain 'miles' or 'km'
						var distance_units = thiz.get_distance_units(results)
						localStorage['units_of_measurement'] = distance_units
                        // Set form to display the distance units of the country in which the user searched
                        thiz.$('.units').val(distance_units)
					}

                    // TODO: Send the request to Google; if Google says the location is ambiguous,
                    //  then use one of the location methods above (geolocation, etc.) to send Google
                    //  a hint about in which country the user is attempting to search.
             		// TODO: Event handler: On search results being returned to the browser from the
                    //  Google Maps API, Google's geocode responses state in which country the searched-for
                    //  location is found, so after they search, you can set their distance units for them
                    //  (in a preference and in the form) based on the country, unless (in a preference you can see)
                    //  they have already selected a distance unit manually.
                } else {
                    alert("Geocode was not successful for the following reason: " + status);
                }
            });
		}
    });
});<|endoftext|>


<commit_before>// Update with your config settings.
require('dotenv').config({silent:true});

module.exports = {
  development: {
    client: 'pg',
    connection: 'postgres://localhost/microlens'
  },
  production: {
    client: 'pg',
    connection: process.env.DATABASE_URL
}

}
<commit_msg>modified knexfile again<commit_after>// Update with your config settings.
require('dotenv').config();

module.exports = {
  development: {
    client: 'pg',
    connection: 'postgres://localhost/microlens'
  },
  production: {
    client: 'pg',
    connection: process.env.DATABASE_URL
}

}
<|endoftext|>