<commit_before>define( [   'dojo/_base/declare',
            'dojo/_base/lang',
            'dojo/_base/array',
            'dojo/Deferred',
            'JBrowse/Model/SimpleFeature',
            'JBrowse/Store/SeqFeature',
            'JBrowse/Store/DeferredFeaturesMixin',
            'JBrowse/Store/DeferredStatsMixin',
            'JBrowse/Store/SeqFeature/GlobalStatsEstimationMixin',
            'JBrowse/Store/SeqFeature/GFF3/Parser',
            'JBrowse/Store/SeqFeature/GFF3',
            'WebApollo/SequenceOntologyUtils'
        ],
        function(
            declare,
            lang,
            array,
            Deferred,
            SimpleFeature,
            SeqFeatureStore,
            DeferredFeatures,
            DeferredStats,
            GlobalStatsEstimationMixin,
            Parser,
            GFF3,
            SeqOnto
        )
        {

return declare( [ GFF3 ],
{
    /* overriding _loadFeatures to handle common case of three-level gene-transcript-exon hierarchy,
     *   when three-level hierarchy is fully represented in the data model, currently HTMLFeatures and DraggableHTMLFeatures can't render it correctly
     *   (always renders the top two levels of a feature hierarchy)
     *   therefore when detecting this case, ApolloGFF3 removes the top "gene" level of the hierarchy
     */
    _loadFeatures: function() {
        //        this.inherited( arguments );
        var thisB = this;
        var features = this.bareFeatures = [];

        var featuresSorted = true;
        var seenRefs = this.refSeqs = {};
        var parser = new Parser(
            {
                featureCallback: function(fs) {
                    array.forEach( fs, function( feature ) {
                                       var prevFeature = features[ features.length-1 ];
                                       var regRefName = thisB.browser.regularizeReferenceName( feature.seq_id );
                                       if( regRefName in seenRefs && prevFeature && prevFeature.seq_id != feature.seq_id )
                                           featuresSorted = false;
                                       if( prevFeature && prevFeature.seq_id == feature.seq_id && feature.start < prevFeature.start )
                                           featuresSorted = false;

                                       if( !( regRefName in seenRefs ))
                                           seenRefs[ regRefName ] = features.length;

                                       feature.strand = {'+':1,'-':-1}[feature.strand] || 0;
                                       features.push( feature );
                                   });
                },
                endCallback:     function()  {
                    var newfeats = [];
                    for (var i=0; i<features.length; i++) {
                        var oldfeat = features[i];
                        var type = oldfeat.type;
                        var transformed = false;
                        if (SeqOnto.geneTerms[type] && oldfeat.child_features)  {
                            // special-casing for typical gene-mRNA-exon hierarchy:
                            // if it's a gene, and find transcript term underneath, promote all children to top and strip out parent attribute
                            var subfeats = oldfeat.child_features;
                            var has_transcript = false;
                            for (var k=0; k<subfeats.length; k++)  {
                                var subfeat = subfeats[k];
                                if (lang.isArray(subfeat)) {
                                    // hack due to weirdness in current GFF3 parser data struct where all subfeats are wrapped with an extra array
                                    subfeat = subfeat[0];
                                }
                                if (SeqOnto.transcriptTerms[subfeat.type]) { has_transcript = true; }
                                break;
                            }
                            if (has_transcript) {
                                for (k=0; k<subfeats.length; k++) {
                                    var subfeat = subfeats[k];
                                    // hack due to weirdness in current GFF3 parser data struct where all subfeats are wrapped with an extra array
                                    if (lang.isArray(subfeat)) { subfeat = subfeat[0]; }
                                    var test = true;
                                    if (subfeat.attributes.Parent) {
                                        subfeat.attributes.ParentGene = subfeat.attributes.Parent;
                                        // just nulling out causes errors when GFF3._formatData tries to join attributes
                                        // so need to delete, even though delete is a much slower operation
                                        // subfeat.attributes.Parent = null;
                                        delete subfeat.attributes.Parent;
                                    }
                                    newfeats.push( subfeat );
                                }
                                transformed = true;
                            }
                        }
                        if (! transformed) {
                            newfeats.push( oldfeat );
                        }
                    }
                    thisB.bareFeatures = newfeats;
                    features = newfeats;
                    if( ! featuresSorted ) {
                        features.sort( thisB._compareFeatureData );
                        // need to rebuild the refseq index if changing the sort order
                        thisB._rebuildRefSeqs( features );
                    }

                    thisB._estimateGlobalStats()
                         .then( function( stats ) {
                                    thisB.globalStats = stats;
                                    thisB._deferred.stats.resolve();
                                });

                    thisB._deferred.features.resolve( features );
                }
            });

        // parse the whole file and store it
        this.data.fetchLines(
            function( line ) {
                parser.addLine(line);
            },
            lang.hitch( parser, 'finish' ),
            lang.hitch( this, '_failAllDeferred' )
        );
    }

});
});
<commit_msg>Remove the strand parser from ApolloGFF3 since this is done inside JBrowse core now<commit_after>define( [   'dojo/_base/declare',
            'dojo/_base/lang',
            'dojo/_base/array',
            'dojo/Deferred',
            'JBrowse/Model/SimpleFeature',
            'JBrowse/Store/SeqFeature',
            'JBrowse/Store/DeferredFeaturesMixin',
            'JBrowse/Store/DeferredStatsMixin',
            'JBrowse/Store/SeqFeature/GlobalStatsEstimationMixin',
            'JBrowse/Store/SeqFeature/GFF3/Parser',
            'JBrowse/Store/SeqFeature/GFF3',
            'WebApollo/SequenceOntologyUtils'
        ],
        function(
            declare,
            lang,
            array,
            Deferred,
            SimpleFeature,
            SeqFeatureStore,
            DeferredFeatures,
            DeferredStats,
            GlobalStatsEstimationMixin,
            Parser,
            GFF3,
            SeqOnto
        )
        {

return declare( [ GFF3 ],
{
    /* overriding _loadFeatures to handle common case of three-level gene-transcript-exon hierarchy,
     *   when three-level hierarchy is fully represented in the data model, currently HTMLFeatures and DraggableHTMLFeatures can't render it correctly
     *   (always renders the top two levels of a feature hierarchy)
     *   therefore when detecting this case, ApolloGFF3 removes the top "gene" level of the hierarchy
     */
    _loadFeatures: function() {
        //        this.inherited( arguments );
        var thisB = this;
        var features = this.bareFeatures = [];

        var featuresSorted = true;
        var seenRefs = this.refSeqs = {};
        var parser = new Parser(
            {
                featureCallback: function(fs) {
                    array.forEach( fs, function( feature ) {
                                       var prevFeature = features[ features.length-1 ];
                                       var regRefName = thisB.browser.regularizeReferenceName( feature.seq_id );
                                       if( regRefName in seenRefs && prevFeature && prevFeature.seq_id != feature.seq_id )
                                           featuresSorted = false;
                                       if( prevFeature && prevFeature.seq_id == feature.seq_id && feature.start < prevFeature.start )
                                           featuresSorted = false;

                                       if( !( regRefName in seenRefs ))
                                           seenRefs[ regRefName ] = features.length;

                                       features.push( feature );
                                   });
                },
                endCallback:     function()  {
                    var newfeats = [];
                    for (var i=0; i<features.length; i++) {
                        var oldfeat = features[i];
                        var type = oldfeat.type;
                        var transformed = false;
                        if (SeqOnto.geneTerms[type] && oldfeat.child_features)  {
                            // special-casing for typical gene-mRNA-exon hierarchy:
                            // if it's a gene, and find transcript term underneath, promote all children to top and strip out parent attribute
                            var subfeats = oldfeat.child_features;
                            var has_transcript = false;
                            for (var k=0; k<subfeats.length; k++)  {
                                var subfeat = subfeats[k];
                                if (lang.isArray(subfeat)) {
                                    // hack due to weirdness in current GFF3 parser data struct where all subfeats are wrapped with an extra array
                                    subfeat = subfeat[0];
                                }
                                if (SeqOnto.transcriptTerms[subfeat.type]) { has_transcript = true; }
                                break;
                            }
                            if (has_transcript) {
                                for (k=0; k<subfeats.length; k++) {
                                    var subfeat = subfeats[k];
                                    // hack due to weirdness in current GFF3 parser data struct where all subfeats are wrapped with an extra array
                                    if (lang.isArray(subfeat)) { subfeat = subfeat[0]; }
                                    var test = true;
                                    if (subfeat.attributes.Parent) {
                                        subfeat.attributes.ParentGene = subfeat.attributes.Parent;
                                        // just nulling out causes errors when GFF3._formatData tries to join attributes
                                        // so need to delete, even though delete is a much slower operation
                                        // subfeat.attributes.Parent = null;
                                        delete subfeat.attributes.Parent;
                                    }
                                    newfeats.push( subfeat );
                                }
                                transformed = true;
                            }
                        }
                        if (! transformed) {
                            newfeats.push( oldfeat );
                        }
                    }
                    thisB.bareFeatures = newfeats;
                    features = newfeats;
                    if( ! featuresSorted ) {
                        features.sort( thisB._compareFeatureData );
                        // need to rebuild the refseq index if changing the sort order
                        thisB._rebuildRefSeqs( features );
                    }

                    thisB._estimateGlobalStats()
                         .then( function( stats ) {
                                    thisB.globalStats = stats;
                                    thisB._deferred.stats.resolve();
                                });

                    thisB._deferred.features.resolve( features );
                }
            });

        // parse the whole file and store it
        this.data.fetchLines(
            function( line ) {
                parser.addLine(line);
            },
            lang.hitch( parser, 'finish' ),
            lang.hitch( this, '_failAllDeferred' )
        );
    }

});
});
<|endoftext|>


