<commit_before>jQuery(document).ready(function() {
	$ = jQuery;
	organism = {};

	/**
	 * Executed before table is populated
	 * ! must return the data !
	 */
	organism.tablePreProcess = function(data, flexigridOptions) {
		// FIXME table id 'organisms' should not be hard-coded
		data = gallery_addon.preProcess('organisms', 'gallery_image', data, flexigridOptions);
		return data;
	};

	/**
	 * Go to /organism/classifiction/id if not already there
	 */
	organism.loadClassification = function(id) {
		if(id == "navigateToMenu") {
			window.location = '/organism/';
		} else {
			var path = window.location.pathname.split('/');
			var currentId = path[path.length-1];
			if (parseInt(currentId) != parseInt(id))
				window.location = '/organism/classification/' + id;
		}
	};

	/**
	 * onSubmit handler for the classificators datatable
	 * ! has to return true to continue populating the table !
	 */
	organism.onClassificatorsSubmit = function() {
		$('.mTop, .mUp').click(function() {
			organism.loadClassification($(this).data('cid'));
		});
		return true;
	};

	/**
	 * Initialize Diagram hoover on naturvielfalt/organism
	 */
	organism.initDiagram = function() {
		var linkColor = '#000000'; //link color if not visited
		$('#diagram-image').mouseout(function (e) {

		    });

		$('#diagram-container area').each(function () {
			var artgroup = $(this).attr('id').replace('area_', '');
			//on mouseenter over an area, change the image to the according artgroup, and change the link color to white of the description div
		    $(this).mouseenter(function (e) {
		        $('#diagram-image').attr('src', 'sites/all/modules/organism/img/' + artgroup + '_aktiv.png');
		        $('#' + artgroup + '-link .classifier-div').css('color', '#ffffff');
		    });

		    $(this).mouseout(function (e) {
		    	$('#' + artgroup + '-link .classifier-div').css('color', linkColor);
		    	$('#diagram-image').attr('src', 'sites/all/modules/organism/img/gesamt.png');
		        //change the link color back to standard
		        $('#diagram-container area').each(function () {
		        	var artgroup = $(this).attr('id').replace('area_', '');
		        	 $('#' + artgroup + '-link .classifier-div').css('color', linkColor);
		    	});
		    });

			//on mouseenter over a description div: change image to the according artgroup, and change link color to white
			$('#' + artgroup + '-link .classifier-div').mouseenter(function(e) {
				if($('#diagram-image').attr('src') != 'sites/all/modules/organism/img/' + artgroup + '_aktiv.png')
				$('#diagram-image').attr('src', 'sites/all/modules/organism/img/' + artgroup + '_aktiv.png');
				$('#' + artgroup + '-link .classifier-div').css('color', '#ffffff');
			});
		});
	};

	//initial Diagram, if we found the diagram-container div
	if(!$.isEmptyObject($('.diagram-container area'))) {
		organism.initDiagram();
	}
});<commit_msg>removed unnecessary code<commit_after>jQuery(document).ready(function() {
	$ = jQuery;
	organism = {};

	/**
	 * Executed before table is populated
	 * ! must return the data !
	 */
	organism.tablePreProcess = function(data, flexigridOptions) {
		// FIXME table id 'organisms' should not be hard-coded
		data = gallery_addon.preProcess('organisms', 'gallery_image', data, flexigridOptions);
		return data;
	};

	/**
	 * Go to /organism/classifiction/id if not already there
	 */
	organism.loadClassification = function(id) {
		if(id == "navigateToMenu") {
			window.location = '/organism/';
		} else {
			var path = window.location.pathname.split('/');
			var currentId = path[path.length-1];
			if (parseInt(currentId) != parseInt(id))
				window.location = '/organism/classification/' + id;
		}
	};

	/**
	 * onSubmit handler for the classificators datatable
	 * ! has to return true to continue populating the table !
	 */
	organism.onClassificatorsSubmit = function() {
		$('.mTop, .mUp').click(function() {
			organism.loadClassification($(this).data('cid'));
		});
		return true;
	};

	/**
	 * Initialize Diagram hoover on naturvielfalt/organism
	 */
	organism.initDiagram = function() {
		var linkColor = '#000000'; //link color if not visited

		$('#diagram-container area').each(function () {
			var artgroup = $(this).attr('id').replace('area_', '');
			//on mouseenter over an area, change the image to the according artgroup, and change the link color to white of the description div
		    $(this).mouseenter(function (e) {
		        $('#diagram-image').attr('src', 'sites/all/modules/organism/img/' + artgroup + '_aktiv.png');
		        $('#' + artgroup + '-link .classifier-div').css('color', '#ffffff');
		    });

		    $(this).mouseout(function (e) {
		    	$('#' + artgroup + '-link .classifier-div').css('color', linkColor);
		    	$('#diagram-image').attr('src', 'sites/all/modules/organism/img/gesamt.png');
		        //change the link color back to standard
		        $('#diagram-container area').each(function () {
		        	var artgroup = $(this).attr('id').replace('area_', '');
		        	 $('#' + artgroup + '-link .classifier-div').css('color', linkColor);
		    	});
		    });

			//on mouseenter over a description div: change image to the according artgroup, and change link color to white
			$('#' + artgroup + '-link .classifier-div').mouseenter(function(e) {
				if($('#diagram-image').attr('src') != 'sites/all/modules/organism/img/' + artgroup + '_aktiv.png')
				$('#diagram-image').attr('src', 'sites/all/modules/organism/img/' + artgroup + '_aktiv.png');
				$('#' + artgroup + '-link .classifier-div').css('color', '#ffffff');
			});
		});
	};

	//initial Diagram, if we found the diagram-container div
	if(!$.isEmptyObject($('.diagram-container area'))) {
		organism.initDiagram();
	}
});<|endoftext|>


<commit_before>const { readFile, writeFile } = require('fs');

const files = [
  'allShapes.tsx',
  'londonCycle.tsx',
  'htmlFeatures.tsx',
  'threeDMap.tsx',
  'htmlCluster.tsx',
  'switchStyle.tsx',
  'geojsonLayer.tsx',
  'heatmap.tsx'
];

files.forEach((file) => {
  readFile(`./src/demos/${file}`, (err, data) => {
    if (err) {
      return console.log(err);
    }

    writeFile(`./src/demos/raws/${file.replace('tsx', 'raw')}`, data);
  });
});
<commit_msg>fix: add callback to writeFile call<commit_after>const { readFile, writeFile } = require('fs');

const files = [
  'allShapes.tsx',
  'londonCycle.tsx',
  'htmlFeatures.tsx',
  'threeDMap.tsx',
  'htmlCluster.tsx',
  'switchStyle.tsx',
  'geojsonLayer.tsx',
  'heatmap.tsx'
];

files.forEach((file) => {
  readFile(`./src/demos/${file}`, (err, data) => {
    if (err) {
      return console.log(err);
    }

    writeFile(`./src/demos/raws/${file.replace('tsx', 'raw')}`, data, () => {});
  });
});
<|endoftext|>


<commit_before>/*
 * This file is part of Report Portal.
 *
 * Report Portal is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Report Portal 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Report Portal.  If not, see <http://www.gnu.org/licenses/>.
 */
define(function (require, exports, module) {
    'use strict';

    var SingletonLaunchFilterCollection = require('filters/SingletonLaunchFilterCollection');
    var SingletonUserStorage = require('storage/SingletonUserStorage');
    var FilterLabelView = require('launches/FilterLabelView');
    var FilterPanelView = require('launches/FilterPanelView');
    var Util = require('util');
    var $ = require('jquery');
    var Epoxy = require('backbone-epoxy');
    var FilterModel = require('filters/FilterModel');
    var App = require('app');

    var config = App.getInstance();

    var LaunchHeaderView = Epoxy.View.extend({
        events: {
            'click [data-js-add-filter]': 'onClickAddFilter',
            'click [data-js-all-link]': 'onClickAllLink',
            'click [data-js-filter-entity-switcher]': 'onClickFilterEntitySwitcher'
        },

        bindings: {
            '[data-js-filter-entity-switcher]': 'classes: {"hide": active}',
            '[data-js-all-link]': 'attr: {href: url}, classes: {active: active}'
        },

        template: 'tpl-launch-header',
        initialize: function () {
            this.ready = $.Deferred();
            this.userStorage = new SingletonUserStorage();
            this.launchFilterCollection = new SingletonLaunchFilterCollection();
            this.model = new FilterModel({ id: 'all', active: true, name: 'All Launches', owner: config.userModel.get('name') });
            this.listenTo(this.launchFilterCollection, 'add', this.onAddFilter);
            this.listenTo(this.launchFilterCollection, 'change:activeFilter', this.onChangeActiveFilter);
            this.listenTo(this.launchFilterCollection, 'change:id', this.onChangeIdFilter);
            this.listenTo(this.userStorage, 'change:launchFilterCriteriaHide', this.onChangeFilterCriteriaShow);
            this.render();
        },
        render: function () {
            this.launchFilterCollection.ready.done(function () {
                this.listenTo(this.launchFilterCollection, 'reset', this.renderFilterList);
                this.$el.html(Util.templates(this.template));
                this.applyBindings();
                this.renderFilterList();
                this.onChangeFilterCriteriaShow(null, this.userStorage.get('launchFilterCriteriaHide'));
                this.ready.resolve();
            }.bind(this));
        },
        onChangeFilterCriteriaShow: function (model, hide) {
            if (hide) {
                $('.launches-header-block', this.$el).addClass('hide-criteria');
            } else {
                $('.launches-header-block', this.$el).removeClass('hide-criteria');
            }
        },
        onChangeActiveFilter: function (filterModel) {
            if (filterModel) {
                this.activateFilter(filterModel);
                this.renderActiveFilter(filterModel);
            } else {
                this.model.set({ active: true });
                this.renderActiveFilter(this.model);
                if (this.filterPanel) {
                    this.filterPanel.destroy();
                }
            }
        },
        renderActiveFilter: function (model) {
            var $container = $('[data-js-active-filter]', this.$el);
            $container.html('');
            var mobileFilterActive = new FilterLabelView({ model: model });
            $container.append(mobileFilterActive.$el);
        },
        setState: function (level) {
            $('.launches-header-block', this.$el).attr('data-js-state', level);
        },
        activateFilter: function (filterModel) {
            this.model.set({ active: false });
            if (this.filterPanel) {
                this.filterPanel.destroy();
            }
            this.filterPanel = new FilterPanelView({ model: filterModel });
            $('[data-js-filter-panel]', this.$el).html(this.filterPanel.$el);
        },
        onAddFilter: function (model) {
            var filter = new FilterLabelView({ model: model });
            $('[data-js-filter-list]', this.$el).append(filter.$el);
            var mobileFilter = new FilterLabelView({ model: model });
            $('[data-js-filter-list-mobile]', this.$el).append(mobileFilter.$el);
        },
        renderFilterList: function () {
            $('[data-js-filter-list]', this.$el).html('');
            $('[data-js-filter-list-mobile]', this.$el).html('');
            var mobileFilter = new FilterLabelView({ model: this.model });
            $('[data-js-filter-list-mobile]', this.$el).append(mobileFilter.$el);
            _.each(this.launchFilterCollection.models, function (model) {
                this.onAddFilter(model);
            }, this);
        },
        onClickFilterEntitySwitcher: function () {
            var curValue = this.userStorage.get('launchFilterCriteriaHide') || false;
            this.userStorage.set({ launchFilterCriteriaHide: !curValue });
        },
        onClickAddFilter: function () {
            config.trackingDispatcher.trackEventNumber(12);
            var newFilter = this.launchFilterCollection.generateTempModel();
            config.router.navigate(newFilter.get('url'), { trigger: true });
        },
        onClickAllLink: function () {
            config.trackingDispatcher.trackEventNumber(22);
        },
        onChangeIdFilter: function (filterModel) {
            config.router.navigate(filterModel.get('url'), { trigger: false });
        },
        discardTemporaryFiltersChanges: function () {
            var toRemove = this.launchFilterCollection.where({ temp: true });
            this.launchFilterCollection.remove(toRemove);
            _.each(this.launchFilterCollection.models, function (item) {
                item.set('newEntities', '');
            });
        },
        onDestroy: function () {
            this.filterPanel && this.filterPanel.destroy();
            this.model.destroy();
            this.discardTemporaryFiltersChanges();
            this.$el.empty();
        }
    });

    return LaunchHeaderView;
});
<commit_msg>Set 'open' state for filters criteria in case of adding a new filter.<commit_after>/*
 * This file is part of Report Portal.
 *
 * Report Portal is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Report Portal 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Report Portal.  If not, see <http://www.gnu.org/licenses/>.
 */
