2 package Moose::Meta::Class;
9 use Carp qw( confess );
11 use List::Util qw( first );
12 use List::MoreUtils qw( any all uniq first_index );
13 use Scalar::Util 'blessed';
15 use Moose::Meta::Method::Overridden;
16 use Moose::Meta::Method::Augmented;
17 use Moose::Error::Default;
18 use Moose::Meta::Class::Immutable::Trait;
19 use Moose::Meta::Method::Constructor;
20 use Moose::Meta::Method::Destructor;
21 use Moose::Meta::Method::Meta;
23 use Class::MOP::MiniTrait;
25 use base 'Class::MOP::Class';
27 Class::MOP::MiniTrait::apply(__PACKAGE__, 'Moose::Meta::Object::Trait');
29 __PACKAGE__->meta->add_attribute('roles' => (
31 default => sub { [] },
32 Class::MOP::_definition_context(),
35 __PACKAGE__->meta->add_attribute('role_applications' => (
36 reader => '_get_role_applications',
37 default => sub { [] },
38 Class::MOP::_definition_context(),
41 __PACKAGE__->meta->add_attribute(
42 Class::MOP::Attribute->new('immutable_trait' => (
43 accessor => "immutable_trait",
44 default => 'Moose::Meta::Class::Immutable::Trait',
45 Class::MOP::_definition_context(),
49 __PACKAGE__->meta->add_attribute('constructor_class' => (
50 accessor => 'constructor_class',
51 default => 'Moose::Meta::Method::Constructor',
52 Class::MOP::_definition_context(),
55 __PACKAGE__->meta->add_attribute('destructor_class' => (
56 accessor => 'destructor_class',
57 default => 'Moose::Meta::Method::Destructor',
58 Class::MOP::_definition_context(),
61 __PACKAGE__->meta->add_attribute('error_class' => (
62 accessor => 'error_class',
63 default => 'Moose::Error::Default',
64 Class::MOP::_definition_context(),
70 unshift @args, 'package' if @args % 2;
72 my $package = delete $opts{package};
73 return Class::MOP::get_metaclass_by_name($package)
74 || $class->SUPER::initialize($package,
75 'attribute_metaclass' => 'Moose::Meta::Attribute',
76 'method_metaclass' => 'Moose::Meta::Method',
77 'instance_metaclass' => 'Moose::Meta::Instance',
86 unshift @args, 'package' if @args % 2 == 1;
89 (ref $options{roles} eq 'ARRAY')
90 || $class->throw_error("You must pass an ARRAY ref of roles", data => $options{roles})
91 if exists $options{roles};
93 my $package = delete $options{package};
94 my $roles = delete $options{roles};
96 my $new_meta = $class->SUPER::create($package, %options);
99 Moose::Util::apply_all_roles( $new_meta, @$roles );
105 sub _meta_method_class { 'Moose::Meta::Method::Meta' }
107 sub _anon_package_prefix { 'Moose::Meta::Class::__ANON__::SERIAL::' }
109 sub _anon_cache_key {
113 my $superclass_key = join('|',
114 map { $_->[0] } @{ Data::OptList::mkopt($options{superclasses} || []) }
117 my $roles = Data::OptList::mkopt(($options{roles} || []), {
119 val_test => sub { ref($_[0]) eq 'HASH' },
123 for my $role_spec (@$roles) {
124 my ($role, $params) = @$role_spec;
125 $params = { %$params } if $params;
127 my $key = blessed($role) ? $role->name : $role;
129 if ($params && %$params) {
130 my $alias = delete $params->{'-alias'}
131 || delete $params->{'alias'}
133 my $excludes = delete $params->{'-excludes'}
134 || delete $params->{'excludes'}
136 $excludes = [$excludes] unless ref($excludes) eq 'ARRAY';
139 warn "Roles with parameters cannot be cached. Consider "
140 . "applying the parameters before calling "
141 . "create_anon_class, or using 'weaken => 0' instead";
145 my $alias_key = join('%',
146 map { $_ => $alias->{$_} } sort keys %$alias
148 my $excludes_key = join('%',
151 $key .= '<' . join('+', 'a', $alias_key, 'e', $excludes_key) . '>';
154 push @role_keys, $key;
157 my $role_key = join('|', sort @role_keys);
159 # Makes something like Super::Class|Super::Class::2=Role|Role::1
160 return join('=', $superclass_key, $role_key);
167 my $meta = blessed $pkg ? $pkg : Class::MOP::class_of($pkg);
169 my %existing_classes;
171 %existing_classes = map { $_ => $meta->$_() } qw(
174 wrapped_method_metaclass
182 return $self->SUPER::reinitialize(
190 my ($self, $role) = @_;
191 (blessed($role) && $role->isa('Moose::Meta::Role'))
192 || $self->throw_error("Roles must be instances of Moose::Meta::Role", data => $role);
193 push @{$self->roles} => $role;
196 sub role_applications {
199 return @{$self->_get_role_applications};
202 sub add_role_application {
203 my ($self, $application) = @_;
204 (blessed($application) && $application->isa('Moose::Meta::Role::Application::ToClass'))
205 || $self->throw_error("Role applications must be instances of Moose::Meta::Role::Application::ToClass", data => $application);
206 push @{$self->_get_role_applications} => $application;
209 sub calculate_all_roles {
212 grep { !$seen{$_->name}++ } map { $_->calculate_all_roles } @{ $self->roles };
215 sub calculate_all_roles_with_inheritance {
218 grep { !$seen{$_->name}++ }
219 map { Class::MOP::class_of($_)->can('calculate_all_roles')
220 ? Class::MOP::class_of($_)->calculate_all_roles
222 $self->linearized_isa;
226 my ($self, $role_name) = @_;
229 || $self->throw_error("You must supply a role name to look for");
231 foreach my $class ($self->class_precedence_list) {
232 my $meta = Class::MOP::class_of($class);
233 # when a Moose metaclass is itself extended with a role,
234 # this check needs to be done since some items in the
235 # class_precedence_list might in fact be Class::MOP
237 next unless $meta && $meta->can('roles');
238 foreach my $role (@{$meta->roles}) {
239 return 1 if $role->does_role($role_name);
246 my ($self, $role_name) = @_;
249 || $self->throw_error("You must supply a role name to look for");
251 foreach my $class ($self->class_precedence_list) {
252 my $meta = Class::MOP::class_of($class);
253 # when a Moose metaclass is itself extended with a role,
254 # this check needs to be done since some items in the
255 # class_precedence_list might in fact be Class::MOP
257 next unless $meta && $meta->can('roles');
258 foreach my $role (@{$meta->roles}) {
259 return 1 if $role->excludes_role($role_name);
267 my $params = @_ == 1 ? $_[0] : {@_};
268 my $object = $self->SUPER::new_object($params);
270 foreach my $attr ( $self->get_all_attributes() ) {
272 next unless $attr->can('has_trigger') && $attr->has_trigger;
274 my $init_arg = $attr->init_arg;
276 next unless defined $init_arg;
278 next unless exists $params->{$init_arg};
284 ? $attr->get_read_method_ref->($object)
285 : $params->{$init_arg}
290 $object->BUILDALL($params) if $object->can('BUILDALL');
295 sub _generate_fallback_constructor {
298 return $class . '->Moose::Object::new(@_)'
303 my ($params, $class) = @_;
305 'my ' . $params . ' = ',
306 $self->_inline_BUILDARGS($class, '@_'),
311 sub _inline_BUILDARGS {
313 my ($class, $args) = @_;
315 my $buildargs = $self->find_method_by_name("BUILDARGS");
318 && (!$buildargs or $buildargs->body == \&Moose::Object::BUILDARGS)) {
322 'if (scalar @_ == 1) {',
323 'if (!defined($_[0]) || ref($_[0]) ne \'HASH\') {',
324 $self->_inline_throw_error(
325 '"Single parameters to new() must be a HASH ref"',
329 '$params = { %{ $_[0] } };',
333 '"The new() method for ' . $class . ' expects a '
334 . 'hash reference or a key/value list. You passed an '
335 . 'odd number of arguments"',
337 '$params = {@_, undef};',
347 return $class . '->BUILDARGS(' . $args . ')';
351 sub _inline_slot_initializer {
353 my ($attr, $idx) = @_;
357 $self->_inline_check_required_attr($attr),
358 $self->SUPER::_inline_slot_initializer(@_),
362 sub _inline_check_required_attr {
366 return unless defined $attr->init_arg;
367 return unless $attr->can('is_required') && $attr->is_required;
368 return if $attr->has_default || $attr->has_builder;
371 'if (!exists $params->{\'' . $attr->init_arg . '\'}) {',
372 $self->_inline_throw_error(
373 '"Attribute (' . quotemeta($attr->name) . ') is required"'
379 # XXX: these two are duplicated from cmop, because we have to pass the tc stuff
380 # through to _inline_set_value - this should probably be fixed, but i'm not
381 # quite sure how. -doy
382 sub _inline_init_attr_from_constructor {
384 my ($attr, $idx) = @_;
386 my @initial_value = $attr->_inline_set_value(
388 '$params->{\'' . $attr->init_arg . '\'}',
389 '$type_constraint_bodies[' . $idx . ']',
390 '$type_coercions[' . $idx . ']',
391 '$type_constraint_messages[' . $idx . ']',
395 push @initial_value, (
396 '$attrs->[' . $idx . ']->set_initial_value(',
398 $attr->_inline_instance_get('$instance'),
400 ) if $attr->has_initializer;
402 return @initial_value;
405 sub _inline_init_attr_from_default {
407 my ($attr, $idx) = @_;
409 return if $attr->can('is_lazy') && $attr->is_lazy;
410 my $default = $self->_inline_default_value($attr, $idx);
411 return unless $default;
413 my @initial_value = (
414 'my $default = ' . $default . ';',
415 $attr->_inline_set_value(
418 '$type_constraint_bodies[' . $idx . ']',
419 '$type_coercions[' . $idx . ']',
420 '$type_constraint_messages[' . $idx . ']',
425 push @initial_value, (
426 '$attrs->[' . $idx . ']->set_initial_value(',
428 $attr->_inline_instance_get('$instance'),
430 ) if $attr->has_initializer;
432 return @initial_value;
435 sub _inline_extra_init {
438 $self->_inline_triggers,
439 $self->_inline_BUILDALL,
443 sub _inline_triggers {
447 my @attrs = sort { $a->name cmp $b->name } $self->get_all_attributes;
448 for my $i (0 .. $#attrs) {
449 my $attr = $attrs[$i];
451 next unless $attr->can('has_trigger') && $attr->has_trigger;
453 my $init_arg = $attr->init_arg;
454 next unless defined $init_arg;
457 'if (exists $params->{\'' . $init_arg . '\'}) {',
458 '$triggers->[' . $i . ']->(',
460 $attr->_inline_instance_get('$instance') . ',',
465 return @trigger_calls;
468 sub _inline_BUILDALL {
471 my @methods = reverse $self->find_all_methods_by_name('BUILD');
474 foreach my $method (@methods) {
476 '$instance->' . $method->{class} . '::BUILD($params);';
482 sub _eval_environment {
485 my @attrs = sort { $a->name cmp $b->name } $self->get_all_attributes;
488 map { $_->can('has_trigger') && $_->has_trigger ? $_->trigger : undef }
492 # We need to check if the attribute ->can('type_constraint')
493 # since we may be trying to immutabilize a Moose meta class,
494 # which in turn has attributes which are Class::MOP::Attribute
495 # objects, rather than Moose::Meta::Attribute. And
496 # Class::MOP::Attribute attributes have no type constraints.
497 # However we need to make sure we leave an undef value there
498 # because the inlined code is using the index of the attributes
499 # to determine where to find the type constraint
501 my @type_constraints = map {
502 $_->can('type_constraint') ? $_->type_constraint : undef
505 my @type_constraint_bodies = map {
506 defined $_ ? $_->_compiled_type_constraint : undef;
509 my @type_coercions = map {
510 defined $_ && $_->has_coercion
511 ? $_->coercion->_compiled_type_coercion
515 my @type_constraint_messages = map {
517 ? ($_->has_message ? $_->message : $_->_default_message)
522 %{ $self->SUPER::_eval_environment },
523 ((any { defined && $_->has_initializer } @attrs)
524 ? ('$attrs' => \[@attrs])
526 '$triggers' => \$triggers,
527 '@type_coercions' => \@type_coercions,
528 '@type_constraint_bodies' => \@type_constraint_bodies,
529 '@type_constraint_messages' => \@type_constraint_messages,
530 ( map { defined($_) ? %{ $_->inline_environment } : () }
532 # pretty sure this is only going to be closed over if you use a custom
533 # error class at this point, but we should still get rid of this
541 my $supers = Data::OptList::mkopt(\@_);
542 foreach my $super (@{ $supers }) {
543 my ($name, $opts) = @{ $super };
544 Class::MOP::load_class($name, $opts);
545 my $meta = Class::MOP::class_of($name);
546 $self->throw_error("You cannot inherit from a Moose Role ($name)")
547 if $meta && $meta->isa('Moose::Meta::Role')
549 return $self->SUPER::superclasses(map { $_->[0] } @{ $supers });
552 ### ---------------------------------------------
557 (blessed $_[0] && $_[0]->isa('Class::MOP::Attribute')
559 : $self->_process_attribute(@_));
560 $self->SUPER::add_attribute($attr);
561 # it may be a Class::MOP::Attribute, theoretically, which doesn't have
562 # 'bare' and doesn't implement this method
563 if ($attr->can('_check_associated_methods')) {
564 $attr->_check_associated_methods;
569 sub add_override_method_modifier {
570 my ($self, $name, $method, $_super_package) = @_;
572 (!$self->has_method($name))
573 || $self->throw_error("Cannot add an override method if a local method is already present");
575 $self->add_method($name => Moose::Meta::Method::Overridden->new(
578 package => $_super_package, # need this for roles
583 sub add_augment_method_modifier {
584 my ($self, $name, $method) = @_;
585 (!$self->has_method($name))
586 || $self->throw_error("Cannot add an augment method if a local method is already present");
588 $self->add_method($name => Moose::Meta::Method::Augmented->new(
595 ## Private Utility methods ...
597 sub _find_next_method_by_name_which_is_not_overridden {
598 my ($self, $name) = @_;
599 foreach my $method ($self->find_all_methods_by_name($name)) {
600 return $method->{code}
601 if blessed($method->{code}) && !$method->{code}->isa('Moose::Meta::Method::Overridden');
606 ## Metaclass compatibility
608 sub _base_metaclasses {
610 my %metaclasses = $self->SUPER::_base_metaclasses;
611 for my $class (keys %metaclasses) {
612 $metaclasses{$class} =~ s/^Class::MOP/Moose::Meta/;
616 error_class => 'Moose::Error::Default',
620 sub _fix_class_metaclass_incompatibility {
622 my ($super_meta) = @_;
624 $self->SUPER::_fix_class_metaclass_incompatibility(@_);
626 if ($self->_class_metaclass_can_be_made_compatible($super_meta)) {
628 || confess "Can't fix metaclass incompatibility for "
630 . " because it is not pristine.";
631 my $super_meta_name = $super_meta->_real_ref_name;
632 my $class_meta_subclass_meta_name = Moose::Util::_reconcile_roles_for_metaclass(blessed($self), $super_meta_name);
633 my $new_self = $class_meta_subclass_meta_name->reinitialize(
637 $self->_replace_self( $new_self, $class_meta_subclass_meta_name );
641 sub _fix_single_metaclass_incompatibility {
643 my ($metaclass_type, $super_meta) = @_;
645 $self->SUPER::_fix_single_metaclass_incompatibility(@_);
647 if ($self->_single_metaclass_can_be_made_compatible($super_meta, $metaclass_type)) {
649 || confess "Can't fix metaclass incompatibility for "
651 . " because it is not pristine.";
652 my $super_meta_name = $super_meta->_real_ref_name;
653 my $class_specific_meta_subclass_meta_name = Moose::Util::_reconcile_roles_for_metaclass($self->$metaclass_type, $super_meta->$metaclass_type);
654 my $new_self = $super_meta->reinitialize(
656 $metaclass_type => $class_specific_meta_subclass_meta_name,
659 $self->_replace_self( $new_self, $super_meta_name );
665 my ( $new_self, $new_class) = @_;
668 bless $self, $new_class;
670 # We need to replace the cached metaclass instance or else when it goes
671 # out of scope Class::MOP::Class destroy's the namespace for the
672 # metaclass's class, causing much havoc.
673 my $weaken = Class::MOP::metaclass_is_weak( $self->name );
674 Class::MOP::store_metaclass_by_name( $self->name, $self );
675 Class::MOP::weaken_metaclass( $self->name ) if $weaken;
678 sub _process_attribute {
679 my ( $self, $name, @args ) = @_;
681 @args = %{$args[0]} if scalar @args == 1 && ref($args[0]) eq 'HASH';
683 if (($name || '') =~ /^\+(.*)/) {
684 return $self->_process_inherited_attribute($1, @args);
687 return $self->_process_new_attribute($name, @args);
691 sub _process_new_attribute {
692 my ( $self, $name, @args ) = @_;
694 $self->attribute_metaclass->interpolate_class_and_new($name, @args);
697 sub _process_inherited_attribute {
698 my ($self, $attr_name, %options) = @_;
699 my $inherited_attr = $self->find_attribute_by_name($attr_name);
700 (defined $inherited_attr)
701 || $self->throw_error("Could not find an attribute by the name of '$attr_name' to inherit from in ${\$self->name}", data => $attr_name);
702 if ($inherited_attr->isa('Moose::Meta::Attribute')) {
703 return $inherited_attr->clone_and_inherit_options(%options);
707 # kind of a kludge to handle Class::MOP::Attributes
708 return $inherited_attr->Moose::Meta::Attribute::clone_and_inherit_options(%options);
712 # reinitialization support
714 sub _restore_metaobjects_from {
718 $self->SUPER::_restore_metaobjects_from($old_meta);
720 for my $role ( @{ $old_meta->roles } ) {
721 $self->add_role($role);
724 for my $application ( @{ $old_meta->_get_role_applications } ) {
725 $application->class($self);
726 $self->add_role_application ($application);
732 sub _immutable_options {
733 my ( $self, @args ) = @_;
735 $self->SUPER::_immutable_options(
736 inline_destructor => 1,
738 # Moose always does this when an attribute is created
739 inline_accessors => 0,
745 ## -------------------------------------------------
750 my ( $self, @args ) = @_;
751 local $error_level = ($error_level || 0) + 1;
752 $self->raise_error($self->create_error(@args));
755 sub _inline_throw_error {
756 my ( $self, @args ) = @_;
757 $self->_inline_raise_error($self->_inline_create_error(@args));
761 my ( $self, @args ) = @_;
765 sub _inline_raise_error {
766 my ( $self, $message ) = @_;
768 return 'die ' . $message;
772 my ( $self, @args ) = @_;
776 local $error_level = ($error_level || 0 ) + 1;
778 if ( @args % 2 == 1 ) {
779 unshift @args, "message";
782 my %args = ( metaclass => $self, last_error => $@, @args );
784 $args{depth} += $error_level;
786 my $class = ref $self ? $self->error_class : "Moose::Error::Default";
788 Class::MOP::load_class($class);
791 Carp::caller_info($args{depth}),
796 sub _inline_create_error {
797 my ( $self, $msg, $args ) = @_;
798 # XXX ignore $args for now, nothing currently uses it anyway
808 my $class = ref $self ? $self->error_class : "Moose::Error::Default";
810 Class::MOP::load_class($class);
812 # don't check inheritance here - the intention is that the class needs
813 # to provide a non-inherited inlining method, because falling back to
814 # the default inlining method is most likely going to be wrong
815 # yes, this is a huge hack, but so is the entire error system, so.
816 return '$meta->create_error(' . $msg . ', ' . $args . ');'
817 unless $class->meta->has_method('_inline_new');
820 # XXX ignore this for now too
821 # Carp::caller_info($args{depth}),
828 # ABSTRACT: The Moose metaclass
836 This class is a subclass of L<Class::MOP::Class> that provides
837 additional Moose-specific functionality.
839 To really understand this class, you will need to start with the
840 L<Class::MOP::Class> documentation. This class can be understood as a
841 set of additional features on top of the basic feature provided by
846 C<Moose::Meta::Class> is a subclass of L<Class::MOP::Class>.
852 =item B<< Moose::Meta::Class->initialize($package_name, %options) >>
854 This overrides the parent's method in order to provide its own
855 defaults for the C<attribute_metaclass>, C<instance_metaclass>, and
856 C<method_metaclass> options.
858 These all default to the appropriate Moose class.
860 =item B<< Moose::Meta::Class->create($package_name, %options) >>
862 This overrides the parent's method in order to accept a C<roles>
863 option. This should be an array reference containing roles
864 that the class does, each optionally followed by a hashref of options
865 (C<-excludes> and C<-alias>).
867 my $metaclass = Moose::Meta::Class->create( 'New::Class', roles => [...] );
869 =item B<< Moose::Meta::Class->create_anon_class >>
871 This overrides the parent's method to accept a C<roles> option, just
874 It also accepts a C<cache> option. If this is true, then the anonymous
875 class will be cached based on its superclasses and roles. If an
876 existing anonymous class in the cache has the same superclasses and
877 roles, it will be reused.
879 my $metaclass = Moose::Meta::Class->create_anon_class(
880 superclasses => ['Foo'],
881 roles => [qw/Some Roles Go Here/],
885 Each entry in both the C<superclasses> and the C<roles> option can be
886 followed by a hash reference with arguments. The C<superclasses>
887 option can be supplied with a L<-version|Class::MOP/Class Loading
888 Options> option that ensures the loaded superclass satisfies the
889 required version. The C<role> option also takes the C<-version> as an
890 argument, but the option hash reference can also contain any other
891 role relevant values like exclusions or parameterized role arguments.
893 =item B<< $metaclass->make_immutable(%options) >>
895 This overrides the parent's method to add a few options. Specifically,
896 it uses the Moose-specific constructor and destructor classes, and
897 enables inlining the destructor.
899 Since Moose always inlines attributes, it sets the C<inline_accessors> option
902 =item B<< $metaclass->new_object(%params) >>
904 This overrides the parent's method in order to add support for
907 =item B<< $metaclass->superclasses(@superclasses) >>
909 This is the accessor allowing you to read or change the parents of
912 Each superclass can be followed by a hash reference containing a
913 L<-version|Class::MOP/Class Loading Options> value. If the version
914 requirement is not satisfied an error will be thrown.
916 =item B<< $metaclass->add_override_method_modifier($name, $sub) >>
918 This adds an C<override> method modifier to the package.
920 =item B<< $metaclass->add_augment_method_modifier($name, $sub) >>
922 This adds an C<augment> method modifier to the package.
924 =item B<< $metaclass->calculate_all_roles >>
926 This will return a unique array of C<Moose::Meta::Role> instances
927 which are attached to this class.
929 =item B<< $metaclass->calculate_all_roles_with_inheritance >>
931 This will return a unique array of C<Moose::Meta::Role> instances
932 which are attached to this class, and each of this class's ancestors.
934 =item B<< $metaclass->add_role($role) >>
936 This takes a L<Moose::Meta::Role> object, and adds it to the class's
937 list of roles. This I<does not> actually apply the role to the class.
939 =item B<< $metaclass->role_applications >>
941 Returns a list of L<Moose::Meta::Role::Application::ToClass>
942 objects, which contain the arguments to role application.
944 =item B<< $metaclass->add_role_application($application) >>
946 This takes a L<Moose::Meta::Role::Application::ToClass> object, and
947 adds it to the class's list of role applications. This I<does not>
948 actually apply any role to the class; it is only for tracking role
951 =item B<< $metaclass->does_role($role) >>
953 This returns a boolean indicating whether or not the class does the specified
954 role. The role provided can be either a role name or a L<Moose::Meta::Role>
955 object. This tests both the class and its parents.
957 =item B<< $metaclass->excludes_role($role_name) >>
959 A class excludes a role if it has already composed a role which
960 excludes the named role. This tests both the class and its parents.
962 =item B<< $metaclass->add_attribute($attr_name, %params|$params) >>
964 This overrides the parent's method in order to allow the parameters to
965 be provided as a hash reference.
967 =item B<< $metaclass->constructor_class($class_name) >>
969 =item B<< $metaclass->destructor_class($class_name) >>
971 These are the names of classes used when making a class immutable. These
972 default to L<Moose::Meta::Method::Constructor> and
973 L<Moose::Meta::Method::Destructor> respectively. These accessors are
974 read-write, so you can use them to change the class name.
976 =item B<< $metaclass->error_class($class_name) >>
978 The name of the class used to throw errors. This defaults to
979 L<Moose::Error::Default>, which generates an error with a stacktrace
980 just like C<Carp::confess>.
982 =item B<< $metaclass->throw_error($message, %extra) >>
984 Throws the error created by C<create_error> using C<raise_error>
990 See L<Moose/BUGS> for details on reporting bugs.