<commit_before>(function() {
    'use strict';

    LiveblogFreetypesController.$inject = ['api', '$location', 'notify', 'gettext',
    '$q', '$sce', 'config', 'lodash', 'upload', 'blogService', 'modal'];
    function LiveblogFreetypesController(api, $location, notify, gettext,
    $q, $sce, config, _, upload, blogService, modal) {
        var vm = this;

        function getFreetypes() {
            api.freetypes.query().then(function(data) {
                vm.freetypes = data._items;
                notify.info('Free types loaded');
            }, function(data) {
                notify.error(gettext('There was an error getting the free type'));
            })
        };

        angular.extend(vm, {
            //new item type modal is closed by default§
            freetypeModalActive: false,
            editFreetype: false,
            dialogFreetype: {
                loading: false,
                name: '',
                template: ''
            },
            //open dialog for adding editing an item type
            openFreetypeDialog: function(freetype) {

                vm.editFreetype = freetype || false;

                if (vm.editFreetype) {
                    vm.dialogFreetype.name = vm.editFreetype.name;
                    vm.dialogFreetype.template = vm.editFreetype.template;
                } else {
                    vm.dialogFreetype.name = '';
                    vm.dialogFreetype.template = '';
                }
                vm.freetypeModalActive = true;
            },
            handleSaveError: function(data) {
                var errorMsg = gettext('Saving did not work, please try again later!');
                if (data.data._issues.template) {
                    errorMsg = gettext(data.data._issues.template);
                }
                notify.error(errorMsg, 10000);
            },
            saveFreetype: function() {

                vm.dialogFreetype.loading = true;
                if (vm.editFreetype) {
                    api.freetypes.save(vm.editFreetype, {name: vm.dialogFreetype.name, template: vm.dialogFreetype.template}).then(function(data) {
                        vm.dialogFreetype.loading = false;
                        vm.freetypeModalActive = false;
                        getFreetypes();
                        vm.editFreetype = false;
                    }, function(data) {
                        vm.handleSaveError(data);
                    });
                } else {
                    api.freetypes.save({name: vm.dialogFreetype.name, template: vm.dialogFreetype.template}).then(function(data) {
                        vm.dialogFreetype.loading = false;
                        vm.freetypeModalActive = false;
                        getFreetypes();
                    }, function(data) {
                        vm.handleSaveError(data);
                    });
                }
            },
            removeFreetype: function(freetype, $index) {
                modal.confirm(gettext('Are you sure you want to remove this free type?')).then(function() {
                    api.freetypes.remove(freetype).then(function(data) {
                        vm.freetypes.splice($index, 1);
                    }, function(data) {
                        notify.errorp(gettext('Can\'t remove free type'));
                    });
                });
            },
            cancelCreate: function() {
                vm.freetypeModalActive = false;
            }
        });

        getFreetypes();
    }

    var liveblogFreetypesModule = angular.module('liveblog.freetypes', [])
    .config(['superdeskProvider', function(superdesk) {
        if (config.subscriptionLevel != 'solo')
            superdesk
                .activity('/freetypes/', {
                    label: gettext('Free types manager'),
                    controller: LiveblogFreetypesController,
                    controllerAs: 'vm',
                    betaMark: true,
                    category: superdesk.MENU_MAIN,
                    adminTools: true,
                    privileges: {'global_preferences': 1},
                    templateUrl: 'scripts/liveblog-freetypes/views/list.html'
                });
    }])
    .config(['apiProvider', function(apiProvider) {
        apiProvider.api('freetypes', {
            type: 'http',
            backend: {rel: 'freetypes'}
        });
    }])
    .directive("templateEditable", function() {
        return {
            restrict: "A",
            require: "ngModel",
            link: function(scope, element, attrs, ngModel) {
                function read() {
                    ngModel.$setViewValue(element.text());
                }
                ngModel.$render = function() {
                    element.text(ngModel.$viewValue || "");
                };
                element.bind("blur keyup change", function() {
                    scope.$apply(read);
                });
            }
        }
    });
    return liveblogFreetypesModule;

})();
<commit_msg>Added variable check<commit_after>(function() {
    'use strict';

    LiveblogFreetypesController.$inject = ['api', '$location', 'notify', 'gettext',
    '$q', '$sce', 'config', 'lodash', 'upload', 'blogService', 'modal'];
    function LiveblogFreetypesController(api, $location, notify, gettext,
    $q, $sce, config, _, upload, blogService, modal) {
        var vm = this;

        function getFreetypes() {
            api.freetypes.query().then(function(data) {
                vm.freetypes = data._items;
                notify.info('Free types loaded');
            }, function(data) {
                notify.error(gettext('There was an error getting the free type'));
            })
        };

        angular.extend(vm, {
            //new item type modal is closed by default§
            freetypeModalActive: false,
            editFreetype: false,
            dialogFreetype: {
                loading: false,
                name: '',
                template: ''
            },
            //open dialog for adding editing an item type
            openFreetypeDialog: function(freetype) {

                vm.editFreetype = freetype || false;

                if (vm.editFreetype) {
                    vm.dialogFreetype.name = vm.editFreetype.name;
                    vm.dialogFreetype.template = vm.editFreetype.template;
                } else {
                    vm.dialogFreetype.name = '';
                    vm.dialogFreetype.template = '';
                }
                vm.freetypeModalActive = true;
            },
            handleSaveError: function(data) {
                var errorMsg = gettext('Saving did not work, please try again later!');
                if (data.data._issues.template) {
                    errorMsg = gettext(data.data._issues.template);
                }
                notify.error(errorMsg, 10000);
            },
            preSaveChecks: function(template) {
                var valid = true;
                //check for variables
                var patt = /\$([\$a-z0-9_.\[\]]+)/gi;
                if (!patt.test(template)) {
                    valid = false;
                    notify.error(gettext('Template must contain at least one variable! Check the documentation for further information'), 10000);
                }
                return valid
            },
            saveFreetype: function() {
                if (vm.preSaveChecks(vm.dialogFreetype.template)) {
                    vm.dialogFreetype.loading = true;
                    if (vm.editFreetype) {
                        api.freetypes.save(vm.editFreetype, {name: vm.dialogFreetype.name, template: vm.dialogFreetype.template}).then(function(data) {
                            vm.dialogFreetype.loading = false;
                            vm.freetypeModalActive = false;
                            getFreetypes();
                            vm.editFreetype = false;
                        }, function(data) {
                            vm.handleSaveError(data);
                        });
                    } else {
                        api.freetypes.save({name: vm.dialogFreetype.name, template: vm.dialogFreetype.template}).then(function(data) {
                            vm.dialogFreetype.loading = false;
                            vm.freetypeModalActive = false;
                            getFreetypes();
                        }, function(data) {
                            vm.handleSaveError(data);
                        });
                    }
                }
            },
            removeFreetype: function(freetype, $index) {
                modal.confirm(gettext('Are you sure you want to remove this free type?')).then(function() {
                    api.freetypes.remove(freetype).then(function(data) {
                        vm.freetypes.splice($index, 1);
                    }, function(data) {
                        notify.errorp(gettext('Can\'t remove free type'));
                    });
                });
            },
            cancelCreate: function() {
                vm.freetypeModalActive = false;
            }
        });

        getFreetypes();
    }

    var liveblogFreetypesModule = angular.module('liveblog.freetypes', [])
    .config(['superdeskProvider', function(superdesk) {
        if (config.subscriptionLevel != 'solo')
            superdesk
                .activity('/freetypes/', {
                    label: gettext('Free types manager'),
                    controller: LiveblogFreetypesController,
                    controllerAs: 'vm',
                    betaMark: true,
                    category: superdesk.MENU_MAIN,
                    adminTools: true,
                    privileges: {'global_preferences': 1},
                    templateUrl: 'scripts/liveblog-freetypes/views/list.html'
                });
    }])
    .config(['apiProvider', function(apiProvider) {
        apiProvider.api('freetypes', {
            type: 'http',
            backend: {rel: 'freetypes'}
        });
    }])
    .directive("templateEditable", function() {
        return {
            restrict: "A",
            require: "ngModel",
            link: function(scope, element, attrs, ngModel) {
                function read() {
                    ngModel.$setViewValue(element.text());
                }
                ngModel.$render = function() {
                    element.text(ngModel.$viewValue || "");
                };
                element.bind("blur keyup change", function() {
                    scope.$apply(read);
                });
            }
        }
    });
    return liveblogFreetypesModule;

})();
<|endoftext|>


<commit_before>'use strict';

angular.module('liveblog.security', [])
.service('blogSecurityService',
    ['$q', '$rootScope', '$route', 'blogService', '$location', 'privileges',
    function($q, $rootScope, $route, blogService, $location, privileges) {
        function canPublishAPost(blog) {
            return privileges.userHasPrivileges({'publish_post': 1});
        }
        function canCreateABlog() {
            return privileges.userHasPrivileges({'blogs': 1});
        }
        function isMemberOfBlog(blog) {
            // add the owner
            var ids = [blog.original_creator._id];
            // add the members
            if (blog.members) {
                ids.push.apply(ids, blog.members.map(function(member) {return member.user;}));
            }
            return ids.indexOf($rootScope.currentUser._id) > -1;
        }
        function canAccessBlog(blog) {
            return isAdmin() || isMemberOfBlog(blog);
        }
        function isAdmin() {
            return $rootScope.currentUser.user_type === 'administrator';
        }
        function isUserOwnerOrAdmin(archive) {
            return $rootScope.currentUser._id === archive.original_creator || isAdmin();
        }
        function isUserOwnerOrCanPublishAPost(archive) {
            return $rootScope.currentUser._id === archive.original_creator || canPublishAPost(archive);
        }
        function canAccessSettings(archive) {
            return canCreateABlog() && isUserOwnerOrAdmin(archive);
        }
        function goToSettings() {
            var def = $q.defer();
            blogService.get($route.current.params._id)
            .then(function(response) {
                if (canAccessSettings(response)) {
                    def.resolve();
                } else {
                    def.reject();
                    $location.path('/liveblog/edit/' + $route.current.params._id);
                }
            }, function() {
                $location.path('/liveblog');
                def.reject('You do not have permission to change the settings of this blog');
            });
            return def.promise;
        }
        return {
            goToSettings: goToSettings,
            isUserOwnerOrAdmin: isUserOwnerOrAdmin,
            isUserOwnerOrCanPublishAPost: isUserOwnerOrCanPublishAPost,
            canAccessSettings: canAccessSettings,
            canPublishAPost: canPublishAPost,
            canCreateABlog: canCreateABlog,
            canAccessBlog: canAccessBlog
        };
    }
]);
<commit_msg>security: unecessary parameter removed<commit_after>'use strict';

angular.module('liveblog.security', [])
.service('blogSecurityService',
    ['$q', '$rootScope', '$route', 'blogService', '$location', 'privileges',
    function($q, $rootScope, $route, blogService, $location, privileges) {
        function canPublishAPost() {
            return privileges.userHasPrivileges({'publish_post': 1});
        }
        function canCreateABlog() {
            return privileges.userHasPrivileges({'blogs': 1});
        }
        function isMemberOfBlog(blog) {
            // add the owner
            var ids = [blog.original_creator._id];
            // add the members
            if (blog.members) {
                ids.push.apply(ids, blog.members.map(function(member) {return member.user;}));
            }
            return ids.indexOf($rootScope.currentUser._id) > -1;
        }
        function canAccessBlog(blog) {
            return isAdmin() || isMemberOfBlog(blog);
        }
        function isAdmin() {
            return $rootScope.currentUser.user_type === 'administrator';
        }
        function isUserOwnerOrAdmin(archive) {
            return $rootScope.currentUser._id === archive.original_creator || isAdmin();
        }
        function isUserOwnerOrCanPublishAPost(archive) {
            return $rootScope.currentUser._id === archive.original_creator || canPublishAPost();
        }
        function canAccessSettings(archive) {
            return canCreateABlog() && isUserOwnerOrAdmin(archive);
        }
        function goToSettings() {
            var def = $q.defer();
            blogService.get($route.current.params._id)
            .then(function(response) {
                if (canAccessSettings(response)) {
                    def.resolve();
                } else {
                    def.reject();
                    $location.path('/liveblog/edit/' + $route.current.params._id);
                }
            }, function() {
                $location.path('/liveblog');
                def.reject('You do not have permission to change the settings of this blog');
            });
            return def.promise;
        }
        return {
            goToSettings: goToSettings,
            isUserOwnerOrAdmin: isUserOwnerOrAdmin,
            isUserOwnerOrCanPublishAPost: isUserOwnerOrCanPublishAPost,
            canAccessSettings: canAccessSettings,
            canPublishAPost: canPublishAPost,
            canCreateABlog: canCreateABlog,
            canAccessBlog: canAccessBlog
        };
    }
]);
<|endoftext|>


<commit_before>const REPO_URL = 'https://api.github.com/repos/leonidas/gulp-project-template';

export function getRepo() {
  return fetch(REPO_URL).then(res => res.json());
}

export function getCommits() {
  return fetch(`${REPO_URL}/commits`)
    .then(res => res.json())
    .then(commits => {
      return commits.map(({commit}) => commit);
    });
}
<commit_msg>remove code from template<commit_after><|endoftext|>


<commit_before>import { isArray, isNumeric } from 'utils/is';

var refPattern = /\[\s*(\*|[0-9]|[1-9][0-9]+)\s*\]/g;

export function assignNewKeypath ( target, property, oldKeypath, newKeypath ) {
	var existingKeypath = target[ property ];

	if ( !existingKeypath || equalsOrStartsWith( existingKeypath, newKeypath ) || !equalsOrStartsWith( existingKeypath, oldKeypath ) ) {
		return;
	}

	target[ property ] = getNewKeypath( existingKeypath, oldKeypath, newKeypath );
	return true;
}

export function decodeKeypath ( keypath ) {
	var value = keypath.slice( 2 );

	if ( keypath[1] === 'i' ) {
		return isNumeric( value ) ? +value : value;
	} else {
		return value;
	}
}

export function equalsOrStartsWith ( target, keypath) {
	return target === keypath || startsWithKeypath(target, keypath);
}

export function getKey ( keypath ) {
	var index = keypath.indexOf( '.' );
	return ~index ? keypath.slice( 0, index ) : keypath;
}