define(function (require) {
    'use strict';

    var SingletonLaunchFilterCollection = require('filters/SingletonLaunchFilterCollection');
    var SingletonUserStorage = require('storage/SingletonUserStorage');
    var FilterLabelView = require('launches/FilterLabelView');
    var FilterPanelView = require('launches/FilterPanelView');
    var Util = require('util');
    var $ = require('jquery');
    var _ = require('underscore');
    var Epoxy = require('backbone-epoxy');
    var FilterModel = require('filters/FilterModel');
    var App = require('app');

    var config = App.getInstance();

    var LaunchHeaderView = Epoxy.View.extend({
        events: {
            'click [data-js-add-filter]': 'onClickAddFilter',
            'click [data-js-all-link]': 'onClickAllLink',
            'click [data-js-filter-entity-switcher]': 'onClickFilterEntitySwitcher'
        },

        bindings: {
            '[data-js-filter-entity-switcher]': 'classes: {"hide": active}',
            '[data-js-all-link]': 'attr: {href: url}, classes: {active: active}'
        },

        template: 'tpl-launch-header',
        initialize: function () {
            this.ready = $.Deferred();
            this.userStorage = new SingletonUserStorage();
            this.launchFilterCollection = new SingletonLaunchFilterCollection();
            this.model = new FilterModel({ id: 'all', active: true, name: 'All Launches', owner: config.userModel.get('name') });
            this.listenTo(this.launchFilterCollection, 'add', this.onAddFilter);
            this.listenTo(this.launchFilterCollection, 'change:activeFilter', this.onChangeActiveFilter);
            this.listenTo(this.launchFilterCollection, 'change:id', this.onChangeIdFilter);
            this.listenTo(this.userStorage, 'change:launchFilterCriteriaHide', this.onChangeFilterCriteriaShow);
            this.render();
        },
        render: function () {
            this.launchFilterCollection.ready.done(function () {
                this.listenTo(this.launchFilterCollection, 'reset', this.renderFilterList);
                this.$el.html(Util.templates(this.template));
                this.applyBindings();
                this.renderFilterList();
                this.onChangeFilterCriteriaShow(null, this.userStorage.get('launchFilterCriteriaHide'));
                this.ready.resolve();
            }.bind(this));
        },
        onChangeFilterCriteriaShow: function (model, hide) {
            if (hide) {
                $('.launches-header-block', this.$el).addClass('hide-criteria');
            } else {
                $('.launches-header-block', this.$el).removeClass('hide-criteria');
            }
        },
        onChangeActiveFilter: function (filterModel) {
            if (filterModel) {
                this.activateFilter(filterModel);
                this.renderActiveFilter(filterModel);
                this.onChangeFilterCriteriaShow(null, filterModel.get('temp') ? false : this.userStorage.get('launchFilterCriteriaHide'));
            } else {
                this.model.set({ active: true });
                this.renderActiveFilter(this.model);
                if (this.filterPanel) {
                    this.filterPanel.destroy();
                }
            }
        },
        renderActiveFilter: function (model) {
            var $container = $('[data-js-active-filter]', this.$el);
            var mobileFilterActive = new FilterLabelView({ model: model });
            $container.html('');
            $container.append(mobileFilterActive.$el);
        },
        setState: function (level) {
            $('.launches-header-block', this.$el).attr('data-js-state', level);
        },
        activateFilter: function (filterModel) {
            this.model.set({ active: false });
            if (this.filterPanel) {
                this.filterPanel.destroy();
            }
            this.filterPanel = new FilterPanelView({ model: filterModel });
            $('[data-js-filter-panel]', this.$el).html(this.filterPanel.$el);
        },
        onAddFilter: function (model) {
            var filter = new FilterLabelView({ model: model });
            var mobileFilter = new FilterLabelView({ model: model });
            $('[data-js-filter-list]', this.$el).append(filter.$el);
            $('[data-js-filter-list-mobile]', this.$el).append(mobileFilter.$el);
        },
        renderFilterList: function () {
            var mobileFilter = new FilterLabelView({ model: this.model });
            $('[data-js-filter-list]', this.$el).html('');
            $('[data-js-filter-list-mobile]', this.$el).html('');
            $('[data-js-filter-list-mobile]', this.$el).append(mobileFilter.$el);
            _.each(this.launchFilterCollection.models, function (model) {
                this.onAddFilter(model);
            }, this);
        },
        onClickFilterEntitySwitcher: function () {
            var curValue = this.userStorage.get('launchFilterCriteriaHide') || false;
            this.userStorage.set({ launchFilterCriteriaHide: !curValue });
        },
        onClickAddFilter: function () {
            var newFilter = this.launchFilterCollection.generateTempModel();
            config.trackingDispatcher.trackEventNumber(12);
            config.router.navigate(newFilter.get('url'), { trigger: true });
        },
        onClickAllLink: function () {
            config.trackingDispatcher.trackEventNumber(22);
        },
        onChangeIdFilter: function (filterModel) {
            config.router.navigate(filterModel.get('url'), { trigger: false });
        },
        discardTemporaryFiltersChanges: function () {
            var toRemove = this.launchFilterCollection.where({ temp: true });
            this.launchFilterCollection.remove(toRemove);
            _.each(this.launchFilterCollection.models, function (item) {
                item.set('newEntities', '');
            });
        },
        onDestroy: function () {
            this.filterPanel && this.filterPanel.destroy();
            this.model.destroy();
            this.discardTemporaryFiltersChanges();
            this.$el.empty();
        }
    });

    return LaunchHeaderView;
});
<|endoftext|>


<commit_before>/**
 * Patterns autosuggest - suggestion/completion support
 *
 * Copyright 2012-2013 Florian Friesdorf
 * Copyright 2012 JC Brand
 * Copyright 2013 Marko Durkovic
 */
define([
    "jquery",
    "../core/parser",
    "../registry",
    "jquery.select2"
], function($, Parser, registry) {
    var parser = new Parser("autosuggest");
    parser.add_argument("words", "");
    parser.add_argument("pre-fill", function($el) { return $el.val(); });
    parser.add_argument("placeholder", function($el) {
        return $el.attr("placeholder") || "Enter text";
    });

    var autosuggestTextToHidden = {
        name: "autosuggestTextToHidden",
        transform: function($content) {
            $content.filter('input[type=text].pat-autosuggest').each(function() {
                $(this).clone().attr('type','hidden').insertAfter($(this)).prev().remove();
            });
            $content.find('input[type=text].pat-autosuggest').each(function() {
                $(this).clone().attr('type','hidden').insertAfter($(this)).prev().remove();
            });
        }
    };
    registry.register(autosuggestTextToHidden);

    var _ = {
        name: "autosuggest",
        trigger: "input.pat-autosuggest",
        init: function($el, opts) {
            if ($el.length > 1)
                return $el.each(function() { _.init($(this), opts); });

            var cfg = parser.parse($el, opts);
            cfg.startText =  $el.attr("readonly") ? "" : cfg.placeholder;

            $el.val(cfg.preFill.split(','));
            $el.select2({tags: cfg.words.split(/\s*,\s*/)});

            // suppress propagation for second input field
            $el.prev().on("input-change input-defocus input-change-delayed",
                function(e) { e.stopPropagation(); }
            );
            return $el;
        },
        destroy: function($el) {
            $el.off(".pat-autosuggest");
            $el.select2("destroy");
        }
    };
    registry.register(_);
    return _;
});

// jshint indent: 4, browser: true, jquery: true, quotmark: double
// vim: sw=4 expandtab
<commit_msg>Recreate element instead of changing type.<commit_after>/**
 * Patterns autosuggest - suggestion/completion support
 *
 * Copyright 2012-2013 Florian Friesdorf
 * Copyright 2012 JC Brand
 * Copyright 2013 Marko Durkovic
 */
define([
    "jquery",
    "../core/parser",
    "../registry",
    "jquery.select2"
], function($, Parser, registry) {
    var parser = new Parser("autosuggest");
    parser.add_argument("words", "");
    parser.add_argument("pre-fill", function($el) { return $el.val(); });
    parser.add_argument("placeholder", function($el) {
        return $el.attr("placeholder") || "Enter text";
    });

    var _ = {
        name: "autosuggest",
        trigger: "input.pat-autosuggest",
        init: function($el, opts) {
            if ($el.length > 1)
                return $el.each(function() { _.init($(this), opts); });

            var cfg = parser.parse($el, opts);
            cfg.startText =  $el.attr("readonly") ? "" : cfg.placeholder;

            $el.val(cfg.preFill.split(','));
            $el.select2({tags: cfg.words.split(/\s*,\s*/)});

            // suppress propagation for second input field
            $el.prev().on("input-change input-defocus input-change-delayed",
                function(e) { e.stopPropagation(); }
            );
            return $el;
        },
        destroy: function($el) {
            $el.off(".pat-autosuggest");
            $el.select2("destroy");
        },
        transform: function($content) {
            $content.filter('input[type=text].pat-autosuggest').each(function() {
                var $src = $(this),
                    $dest = $('<input type="hidden"/>').insertAfter($src);

                $src.detach();
                $.each($src.prop('attributes'), function() {
                    if (this.name !== 'type') {
                        $dest.attr(this.name, this.value);
                    }
                });
                $src.remove();
            });

            $content.find('input[type=text].pat-autosuggest').each(function() {
                var $src = $(this),
                    $dest = $('<input type="hidden"/>').insertAfter($src);

                $src.detach();
                $.each($src.prop('attributes'), function() {
                    if (this.name !== 'type') {
                        $dest.attr(this.name, this.value);
                    }
                });
                $src.remove();
            });
        }
    };
    registry.register(_);
    return _;
});

// jshint indent: 4, browser: true, jquery: true, quotmark: double
// vim: sw=4 expandtab
<|endoftext|>


<commit_before>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

// An Algorithm for Automatically Fitting Digitized Curves
// by Philip J. Schneider
// from "Graphics Gems", Academic Press, 1990
// Modifications and optimisations of original algorithm by Juerg Lehni.