export function getMatchingKeypaths ( ractive, pattern ) {
	var keys, key, matchingKeypaths;

	keys = pattern.split( '.' );
	matchingKeypaths = [ '' ];

	while ( key = keys.shift() ) {
		if ( key === '*' ) {
			// expand to find all valid child keypaths
			matchingKeypaths = matchingKeypaths.reduce( expand, [] );
		}

		else {
			if ( matchingKeypaths[0] === '' ) { // first key
				matchingKeypaths[0] = key;
			} else {
				matchingKeypaths = matchingKeypaths.map( concatenate( key ) );
			}
		}
	}

	return matchingKeypaths;

	function expand ( matchingKeypaths, keypath ) {
		var value, key, childKeypath;

		value = ( ractive.viewmodel.wrapped[ keypath ] ? ractive.viewmodel.wrapped[ keypath ].get() : ractive.get( keypath ) );

		for ( key in value ) {
			if ( value.hasOwnProperty( key ) && ( key !== '_ractive' || !isArray( value ) ) ) { // for benefit of IE8
				childKeypath = keypath ? keypath + '.' + key : key;
				matchingKeypaths.push( childKeypath );
			}
		}

		return matchingKeypaths;
	}
}

function concatenate ( key ) {
	return function ( keypath ) {
		return keypath ? keypath + '.' + key : key;
	};
}

export function getNewKeypath( targetKeypath, oldKeypath, newKeypath ) {
	// exact match
	if ( targetKeypath === oldKeypath ) {
		return newKeypath !== undefined ? newKeypath : null;
	}

	// partial match based on leading keypath segments
	if ( startsWithKeypath( targetKeypath, oldKeypath ) ){
		return newKeypath === null ? newKeypath : targetKeypath.replace( oldKeypath + '.', newKeypath + '.' );
	}
}

export function normalise ( ref ) {
	return ref ? ref.replace( refPattern, '.$1' ) : '';
}

export function startsWithKeypath( target, keypath) {
	return target && keypath && target.substr( 0, keypath.length + 1 ) === keypath + '.';
}
<commit_msg>add Keypath object<commit_after>import { isArray, isNumeric } from 'utils/is';

var refPattern, keypathCache, Keypath;

refPattern = /\[\s*(\*|[0-9]|[1-9][0-9]+)\s*\]/g;

keypathCache = {};

var Keypath = function ( str ) {
	var keys = str.split( '.' );

	this.str = str;

	if ( str[0] === '@' ) {
		this.isSpecial = true;
		this.value = decodeKeypath( str );
	}

	this.firstKey = keys[0];
	this.lastKey = keys.pop();

	this.parent = str === '' ? null : getKeypath( keys.join( '.' ) );
	this.isRoot = !str;
};

Keypath.prototype.toString = function () {
	return this.str;
};

export function assignNewKeypath ( target, property, oldKeypath, newKeypath ) {
	var existingKeypath = target[ property ];

	if ( !existingKeypath || equalsOrStartsWith( existingKeypath, newKeypath ) || !equalsOrStartsWith( existingKeypath, oldKeypath ) ) {
		return;
	}

	target[ property ] = getNewKeypath( existingKeypath, oldKeypath, newKeypath );
	return true;
}

export function decodeKeypath ( keypath ) {
	var value = keypath.slice( 2 );

	if ( keypath[1] === 'i' ) {
		return isNumeric( value ) ? +value : value;
	} else {
		return value;
	}
}

export function equalsOrStartsWith ( target, keypath) {
	return target === keypath || startsWithKeypath(target, keypath);
}

export function getKey ( keypath ) {
	var index = keypath.indexOf( '.' );
	return ~index ? keypath.slice( 0, index ) : keypath;
}

export function getKeypath ( str ) {
	return keypathCache[ str ] || ( keypathCache[ str ] = new Keypath( str ) );
}

export function getMatchingKeypaths ( ractive, pattern ) {
	var keys, key, matchingKeypaths;

	keys = pattern.split( '.' );
	matchingKeypaths = [ '' ];

	while ( key = keys.shift() ) {
		if ( key === '*' ) {
			// expand to find all valid child keypaths
			matchingKeypaths = matchingKeypaths.reduce( expand, [] );
		}

		else {
			if ( matchingKeypaths[0] === '' ) { // first key
				matchingKeypaths[0] = key;
			} else {
				matchingKeypaths = matchingKeypaths.map( concatenate( key ) );
			}
		}
	}

	return matchingKeypaths;

	function expand ( matchingKeypaths, keypath ) {
		var value, key, childKeypath;

		value = ( ractive.viewmodel.wrapped[ keypath ] ? ractive.viewmodel.wrapped[ keypath ].get() : ractive.get( keypath ) );

		for ( key in value ) {
			if ( value.hasOwnProperty( key ) && ( key !== '_ractive' || !isArray( value ) ) ) { // for benefit of IE8
				childKeypath = keypath ? keypath + '.' + key : key;
				matchingKeypaths.push( childKeypath );
			}
		}

		return matchingKeypaths;
	}
}

function concatenate ( key ) {
	return function ( keypath ) {
		return keypath ? keypath + '.' + key : key;
	};
}

export function getNewKeypath( targetKeypath, oldKeypath, newKeypath ) {
	// exact match
	if ( targetKeypath === oldKeypath ) {
		return newKeypath !== undefined ? newKeypath : null;
	}

	// partial match based on leading keypath segments
	if ( startsWithKeypath( targetKeypath, oldKeypath ) ){
		return newKeypath === null ? newKeypath : targetKeypath.replace( oldKeypath + '.', newKeypath + '.' );
	}
}

export function normalise ( ref ) {
	return ref ? ref.replace( refPattern, '.$1' ) : '';
}

export function startsWithKeypath( target, keypath) {
	return target && keypath && target.substr( 0, keypath.length + 1 ) === keypath + '.';
}
<|endoftext|>


<commit_before>'use strict';

const { MovieInfo, SearchResult } = require('../../models/types.js');
const leech = require('../leech-promise.js');
const util = require('../util.js');
const parseURL = require('url').parse;

const NAME = 'javlibrary';
module.exports.name = function () {
    return NAME;
}

const TEMPLATE = {
    "search": "http://www.javlibrary.com/{lang}/vl_searchbyid.php?keyword={qtext}",
    "id": "http://www.javlibrary.com/{lang}/{qtext}",
}

const DOMAIN = 'www.javlibrary.com';
module.exports.domain = function () {
    return DOMAIN;
}

const BASE_URL = 'http://' + DOMAIN;

function formatDuration (val) {
    let minutes = parseInt(val);
    let hours = Math.floor(minutes / 60);
    minutes = minutes - hours * 60;

    if (hours < 10) { hours = '0' + hours; }
    if (minutes < 10) { minutes = '0' + minutes; }

    return hours + ':' + minutes + ':' + '00';
}

function getFootprint (data) {
    return {
        "crawler": NAME,
        "id": data.title,
    }
}

function thenIfSearch ($, url, urlpath, lang) {
    let result = new SearchResult({
        url: url,
        queryString:
            util.replaceAll(url.split('keyword=')[1], '+', ' '),
        footprint: getFootprint
    });

    $('div.videos > div').each((i, el) => {
        let info = new MovieInfo();

        let ele = $(el);
        info.url = urlpath + ele.find('a').attr('href').substring(1);
        info.title = ele.find('a div.id').text().toUpperCase();

        let val = ele.find('a img').attr('src');
        if (val != '//') {
            info.posters.push({
                url: 'http:' + val
            });
        }

        if (lang == 'en') {
            info.transtitle = ele.find('a div.title').text();
        }
        if (lang == 'ja') {
            info.title = ele.find('a div.title').text();
        }

        result.results.push(info);
    });

    result.more = $('div.page_selector').length > 0;

    let mov = result.results[0];
    if (result.queryString == mov.title) {
        return leech.get(mov.url)
        .then($$ => {
            return thenIfId($$, mov.url, urlpath);
        })
    }

    return result;
}

function thenIfId ($, url, urlpath, lang) {
    let info = new MovieInfo({
        url: url,
        country: 'Japan',
        origlang: 'Japanese'
    });

    let movid = $('div#video_id td.text').text();

    let val = $('div#video_jacket img').attr('src');
    if (val.indexOf('img/noimagepl.gif') == - 1) {
        info.posters.push({
            url: 'http:' + val
        });
    }

    info.title = movid.toUpperCase();

    if (lang == 'en') {
        info.transtitle = $('h3.post-title.text').text()
            .replace(movid, '')
            .trim();
    }

    if (lang == 'ja') {
        info.origtitle = $('h3.post-title.text').text()
            .replace(movid, '')
            .trim();
    }

    info.releasedate = $('div#video_date td.text').text();
    info.year = info.releasedate.substring(0, 4);

    info.duration = formatDuration(
        $('div#video_length span.text').text()
    );

    let ele = $('div#video_director a');
    if (ele.length > 0) {
        info.director = {
            url: urlpath + ele.attr('href'),
            text: ele.text(),
        };
    }

    ele = $('div#video_maker a');
    if (ele.length > 0) {
        info.maker = ele.text();
    }

    ele = $('div#video_label a');
    if (ele.length > 0) {
        info.label = {
            url: urlpath + ele.attr('href'),
            text: ele.text(),
        };
    }

    $('div#video_genres a').each((i, el) => {
        let ele = $(el);
        let genre = {
            url: urlpath + ele.attr('href'),
            text: ele.text(),
        }

        info.genres.push(genre);
    });

    $('div#video_cast a').each((i, el) => {
        let ele = $(el);
        let actor = {
            url: urlpath + ele.attr('href'),
            text: ele.text(),
        }

        info.actors.push(actor);
    });

    return info;
}

function catchError (err, resolve, reject) {
    var mss = err.message;
    if (mss.indexOf('HTTP Code') >= 0) {
        console.log('<' + mss + '> at ' + url)
        resolve(null);
    } else {
        reject(err);
    }
}

function crawl (opt) {
    let url = "";
    let lang = "en";
    if (typeof opt == 'string') {
        url = opt;
    }

    if (typeof opt == 'object') {
        let type = opt.type || '';
        let qtext = opt.qtext || '';
        lang = opt.lang || 'en';
        if (type && qtext) {
            url = TEMPLATE[type]
                .replace('{lang}', lang)
                .replace('{qtext}', qtext);
        }
    }

    if (url == "") {
        throw new Error("Invalid Arguments");
    }

    let url_parsed = parseURL(url);
    let urlpath = BASE_URL +
        url_parsed.pathname.substring(0, url_parsed.pathname.lastIndexOf('/'));

    return new Promise((resolve, reject) => {
        leech.get(url)
        .then($ => {
            if ($('title:contains("404")').length > 0 ||
                $('div:contains("Search Tips")').length > 0 ||
                $('div:contains("検索ヒント")').length > 0) {
                resolve(null);
            } else {

                if ($('div:contains("ID Search Result")').length > 0 ||
                    $('div:contains("品番検索結果")').length > 0) {
                    // Search result
                    Promise.resolve(thenIfSearch($, url, urlpath, lang))
                        .then(data => resolve(data))
                        .catch(err => catchError(err, resolve, reject));
                }

                else {
                    // Movie content
                    try {
                        let info = thenIfId($, url, urlpath, lang);
                        resolve(info);
                    } catch (ex) {
                        reject(ex);
                    }
                }
            }
        })
        .catch(err => catchError(err, resolve, reject));
    });
}

module.exports.crawl = crawl;
<commit_msg>Clean code.<commit_after>'use strict';

const { MovieInfo, SearchResult } = require('../../models/types.js');
const leech = require('../leech-promise.js');
const util = require('../util.js');
const parseURL = require('url').parse;

const NAME = 'javlibrary';
module.exports.name = function () {
    return NAME;
}

const TEMPLATE = {
    "search": "http://www.javlibrary.com/{lang}/vl_searchbyid.php?keyword={qtext}",
    "id": "http://www.javlibrary.com/{lang}/{qtext}",
}

const DOMAIN = 'www.javlibrary.com';
module.exports.domain = function () {
    return DOMAIN;
}

const BASE_URL = 'http://' + DOMAIN;

function formatDuration (val) {
    let minutes = parseInt(val);
    let hours = Math.floor(minutes / 60);
    minutes = minutes - hours * 60;

    if (hours < 10) { hours = '0' + hours; }
    if (minutes < 10) { minutes = '0' + minutes; }

    return hours + ':' + minutes + ':' + '00';
}

function getFootprint (data) {
    return {
        "crawler": NAME,
        "id": data.title,
    }
}

function thenIfSearch ($, url, urlpath, lang) {
    let result = new SearchResult({
        url: url,
        queryString:
            util.replaceAll(url.split('keyword=')[1], '+', ' '),
        footprint: getFootprint
    });

    $('div.videos > div').each((i, el) => {
        let info = new MovieInfo();

        let ele = $(el);
        info.url = urlpath + ele.find('a').attr('href').substring(1);
        info.title = ele.find('a div.id').text().toUpperCase();

        let val = ele.find('a img').attr('src');
        if (val != '//') {
            info.posters.push({
                url: 'http:' + val
            });
        }

        if (lang == 'en') {
            info.transtitle = ele.find('a div.title').text();
        }
        if (lang == 'ja') {
            info.title = ele.find('a div.title').text();
        }

        result.results.push(info);
    });

    result.more = $('div.page_selector').length > 0;

    // let mov = result.results[0];
    // if (result.queryString == mov.title) {
    //     return leech.get(mov.url)
    //     .then($$ => {
    //         return thenIfId($$, mov.url, urlpath);
    //     })
    // }

    return result;
}

function thenIfId ($, url, urlpath, lang) {
    let info = new MovieInfo({
        url: url,
        country: 'Japan',
        origlang: 'Japanese'
    });

    let movid = $('div#video_id td.text').text();

    let val = $('div#video_jacket img').attr('src');
    if (val.indexOf('img/noimagepl.gif') == - 1) {
        info.posters.push({
            url: 'http:' + val
        });
    }

    info.title = movid.toUpperCase();

    if (lang == 'en') {
        info.transtitle = $('h3.post-title.text').text()
            .replace(movid, '')
            .trim();
    }

    if (lang == 'ja') {
        info.origtitle = $('h3.post-title.text').text()
            .replace(movid, '')
            .trim();
    }

    info.releasedate = $('div#video_date td.text').text();
    info.year = info.releasedate.substring(0, 4);

    info.duration = formatDuration(
        $('div#video_length span.text').text()
    );

    let ele = $('div#video_director a');
    if (ele.length > 0) {
        info.director = {
            url: urlpath + ele.attr('href'),
            text: ele.text(),
        };
    }

    ele = $('div#video_maker a');
    if (ele.length > 0) {
        info.maker = ele.text();
    }

    ele = $('div#video_label a');
    if (ele.length > 0) {
        info.label = {
            url: urlpath + ele.attr('href'),
            text: ele.text(),
        };
    }

    $('div#video_genres a').each((i, el) => {
        let ele = $(el);
        let genre = {
            url: urlpath + ele.attr('href'),
            text: ele.text(),
        }

        info.genres.push(genre);
    });

    $('div#video_cast a').each((i, el) => {
        let ele = $(el);
        let actor = {
            url: urlpath + ele.attr('href'),
            text: ele.text(),
        }

        info.actors.push(actor);
    });

    return info;
}

function catchError (err, resolve, reject) {
    var mss = err.message;
    if (mss.indexOf('HTTP Code') >= 0) {
        console.log('<' + mss + '> at ' + url)
        resolve(null);
    } else {
        reject(err);
    }
}

function crawl (opt) {
    let url = "";
    let lang = "en";
    if (typeof opt == 'string') {
        url = opt;
    }

    if (typeof opt == 'object') {
        let type = opt.type || '';
        let qtext = opt.qtext || '';
        lang = opt.lang || 'en';
        if (type && qtext) {
            url = TEMPLATE[type]
                .replace('{lang}', lang)
                .replace('{qtext}', qtext);
        }
    }

    if (url == "") {
        throw new Error("Invalid Arguments");
    }

    let url_parsed = parseURL(url);
    let urlpath = BASE_URL +
        url_parsed.pathname.substring(0, url_parsed.pathname.lastIndexOf('/'));

    return new Promise((resolve, reject) => {
        leech.get(url)
        .then($ => {
            if ($('title:contains("404")').length > 0 ||
                $('div:contains("Search Tips")').length > 0 ||
                $('div:contains("検索ヒント")').length > 0) {
                resolve(null);
            } else {

                if ($('div:contains("ID Search Result")').length > 0 ||
                    $('div:contains("品番検索結果")').length > 0) {
                    // Search result
                    Promise.resolve(thenIfSearch($, url, urlpath, lang))
                        .then(data => resolve(data))
                        .catch(err => catchError(err, resolve, reject));
                }

                else {
                    // Movie content
                    try {
                        let info = thenIfId($, url, urlpath, lang);
                        resolve(info);
                    } catch (ex) {
                        reject(ex);
                    }
                }
            }
        })
        .catch(err => catchError(err, resolve, reject));
    });
}

module.exports.crawl = crawl;
<|endoftext|>


<commit_before>App = undefined;

(function() {
  "use strict";

  // Application:
  App = Ember.Application.create();

  /* ==========
   * Globals
   * ==========
   * */
  App.Globals = {
    title: "HGO Türschloss",
    version: "0.0.0"
  };

  /* ==========
   * Store
   * ==========
   * */
  // Fetch
  App.ApplicationAdapter = DS.RESTAdapter.extend({
    namespace: 'api/v1'
  });
  App.Store = DS.Store.extend({
    adapter: 'App.ApplicationAdapter'
  });

  /* ==========
   * Routing
   * ==========
   * */
  App.Router.reopen({
    rootURL: '/app'
  });
  App.Router.map(function() {
    this.resource('admin', function() {
      /* TODO: may specify sub-routes for specific users to be shown to the admin */
      this.route('new');
      this.route('user', {
        path: '/user/:userid'
      });
    });

    this.route('about');
    this.route('readme');
  });

  /*
   * ==========
   * Global controller
   * ==========
   * */
   // dirty:
   App.ApplicationController = Ember.ObjectController.extend({
     _isPrivileged: null,
     isPrivileged: function() {
       if ( this.get('_isPrivileged') === null ) {
         this.priviledgeUpdater();
         this.set('_isPrivileged', false);
       }
       return this.get('_isPrivileged');
     }.property('_isPrivileged'),

     // updates the isPrivileged property based on the /user object.
     priviledgeUpdater: function() {
       var self = this;

       return Ember.$.get('/user').then(function(user) {
         // check if the user objects is a user
         var isUser = true;
         if ( user && user.type ) {
           isUser = ( user.type === 'user' );
         }
         self.set('_isPrivileged', !isUser);
       });
     }
   });
}());
<commit_msg>Exporting currentUser on ApplicationController.<commit_after>App = undefined;

(function() {
  "use strict";

  // Application:
  App = Ember.Application.create();

  /* ==========
   * Globals
   * ==========
   * */
  App.Globals = {
    title: "HGO Türschloss",
    version: "0.0.0"
  };

  /* ==========
   * Store
   * ==========
   * */
  // Fetch
  App.ApplicationAdapter = DS.RESTAdapter.extend({
    namespace: 'api/v1'
  });
  App.Store = DS.Store.extend({
    adapter: 'App.ApplicationAdapter'
  });

  /* ==========
   * Routing
   * ==========
   * */
  App.Router.reopen({
    rootURL: '/app'
  });
  App.Router.map(function() {
    this.resource('admin', function() {
      /* TODO: may specify sub-routes for specific users to be shown to the admin */
      this.route('new');
      this.route('user', {
        path: '/user/:userid'
      });
    });

    this.route('about');
    this.route('readme');
  });

  /*
   * ==========
   * Global controller
   * ==========
   * */
   // dirty:
   App.ApplicationController = Ember.ObjectController.extend({
     currentUser: null,

     _isPrivileged: null,
     isPrivileged: function() {
       if ( this.get('_isPrivileged') === null ) {
         this.priviledgeUpdater();
         this.set('_isPrivileged', false);
       }
       return this.get('_isPrivileged');
     }.property('_isPrivileged'),

     // updates the isPrivileged property based on the /user object.
     priviledgeUpdater: function() {
       var self = this;

       return Ember.$.get('/user').then(function(user) {
         self.set('currentUser', user);

         // check if the user objects is a user
         var isUser = true;
         if ( user && user.type ) {
           isUser = ( user.type === 'user' );
         }
         self.set('_isPrivileged', !isUser);
       });
     }
   });
}());
<|endoftext|>


<commit_before>/**
 * Welcome to RendererGL Immediate Mode.
 * Immediate mode is used for drawing custom shapes
 * from a set of vertices.  Immediate Mode is activated
 * when you call beginShape() & de-activated when you call endShape().
 * Immediate mode is a style of programming borrowed
 * from OpenGL's (now-deprecated) immediate mode.
 * It differs from p5.js' default, Retained Mode, which caches
 * geometries and buffers on the CPU to reduce the number of webgl
 * draw calls. Retained mode is more efficient & performative,
 * however, Immediate Mode is useful for sketching quick
 * geometric ideas.
 */
'use strict';

var p5 = require('../core/main');
var constants = require('../core/constants');

/**
 * Begin shape drawing.  This is a helpful way of generating
 * custom shapes quickly.  However in WEBGL mode, application
 * performance will likely drop as a result of too many calls to
 * beginShape() / endShape().  As a high performance alternative,
 * please use p5.js geometry primitives.
 * @private
 * @method beginShape
 * @param  {Number} mode webgl primitives mode.  beginShape supports the
 *                       following modes:
 *                       POINTS,LINES,LINE_STRIP,LINE_LOOP,TRIANGLES,
 *                       TRIANGLE_STRIP,and TRIANGLE_FAN.
 * @chainable
 */
p5.RendererGL.prototype.beginShape = function(mode) {
  //default shape mode is line_strip
  this.immediateMode.shapeMode =
    mode !== undefined ? mode : constants.LINE_STRIP;
  //if we haven't yet initialized our
  //immediateMode vertices & buffers, create them now!
  if (this.immediateMode.vertices === undefined) {
    this.immediateMode.vertices = [];
    this.immediateMode.edges = [];
    this.immediateMode.lineVertices = [];
    this.immediateMode.vertexColors = [];
    this.immediateMode.lineNormals = [];
    this.immediateMode.uvCoords = [];
    this.immediateMode.vertexBuffer = this.GL.createBuffer();
    this.immediateMode.colorBuffer = this.GL.createBuffer();
    this.immediateMode.uvBuffer = this.GL.createBuffer();
    this.immediateMode.lineVertexBuffer = this.GL.createBuffer();
    this.immediateMode.lineNormalBuffer = this.GL.createBuffer();
    this.immediateMode.pointVertexBuffer = this.GL.createBuffer();
    this.immediateMode._bezierVertex = [];
    this.immediateMode._quadraticVertex = [];
    this.immediateMode._curveVertex = [];
  } else {
    this.immediateMode.vertices.length = 0;
    this.immediateMode.edges.length = 0;
    this.immediateMode.lineVertices.length = 0;
    this.immediateMode.lineNormals.length = 0;
    this.immediateMode.vertexColors.length = 0;
    this.immediateMode.uvCoords.length = 0;
  }
  this.isImmediateDrawing = true;
  return this;
};
/**
 * adds a vertex to be drawn in a custom Shape.
 * @private
 * @method vertex
 * @param  {Number} x x-coordinate of vertex
 * @param  {Number} y y-coordinate of vertex
 * @param  {Number} z z-coordinate of vertex
 * @chainable
 * @TODO implement handling of p5.Vector args
 */