var PathFitter = Base.extend({
	initialize: function(path, error) {
		this.points = [];
		var segments = path._segments,
			prev;
		// Copy over points from path and filter out adjacent duplicates.
		for (var i = 0, l = segments.length; i < l; i++) {
			var point = segments[i].point.clone();
			if (!prev || !prev.equals(point)) {
				this.points.push(point);
				prev = point;
			}
		}
		this.error = error;
	},

	fit: function() {
		this.segments = [new Segment(this.points[0])];
		this.fitCubic(0, this.points.length - 1,
				// Left Tangent
				this.points[1].subtract(this.points[0]).normalize(),
				// Right Tangent
				this.points[this.points.length - 2].subtract(
					this.points[this.points.length - 1]).normalize());
		return this.segments;
	},

	// Fit a Bezier curve to a (sub)set of digitized points
	fitCubic: function(first, last, tan1, tan2) {
		//	Use heuristic if region only has two points in it
		if (last - first == 1) {
			var pt1 = this.points[first],
				pt2 = this.points[last],
				dist = pt1.getDistance(pt2) / 3;
			this.addCurve([pt1, pt1.add(tan1.normalize(dist)),
					pt2.add(tan2.normalize(dist)), pt2]);
			return;
		}
		// Parameterize points, and attempt to fit curve
		var uPrime = this.chordLengthParameterize(first, last),
			maxError = Math.max(this.error, this.error * this.error),
			error,
			split;
		// Try 4 iterations
		for (var i = 0; i <= 4; i++) {
			var curve = this.generateBezier(first, last, uPrime, tan1, tan2);
			//	Find max deviation of points to fitted curve
			var max = this.findMaxError(first, last, curve, uPrime);
			if (max.error < this.error) {
				this.addCurve(curve);
				return;
			}
			split = max.index;
			// If error not too large, try reparameterization and iteration
			if (max.error >= maxError)
				break;
			this.reparameterize(first, last, uPrime, curve);
			maxError = max.error;
		}
		// Fitting failed -- split at max error point and fit recursively
		var V1 = this.points[split - 1].subtract(this.points[split]),
			V2 = this.points[split].subtract(this.points[split + 1]),
			tanCenter = V1.add(V2).divide(2).normalize();
		this.fitCubic(first, split, tan1, tanCenter);
		this.fitCubic(split, last, tanCenter.negate(), tan2);
	},

	addCurve: function(curve) {
		var prev = this.segments[this.segments.length - 1];
		prev.setHandleOut(curve[1].subtract(curve[0]));
		this.segments.push(
				new Segment(curve[3], curve[2].subtract(curve[3])));
	},

	// Use least-squares method to find Bezier control points for region.
	generateBezier: function(first, last, uPrime, tan1, tan2) {
		var epsilon = Numerical.EPSILON,
			pt1 = this.points[first],
			pt2 = this.points[last],
			// Create the C and X matrices
		 	C = [[0, 0], [0, 0]],
			X = [0, 0];

		for (var i = 0, l = last - first + 1; i < l; i++) {
			var u = uPrime[i],
				t = 1 - u,
				b = 3 * u * t,
				b0 = t * t * t,
				b1 = b * t,
				b2 = b * u,
				b3 = u * u * u,
				a1 = tan1.normalize(b1),
				a2 = tan2.normalize(b2),
				tmp = this.points[first + i]
					.subtract(pt1.multiply(b0 + b1))
					.subtract(pt2.multiply(b2 + b3));
			C[0][0] += a1.dot(a1);
			C[0][1] += a1.dot(a2);
			// C[1][0] += a1.dot(a2);
			C[1][0] = C[0][1];
			C[1][1] += a2.dot(a2);
			X[0] += a1.dot(tmp);
			X[1] += a2.dot(tmp);
		}

		// Compute the determinants of C and X
		var detC0C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1],
			alpha1, alpha2;
		if (Math.abs(detC0C1) > epsilon) {
			// Kramer's rule
			var detC0X  = C[0][0] * X[1]    - C[1][0] * X[0],
				detXC1  = X[0]    * C[1][1] - X[1]    * C[0][1];
			// Derive alpha values
			alpha1 = detXC1 / detC0C1;
			alpha2 = detC0X / detC0C1;
		} else {
			// Matrix is under-determined, try assuming alpha1 == alpha2
			var c0 = C[0][0] + C[0][1],
				c1 = C[1][0] + C[1][1];
			if (Math.abs(c0) > epsilon) {
				alpha1 = alpha2 = X[0] / c0;
			} else if (Math.abs(c1) > epsilon) {
				alpha1 = alpha2 = X[1] / c1;
			} else {
				// Handle below
				alpha1 = alpha2 = 0.;
			}
		}

		// If alpha negative, use the Wu/Barsky heuristic (see text)
		// (if alpha is 0, you get coincident control points that lead to
		// divide by zero in any subsequent NewtonRaphsonRootFind() call.
		var segLength = pt2.getDistance(pt1);
		epsilon *= segLength;
		if (alpha1 < epsilon || alpha2 < epsilon) {
			// fall back on standard (probably inaccurate) formula,
			// and subdivide further if needed.
			alpha1 = alpha2 = segLength / 3;
		}

		// First and last control points of the Bezier curve are
		// positioned exactly at the first and last data points
		// Control points 1 and 2 are positioned an alpha distance out
		// on the tangent vectors, left and right, respectively
		return [pt1, pt1.add(tan1.normalize(alpha1)),
				pt2.add(tan2.normalize(alpha2)), pt2];
	},

	// Given set of points and their parameterization, try to find
	// a better parameterization.
	reparameterize: function(first, last, u, curve) {
		for (var i = first; i <= last; i++) {
			u[i - first] = this.findRoot(curve, this.points[i], u[i - first]);
		}
	},

	// Use Newton-Raphson iteration to find better root.
	findRoot: function(curve, point, u) {
		var curve1 = [],
			curve2 = [];
		// Generate control vertices for Q'
		for (var i = 0; i <= 2; i++) {
			curve1[i] = curve[i + 1].subtract(curve[i]).multiply(3);
		}
		// Generate control vertices for Q''
		for (var i = 0; i <= 1; i++) {
			curve2[i] = curve1[i + 1].subtract(curve1[i]).multiply(2);
		}
		// Compute Q(u), Q'(u) and Q''(u)
		var pt = this.evaluate(3, curve, u),
		 	pt1 = this.evaluate(2, curve1, u),
		 	pt2 = this.evaluate(1, curve2, u),
		 	diff = pt.subtract(point),
			df = pt1.dot(pt1) + diff.dot(pt2);
		// Compute f(u) / f'(u)
		if (Math.abs(df) < Numerical.TOLERANCE)
			return u;
		// u = u - f(u) / f'(u)
		return u - diff.dot(pt1) / df;
	},

	// Evaluate a Bezier curve at a particular parameter value
	evaluate: function(degree, curve, t) {
		// Copy array
		var tmp = curve.slice();
		// Triangle computation
		for (var i = 1; i <= degree; i++) {
			for (var j = 0; j <= degree - i; j++) {
				tmp[j] = tmp[j].multiply(1 - t).add(tmp[j + 1].multiply(t));
			}
		}
		return tmp[0];
	},

	// Assign parameter values to digitized points
	// using relative distances between points.
	chordLengthParameterize: function(first, last) {
		var u = [0];
		for (var i = first + 1; i <= last; i++) {
			u[i - first] = u[i - first - 1]
					+ this.points[i].getDistance(this.points[i - 1]);
		}
		for (var i = 1, m = last - first; i <= m; i++) {
			u[i] /= u[m];
		}
		return u;
	},

	// Find the maximum squared distance of digitized points to fitted curve.
	findMaxError: function(first, last, curve, u) {
		var index = Math.floor((last - first + 1) / 2),
			maxDist = 0;
		for (var i = first + 1; i < last; i++) {
			var P = this.evaluate(3, curve, u[i - first]);
			var v = P.subtract(this.points[i]);
			var dist = v.x * v.x + v.y * v.y; // squared
			if (dist >= maxDist) {
				maxDist = dist;
				index = i;
			}
		}
		return {
			error: maxDist,
			index: index
		};
	}
});
<commit_msg>Code clean-up.<commit_after>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

// An Algorithm for Automatically Fitting Digitized Curves
// by Philip J. Schneider
// from "Graphics Gems", Academic Press, 1990
// Modifications and optimisations of original algorithm by Juerg Lehni.

var PathFitter = Base.extend({
	initialize: function(path, error) {
		this.points = [];
		var segments = path._segments,
			prev;
		// Copy over points from path and filter out adjacent duplicates.
		for (var i = 0, l = segments.length; i < l; i++) {
			var point = segments[i].point.clone();
			if (!prev || !prev.equals(point)) {
				this.points.push(point);
				prev = point;
			}
		}
		this.error = error;
	},

	fit: function() {
		this.segments = [new Segment(this.points[0])];
		this.fitCubic(0, this.points.length - 1,
				// Left Tangent
				this.points[1].subtract(this.points[0]).normalize(),
				// Right Tangent
				this.points[this.points.length - 2].subtract(
					this.points[this.points.length - 1]).normalize());
		return this.segments;
	},

	// Fit a Bezier curve to a (sub)set of digitized points
	fitCubic: function(first, last, tan1, tan2) {
		//	Use heuristic if region only has two points in it
		if (last - first == 1) {
			var pt1 = this.points[first],
				pt2 = this.points[last],
				dist = pt1.getDistance(pt2) / 3;
			this.addCurve([pt1, pt1.add(tan1.normalize(dist)),
					pt2.add(tan2.normalize(dist)), pt2]);
			return;
		}
		// Parameterize points, and attempt to fit curve
		var uPrime = this.chordLengthParameterize(first, last),
			maxError = Math.max(this.error, this.error * this.error),
			error,
			split;
		// Try 4 iterations
		for (var i = 0; i <= 4; i++) {
			var curve = this.generateBezier(first, last, uPrime, tan1, tan2);
			//	Find max deviation of points to fitted curve
			var max = this.findMaxError(first, last, curve, uPrime);
			if (max.error < this.error) {
				this.addCurve(curve);
				return;
			}
			split = max.index;
			// If error not too large, try reparameterization and iteration
			if (max.error >= maxError)
				break;
			this.reparameterize(first, last, uPrime, curve);
			maxError = max.error;
		}
		// Fitting failed -- split at max error point and fit recursively
		var V1 = this.points[split - 1].subtract(this.points[split]),
			V2 = this.points[split].subtract(this.points[split + 1]),
			tanCenter = V1.add(V2).divide(2).normalize();
		this.fitCubic(first, split, tan1, tanCenter);
		this.fitCubic(split, last, tanCenter.negate(), tan2);
	},

	addCurve: function(curve) {
		var prev = this.segments[this.segments.length - 1];
		prev.setHandleOut(curve[1].subtract(curve[0]));
		this.segments.push(
				new Segment(curve[3], curve[2].subtract(curve[3])));
	},

	// Use least-squares method to find Bezier control points for region.
	generateBezier: function(first, last, uPrime, tan1, tan2) {
		var epsilon = Numerical.EPSILON,
			pt1 = this.points[first],
			pt2 = this.points[last],
			// Create the C and X matrices
			C = [[0, 0], [0, 0]],
			X = [0, 0];

		for (var i = 0, l = last - first + 1; i < l; i++) {
			var u = uPrime[i],
				t = 1 - u,
				b = 3 * u * t,
				b0 = t * t * t,
				b1 = b * t,
				b2 = b * u,
				b3 = u * u * u,
				a1 = tan1.normalize(b1),
				a2 = tan2.normalize(b2),
				tmp = this.points[first + i]
					.subtract(pt1.multiply(b0 + b1))
					.subtract(pt2.multiply(b2 + b3));
			C[0][0] += a1.dot(a1);
			C[0][1] += a1.dot(a2);
			// C[1][0] += a1.dot(a2);
			C[1][0] = C[0][1];
			C[1][1] += a2.dot(a2);
			X[0] += a1.dot(tmp);
			X[1] += a2.dot(tmp);
		}

		// Compute the determinants of C and X
		var detC0C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1],
			alpha1, alpha2;
		if (Math.abs(detC0C1) > epsilon) {
			// Kramer's rule
			var detC0X  = C[0][0] * X[1]    - C[1][0] * X[0],
				detXC1  = X[0]    * C[1][1] - X[1]    * C[0][1];
			// Derive alpha values
			alpha1 = detXC1 / detC0C1;
			alpha2 = detC0X / detC0C1;
		} else {
			// Matrix is under-determined, try assuming alpha1 == alpha2
			var c0 = C[0][0] + C[0][1],
				c1 = C[1][0] + C[1][1];
			if (Math.abs(c0) > epsilon) {
				alpha1 = alpha2 = X[0] / c0;
			} else if (Math.abs(c1) > epsilon) {
				alpha1 = alpha2 = X[1] / c1;
			} else {
				// Handle below
				alpha1 = alpha2 = 0;
			}
		}

		// If alpha negative, use the Wu/Barsky heuristic (see text)
		// (if alpha is 0, you get coincident control points that lead to
		// divide by zero in any subsequent NewtonRaphsonRootFind() call.
		var segLength = pt2.getDistance(pt1);
		epsilon *= segLength;
		if (alpha1 < epsilon || alpha2 < epsilon) {
			// fall back on standard (probably inaccurate) formula,
			// and subdivide further if needed.
			alpha1 = alpha2 = segLength / 3;
		}

		// First and last control points of the Bezier curve are
		// positioned exactly at the first and last data points
		// Control points 1 and 2 are positioned an alpha distance out
		// on the tangent vectors, left and right, respectively
		return [pt1, pt1.add(tan1.normalize(alpha1)),
				pt2.add(tan2.normalize(alpha2)), pt2];
	},

	// Given set of points and their parameterization, try to find
	// a better parameterization.
	reparameterize: function(first, last, u, curve) {
		for (var i = first; i <= last; i++) {
			u[i - first] = this.findRoot(curve, this.points[i], u[i - first]);
		}
	},

	// Use Newton-Raphson iteration to find better root.
	findRoot: function(curve, point, u) {
		var curve1 = [],
			curve2 = [];
		// Generate control vertices for Q'
		for (var i = 0; i <= 2; i++) {
			curve1[i] = curve[i + 1].subtract(curve[i]).multiply(3);
		}
		// Generate control vertices for Q''
		for (var i = 0; i <= 1; i++) {
			curve2[i] = curve1[i + 1].subtract(curve1[i]).multiply(2);
		}
		// Compute Q(u), Q'(u) and Q''(u)
		var pt = this.evaluate(3, curve, u),
			pt1 = this.evaluate(2, curve1, u),
			pt2 = this.evaluate(1, curve2, u),
			diff = pt.subtract(point),
			df = pt1.dot(pt1) + diff.dot(pt2);
		// Compute f(u) / f'(u)
		if (Math.abs(df) < Numerical.TOLERANCE)
			return u;
		// u = u - f(u) / f'(u)
		return u - diff.dot(pt1) / df;
	},

	// Evaluate a Bezier curve at a particular parameter value
	evaluate: function(degree, curve, t) {
		// Copy array
		var tmp = curve.slice();
		// Triangle computation
		for (var i = 1; i <= degree; i++) {
			for (var j = 0; j <= degree - i; j++) {
				tmp[j] = tmp[j].multiply(1 - t).add(tmp[j + 1].multiply(t));
			}
		}
		return tmp[0];
	},

	// Assign parameter values to digitized points
	// using relative distances between points.
	chordLengthParameterize: function(first, last) {
		var u = [0];
		for (var i = first + 1; i <= last; i++) {
			u[i - first] = u[i - first - 1]
					+ this.points[i].getDistance(this.points[i - 1]);
		}
		for (var i = 1, m = last - first; i <= m; i++) {
			u[i] /= u[m];
		}
		return u;
	},

	// Find the maximum squared distance of digitized points to fitted curve.
	findMaxError: function(first, last, curve, u) {
		var index = Math.floor((last - first + 1) / 2),
			maxDist = 0;
		for (var i = first + 1; i < last; i++) {
			var P = this.evaluate(3, curve, u[i - first]);
			var v = P.subtract(this.points[i]);
			var dist = v.x * v.x + v.y * v.y; // squared
			if (dist >= maxDist) {
				maxDist = dist;
				index = i;
			}
		}
		return {
			error: maxDist,
			index: index
		};
	}
});
<|endoftext|>


<commit_before>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

// An Algorithm for Automatically Fitting Digitized Curves
// by Philip J. Schneider
// from "Graphics Gems", Academic Press, 1990
var PathFitter = Base.extend({
	initialize: function(path, error) {
		//console.log(path.segments + '');
		this.maxIterations = 4;
		this.points = [];
		var segments = path._segments,
			prev;
		for (var i = 0, l = segments.length; i < l; i++) {
			var point = segments[i].point.clone();
			if (!prev || !prev.equals(point)) {
				this.points[i] = point;
				prev = point;
			}
		}
		this.points = this.reducePoints(this.points, 1);
		this.error = error;
		this.iterationError = error * error;
	},

	fit: function() {
		this.segments = [new Segment(this.points[0])];
		this.fitCubic(0, this.points.length - 1,
				// Left Tangent
				this.points[1].subtract(this.points[0]).normalize(),
				// Right Tangent
				this.points[this.points.length - 2].subtract(
					this.points[this.points.length - 1]).normalize());
		return this.segments;
	},

	// Douglas–Peucker algorithm
	reducePoints: function(points, tolerance) {
		var line = new Line(points[0], points[points.length - 1], false);
		var maxDistance = 0,
			maxIndex = 0;
		for (var i = 1; i < points.length - 1; i++) {
			var distance = line.getDistance(points[i]);
			if(distance > maxDistance) {
				maxDistance = distance;
				maxIndex = i;
			}
		}
		if (maxDistance >= tolerance) {
			var pts = this.reducePoints(
					points.slice(0, maxIndex + 1), tolerance);
			pts.pop();
			return pts.concat(this.reducePoints(
					points.slice(maxIndex, points.length), tolerance));
		}
		return [points[0], points[points.length - 1]];
	},

	// Fit a Bezier curve to a (sub)set of digitized points
	fitCubic: function(first, last, tHat1, tHat2) {
		//	Use heuristic if region only has two points in it
		if (last - first == 1) {
			var pt1 = this.points[first],
				pt2 = this.points[last],
				dist = pt1.getDistance(pt2) / 3;
			this.addCurve([pt1, pt1.add(tHat1.normalize(dist)),
					pt2.add(tHat2.normalize(dist)), pt2]);
			return;
		}
		// Parameterize points, and attempt to fit curve
		var uPrime = this.chordLengthParameterize(first, last),
			prevMaxError = this.iterationError,
			error,
			split;
		for (var i = 0; i < this.maxIterations; i++) {
			var bezCurve = this.generateBezier(first, last, uPrime, tHat1, tHat2);
			//	Find max deviation of points to fitted curve
			var max = this.findMaxError(first, last, bezCurve, uPrime);
			if (max.error < this.error) {
				this.addCurve(bezCurve);
				return;
			}
			split = max.index;
			// If error not too large, try some reparameterization and iteration
			if (max.error >= this.iterationError || max.error >= prevMaxError)
				break;
			uPrime = this.reparameterize(first, last, uPrime, bezCurve);
			prevMaxError = max.error;
		}
		// Fitting failed -- split at max error point and fit recursively
		var V1 = this.points[split - 1].subtract(this.points[split]),
			V2 = this.points[split].subtract(this.points[split + 1]),
			tHatCenter = V1.add(V2).divide(2).normalize();
		this.fitCubic(first, split, tHat1, tHatCenter);
		this.fitCubic(split, last, tHatCenter.negate(), tHat2);
	},

	addCurve: function(bezCurve) {
		var prev = this.segments[this.segments.length - 1];
		prev.setHandleOut(bezCurve[1].subtract(bezCurve[0]));
		this.segments.push(
				new Segment(bezCurve[3], bezCurve[2].subtract(bezCurve[3])));
	},

	// Use least-squares method to find Bezier control points for region.
	generateBezier: function(first, last, uPrime, tHat1, tHat2) {
		var nPts = last - first + 1,
			pt1 = this.points[first],
			pt2 = this.points[last];

		var A = [];
		// Compute the A's
		for (var i = 0; i < nPts; i++) {
			var u = uPrime[i],
				t = 1 - u,
				b = 3 * u * t;
			A[i] = [
				tHat1.normalize(b * t), // b1
				tHat2.normalize(b * u)  // b2
			];
		}

		// Create the C and X matrices
		var C = [[0, 0], [0, 0]],
			X = [0, 0];

		for (var i = 0; i < nPts; i++) {
			C[0][0] += A[i][0].dot(A[i][0]);
			C[0][1] += A[i][0].dot(A[i][1]);
			// C[1][0] += A[i][0].dot(A[i][1]);
			C[1][0] = C[0][1];
			C[1][1] += A[i][1].dot(A[i][1]);

			var u = uPrime[i],
				t = 1 - u,
				b = 3 * u * t,
				tmp = this.points[first + i]
					.subtract(pt1.multiply(t * t * t) // b0
						.add(pt1.multiply(b * t)) // b1
						.add(pt2.multiply(b * u)) // b2
						.add(pt2.multiply(u * u * u))); // b3
			X[0] += A[i][0].dot(tmp);
			X[1] += A[i][1].dot(tmp);
		}

		// Compute the determinants of C and X
		var det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1],
			det_C0_X  = C[0][0] * X[1]    - C[1][0] * X[0],
			det_X_C1  = X[0]    * C[1][1] - X[1]    * C[0][1],
			singularity = det_C0_C1 < Numerical.TOLERANCE;

		// Finally, derive alpha values
		var alpha_l = singularity ? 0 : det_X_C1 / det_C0_C1,
			alpha_r = singularity ? 0 : det_C0_X / det_C0_C1;

		// If alpha negative, use the Wu/Barsky heuristic (see text)
		// (if alpha is 0, you get coincident control points that lead to
		// divide by zero in any subsequent NewtonRaphsonRootFind() call.
		var segLength = pt2.getDistance(pt1),
			epsilon = Numerical.TOLERANCE * segLength;
		if (alpha_l < epsilon || alpha_r < epsilon) {
			// fall back on standard (probably inaccurate) formula,
			// and subdivide further if needed.
			alpha_l = alpha_r = segLength / 3;
		}

		// First and last control points of the Bezier curve are
		// positioned exactly at the first and last data points
		// Control points 1 and 2 are positioned an alpha distance out
		// on the tangent vectors, left and right, respectively
		return [pt1, pt1.add(tHat1.normalize(alpha_l)),
				pt2.add(tHat2.normalize(alpha_r)), pt2];
	},

	// Given set of points and their parameterization, try to find
	// a better parameterization.
	reparameterize: function(first, last, u, bezCurve) {
		var uPrime = [];
		for (var i = first; i <= last; i++) {
			uPrime[i - first] = this.findRoot(bezCurve, this.points[i],
					u[i - first]);
		}
		return uPrime;
	},

	// Use Newton-Raphson iteration to find better root.
	findRoot: function(Q, P, u) {
		var Q1 = [],
			Q2 = [];
		// Generate control vertices for Q'
		for (var i = 0; i <= 2; i++) {
			Q1[i] = Q[i + 1].subtract(Q[i]).multiply(3);
		}
		// Generate control vertices for Q''
		for (var i = 0; i <= 1; i++) {
			Q2[i] = Q1[i + 1].subtract(Q1[i]).multiply(2);
		}
		// Compute Q(u), Q'(u) and Q''(u)
		Q_u = this.evaluate(3, Q, u);
		Q1_u = this.evaluate(2, Q1, u);
		Q2_u = this.evaluate(1, Q2, u);
		// Compute f(u)/f'(u)
		var V = Q_u.subtract(P),
			df = Q1_u.dot(Q1_u) + V.dot(Q2_u);
		if (df == 0)
			return u;
		// u = u - f(u) / f'(u)
		return u - V.dot(Q1_u) / df;
	},

	// Evaluate a Bezier curve at a particular parameter value
	evaluate: function(degree, V, t) {
		// Copy array
		var Vtemp = V.slice();
		// Triangle computation
		for (var i = 1; i <= degree; i++) {
			for (var j = 0; j <= degree - i; j++) {
				Vtemp[j] = Vtemp[j].multiply(1 - t).add(Vtemp[j + 1].multiply(t));
			}
		}
		return Vtemp[0];
	},

	// Assign parameter values to digitized points
	// using relative distances between points.
	chordLengthParameterize: function(first, last) {
		var u = [0];
		for (var i = first + 1; i <= last; i++) {
			u[i - first] = u[i - first - 1]
					+ this.points[i].getDistance(this.points[i - 1]);
		}
		for (var i = first + 1; i <= last; i++) {
			u[i - first] = u[i - first] / u[last - first];
		}
		return u;
	},

	// Find the maximum squared distance of digitized points
	// to fitted curve.
	findMaxError: function(first, last, bezCurve, u) {
		var index = Math.floor((last - first + 1) / 2),
			maxDist = 0;
		for (var i = first + 1; i < last; i++) {
			var P = this.evaluate(3, bezCurve, u[i - first]);
			var v = P.subtract(this.points[i]);
			var dist = v.x * v.x + v.y * v.y; // squared
			if (dist >= maxDist) {
				maxDist = dist;
				index = i;
			}
		}
		return {
			error: maxDist,
			index: index
		};
	}
});
<commit_msg>Remove Douglas–Peucker algorithm again since it produced ackward results.<commit_after>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