p5.RendererGL.prototype.vertex = function(x, y) {
  var z, u, v;

  // default to (x, y) mode: all other arugments assumed to be 0.
  z = u = v = 0;

  if (arguments.length === 3) {
    // (x, y, z) mode: (u, v) assumed to be 0.
    z = arguments[2];
  } else if (arguments.length === 4) {
    // (x, y, u, v) mode: z assumed to be 0.
    u = arguments[2];
    v = arguments[3];
  } else if (arguments.length === 5) {
    // (x, y, z, u, v) mode
    z = arguments[2];
    u = arguments[3];
    v = arguments[4];
  }
  var vert = new p5.Vector(x, y, z);
  this.immediateMode.vertices.push(vert);
  var vertexColor = this.curFillColor || [0.5, 0.5, 0.5, 1.0];
  this.immediateMode.vertexColors.push(
    vertexColor[0],
    vertexColor[1],
    vertexColor[2],
    vertexColor[3]
  );

  if (this.textureMode === constants.IMAGE) {
    if (this._tex !== null) {
      if (this._tex.width > 0 && this._tex.height > 0) {
        u /= this._tex.width;
        v /= this._tex.height;
      }
    } else if (this._tex === null && arguments.length >= 4) {
      // Only throw this warning if custom uv's have  been provided
      console.warn(
        'You must first call texture() before using' +
          ' vertex() with image based u and v coordinates'
      );
    }
  }

  this.immediateMode.uvCoords.push(u, v);

  this.immediateMode._bezierVertex[0] = x;
  this.immediateMode._bezierVertex[1] = y;
  this.immediateMode._bezierVertex[2] = z;

  this.immediateMode._quadraticVertex[0] = x;
  this.immediateMode._quadraticVertex[1] = y;
  this.immediateMode._quadraticVertex[2] = z;

  return this;
};

/**
 * End shape drawing and render vertices to screen.
 * @chainable
 */
p5.RendererGL.prototype.endShape = function(
  mode,
  isCurve,
  isBezier,
  isQuadratic,
  isContour,
  shapeKind
) {
  if (this.immediateMode.shapeMode === constants.POINTS) {
    this._drawPoints(
      this.immediateMode.vertices,
      this.immediateMode.pointVertexBuffer
    );
  } else if (this.immediateMode.vertices.length > 1) {
    if (this._doStroke && this.drawMode !== constants.TEXTURE) {
      if (this.immediateMode.shapeMode === constants.TRIANGLE_STRIP) {
        var i;
        for (i = 0; i < this.immediateMode.vertices.length - 2; i++) {
          this.immediateMode.edges.push([i, i + 1]);
          this.immediateMode.edges.push([i, i + 2]);
        }
        this.immediateMode.edges.push([i, i + 1]);
      } else if (this.immediateMode.shapeMode === constants.TRIANGLES) {
        for (i = 0; i < this.immediateMode.vertices.length - 2; i = i + 3) {
          this.immediateMode.edges.push([i, i + 1]);
          this.immediateMode.edges.push([i + 1, i + 2]);
          this.immediateMode.edges.push([i + 2, i]);
        }
      } else {
        for (i = 0; i < this.immediateMode.vertices.length - 1; i++) {
          this.immediateMode.edges.push([i, i + 1]);
        }
      }
      if (mode === constants.CLOSE) {
        this.immediateMode.edges.push([
          this.immediateMode.vertices.length - 1,
          0
        ]);
      }

      p5.Geometry.prototype._edgesToVertices.call(this.immediateMode);
      this._drawStrokeImmediateMode();
    }

    if (this._doFill) {
      if (this.isBezier || this.isQuadratic || this.isCurve) {
        var contours = [
          new Float32Array(this._vToNArray(this.immediateMode.vertices))
        ];
        var polyTriangles = this._triangulate(contours);
        this.immediateMode.vertices = [];
        for (
          var j = 0, polyTriLength = polyTriangles.length;
          j < polyTriLength;
          j = j + 3
        ) {
          this.vertex(
            polyTriangles[j],
            polyTriangles[j + 1],
            polyTriangles[j + 2]
          );
        }
      }
      this._drawFillImmediateMode(
        mode,
        isCurve,
        isBezier,
        isQuadratic,
        isContour,
        shapeKind
      );
    }
  }
  //clear out our vertexPositions & colors arrays
  //after rendering
  this.immediateMode.vertices.length = 0;
  this.immediateMode.vertexColors.length = 0;
  this.immediateMode.uvCoords.length = 0;
  this.isImmediateDrawing = false;
  this.isBezier = false;
  this.isQuadratic = false;
  this.isCurve = false;
  this.immediateMode._bezierVertex.length = 0;
  this.immediateMode._quadraticVertex.length = 0;

  this.immediateMode._curveVertex.length = 0;

  return this;
};

p5.RendererGL.prototype._drawFillImmediateMode = function(
  mode,
  isCurve,
  isBezier,
  isQuadratic,
  isContour,
  shapeKind
) {
  var gl = this.GL;
  var shader = this._getImmediateFillShader();
  this._setFillUniforms(shader);

  // initialize the fill shader's 'aPosition' buffer
  if (shader.attributes.aPosition) {
    //vertex position Attribute
    this._bindBuffer(
      this.immediateMode.vertexBuffer,
      gl.ARRAY_BUFFER,
      this._vToNArray(this.immediateMode.vertices),
      Float32Array,
      gl.DYNAMIC_DRAW
    );

    shader.enableAttrib(
      shader.attributes.aPosition.location,
      3,
      gl.FLOAT,
      false,
      0,
      0
    );
  }

  // initialize the fill shader's 'aVertexColor' buffer
  if (this.drawMode === constants.FILL && shader.attributes.aVertexColor) {
    this._bindBuffer(
      this.immediateMode.colorBuffer,
      gl.ARRAY_BUFFER,
      this.immediateMode.vertexColors,
      Float32Array,
      gl.DYNAMIC_DRAW
    );

    shader.enableAttrib(
      shader.attributes.aVertexColor.location,
      4,
      gl.FLOAT,
      false,
      0,
      0
    );
  }

  // initialize the fill shader's 'aTexCoord' buffer
  if (this.drawMode === constants.TEXTURE && shader.attributes.aTexCoord) {
    //texture coordinate Attribute
    this._bindBuffer(
      this.immediateMode.uvBuffer,
      gl.ARRAY_BUFFER,
      this.immediateMode.uvCoords,
      Float32Array,
      gl.DYNAMIC_DRAW
    );

    shader.enableAttrib(
      shader.attributes.aTexCoord.location,
      2,
      gl.FLOAT,
      false,
      0,
      0
    );
  }

  //if (true || mode) {
  if (this.drawMode === constants.FILL || this.drawMode === constants.TEXTURE) {
    switch (this.immediateMode.shapeMode) {
      case constants.LINE_STRIP:
      case constants.LINES:
      case constants.TRIANGLES:
        this.immediateMode.shapeMode =
          this.isBezier ||
          this.isQuadratic ||
          this.isCurve ||
          this.immediateMode.shapeMode === constants.TRIANGLES
            ? constants.TRIANGLES
            : constants.TRIANGLE_FAN;
        break;
    }
  } else {
    switch (this.immediateMode.shapeMode) {
      case constants.LINE_STRIP:
      case constants.LINES:
        this.immediateMode.shapeMode = constants.LINE_LOOP;
        break;
    }
  }
  //}
  //QUADS & QUAD_STRIP are not supported primitives modes
  //in webgl.
  if (
    this.immediateMode.shapeMode === constants.QUADS ||
    this.immediateMode.shapeMode === constants.QUAD_STRIP
  ) {
    throw new Error(
      'sorry, ' +
        this.immediateMode.shapeMode +
        ' not yet implemented in webgl mode.'
    );
  } else {
    this._applyColorBlend(this.curFillColor);
    gl.enable(gl.BLEND);
    gl.drawArrays(
      this.immediateMode.shapeMode,
      0,
      this.immediateMode.vertices.length
    );

    this._pixelsState._pixelsDirty = true;
  }
  // todo / optimizations? leave bound until another shader is set?
  shader.unbindShader();
};

p5.RendererGL.prototype._drawStrokeImmediateMode = function() {
  var gl = this.GL;
  var shader = this._getImmediateStrokeShader();
  this._setStrokeUniforms(shader);

  // initialize the stroke shader's 'aPosition' buffer
  if (shader.attributes.aPosition) {
    this._bindBuffer(
      this.immediateMode.lineVertexBuffer,
      gl.ARRAY_BUFFER,
      this._flatten(this.immediateMode.lineVertices),
      Float32Array,
      gl.STATIC_DRAW
    );

    shader.enableAttrib(
      shader.attributes.aPosition.location,
      3,
      gl.FLOAT,
      false,
      0,
      0
    );
  }

  // initialize the stroke shader's 'aDirection' buffer
  if (shader.attributes.aDirection) {
    this._bindBuffer(
      this.immediateMode.lineNormalBuffer,
      gl.ARRAY_BUFFER,
      this._flatten(this.immediateMode.lineNormals),
      Float32Array,
      gl.STATIC_DRAW
    );
    shader.enableAttrib(
      shader.attributes.aDirection.location,
      4,
      gl.FLOAT,
      false,
      0,
      0
    );
  }

  this._applyColorBlend(this.curStrokeColor);
  gl.drawArrays(gl.TRIANGLES, 0, this.immediateMode.lineVertices.length);

  this._pixelsState._pixelsDirty = true;

  shader.unbindShader();
};

module.exports = p5.RendererGL;
<commit_msg>Fixes WebGL LINES<commit_after>/**
 * Welcome to RendererGL Immediate Mode.
 * Immediate mode is used for drawing custom shapes
 * from a set of vertices.  Immediate Mode is activated
 * when you call beginShape() & de-activated when you call endShape().
 * Immediate mode is a style of programming borrowed
 * from OpenGL's (now-deprecated) immediate mode.
 * It differs from p5.js' default, Retained Mode, which caches
 * geometries and buffers on the CPU to reduce the number of webgl
 * draw calls. Retained mode is more efficient & performative,
 * however, Immediate Mode is useful for sketching quick
 * geometric ideas.
 */
'use strict';

var p5 = require('../core/main');
var constants = require('../core/constants');

/**
 * Begin shape drawing.  This is a helpful way of generating
 * custom shapes quickly.  However in WEBGL mode, application
 * performance will likely drop as a result of too many calls to
 * beginShape() / endShape().  As a high performance alternative,
 * please use p5.js geometry primitives.
 * @private
 * @method beginShape
 * @param  {Number} mode webgl primitives mode.  beginShape supports the
 *                       following modes:
 *                       POINTS,LINES,LINE_STRIP,LINE_LOOP,TRIANGLES,
 *                       TRIANGLE_STRIP,and TRIANGLE_FAN.
 * @chainable
 */
p5.RendererGL.prototype.beginShape = function(mode) {
  //default shape mode is line_strip
  this.immediateMode.shapeMode =
    mode !== undefined ? mode : constants.LINE_STRIP;
  //if we haven't yet initialized our
  //immediateMode vertices & buffers, create them now!
  if (this.immediateMode.vertices === undefined) {
    this.immediateMode.vertices = [];
    this.immediateMode.edges = [];
    this.immediateMode.lineVertices = [];
    this.immediateMode.vertexColors = [];
    this.immediateMode.lineNormals = [];
    this.immediateMode.uvCoords = [];
    this.immediateMode.vertexBuffer = this.GL.createBuffer();
    this.immediateMode.colorBuffer = this.GL.createBuffer();
    this.immediateMode.uvBuffer = this.GL.createBuffer();
    this.immediateMode.lineVertexBuffer = this.GL.createBuffer();
    this.immediateMode.lineNormalBuffer = this.GL.createBuffer();
    this.immediateMode.pointVertexBuffer = this.GL.createBuffer();
    this.immediateMode._bezierVertex = [];
    this.immediateMode._quadraticVertex = [];
    this.immediateMode._curveVertex = [];
  } else {
    this.immediateMode.vertices.length = 0;
    this.immediateMode.edges.length = 0;
    this.immediateMode.lineVertices.length = 0;
    this.immediateMode.lineNormals.length = 0;
    this.immediateMode.vertexColors.length = 0;
    this.immediateMode.uvCoords.length = 0;
  }
  this.isImmediateDrawing = true;
  return this;
};
/**
 * adds a vertex to be drawn in a custom Shape.
 * @private
 * @method vertex
 * @param  {Number} x x-coordinate of vertex
 * @param  {Number} y y-coordinate of vertex
 * @param  {Number} z z-coordinate of vertex
 * @chainable
 * @TODO implement handling of p5.Vector args
 */