// An Algorithm for Automatically Fitting Digitized Curves
// by Philip J. Schneider
// from "Graphics Gems", Academic Press, 1990
var PathFitter = Base.extend({
	initialize: function(path, error) {
		//console.log(path.segments + '');
		this.maxIterations = 4;
		this.points = [];
		var segments = path._segments,
			prev;
		for (var i = 0, l = segments.length; i < l; i++) {
			var point = segments[i].point.clone();
			if (!prev || !prev.equals(point)) {
				this.points[i] = point;
				prev = point;
			}
		}
		this.error = error;
		this.iterationError = error * error;
	},

	fit: function() {
		this.segments = [new Segment(this.points[0])];
		this.fitCubic(0, this.points.length - 1,
				// Left Tangent
				this.points[1].subtract(this.points[0]).normalize(),
				// Right Tangent
				this.points[this.points.length - 2].subtract(
					this.points[this.points.length - 1]).normalize());
		return this.segments;
	},

	// Fit a Bezier curve to a (sub)set of digitized points
	fitCubic: function(first, last, tHat1, tHat2) {
		//	Use heuristic if region only has two points in it
		if (last - first == 1) {
			var pt1 = this.points[first],
				pt2 = this.points[last],
				dist = pt1.getDistance(pt2) / 3;
			this.addCurve([pt1, pt1.add(tHat1.normalize(dist)),
					pt2.add(tHat2.normalize(dist)), pt2]);
			return;
		}
		// Parameterize points, and attempt to fit curve
		var uPrime = this.chordLengthParameterize(first, last),
			prevMaxError = this.iterationError,
			error,
			split;
		for (var i = 0; i < this.maxIterations; i++) {
			var bezCurve = this.generateBezier(first, last, uPrime, tHat1, tHat2);
			//	Find max deviation of points to fitted curve
			var max = this.findMaxError(first, last, bezCurve, uPrime);
			if (max.error < this.error) {
				this.addCurve(bezCurve);
				return;
			}
			split = max.index;
			// If error not too large, try some reparameterization and iteration
			if (max.error >= this.iterationError || max.error >= prevMaxError)
				break;
			uPrime = this.reparameterize(first, last, uPrime, bezCurve);
			prevMaxError = max.error;
		}
		// Fitting failed -- split at max error point and fit recursively
		var V1 = this.points[split - 1].subtract(this.points[split]),
			V2 = this.points[split].subtract(this.points[split + 1]),
			tHatCenter = V1.add(V2).divide(2).normalize();
		this.fitCubic(first, split, tHat1, tHatCenter);
		this.fitCubic(split, last, tHatCenter.negate(), tHat2);
	},

	addCurve: function(bezCurve) {
		var prev = this.segments[this.segments.length - 1];
		prev.setHandleOut(bezCurve[1].subtract(bezCurve[0]));
		this.segments.push(
				new Segment(bezCurve[3], bezCurve[2].subtract(bezCurve[3])));
	},

	// Use least-squares method to find Bezier control points for region.
	generateBezier: function(first, last, uPrime, tHat1, tHat2) {
		var nPts = last - first + 1,
			pt1 = this.points[first],
			pt2 = this.points[last];

		var A = [];
		// Compute the A's
		for (var i = 0; i < nPts; i++) {
			var u = uPrime[i],
				t = 1 - u,
				b = 3 * u * t;
			A[i] = [
				tHat1.normalize(b * t), // b1
				tHat2.normalize(b * u)  // b2
			];
		}

		// Create the C and X matrices
		var C = [[0, 0], [0, 0]],
			X = [0, 0];

		for (var i = 0; i < nPts; i++) {
			C[0][0] += A[i][0].dot(A[i][0]);
			C[0][1] += A[i][0].dot(A[i][1]);
			// C[1][0] += A[i][0].dot(A[i][1]);
			C[1][0] = C[0][1];
			C[1][1] += A[i][1].dot(A[i][1]);

			var u = uPrime[i],
				t = 1 - u,
				b = 3 * u * t,
				tmp = this.points[first + i]
					.subtract(pt1.multiply(t * t * t) // b0
						.add(pt1.multiply(b * t)) // b1
						.add(pt2.multiply(b * u)) // b2
						.add(pt2.multiply(u * u * u))); // b3
			X[0] += A[i][0].dot(tmp);
			X[1] += A[i][1].dot(tmp);
		}

		// Compute the determinants of C and X
		var det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1],
			det_C0_X  = C[0][0] * X[1]    - C[1][0] * X[0],
			det_X_C1  = X[0]    * C[1][1] - X[1]    * C[0][1],
			singularity = det_C0_C1 < Numerical.TOLERANCE;

		// Finally, derive alpha values
		var alpha_l = singularity ? 0 : det_X_C1 / det_C0_C1,
			alpha_r = singularity ? 0 : det_C0_X / det_C0_C1;

		// If alpha negative, use the Wu/Barsky heuristic (see text)
		// (if alpha is 0, you get coincident control points that lead to
		// divide by zero in any subsequent NewtonRaphsonRootFind() call.
		var segLength = pt2.getDistance(pt1),
			epsilon = Numerical.TOLERANCE * segLength;
		if (alpha_l < epsilon || alpha_r < epsilon) {
			// fall back on standard (probably inaccurate) formula,
			// and subdivide further if needed.
			alpha_l = alpha_r = segLength / 3;
		}

		// First and last control points of the Bezier curve are
		// positioned exactly at the first and last data points
		// Control points 1 and 2 are positioned an alpha distance out
		// on the tangent vectors, left and right, respectively
		return [pt1, pt1.add(tHat1.normalize(alpha_l)),
				pt2.add(tHat2.normalize(alpha_r)), pt2];
	},

	// Given set of points and their parameterization, try to find
	// a better parameterization.
	reparameterize: function(first, last, u, bezCurve) {
		var uPrime = [];
		for (var i = first; i <= last; i++) {
			uPrime[i - first] = this.findRoot(bezCurve, this.points[i],
					u[i - first]);
		}
		return uPrime;
	},

	// Use Newton-Raphson iteration to find better root.
	findRoot: function(Q, P, u) {
		var Q1 = [],
			Q2 = [];
		// Generate control vertices for Q'
		for (var i = 0; i <= 2; i++) {
			Q1[i] = Q[i + 1].subtract(Q[i]).multiply(3);
		}
		// Generate control vertices for Q''
		for (var i = 0; i <= 1; i++) {
			Q2[i] = Q1[i + 1].subtract(Q1[i]).multiply(2);
		}
		// Compute Q(u), Q'(u) and Q''(u)
		Q_u = this.evaluate(3, Q, u);
		Q1_u = this.evaluate(2, Q1, u);
		Q2_u = this.evaluate(1, Q2, u);
		// Compute f(u)/f'(u)
		var V = Q_u.subtract(P),
			df = Q1_u.dot(Q1_u) + V.dot(Q2_u);
		if (df == 0)
			return u;
		// u = u - f(u) / f'(u)
		return u - V.dot(Q1_u) / df;
	},

	// Evaluate a Bezier curve at a particular parameter value
	evaluate: function(degree, V, t) {
		// Copy array
		var Vtemp = V.slice();
		// Triangle computation
		for (var i = 1; i <= degree; i++) {
			for (var j = 0; j <= degree - i; j++) {
				Vtemp[j] = Vtemp[j].multiply(1 - t).add(Vtemp[j + 1].multiply(t));
			}
		}
		return Vtemp[0];
	},

	// Assign parameter values to digitized points
	// using relative distances between points.
	chordLengthParameterize: function(first, last) {
		var u = [0];
		for (var i = first + 1; i <= last; i++) {
			u[i - first] = u[i - first - 1]
					+ this.points[i].getDistance(this.points[i - 1]);
		}
		for (var i = first + 1; i <= last; i++) {
			u[i - first] = u[i - first] / u[last - first];
		}
		return u;
	},

	// Find the maximum squared distance of digitized points
	// to fitted curve.
	findMaxError: function(first, last, bezCurve, u) {
		var index = Math.floor((last - first + 1) / 2),
			maxDist = 0;
		for (var i = first + 1; i < last; i++) {
			var P = this.evaluate(3, bezCurve, u[i - first]);
			var v = P.subtract(this.points[i]);
			var dist = v.x * v.x + v.y * v.y; // squared
			if (dist >= maxDist) {
				maxDist = dist;
				index = i;
			}
		}
		return {
			error: maxDist,
			index: index
		};
	}
});
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @format
 * @flow
 */
'use strict';

const findSymlinkedModules = require('./findSymlinkedModules');
const fs = require('fs');
const getPolyfills = require('../../rn-get-polyfills');
const invariant = require('fbjs/lib/invariant');
const path = require('path');

const {Config: MetroConfig} = require('metro');

const RN_CLI_CONFIG = 'rn-cli.config.js';

import type {ConfigT as MetroConfigT} from 'metro';

/**
 * Configuration file of the CLI.
 */
export type ConfigT = MetroConfigT;

function getProjectPath() {
  if (
    __dirname.match(/node_modules[\/\\]react-native[\/\\]local-cli[\/\\]util$/)
  ) {
    // Packager is running from node_modules.
    // This is the default case for all projects created using 'react-native init'.
    return path.resolve(__dirname, '../../../..');
  } else if (__dirname.match(/Pods[\/\\]React[\/\\]packager$/)) {
    // React Native was installed using CocoaPods.
    return path.resolve(__dirname, '../../../..');
  }
  return path.resolve(__dirname, '../..');
}

const resolveSymlinksForRoots = roots =>
  roots.reduce(
    (arr, rootPath) => arr.concat(findSymlinkedModules(rootPath, roots)),
    [...roots],
  );

const getProjectRoots = () => {
  const root = process.env.REACT_NATIVE_APP_ROOT;
  if (root) {
    return resolveSymlinksForRoots([path.resolve(root)]);
  }
  return resolveSymlinksForRoots([getProjectPath()]);
};

/**
 * Module capable of getting the configuration out of a given file.
 *
 * The function will return all the default configuration, as specified by the
 * `DEFAULT` param overriden by those found on `rn-cli.config.js` files, if any. If no
 * default config is provided and no configuration can be found in the directory
 * hierarchy, an error will be thrown.
 */
const Config = {
  DEFAULT: ({
    ...MetroConfig.DEFAULT,
    getProjectRoots,
    getPolyfills,
    getModulesRunBeforeMainModule: () => [
      require.resolve('../../Libraries/Core/InitializeCore'),
    ],
  }: ConfigT),

  find(startDir: string): ConfigT {
    return this.findWithPath(startDir).config;
  },

  findWithPath(startDir: string): {config: ConfigT, projectPath: string} {
    const configPath = findConfigPath(startDir);
    invariant(
      configPath,
      `Can't find "${RN_CLI_CONFIG}" file in any parent folder of "${startDir}"`,
    );
    const projectPath = path.dirname(configPath);
    return {config: this.load(configPath, startDir), projectPath};
  },

  findOptional(startDir: string): ConfigT {
    const configPath = findConfigPath(startDir);
    return configPath ? this.load(configPath, startDir) : {...Config.DEFAULT};
  },

  load(configFile: string): ConfigT {
    return MetroConfig.load(configFile, Config.DEFAULT);
  },
};