p5.RendererGL.prototype.vertex = function(x, y) {
  var z, u, v;

  // default to (x, y) mode: all other arugments assumed to be 0.
  z = u = v = 0;

  if (arguments.length === 3) {
    // (x, y, z) mode: (u, v) assumed to be 0.
    z = arguments[2];
  } else if (arguments.length === 4) {
    // (x, y, u, v) mode: z assumed to be 0.
    u = arguments[2];
    v = arguments[3];
  } else if (arguments.length === 5) {
    // (x, y, z, u, v) mode
    z = arguments[2];
    u = arguments[3];
    v = arguments[4];
  }
  var vert = new p5.Vector(x, y, z);
  this.immediateMode.vertices.push(vert);
  var vertexColor = this.curFillColor || [0.5, 0.5, 0.5, 1.0];
  this.immediateMode.vertexColors.push(
    vertexColor[0],
    vertexColor[1],
    vertexColor[2],
    vertexColor[3]
  );

  if (this.textureMode === constants.IMAGE) {
    if (this._tex !== null) {
      if (this._tex.width > 0 && this._tex.height > 0) {
        u /= this._tex.width;
        v /= this._tex.height;
      }
    } else if (this._tex === null && arguments.length >= 4) {
      // Only throw this warning if custom uv's have  been provided
      console.warn(
        'You must first call texture() before using' +
          ' vertex() with image based u and v coordinates'
      );
    }
  }

  this.immediateMode.uvCoords.push(u, v);

  this.immediateMode._bezierVertex[0] = x;
  this.immediateMode._bezierVertex[1] = y;
  this.immediateMode._bezierVertex[2] = z;

  this.immediateMode._quadraticVertex[0] = x;
  this.immediateMode._quadraticVertex[1] = y;
  this.immediateMode._quadraticVertex[2] = z;

  return this;
};

/**
 * End shape drawing and render vertices to screen.
 * @chainable
 */
p5.RendererGL.prototype.endShape = function(
  mode,
  isCurve,
  isBezier,
  isQuadratic,
  isContour,
  shapeKind
) {
  if (this.immediateMode.shapeMode === constants.POINTS) {
    this._drawPoints(
      this.immediateMode.vertices,
      this.immediateMode.pointVertexBuffer
    );
  } else if (this.immediateMode.vertices.length > 1) {
    if (this._doStroke && this.drawMode !== constants.TEXTURE) {
      if (this.immediateMode.shapeMode === constants.TRIANGLE_STRIP) {
        var i;
        for (i = 0; i < this.immediateMode.vertices.length - 2; i++) {
          this.immediateMode.edges.push([i, i + 1]);
          this.immediateMode.edges.push([i, i + 2]);
        }
        this.immediateMode.edges.push([i, i + 1]);
      } else if (this.immediateMode.shapeMode === constants.TRIANGLES) {
        for (i = 0; i < this.immediateMode.vertices.length - 2; i = i + 3) {
          this.immediateMode.edges.push([i, i + 1]);
          this.immediateMode.edges.push([i + 1, i + 2]);
          this.immediateMode.edges.push([i + 2, i]);
        }
      } else if (this.immediateMode.shapeMode === constants.LINES) {
        for (i = 0; i < this.immediateMode.vertices.length - 1; i = i + 2) {
          this.immediateMode.edges.push([i, i + 1]);
        }
      } else {
        for (i = 0; i < this.immediateMode.vertices.length - 1; i++) {
          this.immediateMode.edges.push([i, i + 1]);
        }
      }
      if (mode === constants.CLOSE) {
        this.immediateMode.edges.push([
          this.immediateMode.vertices.length - 1,
          0
        ]);
      }

      p5.Geometry.prototype._edgesToVertices.call(this.immediateMode);
      this._drawStrokeImmediateMode();
    }

    if (this._doFill && this.immediateMode.shapeMode !== constants.LINES) {
      if (this.isBezier || this.isQuadratic || this.isCurve) {
        var contours = [
          new Float32Array(this._vToNArray(this.immediateMode.vertices))
        ];
        var polyTriangles = this._triangulate(contours);
        this.immediateMode.vertices = [];
        for (
          var j = 0, polyTriLength = polyTriangles.length;
          j < polyTriLength;
          j = j + 3
        ) {
          this.vertex(
            polyTriangles[j],
            polyTriangles[j + 1],
            polyTriangles[j + 2]
          );
        }
      }
      this._drawFillImmediateMode(
        mode,
        isCurve,
        isBezier,
        isQuadratic,
        isContour,
        shapeKind
      );
    }
  }
  //clear out our vertexPositions & colors arrays
  //after rendering
  this.immediateMode.vertices.length = 0;
  this.immediateMode.vertexColors.length = 0;
  this.immediateMode.uvCoords.length = 0;
  this.isImmediateDrawing = false;
  this.isBezier = false;
  this.isQuadratic = false;
  this.isCurve = false;
  this.immediateMode._bezierVertex.length = 0;
  this.immediateMode._quadraticVertex.length = 0;

  this.immediateMode._curveVertex.length = 0;

  return this;
};

p5.RendererGL.prototype._drawFillImmediateMode = function(
  mode,
  isCurve,
  isBezier,
  isQuadratic,
  isContour,
  shapeKind
) {
  var gl = this.GL;
  var shader = this._getImmediateFillShader();
  this._setFillUniforms(shader);

  // initialize the fill shader's 'aPosition' buffer
  if (shader.attributes.aPosition) {
    //vertex position Attribute
    this._bindBuffer(
      this.immediateMode.vertexBuffer,
      gl.ARRAY_BUFFER,
      this._vToNArray(this.immediateMode.vertices),
      Float32Array,
      gl.DYNAMIC_DRAW
    );

    shader.enableAttrib(
      shader.attributes.aPosition.location,
      3,
      gl.FLOAT,
      false,
      0,
      0
    );
  }

  // initialize the fill shader's 'aVertexColor' buffer
  if (this.drawMode === constants.FILL && shader.attributes.aVertexColor) {
    this._bindBuffer(
      this.immediateMode.colorBuffer,
      gl.ARRAY_BUFFER,
      this.immediateMode.vertexColors,
      Float32Array,
      gl.DYNAMIC_DRAW
    );

    shader.enableAttrib(
      shader.attributes.aVertexColor.location,
      4,
      gl.FLOAT,
      false,
      0,
      0
    );
  }

  // initialize the fill shader's 'aTexCoord' buffer
  if (this.drawMode === constants.TEXTURE && shader.attributes.aTexCoord) {
    //texture coordinate Attribute
    this._bindBuffer(
      this.immediateMode.uvBuffer,
      gl.ARRAY_BUFFER,
      this.immediateMode.uvCoords,
      Float32Array,
      gl.DYNAMIC_DRAW
    );

    shader.enableAttrib(
      shader.attributes.aTexCoord.location,
      2,
      gl.FLOAT,
      false,
      0,
      0
    );
  }

  //if (true || mode) {
  if (this.drawMode === constants.FILL || this.drawMode === constants.TEXTURE) {
    switch (this.immediateMode.shapeMode) {
      case constants.LINE_STRIP:
      case constants.LINES:
      case constants.TRIANGLES:
        this.immediateMode.shapeMode =
          this.isBezier ||
          this.isQuadratic ||
          this.isCurve ||
          this.immediateMode.shapeMode === constants.TRIANGLES
            ? constants.TRIANGLES
            : constants.TRIANGLE_FAN;
        break;
    }
  } else {
    switch (this.immediateMode.shapeMode) {
      case constants.LINE_STRIP:
      case constants.LINES:
        this.immediateMode.shapeMode = constants.LINE_LOOP;
        break;
    }
  }
  //}
  //QUADS & QUAD_STRIP are not supported primitives modes
  //in webgl.
  if (
    this.immediateMode.shapeMode === constants.QUADS ||
    this.immediateMode.shapeMode === constants.QUAD_STRIP
  ) {
    throw new Error(
      'sorry, ' +
        this.immediateMode.shapeMode +
        ' not yet implemented in webgl mode.'
    );
  } else {
    this._applyColorBlend(this.curFillColor);
    gl.enable(gl.BLEND);
    gl.drawArrays(
      this.immediateMode.shapeMode,
      0,
      this.immediateMode.vertices.length
    );

    this._pixelsState._pixelsDirty = true;
  }
  // todo / optimizations? leave bound until another shader is set?
  shader.unbindShader();
};

p5.RendererGL.prototype._drawStrokeImmediateMode = function() {
  var gl = this.GL;
  var shader = this._getImmediateStrokeShader();
  this._setStrokeUniforms(shader);

  // initialize the stroke shader's 'aPosition' buffer
  if (shader.attributes.aPosition) {
    this._bindBuffer(
      this.immediateMode.lineVertexBuffer,
      gl.ARRAY_BUFFER,
      this._flatten(this.immediateMode.lineVertices),
      Float32Array,
      gl.STATIC_DRAW
    );

    shader.enableAttrib(
      shader.attributes.aPosition.location,
      3,
      gl.FLOAT,
      false,
      0,
      0
    );
  }

  // initialize the stroke shader's 'aDirection' buffer
  if (shader.attributes.aDirection) {
    this._bindBuffer(
      this.immediateMode.lineNormalBuffer,
      gl.ARRAY_BUFFER,
      this._flatten(this.immediateMode.lineNormals),
      Float32Array,
      gl.STATIC_DRAW
    );
    shader.enableAttrib(
      shader.attributes.aDirection.location,
      4,
      gl.FLOAT,
      false,
      0,
      0
    );
  }

  this._applyColorBlend(this.curStrokeColor);
  gl.drawArrays(gl.TRIANGLES, 0, this.immediateMode.lineVertices.length);

  this._pixelsState._pixelsDirty = true;

  shader.unbindShader();
};

module.exports = p5.RendererGL;
<|endoftext|>


<commit_before>import { Box3, BufferAttribute } from 'three';
import { MeshBVH } from '../core/MeshBVH.js';

export class GenerateMeshBVHWorker {

	constructor() {

		this.running = false;
		this.worker = new Worker( new URL( './generateAsync.worker.js', import.meta.url ), { type: 'module' } );

	}

	generate( geometry, options = {} ) {

		if ( this.running ) {

			throw new Error( 'GenerateMeshBVHWorker: Already running job.' );

		}

		const { worker } = this;
		this.running = true;

		return new Promise( ( resolve, reject ) => {

			worker.onmessage = e => {

				this.running = false;
				const { data } = e;

				if ( data.error ) {

					reject( new Error( data.error ) );
					worker.onmessage = null;

				} else if ( data.serialized ) {

					const { serialized, position } = data;
					const bvh = MeshBVH.deserialize( serialized, geometry, { setIndex: false } );
					const boundsOptions = Object.assign( {

						setBoundingBox: true,

					}, options );

					// we need to replace the arrays because they're neutered entirely by the
					// webworker transfer.
					geometry.attributes.position.array = position;
					if ( geometry.index ) {

						geometry.index.array = serialized.index;

					} else {

						const newIndex = new BufferAttribute( serialized.index, 1, false );
						geometry.setIndex( newIndex );

					}

					if ( boundsOptions.setBoundingBox ) {

						geometry.boundingBox = bvh.getBoundingBox( new Box3() );

					}

					resolve( bvh );
					worker.onmessage = null;

				} else if ( options.onProgress ) {

					options.onProgress( data.progress );

				}

			};

			const index = geometry.index ? geometry.index.array : null;
			const position = geometry.attributes.position.array;

			if ( position.isInterleavedBufferAttribute || index && index.isInterleavedBufferAttribute ) {

				throw new Error( 'GenerateMeshBVHWorker: InterleavedBufferAttribute are not supported for the geometry attributes.' );

			}

			const transferrables = [ position ];
			if ( index ) {

				transferrables.push( index );

			}

			worker.postMessage( {

				index,
				position,
				options: {
					...options,
					onProgress: null,
					includedProgressCallback: Boolean( options.onProgress ),
					groups: [ ... geometry.groups ],
				},

			}, transferrables.map( arr => arr.buffer ) );

		} );

	}

	terminate() {

		this.worker.terminate();

	}

}
<commit_msg>Update GenerateMeshBVHWorker.js<commit_after>import { Box3, BufferAttribute } from 'three';
import { MeshBVH } from '../core/MeshBVH.js';

export class GenerateMeshBVHWorker {

	constructor() {

		this.running = false;
		this.worker = new Worker( new URL( './generateAsync.worker.js', import.meta.url ), { type: 'module' } );

	}

	generate( geometry, options = {} ) {

		if ( this.running ) {

			throw new Error( 'GenerateMeshBVHWorker: Already running job.' );

		}

		const { worker } = this;
		this.running = true;

		return new Promise( ( resolve, reject ) => {

			worker.onmessage = e => {

				this.running = false;
				const { data } = e;

				if ( data.error ) {

					reject( new Error( data.error ) );
					worker.onmessage = null;

				} else if ( data.serialized ) {

					const { serialized, position } = data;
					const bvh = MeshBVH.deserialize( serialized, geometry, { setIndex: false } );
					const boundsOptions = Object.assign( {

						setBoundingBox: true,

					}, options );

					// we need to replace the arrays because they're neutered entirely by the
					// webworker transfer.
					geometry.attributes.position.array = position;
					if ( geometry.index ) {

						geometry.index.array = serialized.index;

					} else {

						const newIndex = new BufferAttribute( serialized.index, 1, false );
						geometry.setIndex( newIndex );

					}

					if ( boundsOptions.setBoundingBox ) {

						geometry.boundingBox = bvh.getBoundingBox( new Box3() );

					}

					resolve( bvh );
					worker.onmessage = null;

				} else if ( options.onProgress ) {

					options.onProgress( data.progress );

				}

			};

			const index = geometry.index ? geometry.index.array : null;
			const position = geometry.attributes.position.array;

			if ( position.isInterleavedBufferAttribute || index && index.isInterleavedBufferAttribute ) {

				throw new Error( 'GenerateMeshBVHWorker: InterleavedBufferAttribute are not supported for the geometry attributes.' );

			}

			const transferrables = [ position ];
			if ( index ) {

				transferrables.push( index );

			}

			worker.postMessage( {

				index,
				position,
				options: {
					...options,
					onProgress: null,
					includedProgressCallback: Boolean( options.onProgress ),
					groups: [ ... geometry.groups ],
				},

			}, transferrables.map( arr => arr.buffer ) );

		} );

	}

	dispose() {

		this.worker.terminate();

	}

	terminate() {

		console.warn( 'GenerateMeshBVHWorker: "terminate" is deprecated. Use "dispose" instead.' );
		this.dispose();

	}

}
<|endoftext|>


<commit_before>import _ from 'intl'
import ActionRowButton from 'action-row-button'
import Icon from 'icon'
import isEmpty from 'lodash/isEmpty'
import Link from 'link'
import map from 'lodash/map'
import SortedTable from 'sorted-table'
import TabButton from 'tab-button'
import Tooltip from 'tooltip'
import Upgrade from 'xoa-upgrade'
import React, { Component } from 'react'
import { Card, CardHeader, CardBlock } from 'card'
import { confirm } from 'modal'
import { deleteMessage, deleteVdi, deleteVm, isSrWritable } from 'xo'
import { FormattedRelative, FormattedTime } from 'react-intl'
import { Container, Row, Col } from 'grid'
import {
  createGetObject,
  createGetObjectsOfType,
  createSelector
} from 'selectors'
import {
  connectStore,
  formatSize,
  noop
} from 'utils'

const SrColContainer = connectStore(() => ({
  container: createGetObject()
}))(({ container }) => <Link to={`pools/${container.id}`}>{container.name_label}</Link>)

const VdiColSr = connectStore(() => ({
  sr: createGetObject()
}))(({ sr }) => {sr.name_label})

const VmColContainer = connectStore(() => ({
  container: createGetObject()
}))(({ container }) => {container.name_label})

const AlarmColObject = connectStore(() => ({
  object: createGetObject()
}))(({ object }) => {object.name_label})

const AlarmColPool = connectStore(() => ({
  pool: createGetObject()
}))(({ pool }) => {pool.name_label})

const SR_COLUMNS = [
  {
    name: _('srName'),
    itemRenderer: sr => sr.name_label,
    sortCriteria: sr => sr.name_label
  },
  {
    name: _('srPool'),
    itemRenderer: sr => <SrColContainer id={sr.$container} />
  },
  {
    name: _('srFormat'),
    itemRenderer: sr => sr.SR_type,
    sortCriteria: sr => sr.SR_type
  },
  {
    name: _('srSize'),
    itemRenderer: sr => formatSize(sr.size),
    sortCriteria: sr => sr.size
  },
  {
    default: true,
    name: _('srUsage'),
    itemRenderer: sr => sr.size > 1 &&
      <Tooltip content={_('spaceLeftTooltip', {used: Math.round((sr.physical_usage / sr.size) * 100), free: formatSize(sr.size - sr.physical_usage)})}>
        <meter value={(sr.physical_usage / sr.size) * 100} min='0' max='100' optimum='40' low='80' high='90' />
      </Tooltip>,
    sortCriteria: sr => sr.physical_usage / sr.size,
    sortOrder: 'desc'
  }
]

const VDI_COLUMNS = [
  {
    name: _('snapshotDate'),
    itemRenderer: vdi => <FormattedTime value={vdi.snapshot_time * 1000} minute='numeric' hour='numeric' day='numeric' month='long' year='numeric' /> (<FormattedRelative value={vdi.snapshot_time * 1000} />),
    sortCriteria: vdi => vdi.snapshot_time,
    sortOrder: 'desc'
  },
  {
    name: _('vdiNameLabel'),
    itemRenderer: vdi => vdi.name_label,
    sortCriteria: vdi => vdi.name_label
  },
  {
    name: _('vdiNameDescription'),
    itemRenderer: vdi => vdi.name_description,
    sortCriteria: vdi => vdi.name_description
  },
  {
    name: _('vdiSize'),
    itemRenderer: vdi => formatSize(vdi.size),
    sortCriteria: vdi => vdi.size
  },
  {
    name: _('vdiSr'),
    itemRenderer: vdi => <VdiColSr id={vdi.$SR} />
  },
  {
    name: _('logAction'),
    itemRenderer: vdi => (
      <ActionRowButton
        btnStyle='danger'
        handler={deleteVdi}
        handlerParam={vdi}
        icon='delete'
      />
    )
  }
]

const VM_COLUMNS = [
  {
    name: _('snapshotDate'),
    itemRenderer: vm => <FormattedTime value={vm.snapshot_time * 1000} minute='numeric' hour='numeric' day='numeric' month='long' year='numeric' /> (<FormattedRelative value={vm.snapshot_time * 1000} />),
    sortCriteria: vm => vm.snapshot_time,
    sortOrder: 'desc'
  },
  {
    name: _('vmNameLabel'),
    itemRenderer: vm => vm.name_label,
    sortCriteria: vm => vm.name_label
  },
  {
    name: _('vmNameDescription'),
    itemRenderer: vm => vm.name_description,
    sortCriteria: vm => vm.name_description
  },
  {
    name: _('vmContainer'),
    itemRenderer: vm => <VmColContainer id={vm.$container} />
  },
  {
    name: _('logAction'),
    itemRenderer: vm => (
      <ActionRowButton
        btnStyle='danger'
        handler={deleteVm}
        handlerParam={vm}
        icon='delete'
      />
    )
  }
]

const ALARM_COLUMNS = [
  {
    name: _('alarmDate'),
    itemRenderer: message => (
      <FormattedTime value={message.time * 1000} minute='numeric' hour='numeric' day='numeric' month='long' year='numeric' /> (<FormattedRelative value={message.time * 1000} />)
    ),
    sortCriteria: message => message.time,
    sortOrder: 'desc'
  },
  {
    name: _('alarmContent'),
    itemRenderer: message => message.body,
    sortCriteria: message => message.body
  },
  {
    name: _('alarmObject'),
    itemRenderer: message => <AlarmColObject id={message.$object} />
  },
  {
    name: _('alarmPool'),
    itemRenderer: message => <AlarmColPool id={message.$pool} />
  },
  {
    name: _('logAction'),
    itemRenderer: message => (
      <ActionRowButton
        btnStyle='danger'
        handler={deleteMessage}
        handlerParam={message}
        icon='delete'
      />
    )
  }
]

@connectStore(() => {
  const getOrphanVdiSnapshots = createGetObjectsOfType('VDI-snapshot')
    .filter([ snapshot => !snapshot.$snapshot_of ])
    .sort()
  const getOrphanVmSnapshots = createGetObjectsOfType('VM-snapshot')
    .filter([ snapshot => !snapshot.$snapshot_of ])
    .sort()
  const getUserSrs = createGetObjectsOfType('SR')
    .filter([ isSrWritable ])
  const getVdiSrs = createGetObjectsOfType('SR')
    .pick(createSelector(
      getOrphanVdiSnapshots,
      snapshots => map(snapshots, '$SR')
    ))
  const getAlertMessages = createGetObjectsOfType('message')
    .filter([ message => message.name === 'ALARM' ])

  return {
    alertMessages: getAlertMessages,
    userSrs: getUserSrs,
    vdiOrphaned: getOrphanVdiSnapshots,
    vdiSr: getVdiSrs,
    vmOrphaned: getOrphanVmSnapshots
  }
})
export default class Health extends Component {
  _deleteOrphanedVdis = () => (
    confirm({
      title: _('removeAllOrphanedObject'),
      body:

{_('removeAllOrphanedModalWarning')}

{_('definitiveMessageModal')}

    }).then(
      () => map(this.props.vdiOrphaned, deleteVdi),
      noop
    )
  )
  _deleteAllLogs = () => (
    confirm({
      title: _('removeAllLogsModalTitle'),
      body:

{_('removeAllLogsModalWarning')}

{_('definitiveMessageModal')}

    }).then(
      () => map(this.props.alertMessages, deleteMessage),
      noop
    )
  )

  _getSrUrl = sr => `srs/${sr.id}`