function findConfigPath(cwd: string): ?string {
  const parentDir = findParentDirectory(cwd, RN_CLI_CONFIG);
  return parentDir ? path.join(parentDir, RN_CLI_CONFIG) : null;
}

// Finds the most near ancestor starting at `currentFullPath` that has
// a file named `filename`
function findParentDirectory(currentFullPath, filename) {
  const root = path.parse(currentFullPath).root;
  const testDir = parts => {
    if (parts.length === 0) {
      return null;
    }

    const fullPath = path.join(root, parts.join(path.sep));

    var exists = fs.existsSync(path.join(fullPath, filename));
    return exists ? fullPath : testDir(parts.slice(0, -1));
  };

  return testDir(currentFullPath.substring(root.length).split(path.sep));
}

module.exports = Config;
<commit_msg>Fix project path resolve path<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @format
 * @flow
 */
'use strict';

const findSymlinkedModules = require('./findSymlinkedModules');
const fs = require('fs');
const getPolyfills = require('../../rn-get-polyfills');
const invariant = require('fbjs/lib/invariant');
const path = require('path');

const {Config: MetroConfig} = require('metro');

const RN_CLI_CONFIG = 'rn-cli.config.js';

import type {ConfigT as MetroConfigT} from 'metro';

/**
 * Configuration file of the CLI.
 */
export type ConfigT = MetroConfigT;

function getProjectPath() {
  if (
    __dirname.match(/node_modules[\/\\]react-native-macos[\/\\]local-cli[\/\\]util$/)
  ) {
    // Packager is running from node_modules.
    // This is the default case for all projects created using 'react-native init'.
    return path.resolve(__dirname, '../../../..');
  } else if (__dirname.match(/Pods[\/\\]React[\/\\]packager$/)) {
    // React Native was installed using CocoaPods.
    return path.resolve(__dirname, '../../../..');
  }
  return path.resolve(__dirname, '../..');
}

const resolveSymlinksForRoots = roots =>
  roots.reduce(
    (arr, rootPath) => arr.concat(findSymlinkedModules(rootPath, roots)),
    [...roots],
  );

const getProjectRoots = () => {
  const root = process.env.REACT_NATIVE_APP_ROOT;
  if (root) {
    return resolveSymlinksForRoots([path.resolve(root)]);
  }
  return resolveSymlinksForRoots([getProjectPath()]);
};

/**
 * Module capable of getting the configuration out of a given file.
 *
 * The function will return all the default configuration, as specified by the
 * `DEFAULT` param overriden by those found on `rn-cli.config.js` files, if any. If no
 * default config is provided and no configuration can be found in the directory
 * hierarchy, an error will be thrown.
 */
const Config = {
  DEFAULT: ({
    ...MetroConfig.DEFAULT,
    getProjectRoots,
    getPolyfills,
    getModulesRunBeforeMainModule: () => [
      require.resolve('../../Libraries/Core/InitializeCore'),
    ],
  }: ConfigT),

  find(startDir: string): ConfigT {
    return this.findWithPath(startDir).config;
  },

  findWithPath(startDir: string): {config: ConfigT, projectPath: string} {
    const configPath = findConfigPath(startDir);
    invariant(
      configPath,
      `Can't find "${RN_CLI_CONFIG}" file in any parent folder of "${startDir}"`,
    );
    const projectPath = path.dirname(configPath);
    return {config: this.load(configPath, startDir), projectPath};
  },

  findOptional(startDir: string): ConfigT {
    const configPath = findConfigPath(startDir);
    return configPath ? this.load(configPath, startDir) : {...Config.DEFAULT};
  },

  load(configFile: string): ConfigT {
    return MetroConfig.load(configFile, Config.DEFAULT);
  },
};

function findConfigPath(cwd: string): ?string {
  const parentDir = findParentDirectory(cwd, RN_CLI_CONFIG);
  return parentDir ? path.join(parentDir, RN_CLI_CONFIG) : null;
}

// Finds the most near ancestor starting at `currentFullPath` that has
// a file named `filename`
function findParentDirectory(currentFullPath, filename) {
  const root = path.parse(currentFullPath).root;
  const testDir = parts => {
    if (parts.length === 0) {
      return null;
    }

    const fullPath = path.join(root, parts.join(path.sep));

    var exists = fs.existsSync(path.join(fullPath, filename));
    return exists ? fullPath : testDir(parts.slice(0, -1));
  };

  return testDir(currentFullPath.substring(root.length).split(path.sep));
}

module.exports = Config;
<|endoftext|>


<commit_before>/* @flow */

// The SSR codegen is essentially extending the default codegen to handle
// SSR-optimizable nodes and turn them into string render fns. In cases where
// a node is not optimizable it simply falls back to the default codegen.

// import * as directives from './directives'
import { optimizability } from './optimizer'
import {
  genIf,
  genFor,
  genData,
  genText,
  genElement,
  genChildren,
  CodegenState
} from 'compiler/codegen/index'

import type { CodegenResult } from 'compiler/codegen/index'

// segment types
const RAW = 0
const INTERPOLATION = 1
const FLOW_CONTROL = 2

type StringSegment = {
  type: number;
  value: string;
};

export function generate (
  ast: ASTElement | void,
  options: CompilerOptions
): CodegenResult {
  const state = new CodegenState(options)
  const code = ast ? genSSRElement(ast, state) : '_c("div")'
  return {
    render: `with(this){return ${code}}`,
    staticRenderFns: state.staticRenderFns
  }
}

function genSSRElement (el: ASTElement, state: CodegenState): string {
  if (el.for && !el.forProcessed) {
    return genFor(el, state, genSSRElement)
  } else if (el.if && !el.ifProcessed) {
    return genIf(el, state, genSSRElement)
  }

  switch (el.ssrOptimizability) {
    case optimizability.FULL:
      // stringify whole tree
      return genStringElement(el, state, true)
    case optimizability.SELF:
      // stringify self and check children
      return genStringElement(el, state, false)
    case optimizability.CHILDREN:
      // generate self as VNode and stringify children
      return genNormalElement(el, state, true)
    case optimizability.PARTIAL:
      // generate self as VNode and check children
      return genNormalElement(el, state, false)
    default:
      // bail whole tree
      return genElement(el, state)
  }
}

function genNormalElement (el, state, stringifyChildren) {
  const data = el.plain ? undefined : genData(el, state)
  const children = stringifyChildren
    ? genStringChildren(el, state)
    : genSSRChildren(el, state, true)
  return `_c('${el.tag}'${
    data ? `,${data}` : ''
  }${
    children ? `,${children}` : ''
  })`
}

function genSSRChildren (el, state, checkSkip) {
  return genChildren(el, state, checkSkip, genSSRElement, genSSRNode)
}

function genSSRNode (el, state) {
  return el.type === 1
    ? genSSRElement(el, state)
    : genText(el, state)
}

function genStringChildren (el, state) {
  return `[_ssrNode(${flattenSegments(childrenToSegments(el, state))})]`
}

function genStringElement (el, state, stringifyChildren) {
  if (stringifyChildren) {
    return `_ssrNode(${flattenSegments(elementToSegments(el, state))})`
  } else {
    const children = genSSRChildren(el, state, true)
    return `_ssrNode(${
      flattenSegments(elementToOpenTagSegments(el, state))
    },"${el.tag}"${
      children ? `,${children}` : ''
    })`
  }
}

function elementToSegments (el, state): Array<StringSegment> {
  if (el.for && !el.forProcessed) {
    el.forProcessed = true
    return [{
      type: FLOW_CONTROL,
      value: genFor(el, state, elementToString, '_ssrList')
    }]
  } else if (el.if && !el.ifProcessed) {
    el.ifProcessed = true
    return [{
      type: FLOW_CONTROL,
      value: genIf(el, state, elementToString, '""')
    }]
  }

  const openSegments = elementToOpenTagSegments(el, state)
  const childrenSegments = childrenToSegments(el, state)
  const { isUnaryTag } = state.options
  const close = (isUnaryTag && isUnaryTag(el.tag))
    ? []
    : [{ type: RAW, value: `</${el.tag}>` }]
  return openSegments.concat(childrenSegments, close)
}

function elementToString (el, state) {
  return flattenSegments(elementToSegments(el, state))
}

function elementToOpenTagSegments (el, state): Array<StringSegment> {
  // TODO: handle v-show, v-html & v-text
  // TODO: handle attrs/props/styles/classes
  return [{ type: RAW, value: `<${el.tag}>` }]
}

function childrenToSegments (el, state): Array<StringSegment> {
  const children = el.children
  if (children) {
    const segments = []
    for (let i = 0; i < children.length; i++) {
      const c = children[i]
      if (c.type === 1) {
        segments.push.apply(segments, elementToSegments(c, state))
      } else if (c.type === 2) {
        segments.push({ type: INTERPOLATION, value: c.expression })
      } else if (c.type === 3) {
        segments.push({ type: RAW, value: c.text })
      }
    }
    return segments
  } else {
    return []
  }
}

function flattenSegments (segments: Array<StringSegment>): string {
  const mergedSegments = []
  let textBuffer = ''

  const pushBuffer = () => {
    if (textBuffer) {
      mergedSegments.push(JSON.stringify(textBuffer))
      textBuffer = ''
    }
  }

  for (let i = 0; i < segments.length; i++) {
    const s = segments[i]
    if (s.type === RAW) {
      textBuffer += s.value
    } else if (s.type === INTERPOLATION) {
      pushBuffer()
      mergedSegments.push(`_ssrEscape(${s.value})`)
    } else if (s.type === FLOW_CONTROL) {
      pushBuffer()
      mergedSegments.push(`(${s.value})`)
    }
  }
  pushBuffer()

  return mergedSegments.join('+')
}
<commit_msg>avoid generating empty ssrNode<commit_after>/* @flow */

// The SSR codegen is essentially extending the default codegen to handle
// SSR-optimizable nodes and turn them into string render fns. In cases where
// a node is not optimizable it simply falls back to the default codegen.

// import * as directives from './directives'
import { optimizability } from './optimizer'
import {
  genIf,
  genFor,
  genData,
  genText,
  genElement,
  genChildren,
  CodegenState
} from 'compiler/codegen/index'

import type { CodegenResult } from 'compiler/codegen/index'

// segment types
const RAW = 0
const INTERPOLATION = 1
const FLOW_CONTROL = 2

type StringSegment = {
  type: number;
  value: string;
};

export function generate (
  ast: ASTElement | void,
  options: CompilerOptions
): CodegenResult {
  const state = new CodegenState(options)
  const code = ast ? genSSRElement(ast, state) : '_c("div")'
  return {
    render: `with(this){return ${code}}`,
    staticRenderFns: state.staticRenderFns
  }
}

function genSSRElement (el: ASTElement, state: CodegenState): string {
  if (el.for && !el.forProcessed) {
    return genFor(el, state, genSSRElement)
  } else if (el.if && !el.ifProcessed) {
    return genIf(el, state, genSSRElement)
  }

  switch (el.ssrOptimizability) {
    case optimizability.FULL:
      // stringify whole tree
      return genStringElement(el, state, true)
    case optimizability.SELF:
      // stringify self and check children
      return genStringElement(el, state, false)
    case optimizability.CHILDREN:
      // generate self as VNode and stringify children
      return genNormalElement(el, state, true)
    case optimizability.PARTIAL:
      // generate self as VNode and check children
      return genNormalElement(el, state, false)
    default:
      // bail whole tree
      return genElement(el, state)
  }
}

function genNormalElement (el, state, stringifyChildren) {
  const data = el.plain ? undefined : genData(el, state)
  const children = stringifyChildren
    ? genStringChildren(el, state)
    : genSSRChildren(el, state, true)
  return `_c('${el.tag}'${
    data ? `,${data}` : ''
  }${
    children ? `,${children}` : ''
  })`
}

function genSSRChildren (el, state, checkSkip) {
  return genChildren(el, state, checkSkip, genSSRElement, genSSRNode)
}

function genSSRNode (el, state) {
  return el.type === 1
    ? genSSRElement(el, state)
    : genText(el, state)
}

function genStringChildren (el, state) {
  return el.children.length
    ? `[_ssrNode(${flattenSegments(childrenToSegments(el, state))})]`
    : ''
}

function genStringElement (el, state, stringifyChildren) {
  if (stringifyChildren) {
    return `_ssrNode(${flattenSegments(elementToSegments(el, state))})`
  } else {
    const children = genSSRChildren(el, state, true)
    return `_ssrNode(${
      flattenSegments(elementToOpenTagSegments(el, state))
    },"${el.tag}"${
      children ? `,${children}` : ''
    })`
  }
}

function elementToSegments (el, state): Array<StringSegment> {
  // v-for / v-if
  if (el.for && !el.forProcessed) {
    el.forProcessed = true
    return [{
      type: FLOW_CONTROL,
      value: genFor(el, state, elementToString, '_ssrList')
    }]
  } else if (el.if && !el.ifProcessed) {
    el.ifProcessed = true
    return [{
      type: FLOW_CONTROL,
      value: genIf(el, state, elementToString, '""')
    }]
  }

  // v-html / v-text
  console.log(el)

  const openSegments = elementToOpenTagSegments(el, state)
  const childrenSegments = childrenToSegments(el, state)
  const { isUnaryTag } = state.options
  const close = (isUnaryTag && isUnaryTag(el.tag))
    ? []
    : [{ type: RAW, value: `</${el.tag}>` }]
  return openSegments.concat(childrenSegments, close)
}

function elementToString (el, state) {
  return flattenSegments(elementToSegments(el, state))
}

function elementToOpenTagSegments (el, state): Array<StringSegment> {
  // TODO: handle v-show, v-html & v-text
  // TODO: handle attrs/props/styles/classes
  return [{ type: RAW, value: `<${el.tag}>` }]
}

function childrenToSegments (el, state): Array<StringSegment> {
  const children = el.children
  if (children) {
    const segments = []
    for (let i = 0; i < children.length; i++) {
      const c = children[i]
      if (c.type === 1) {
        segments.push.apply(segments, elementToSegments(c, state))
      } else if (c.type === 2) {
        segments.push({ type: INTERPOLATION, value: c.expression })
      } else if (c.type === 3) {
        segments.push({ type: RAW, value: c.text })
      }
    }
    return segments
  } else {
    return []
  }
}

function flattenSegments (segments: Array<StringSegment>): string {
  const mergedSegments = []
  let textBuffer = ''

  const pushBuffer = () => {
    if (textBuffer) {
      mergedSegments.push(JSON.stringify(textBuffer))
      textBuffer = ''
    }
  }

  for (let i = 0; i < segments.length; i++) {
    const s = segments[i]
    if (s.type === RAW) {
      textBuffer += s.value
    } else if (s.type === INTERPOLATION) {
      pushBuffer()
      mergedSegments.push(`_ssrEscape(${s.value})`)
    } else if (s.type === FLOW_CONTROL) {
      pushBuffer()
      mergedSegments.push(`(${s.value})`)
    }
  }
  pushBuffer()

  return mergedSegments.join('+')
}
<|endoftext|>


<commit_before>/**
 * Created by ChenDanni on 2016/8/15.
 */

import {get_rec_users} from './RecommendLogic_users'
import {getStarRepoByUser} from '../dao/RepoDAO'
import {connect} from '../config'

let rec_repos = [];
let sim_user_num = 5;

function getSortFun(order, sortBy) {
  var ordAlpah = (order == 'asc') ? '>' : '<';
  var sortFun = new Function('a', 'b', 'return a.' + sortBy + ordAlpah + 'b.' + sortBy + '?1:-1');
  return sortFun;
}

//function getStarRepoByUser(login){
//  if (login == 'u1'){
//    return [{fullname:'r1',stars:10},{fullname:'r2',stars:102},{fullname:'r3',stars:1041}];
//  }
//  if (login == 'u2'){
//    return [{fullname:'r2',stars:10},{fullname:'r22',stars:102},{fullname:'r23',stars:1011}];
//  }
//  if (login == 'u3'){
//    return [{fullname:'r2',stars:10},{fullname:'r12',stars:102},{fullname:'r33',stars:2101}];
//  }
//  if (login == 'u4'){
//    return [{fullname:'r3',stars:10},{fullname:'r22',stars:102},{fullname:'r39',stars:1301}];
//  }
//  if (login == 'u5'){
//    return [{fullname:'r14',stars:310},{fullname:'r12',stars:102},{fullname:'r30',stars:1}];
//  }
//  if (login == 'u11'){
//    return [{fullname:'r13',stars:10},{fullname:'r42',stars:4102},{fullname:'r37',stars:1301}];
//  }
//  if (login == 'u13'){
//    return [{fullname:'r15',stars:410},{fullname:'r22',stars:1102},{fullname:'r73',stars:101}];
//  }
//  if (login == 'u14'){
//    return [{fullname:'r16',stars:310},{fullname:'r12',stars:102},{fullname:'r38',stars:2101}];
//  }
//  if (login == 'u15'){
//    return [{fullname:'r12',stars:810},{fullname:'r22',stars:102},{fullname:'r35',stars:101}];
//  }
//  if (login == 'u21'){
//    return [{fullname:'r18',stars:10},{fullname:'r52',stars:102},{fullname:'r35',stars:101}];
//  }
//  return [];
//}

async function get_rec_repos(login,rec_num){
  let repo_count = [];
  let repo_info = [];
  let rec_repos = [];
  let count_max = -1;
  let star_max = -1;
  //得到最相似的前sim_user_num个用户
  let sim_users = await get_rec_users(login,sim_user_num);

  //统计count/star
  for (let i = 0;i < sim_users.length;i++){
    let temp_login = sim_users[i];
    let temp_repos = await getStarRepoByUser(temp_login);

    for (let j = 0;j < temp_repos.length;j++){
      let repo_name = temp_repos[j].fullname;
      if (repo_count.hasOwnProperty(repo_name)){
        repo_count[repo_name].count += 1;
      }else {
        let repo_info = {
          stars: temp_repos[j].stars,
          count:1
        };
        repo_count[repo_name] = repo_info;
      }
    }
  }

  for (let repo in repo_count){
    let temp_stars = repo_count[repo].stars;
    let temp_count = repo_count[repo].count;

    if (temp_stars > star_max) star_max = temp_stars;
    if (temp_count > count_max) count_max = temp_count;

    let temp_repo = {
      fullname: repo,
      stars: temp_stars,
      count: temp_count,
      score: 0
    };
    repo_info.push(temp_repo);
  }

  //计算推荐度
  for (let i = 0;i < repo_info.length;i++){
    let stars = repo_info[i].stars;
    let count = repo_info[i].count;
    repo_info[i].score = (0.7*count)/count_max + (0.3*stars)/star_max;
  }

  //先按推荐度排序
  repo_info.sort(getSortFun('desc','score'));

  let rec = 0;
  for (let i = 0;i < repo_info.length;i++){
    if (i < rec) break;

    rec_repos.push(repo_info[i].fullname);

    rec++;
    if (rec >= rec_num){
      rec = 0;
      break;
    }
  }

  //console.log(rec_repos);
  return rec_repos;

}
export {get_rec_repos}

//connect();
//get_rec_repos('RickChem',10);

<commit_msg>Fix a bug<commit_after>/**
 * Created by ChenDanni on 2016/8/15.
 */

import {get_rec_users} from './RecommendLogic_users'
import {getStarRepoByUser} from '../dao/RepoDAO'
import {connect} from '../config'

let rec_repos = [];
let sim_user_num = 5;

function getSortFun(order, sortBy) {
  var ordAlpah = (order == 'asc') ? '>' : '<';
  var sortFun = new Function('a', 'b', 'return a.' + sortBy + ordAlpah + 'b.' + sortBy + '?1:-1');
  return sortFun;
}

//function getStarRepoByUser(login){
//  if (login == 'u1'){
//    return [{fullname:'r1',stars:10},{fullname:'r2',stars:102},{fullname:'r3',stars:1041}];
//  }
//  if (login == 'u2'){
//    return [{fullname:'r2',stars:10},{fullname:'r22',stars:102},{fullname:'r23',stars:1011}];
//  }
//  if (login == 'u3'){
//    return [{fullname:'r2',stars:10},{fullname:'r12',stars:102},{fullname:'r33',stars:2101}];
//  }
//  if (login == 'u4'){
//    return [{fullname:'r3',stars:10},{fullname:'r22',stars:102},{fullname:'r39',stars:1301}];
//  }
//  if (login == 'u5'){
//    return [{fullname:'r14',stars:310},{fullname:'r12',stars:102},{fullname:'r30',stars:1}];
//  }
//  if (login == 'u11'){
//    return [{fullname:'r13',stars:10},{fullname:'r42',stars:4102},{fullname:'r37',stars:1301}];
//  }
//  if (login == 'u13'){
//    return [{fullname:'r15',stars:410},{fullname:'r22',stars:1102},{fullname:'r73',stars:101}];
//  }
//  if (login == 'u14'){
//    return [{fullname:'r16',stars:310},{fullname:'r12',stars:102},{fullname:'r38',stars:2101}];
//  }
//  if (login == 'u15'){
//    return [{fullname:'r12',stars:810},{fullname:'r22',stars:102},{fullname:'r35',stars:101}];
//  }
//  if (login == 'u21'){
//    return [{fullname:'r18',stars:10},{fullname:'r52',stars:102},{fullname:'r35',stars:101}];
//  }
//  return [];
//}

async function get_rec_repos(login,rec_num){
  let repo_count = [];
  let repo_info = [];
  let rec_repos = [];
  let count_max = -1;
  let star_max = -1;
  let user_stars = await getStarRepoByUser(login);
  //得到最相似的前sim_user_num个用户
  let sim_users = await get_rec_users(login,sim_user_num);

  //统计count/star
  for (let i = 0;i < sim_users.length;i++){
    let temp_login = sim_users[i];
    let temp_repos = await getStarRepoByUser(temp_login);

    for (let j = 0;j < temp_repos.length;j++){
      let repo_name = temp_repos[j].fullname;
      if (repo_count.hasOwnProperty(repo_name)){
        repo_count[repo_name].count += 1;
      }else {
        let repo_info = {
          stars: temp_repos[j].stars,
          count:1
        };
        repo_count[repo_name] = repo_info;
      }
    }
  }
  //去除重复
  for (let i = 0;i < user_stars.length;i++){
    if (repo_count.hasOwnProperty(user_stars[i].fullname)){
      delete repo_count[user_stars[i].fullname];
    }
  }

  for (let repo in repo_count){
    let temp_stars = repo_count[repo].stars;
    let temp_count = repo_count[repo].count;

    if (temp_stars > star_max) star_max = temp_stars;
    if (temp_count > count_max) count_max = temp_count;

    let temp_repo = {
      fullname: repo,
      stars: temp_stars,
      count: temp_count,
      score: 0
    };
    repo_info.push(temp_repo);
  }

  //计算推荐度
  for (let i = 0;i < repo_info.length;i++){
    let stars = repo_info[i].stars;
    let count = repo_info[i].count;
    repo_info[i].score = (0.7*count)/count_max + (0.3*stars)/star_max;
  }

  //先按推荐度排序
  repo_info.sort(getSortFun('desc','score'));

  let rec = 0;
  for (let i = 0;i < repo_info.length;i++){
    if (i < rec) break;

    rec_repos.push(repo_info[i].fullname);

    rec++;
    if (rec >= rec_num){
      rec = 0;
      break;
    }
  }

  console.log(rec_repos);
  return rec_repos;

}
export {get_rec_repos}

connect();
get_rec_repos('RickChem',10);

<|endoftext|>