  render () {
    return process.env.XOA_PLAN > 3
      ? <Container>
        <Row>
          <Col>
            <Card>
              <CardHeader>
                <Icon icon='disk' /> {_('srStatePanel')}
              </CardHeader>
              <CardBlock>
                {isEmpty(this.props.userSrs)
                  ?
{_('noSrs')}

                  : <Row>
                    <Col>
                      <SortedTable
                        collection={this.props.userSrs}
                        columns={SR_COLUMNS}
                        rowLink={this._getSrUrl}
                      />
                    </Col>
                  </Row>
                }
              </CardBlock>
            </Card>
          </Col>
        </Row>
        <Row>
          <Col>
            <Card>
              <CardHeader>
                <Icon icon='disk' /> {_('orphanedVdis')}
              </CardHeader>
              <CardBlock>
                {isEmpty(this.props.vdiOrphaned)
                  ?
{_('noOrphanedObject')}

                  :

                    <Row>
                      <Col className='text-xs-right'>
                        <TabButton
                          btnStyle='danger'
                          handler={this._deleteOrphanedVdis}
                          icon='delete'
                          labelId='removeAllOrphanedObject'
                        />
                      </Col>
                    </Row>
                    <Row>
                      <Col>
                        <SortedTable collection={this.props.vdiOrphaned} columns={VDI_COLUMNS} />
                      </Col>
                    </Row>

                }
              </CardBlock>
            </Card>
          </Col>
        </Row>
        <Row>
          <Col>
            <Card>
              <CardHeader>
                <Icon icon='vm' /> {_('orphanedVms')}
              </CardHeader>
              <CardBlock>
                {isEmpty(this.props.vmOrphaned)
                  ?
{_('noOrphanedObject')}

                  : <SortedTable collection={this.props.vmOrphaned} columns={VM_COLUMNS} />
                }
              </CardBlock>
            </Card>
          </Col>
        </Row>
        <Row>
          <Col>
            <Card>
              <CardHeader>
                <Icon icon='alarm' /> {_('alarmMessage')}
              </CardHeader>
              <CardBlock>
                {isEmpty(this.props.alertMessages)
                  ?
{_('noAlarms')}

                  :

                    <Row>
                      <Col className='text-xs-right'>
                        <TabButton
                          btnStyle='danger'
                          handler={this._deleteAllLogs}
                          icon='delete'
                          labelId='logRemoveAll'
                        />
                      </Col>
                    </Row>
                    <Row>
                      <Col>
                        <SortedTable collection={this.props.alertMessages} columns={ALARM_COLUMNS} />
                      </Col>
                    </Row>

                }
              </CardBlock>
            </Card>
          </Col>
        </Row>
      </Container>
      : <Container><Upgrade place='health' available={4} /></Container>
  }
}
<commit_msg>feat(health): add links to some objects (#1729)<commit_after>import _ from 'intl'
import ActionRowButton from 'action-row-button'
import Icon from 'icon'
import isEmpty from 'lodash/isEmpty'
import Link from 'link'
import map from 'lodash/map'
import SortedTable from 'sorted-table'
import TabButton from 'tab-button'
import Tooltip from 'tooltip'
import Upgrade from 'xoa-upgrade'
import React, { Component } from 'react'
import { Card, CardHeader, CardBlock } from 'card'
import { confirm } from 'modal'
import { deleteMessage, deleteVdi, deleteVm, isSrWritable } from 'xo'
import { FormattedRelative, FormattedTime } from 'react-intl'
import { Container, Row, Col } from 'grid'
import {
  createGetObject,
  createGetObjectsOfType,
  createSelector
} from 'selectors'
import {
  connectStore,
  formatSize,
  noop
} from 'utils'

const SrColContainer = connectStore(() => ({
  container: createGetObject()
}))(({ container }) => <Link to={`pools/${container.id}`}>{container.name_label}</Link>)

const VdiColSr = connectStore(() => ({
  sr: createGetObject()
}))(({ sr }) => <Link to={`srs/${sr.id}`}>{sr.name_label}</Link>)

const VmColContainer = connectStore(() => ({
  container: createGetObject()
}))(({ container }) => {container.name_label})

const AlarmColObject = connectStore(() => ({
  object: createGetObject()
}))(({ object }) => object.type === 'VM-controller' ? <Link to={`hosts/${object.$container}`}>{object.name_label}</Link> : <Link to={`vms/${object.id}`}>{object.name_label}</Link>)

const AlarmColPool = connectStore(() => ({
  pool: createGetObject()
}))(({ pool }) => <Link to={`pools/${pool.id}`}>{pool.name_label}</Link>)

const SR_COLUMNS = [
  {
    name: _('srName'),
    itemRenderer: sr => sr.name_label,
    sortCriteria: sr => sr.name_label
  },
  {
    name: _('srPool'),
    itemRenderer: sr => <SrColContainer id={sr.$container} />
  },
  {
    name: _('srFormat'),
    itemRenderer: sr => sr.SR_type,
    sortCriteria: sr => sr.SR_type
  },
  {
    name: _('srSize'),
    itemRenderer: sr => formatSize(sr.size),
    sortCriteria: sr => sr.size
  },
  {
    default: true,
    name: _('srUsage'),
    itemRenderer: sr => sr.size > 1 &&
      <Tooltip content={_('spaceLeftTooltip', {used: Math.round((sr.physical_usage / sr.size) * 100), free: formatSize(sr.size - sr.physical_usage)})}>
        <meter value={(sr.physical_usage / sr.size) * 100} min='0' max='100' optimum='40' low='80' high='90' />
      </Tooltip>,
    sortCriteria: sr => sr.physical_usage / sr.size,
    sortOrder: 'desc'
  }
]

const VDI_COLUMNS = [
  {
    name: _('snapshotDate'),
    itemRenderer: vdi => <FormattedTime value={vdi.snapshot_time * 1000} minute='numeric' hour='numeric' day='numeric' month='long' year='numeric' /> (<FormattedRelative value={vdi.snapshot_time * 1000} />),
    sortCriteria: vdi => vdi.snapshot_time,
    sortOrder: 'desc'
  },
  {
    name: _('vdiNameLabel'),
    itemRenderer: vdi => vdi.name_label,
    sortCriteria: vdi => vdi.name_label
  },
  {
    name: _('vdiNameDescription'),
    itemRenderer: vdi => vdi.name_description,
    sortCriteria: vdi => vdi.name_description
  },
  {
    name: _('vdiSize'),
    itemRenderer: vdi => formatSize(vdi.size),
    sortCriteria: vdi => vdi.size
  },
  {
    name: _('vdiSr'),
    itemRenderer: vdi => <VdiColSr id={vdi.$SR} />
  },
  {
    name: _('logAction'),
    itemRenderer: vdi => (
      <ActionRowButton
        btnStyle='danger'
        handler={deleteVdi}
        handlerParam={vdi}
        icon='delete'
      />
    )
  }
]

const VM_COLUMNS = [
  {
    name: _('snapshotDate'),
    itemRenderer: vm => <FormattedTime value={vm.snapshot_time * 1000} minute='numeric' hour='numeric' day='numeric' month='long' year='numeric' /> (<FormattedRelative value={vm.snapshot_time * 1000} />),
    sortCriteria: vm => vm.snapshot_time,
    sortOrder: 'desc'
  },
  {
    name: _('vmNameLabel'),
    itemRenderer: vm => vm.name_label,
    sortCriteria: vm => vm.name_label
  },
  {
    name: _('vmNameDescription'),
    itemRenderer: vm => vm.name_description,
    sortCriteria: vm => vm.name_description
  },
  {
    name: _('vmContainer'),
    itemRenderer: vm => <VmColContainer id={vm.$container} />
  },
  {
    name: _('logAction'),
    itemRenderer: vm => (
      <ActionRowButton
        btnStyle='danger'
        handler={deleteVm}
        handlerParam={vm}
        icon='delete'
      />
    )
  }
]

const ALARM_COLUMNS = [
  {
    name: _('alarmDate'),
    itemRenderer: message => (
      <FormattedTime value={message.time * 1000} minute='numeric' hour='numeric' day='numeric' month='long' year='numeric' /> (<FormattedRelative value={message.time * 1000} />)
    ),
    sortCriteria: message => message.time,
    sortOrder: 'desc'
  },
  {
    name: _('alarmContent'),
    itemRenderer: message => message.body,
    sortCriteria: message => message.body
  },
  {
    name: _('alarmObject'),
    itemRenderer: message => <AlarmColObject id={message.$object} />
  },
  {
    name: _('alarmPool'),
    itemRenderer: message => <AlarmColPool id={message.$pool} />
  },
  {
    name: _('logAction'),
    itemRenderer: message => (
      <ActionRowButton
        btnStyle='danger'
        handler={deleteMessage}
        handlerParam={message}
        icon='delete'
      />
    )
  }
]

@connectStore(() => {
  const getOrphanVdiSnapshots = createGetObjectsOfType('VDI-snapshot')
    .filter([ snapshot => !snapshot.$snapshot_of ])
    .sort()
  const getOrphanVmSnapshots = createGetObjectsOfType('VM-snapshot')
    .filter([ snapshot => !snapshot.$snapshot_of ])
    .sort()
  const getUserSrs = createGetObjectsOfType('SR')
    .filter([ isSrWritable ])
  const getVdiSrs = createGetObjectsOfType('SR')
    .pick(createSelector(
      getOrphanVdiSnapshots,
      snapshots => map(snapshots, '$SR')
    ))
  const getAlertMessages = createGetObjectsOfType('message')
    .filter([ message => message.name === 'ALARM' ])

  return {
    alertMessages: getAlertMessages,
    userSrs: getUserSrs,
    vdiOrphaned: getOrphanVdiSnapshots,
    vdiSr: getVdiSrs,
    vmOrphaned: getOrphanVmSnapshots
  }
})
export default class Health extends Component {
  _deleteOrphanedVdis = () => (
    confirm({
      title: _('removeAllOrphanedObject'),
      body:

{_('removeAllOrphanedModalWarning')}

{_('definitiveMessageModal')}

    }).then(
      () => map(this.props.vdiOrphaned, deleteVdi),
      noop
    )
  )
  _deleteAllLogs = () => (
    confirm({
      title: _('removeAllLogsModalTitle'),
      body:

{_('removeAllLogsModalWarning')}

{_('definitiveMessageModal')}

    }).then(
      () => map(this.props.alertMessages, deleteMessage),
      noop
    )
  )

  _getSrUrl = sr => `srs/${sr.id}`

  render () {
    return process.env.XOA_PLAN > 3
      ? <Container>
        <Row>
          <Col>
            <Card>
              <CardHeader>
                <Icon icon='disk' /> {_('srStatePanel')}
              </CardHeader>
              <CardBlock>
                {isEmpty(this.props.userSrs)
                  ?
{_('noSrs')}

                  : <Row>
                    <Col>
                      <SortedTable
                        collection={this.props.userSrs}
                        columns={SR_COLUMNS}
                        rowLink={this._getSrUrl}
                      />
                    </Col>
                  </Row>
                }
              </CardBlock>
            </Card>
          </Col>
        </Row>
        <Row>
          <Col>
            <Card>
              <CardHeader>
                <Icon icon='disk' /> {_('orphanedVdis')}
              </CardHeader>
              <CardBlock>
                {isEmpty(this.props.vdiOrphaned)
                  ?
{_('noOrphanedObject')}

                  :

                    <Row>
                      <Col className='text-xs-right'>
                        <TabButton
                          btnStyle='danger'
                          handler={this._deleteOrphanedVdis}
                          icon='delete'
                          labelId='removeAllOrphanedObject'
                        />
                      </Col>
                    </Row>
                    <Row>
                      <Col>
                        <SortedTable collection={this.props.vdiOrphaned} columns={VDI_COLUMNS} />
                      </Col>
                    </Row>

                }
              </CardBlock>
            </Card>
          </Col>
        </Row>
        <Row>
          <Col>
            <Card>
              <CardHeader>
                <Icon icon='vm' /> {_('orphanedVms')}
              </CardHeader>
              <CardBlock>
                {isEmpty(this.props.vmOrphaned)
                  ?
{_('noOrphanedObject')}

                  : <SortedTable collection={this.props.vmOrphaned} columns={VM_COLUMNS} />
                }
              </CardBlock>
            </Card>
          </Col>
        </Row>
        <Row>
          <Col>
            <Card>
              <CardHeader>
                <Icon icon='alarm' /> {_('alarmMessage')}
              </CardHeader>
              <CardBlock>
                {isEmpty(this.props.alertMessages)
                  ?
{_('noAlarms')}

                  :

                    <Row>
                      <Col className='text-xs-right'>
                        <TabButton
                          btnStyle='danger'
                          handler={this._deleteAllLogs}
                          icon='delete'
                          labelId='logRemoveAll'
                        />
                      </Col>
                    </Row>
                    <Row>
                      <Col>
                        <SortedTable collection={this.props.alertMessages} columns={ALARM_COLUMNS} />
                      </Col>
                    </Row>

                }
              </CardBlock>
            </Card>
          </Col>
        </Row>
      </Container>
      : <Container><Upgrade place='health' available={4} /></Container>
  }
}
<|endoftext|>