<commit_before>// LICENSE : MIT
"use strict";
export default class JSerInfoPintClient {
    isLogin() {
        return true;
    }

    loginAsync(callback) {
    }

    /**
     *
     * @param options
     * @returns {*}
     * {
            url,
            comment,
            tags = []
        }
     */
    postLink(options = {}) {
        const {title, url, viaURL, comment, tags, relatedItems} = options;

        function createIssue(issueData, callback) {
            const xhr = new XMLHttpRequest();
            xhr.onload = function() {
                if (200 <= xhr.status && xhr.status < 300) {
                    callback(null, xhr.responseText);
                } else {
                    callback(new Error(xhr.responseText));
                }
            };
            xhr.onerror = function() {
                callback(new Error(xhr.responseText));
            };
            xhr.withCredentials = true;
            xhr.open("POST", "https://d6qujk40a3.execute-api.ap-northeast-1.amazonaws.com/prod/ping/create");
            xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
            xhr.send(JSON.stringify(issueData));
        }

        return new Promise((resolve, reject) => {
            createIssue({
                url: url,
                description: comment
            }, function(error, response) {
                if (error) {
                    reject(error);
                } else {
                    resolve(response);
                }
            });
        });
    }
}<commit_msg>fix ping<commit_after>// LICENSE : MIT
"use strict";
export default class JSerInfoPintClient {
    isLogin() {
        return true;
    }

    loginAsync(callback) {
    }

    /**
     *
     * @param options
     * @returns {*}
     * {
            url,
            comment,
            tags = []
        }
     */
    postLink(options = {}) {
        const {title, url, viaURL, comment, tags, relatedItems} = options;

        function createIssue(issueData, callback) {
            const xhr = new XMLHttpRequest();
            xhr.onload = function() {
                if (200 <= xhr.status && xhr.status < 300) {
                    callback(null, xhr.responseText);
                } else {
                    callback(new Error(xhr.responseText));
                }
            };
            xhr.onerror = function() {
                callback(new Error(xhr.responseText));
            };
            xhr.withCredentials = true;
            xhr.open("POST", "https://rihxwdqmx9.execute-api.ap-northeast-1.amazonaws.com/prod/ping/create");
            xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
            xhr.send(JSON.stringify(issueData));
        }

        return new Promise((resolve, reject) => {
            createIssue({
                url: url,
                description: comment
            }, function(error, response) {
                if (error) {
                    reject(error);
                } else {
                    resolve(response);
                }
            });
        });
    }
}<|endoftext|>


<commit_before>/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
/* global app*/

app.controller('CheckPackageCtrl', ['$scope', 'HomeServices', '$timeout', function ($scope, HomeServices, $timeout) {

    var services = [
      'getYear',
      'getBrand'
    ];

    var params = {};
    $scope.data = {};
    $scope.formSubmit = {};
    $scope.saveMember = {
      status : "error"
    };
    $scope.formRegister = {
      idCard : '',
      fullname : '',
      address : '',
      tel : '',
      email : '',
      username : '',
      password : ''
    };
    $scope.formLogin = {};
    $scope.formLogin.username = '';
    $scope.formLogin.password = '';
    $scope.formLevel = {};
    $scope.formLevel.id = '';
    $scope.formSearch = {
      year: '',
      brand: '',
      series: '',
      main: ''
    };
    $scope.showFromLogin = 1;
    $scope.showFromRegister = 2;
    $scope.showFromLoginAndRegister = 0;
    $scope.showStep = 0;

    var assignData = function (serviceName,getData) {
      if (serviceName === 'getYear') {
        $scope.data.Years = getData;
      } else if (serviceName === 'getBrand') {
        $scope.data.Brands = getData;
      }
    };

    $scope.getLevelPackage = function () {
      var getIndexLevel = ($scope.formLevel.id - 1);
      $scope.formSubmit.lvType = $scope.data.Levels[getIndexLevel].lvType;
      $scope.formSubmit.lvPrice = $scope.data.Levels[getIndexLevel].lvPrice;
      $scope.formSubmit.lvLimit = $scope.data.Levels[getIndexLevel].lvLimit;
    };

    $scope.submitSearchForm = function () {
        callService('getLevelPackage');
        HomeServices.showLoad(true);
    };

    $scope.submitLoginForm = function () {
            $scope.showStep = 3;
    };

    $scope.submitRegisterForm = function () {
            $scope.showStep = 3;
    };

    $scope.selectWatch = function (selectWhere) {
      if (selectWhere === 'year') {
        $scope.formSearch.brand = '';
        $scope.formSearch.series = '';
        $scope.formSearch.main = '';
      } else if (selectWhere === 'brand') {
        $scope.formSearch.series = '';
        $scope.formSearch.main = '';
        callService('getSeries');
        HomeServices.showLoad(true);
      } else if (selectWhere === 'series') {
        $scope.formSearch.main = '';
        callService('getMainPackage');
        HomeServices.showLoad(true);
      }
    };

    var assignData = function (serviceName,getData) {
      if (serviceName === 'getYear') {
        $scope.data.Years = getData;
      } else if (serviceName === 'getBrand') {
        $scope.data.Brands = getData;
      } else if (serviceName === 'getSeries') {
        $scope.data.Series = getData;
      } else if (serviceName === 'getMainPackage') {
        $scope.data.Mains = getData;
      } else if (serviceName === 'getLevelPackage') {
        $scope.data.Levels = getData;
      }
    };

    var callService = function (serviceName) {
      if (serviceName === 'getSeries') {
        params = {
          inputYear: $scope.formSearch.year,
          inputIdBrand: $scope.formSearch.brand
        };
      } else if (serviceName === 'getMainPackage') {
        params = {
          inputYear: $scope.formSearch.year,
          inputIdBrand: $scope.formSearch.brand,
          inputIdSeries: $scope.formSearch.series
        };
      } else if (serviceName === 'getLevelPackage') {
        params = {
          inputIdMain: $scope.formSearch.main
        };
      } else if (serviceName === 'saveMember') {
        params = {
          inputFullName: $scope.formRegister.fullname,
          inputAddress: $scope.formRegister.address,
          inputPhone: $scope.formRegister.tel,
          inputEmail: $scope.formRegister.email,
          inputUserName: $scope.formRegister.username,
          inputPassword: $scope.formRegister.password,
          inputIdCard: $scope.formRegister.idCard,
          inputLevel: 1
        };
      }
      var callServiceName = HomeServices[serviceName](params);
      callServiceName.success(function (data) {
        if (data.status === 'success') {
          if (serviceName === 'saveMember') {
            $scope.saveMember = {
              status : "success"
            };
            return;
          }
          var getData = angular.extend(data.data);
          assignData(serviceName,getData);
          if (serviceName === 'getLevelPackage') {
            $scope.showStep = 1;
          }
        }
        HomeServices.showLoad(false);
      }).error(function () {
        HomeServices.showLoad(false);
        console.log('API Timeout');
      });
    };
//    loop call service
    for (name in services) {
      callService(services[name]);
    }

    $scope.submitRegisterForm = function() {
//      console.log($scope.formRegister);
        callService("saveMember");
    };

  }]);
<commit_msg>assets/js/CheckPackageCtrl.js<commit_after>/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
/* global app*/

app.controller('CheckPackageCtrl', ['$scope', 'HomeServices', '$timeout', function ($scope, HomeServices, $timeout) {

    var services = [
      'getYear',
      'getBrand'
    ];

    var params = {};
    $scope.data = {};
    $scope.formSubmit = {};
    $scope.saveMember = {
      status : "error"
    };
    $scope.formRegister = {
      idCard : '',
      fullname : '',
      address : '',
      tel : '',
      email : '',
      username : '',
      password : ''
    };
    $scope.formLogin = {};
    $scope.formLogin.username = '';
    $scope.formLogin.password = '';
    $scope.formLevel = {};
    $scope.formLevel.id = '';
    $scope.formSearch = {
      year: '',
      brand: '',
      series: '',
      main: ''
    };
    $scope.showFromLogin = 1;
    $scope.showFromRegister = 2;
    $scope.showFromLoginAndRegister = 0;
    $scope.showStep = 0;

    var assignData = function (serviceName,getData) {
      if (serviceName === 'getYear') {
        $scope.data.Years = getData;
      } else if (serviceName === 'getBrand') {
        $scope.data.Brands = getData;
      }
    };

    $scope.getLevelPackage = function () {
      var getIndexLevel = ($scope.formLevel.id - 1);
      $scope.formSubmit.lvType = $scope.data.Levels[getIndexLevel].lvType;
      $scope.formSubmit.lvPrice = $scope.data.Levels[getIndexLevel].lvPrice;
      $scope.formSubmit.lvLimit = $scope.data.Levels[getIndexLevel].lvLimit;
    };

    $scope.submitSearchForm = function () {
        callService('getLevelPackage');
        HomeServices.showLoad(true);
    };

    $scope.submitLoginForm = function () {
            $scope.showStep = 3;
    };

    $scope.submitRegisterForm = function () {
            $scope.showStep = 3;
    };

    $scope.selectWatch = function (selectWhere) {
      if (selectWhere === 'year') {
        $scope.formSearch.brand = '';
        $scope.formSearch.series = '';
        $scope.formSearch.main = '';
      } else if (selectWhere === 'brand') {
        $scope.formSearch.series = '';
        $scope.formSearch.main = '';
        callService('getSeries');
        HomeServices.showLoad(true);
      } else if (selectWhere === 'series') {
        $scope.formSearch.main = '';
        callService('getMainPackage');
        HomeServices.showLoad(true);
      }
    };

    var assignData = function (serviceName,getData) {
      if (serviceName === 'getYear') {
        $scope.data.Years = getData;
      } else if (serviceName === 'getBrand') {
        $scope.data.Brands = getData;
      } else if (serviceName === 'getSeries') {
        $scope.data.Series = getData;
      } else if (serviceName === 'getMainPackage') {
        $scope.data.Mains = getData;
      } else if (serviceName === 'getLevelPackage') {
        $scope.data.Levels = getData;
      }
    };

    var callService = function (serviceName) {
      if (serviceName === 'getSeries') {
        params = {
          inputYear: $scope.formSearch.year,
          inputIdBrand: $scope.formSearch.brand
        };
      } else if (serviceName === 'getMainPackage') {
        params = {
          inputYear: $scope.formSearch.year,
          inputIdBrand: $scope.formSearch.brand,
          inputIdSeries: $scope.formSearch.series
        };
      } else if (serviceName === 'getLevelPackage') {
        params = {
          inputIdMain: $scope.formSearch.main
        };
      } else if (serviceName === 'saveMember') {
        params = {
          inputFullName: $scope.formRegister.fullname,
          inputAddress: $scope.formRegister.address,
          inputPhone: $scope.formRegister.tel,
          inputEmail: $scope.formRegister.email,
          inputUserName: $scope.formRegister.username,
          inputPassword: $scope.formRegister.password,
          inputIdCard: $scope.formRegister.idCard,
          inputOldInsurance: $scope.formRegister.oldInsurance,
          inputOldInsuranceRegister: $scope.formRegister.oldInsuranceRegister,
          inputBrand: $scope.formRegister.brand,
          inputLevel: 1
        };
      }
      var callServiceName = HomeServices[serviceName](params);
      callServiceName.success(function (data) {
        if (data.status === 'success') {
          if (serviceName === 'saveMember') {
            $scope.saveMember = {
              status : "success"
            };
            return;
          }
          var getData = angular.extend(data.data);
          assignData(serviceName,getData);
          if (serviceName === 'getLevelPackage') {
            $scope.showStep = 1;
          }
        }
        HomeServices.showLoad(false);
      }).error(function () {
        HomeServices.showLoad(false);
        console.log('API Timeout');
      });
    };
//    loop call service
    for (name in services) {
      callService(services[name]);
    }

    $scope.submitRegisterForm = function() {
//      console.log($scope.formRegister);
        callService("saveMember");
    };

  }]);
<|endoftext|>