Activities of "AI-Bot"

  • In ABP Angular v10, abp-dynamic-layout still works, but it depends on ABP’s layout system being properly provided/bootstrapped and on routes being compatible with the post-v9 Angular routing approach (standalone + updated route factories).
  • The most common upgrade pitfall that results in an “empty dynamic layout” (only containers, no rendered layout + no routed content) is that the app is effectively running with incomplete ABP Angular provider setup (theme/layout providers not registered the “v10 way”), or the routes were migrated in a way that no longer matches what ABP expects for layout resolution.

Do the following (these are the verified migration areas between v9 and v10 that affect Angular routing/layout behavior):

  1. Align routing to the newer ABP Angular approach (standalone routing factories) If you still have older lazy-loading patterns (module-based forLazy()), migrate them to the new pattern used by ABP packages, i.e. createRoutes(...).

Example (conceptual):

{
  path: 'identity',
  loadChildren: () => import('@volo/abp.ng.identity').then(m => m.createRoutes()),
}

If your own feature modules still use “old style” lazy loading, ABP layout resolution can silently fail to match the route tree as expected in newer Angular/ABP setups.

  1. Ensure your app is using the v10 standalone/provider-based bootstrapping correctly With Angular 19+ standalone defaults, ABP’s Angular packages are designed to be configured via ApplicationConfig providers (e.g. app.config.ts). Make sure you didn’t miss the ABP providers responsible for theme/layout.

Practically:

  • Ensure you are calling the ABP theme shared + LeptonX theme providers as required by your template.
  • Ensure the route provider setup is present (ABP route provider).

This is especially important if you upgraded “in place” instead of regenerating a v10 Angular UI and diffing the bootstrap/config.

  1. Verify you actually migrated to the newer ABP Angular package structure expectations (standalone support) ABP introduced official support for Angular standalone structure around v9.3, and this affects how routing is shaped and how components/modules are wired. Even if you keep module-based structure, your routing and app initialization should be compatible.

If you want a concrete checklist for what changed in ABP Angular around routing/standalone, use these (verified) references and compare your project with the template produced by ABP 10.x:

Sources (validated)

  • https://abp.io/docs/10.0/release-info/migration-guides/abp-10-0
  • https://abp.io/docs/latest/release-info/migration-guides/abp-9-3
  • https://abp.io/community/articles/zzi2rr2z

This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • Your restore behavior (only that package/version returning 403 while the rest restore fine) matches module entitlement restriction on the commercial feed, not a local NuGet/auth/cache issue.
  • Volo.Abp.OperationRateLimiting is a Pro module and it requires ABP Team (or higher) to use/download. This is explicitly stated in ABP’s Operation Rate Limiting documentation, and it also notes that the module is used by Account (Pro) modules and can come pre-installed in the latest startup templates.

So for your two concrete questions:

  1. Does your current license tier include Volo.Abp.OperationRateLimiting?
    I can’t see your license tier from here, but the rule is definitive: only Team (or higher) includes it. If you’re on a lower tier, you will get 403 exactly like this when restoring Volo.Abp.OperationRateLimiting.Domain (10.3.0 included).

  2. Why does the default app template pull it?
    Because in v10.3 the module is used internally by Account (Pro) modules and is also described as pre-installed in the latest startup templates. If your template selection (e.g., Social Login / OpenIddictAdmin / other Pro account-related features) caused Account Pro packages/modules to be included, they can bring OperationRateLimiting as a dependency—then restore fails on tiers that don’t include it. Practically, this means the generated solution can become “unbuildable out of the box” unless the generator filters Pro-only modules based on license, which appears to be the gap you’re hitting.

Workarounds you can apply immediately (to make the solution build without upgrading):

  • Remove the Pro dependency that pulls OperationRateLimiting:
    • In your *.csproj files, remove any PackageReference to Volo.Abp.OperationRateLimiting.* (if present).
    • Also check your DependsOn(...) chain in your POC.ApiSports*.Module classes and remove any module dependency related to OperationRateLimiting (directly) and/or the specific Pro module that introduced it (often via Account Pro features).
  • Regenerate the solution without the feature set that brings Account Pro dependencies (e.g., avoid selecting options that require Pro modules), if possible for the POC.

If you want this treated as a template/generation issue (so ABP Studio/CLI warns or excludes it based on license), please report it through the official channel so the team can reproduce it against your exact template options and license entitlement:

  • https://abp.io/contact

(Links validated.)

Sources:

  • https://abp.io/docs/latest/modules/operation-rate-limiting
  • https://abp.io/pricing
  • https://abp.io/contact

This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • Volo.Abp.OperationRateLimiting.Domain is a commercial (Pro) module, and it is not available for every commercial license tier. If your license doesn’t include that module, the ABP private feed returns 403 (Forbidden) for that specific package/version, while other Volo.Abp.* packages may still restore successfully (because they are included in your tier).
  • For v10.3.x, this module specifically requires ABP Team (or higher). So in your case, the restore error is consistent with a license/module entitlement restriction, not a corrupted project or NuGet client problem.

What to do (pick one):

  1. If you want to use Operation Rate Limiting

    • Upgrade to a license tier that includes it (Team or higher).
    • Then restore again (the 403 should disappear).
  2. If you don’t need Operation Rate Limiting in this POC

    • Remove the dependency chain that brings it in. In your template, it’s commonly pulled indirectly by Account Pro / related pro modules (and possibly by default template wiring).
    • Practical steps:
      • Search in your solution for any package references like:
        • Volo.Abp.OperationRateLimiting.*
      • Remove those package references and/or remove the module dependency from your DependsOn(...) chain in your *.WebModule / *.HttpApiHostModule (where it gets brought in).
  3. If you believe you should have access but still get 403

    • Re-authenticate your ABP credentials/token and try again (sometimes the local token is stale on a new machine/agent):
abp logout
     abp login
     dotnet nuget locals all --clear
     dotnet restore

Sources:

  • https://abp.io/docs/latest/modules/operation-rate-limiting
  • https://abp.io/pricing
  • https://abp.io/contact

This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • In Mapperly, the equivalent of an AutoMapper ITypeConverter<TSource, TDestination> is to add a custom mapping method (a normal C# method) that Mapperly will use when it needs to map between those types.

1) Solution

Create a Mapperly mapper (ABP style) and add a method which maps double? → CurrencyObject[]?:

using Riok.Mapperly.Abstractions;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Mapperly;

public class CurrencyObject
{
    public double CurrencyValue { get; set; }
    public string? Currency { get; set; }
}

[Mapper]
public partial class SurveyCurrencyMapper
    : MapperBase<double?, CurrencyObject[]?>, ITransientDependency
{
    // ABP expects these overrides for ObjectMapper.Map<double?, CurrencyObject[]?>()
    public override partial CurrencyObject[]? Map(double? source);
    public override partial void Map(double? source, CurrencyObject[]? destination);

    // Mapperly custom conversion (this replaces AutoMapper ITypeConverter)
    private static CurrencyObject[]? MapToCurrencyObjectArray(double? source)
        => source.HasValue
            ? new[]
              {
                  new CurrencyObject
                  {
                      CurrencyValue = source.Value,
                      Currency = "USD"
                  }
              }
            : null;
}

How it works:

  • When Mapperly sees it must map double? to CurrencyObject[]?, it can use your custom method.
  • In ABP, inheriting from MapperBase<TSource, TDestination> + ITransientDependency allows ObjectMapper.Map<,> to resolve it via the Mapperly provider.

If you don’t need ObjectMapper.Map<double?, CurrencyObject[]?>() directly and only need it as part of a larger mapping (e.g., UploadedSurveyData -> SurveyData), you can also just put the MapToCurrencyObjectArray(double?) method inside that mapper class; Mapperly will reuse it for that conversion.

2) Sources

  • https://abp.io/docs/latest/framework/infrastructure/object-to-object-mapping
  • https://abp.io/docs/10.2/release-info/migration-guides/AutoMapper-To-Mapperly
  • https://mapperly.riok.app/docs/intro/

This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • Mapperly (and ABP’s Mapperly integration) is compile-time / static mapping. Your AutoMapper extension is runtime / reflection-based (“ignore everything not in this string list”). So if you truly need a List<string> decided at runtime, you will not get an equivalent without either:

    1. doing a runtime reflection-based copy yourself (outside Mapperly), or
    2. redesigning the API to avoid “string list of fields”.
  • If you have 100+ properties and this pattern is used in many mappings, the two scalable options are:

1) Keep Mapperly for normal mapping, but implement a reusable runtime “patch” helper (reflection) once

This keeps your “only map these fields” behavior without hardcoding 100 property names and works for all DTO/entity pairs.

using System.Reflection;

public static class PatchMappingExtensions
{
    /// <summary>
    /// Copies values from <paramref name="source"/> to <paramref name="destination"/>
    /// only for destination properties whose names are in <paramref name="requiredProperties"/>.
    /// </summary>
    public static void PatchByPropertyList<TSource, TDestination>(
        TSource source,
        TDestination destination,
        IReadOnlyCollection<string> requiredProperties)
        where TDestination : class
    {
        if (requiredProperties == null || requiredProperties.Count == 0)
        {
            return; // same semantics as your current extension
        }

        var srcType = typeof(TSource);
        var destType = typeof(TDestination);

        // Build lookup for source properties by name (public instance)
        var srcProps = srcType
            .GetProperties(BindingFlags.Instance | BindingFlags.Public)
            .Where(p => p.CanRead)
            .ToDictionary(p => p.Name, p => p);

        foreach (var destProp in destType.GetProperties(BindingFlags.Instance | BindingFlags.Public))
        {
            if (!destProp.CanWrite)
            {
                continue;
            }

            if (!requiredProperties.Contains(destProp.Name))
            {
                continue;
            }

            if (!srcProps.TryGetValue(destProp.Name, out var srcProp))
            {
                continue;
            }

            // Only assign when compatible (basic safety)
            if (!destProp.PropertyType.IsAssignableFrom(srcProp.PropertyType))
            {
                continue;
            }

            var value = srcProp.GetValue(source);
            destProp.SetValue(destination, value);
        }
    }
}

Usage with Mapperly in ABP:

  • Use Mapperly for the normal case (full mapping).
  • Use PatchByPropertyList for this special dynamic-field-list case:
// Full map (generated, fast)
mapper.Map(uploaded, surveyData);

// Dynamic partial update (runtime)
PatchMappingExtensions.PatchByPropertyList(uploaded, surveyData, requiredProperties);

This is essentially what AutoMapper was doing for you (runtime reflection), but now it’s explicit, reusable, and you write it once.

2) Change the contract: use a “patch DTO” (only contains allowed fields) instead of a string list

This is the most Mapperly-friendly approach: define a DTO that contains only the fields that can be updated, and map that DTO to the entity. No reflection, no list of strings, no 100-case switch.

Example idea:

  • UploadedSurveyDataPatchDto includes only patchable properties (maybe nullable)
  • mapper maps patch DTO → entity (to existing)
  • you decide which fields are present by model binding / JSON payload rather than a separate list.

This approach aligns with Mapperly’s compile-time nature and is typically cleaner long-term, but it requires changing your API shape.


Validated references:

  • https://abp.io/docs/latest/framework/infrastructure/object-to-object-mapping
  • https://abp.io/docs/10.2/release-info/migration-guides/AutoMapper-To-Mapperly
  • https://mapperly.riok.app/docs/intro/

This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • You can’t migrate this IgnoreNotInListMembers(List<string>) concept 1:1 to Mapperly.
    AutoMapper can decide at runtime which destination members to ignore using reflection. Mapperly generates mapping code at compile time, so “ignore members by a runtime string list” is not something it can express via attributes.

  • Recommended migration approach (Mapperly + manual “patch” mapping):
    Treat this as a partial update (“patch”) use-case and apply the requiredProperties list yourself after (or instead of) mapping.

    Example:

using Riok.Mapperly.Abstractions;

  public class UploadedSurveyData
  {
      // source props...
  }

  public class SurveyData
  {
      // destination props...
      public string? Q1 { get; set; }
      public string? Q2 { get; set; }
      public string? Q3 { get; set; }
  }

  [Mapper]
  public partial class SurveyDataMapper
  {
      // Normal full mapping (Mapperly generates this)
      public partial SurveyData Map(UploadedSurveyData source);

      // Update existing destination (Mapperly generates this)
      public partial void Map(UploadedSurveyData source, SurveyData destination);
  }

  public static class SurveyDataPatchMapping
  {
      // Runtime selective update (replacement for IgnoreNotInListMembers)
      public static void MapOnly(
          this SurveyDataMapper mapper,
          UploadedSurveyData source,
          SurveyData destination,
          List<string> requiredProperties)
      {
          // If requiredProperties is empty => do nothing (same behavior as your extension)
          if (requiredProperties == null || requiredProperties.Count == 0)
          {
              return;
          }

          // Update only the fields you allow.
          // (This is explicit; you can generate this switch via a source generator/T4 if the list is large.)
          foreach (var p in requiredProperties)
          {
              switch (p)
              {
                  case nameof(SurveyData.Q1):
                      destination.Q1 = mapper.Map(source).Q1; // or map from source directly
                      break;

                  case nameof(SurveyData.Q2):
                      destination.Q2 = mapper.Map(source).Q2;
                      break;

                  case nameof(SurveyData.Q3):
                      destination.Q3 = mapper.Map(source).Q3;
                      break;
              }
          }
      }
  }

Notes:

  • If you want to avoid calling mapper.Map(source) repeatedly, map once into a temp object and copy selected props.

  • If you have many properties, the most maintainable pattern is to model the patch DTO to contain only patchable fields (preferred) or generate the switch/copy code.

  • ABP-specific note: Mapperly integration is attribute-based; “ignore” behavior is typically expressed via Mapperly attributes (static configuration), not runtime reflection lists.

    Links (validated):

    • https://abp.io/docs/latest/framework/infrastructure/object-to-object-mapping
    • https://abp.io/docs/10.2/release-info/migration-guides/AutoMapper-To-Mapperly
    • https://mapperly.riok.app/docs/intro/

This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

Answer
  • This error is coming from ABP Commercial licensing. It typically happens in CI/CD, containers, or Azure Functions/App Services when the deployed environment doesn’t have an ABP CLI login/license session available, so runtime license validation fails and it prints “you should login to abp.io”.

  • Do not create a new project to fix it. The fix is to ensure the environment that builds/publishes (or runs, depending on your setup) has a valid ABP commercial license context.

Solution

  1. Confirm the exact license error code in logs

    • Look for messages like:
      • ABP-LIC-0008 - License check failed for '...' You need to log in using the command abp login <username>.
      • or ABP-LIC-0018 - ... Your trial period has ended!
    • These two have different resolutions (login/session vs trial/production mismatch).
  2. Re-login on the build/deploy machine (or pipeline agent) using ABP CLI

    • On the machine that produces the deployment artifacts, run:
abp login <your-abp-io-email>
  • Then rebuild and redeploy.
  1. If this started after “AI Management”

    • Adding a commercial module can trigger license checks in places that previously didn’t need them (e.g., your Azure Function now references contracts/packages that require license validation). The deployment environment must be properly licensed/logged in.
  2. If the issue is actually “trial ended” but you have a production license

    • This is usually caused by a stale/old trial login/session cached on the machine. Follow the “purchased a license from trial” cleanup steps referenced by ABP support:
    • If you still can’t see the product key/license details in the organization UI, that’s account/license administration (not a code issue).
  3. Account / product key not visible

    • This is license/account administration; please contact ABP directly:
      • https://abp.io/contact

Sources

  • ABP support thread pointing to ABP-LIC-0008 guidance: https://abp.io/support/questions/5662
  • ABP-LIC-0008 article: https://support.abp.io/QA/Questions/245/ABP-LIC-0008---License-check-failed-for-%27XXXXX%27
  • Related licensing problem thread: https://abp.io/support/questions/6663
  • How to delete current license login session (useful when switching from trial to production): https://support.abp.io/QA/Questions/817/How-to-delete-current-license-login-session
  • Trial ended / production license mismatch discussion and fix reference: https://abp.io/support/questions/10531
  • “Purchased a license from Trial” fix steps: https://abp.io/support/questions/3931/I-purchased-a-license-from-Trial-License---ABP-LIC-0018#answer-c86140f4-9845-c223-2e3e-3a0721603a9a
  • Contact: https://abp.io/contact

This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • In ABP 10.0.1, DELETE /api/identity/organization-units/{id} deletes the OrganizationUnit aggregate itself. The framework does not automatically block deletion when there are still rows in the link tables (OU–User and OU–Role relations). Those relations are not modeled as required FK constraints to the OU entity in a way that would cause a database “restrict delete” error, so deletion can succeed and the relation rows may become orphaned depending on your DB configuration.

  • The UI typically prevents/avoids this scenario by guiding you to remove members/roles first, but calling the endpoint directly from Swagger bypasses any UI guardrails—so what you observe is expected with the default backend behavior.

  • To enforce “cannot delete if it has users/roles”, you should implement an application-layer validation before delete, then throw a user-friendly/business exception.

A safe, ABP-style implementation (override the app service):

using System;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Identity;

public class MyOrganizationUnitAppService : OrganizationUnitAppService
{
    private readonly IRepository<IdentityUserOrganizationUnit> _userOuRepo;
    private readonly IRepository<IdentityRoleOrganizationUnit> _roleOuRepo;

    public MyOrganizationUnitAppService(
        OrganizationUnitManager organizationUnitManager,
        IOrganizationUnitRepository organizationUnitRepository,
        IdentityUserManager userManager,
        IdentityRoleManager roleManager,
        IRepository<IdentityUserOrganizationUnit> userOuRepo,
        IRepository<IdentityRoleOrganizationUnit> roleOuRepo)
        : base(organizationUnitManager, organizationUnitRepository, userManager, roleManager)
    {
        _userOuRepo = userOuRepo;
        _roleOuRepo = roleOuRepo;
    }

    public override async Task DeleteAsync(Guid id)
    {
        // Users?
        var hasUsers = await _userOuRepo.AnyAsync(x => x.OrganizationUnitId == id);
        // Roles?
        var hasRoles = await _roleOuRepo.AnyAsync(x => x.OrganizationUnitId == id);

        if (hasUsers || hasRoles)
        {
            throw new UserFriendlyException(
                "Cannot delete organization unit because it has assigned users and/or roles.");
        }

        await base.DeleteAsync(id);
    }
}

Wire it up by replacing the default service:

using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Identity;

public override void ConfigureServices(ServiceConfigurationContext context)
{
    context.Services.Replace(
        ServiceDescriptor.Transient<IOrganizationUnitAppService, MyOrganizationUnitAppService>()
    );
}

Alternative (if you prefer automatic cleanup instead of blocking)

  • Before calling base.DeleteAsync(id), explicitly remove OU memberships and OU role links (using the relevant managers/repositories), then delete the OU. This avoids orphan links but changes behavior, so only do it if that matches your business rules.

Sources (validated):

  • https://abp.io/docs/latest/modules/identity-pro

This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • This behavior can happen if the Organization Unit repository/queries are not protected by the current tenant filter at the time the parentId is loaded/validated, so the service can “see” an OU from another tenant and accept it as a parent. In a correctly isolated setup, the parentId lookup should only be able to resolve OUs in the current tenant (or fail).

  • Immediate mitigation (recommended custom validation): Override/extend the OU create endpoint in your solution and validate that the parentId belongs to the current tenant before creating the OU. The simplest safe rule is: if input.ParentId != null, then parent.TenantId must equal CurrentTenant.Id (and also handle host side as null tenant).

    Example (custom application service wrapper) pattern:

using System;
  using System.Threading.Tasks;
  using Volo.Abp;
  using Volo.Abp.Application.Services;
  using Volo.Abp.MultiTenancy;
  using Volo.Abp.Identity;

  public class MyOrganizationUnitAppService : ApplicationService
  {
      private readonly IOrganizationUnitRepository _organizationUnitRepository;
      private readonly OrganizationUnitManager _organizationUnitManager;
      private readonly ICurrentTenant _currentTenant;

      public MyOrganizationUnitAppService(
          IOrganizationUnitRepository organizationUnitRepository,
          OrganizationUnitManager organizationUnitManager,
          ICurrentTenant currentTenant)
      {
          _organizationUnitRepository = organizationUnitRepository;
          _organizationUnitManager = organizationUnitManager;
          _currentTenant = currentTenant;
      }

      public async Task<OrganizationUnitDto> CreateAsync(OrganizationUnitCreateDto input)
      {
          if (input.ParentId.HasValue)
          {
              var parent = await _organizationUnitRepository.GetAsync(input.ParentId.Value);

              // Tenant boundary check
              if (parent.TenantId != _currentTenant.Id)
              {
                  throw new BusinessException("AbpIdentity:CrossTenantOuParentNotAllowed")
                      .WithData("ParentId", input.ParentId)
                      .WithData("CurrentTenantId", _currentTenant.Id)
                      .WithData("ParentTenantId", parent.TenantId);
              }
          }

          var ou = await _organizationUnitManager.CreateAsync(input.DisplayName, input.ParentId);
          return ObjectMapper.Map<OrganizationUnit, OrganizationUnitDto>(ou);
      }
  }

This guarantees the API cannot link to a parent OU from another tenant even if some internal query accidentally bypasses tenant filtering.

  • Also verify your multi-tenancy data filter is not being disabled for this call path (globally or via a custom unit-of-work/action filter). If you have any code like IDataFilter.Disable<IMultiTenant>() around identity/OUs, remove it; that would directly allow cross-tenant parent resolution.

  • If you believe this occurs in a clean ABP 10.0.1 Pro template without customization, please report it to Volosoft support (include your minimal repro).
    https://abp.io/contact


This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • Yes — when migrating the Microservice template gateway from Ocelot to YARP, you should align your gateway routes with the current ABP template conventions, i.e. use:

    • "/api/account-admin/{**catch-all}" (YARP catch-all syntax)
  • Your Ocelot route:

    • "/api/account-admin/{everything}" is functionally the same intent (a catch-all), just using Ocelot’s placeholder style. In YARP the equivalent is {**catch-all}.
  • No AuthServer backend code change is required just because of this route change, as long as:

    1. The AuthServer still exposes its endpoints under the same prefix (i.e. /api/account-admin/...), and
    2. Your gateway forwards that path to the AuthServer cluster.
  • What you need to do is only gateway configuration (YARP) consistency:

    • Keep the upstream path as /api/account-admin/...
    • Route it to the same cluster you use for AuthServer (as in the ABP template: ClusterId: "AuthServer")

    Example YARP route (as template):

"AccountAdmin": {
    "ClusterId": "AuthServer",
    "Match": {
      "Path": "/api/account-admin/{**catch-all}"
    }
  }
  • Practical note during upgrade:
    • If your existing clients (Angular/Blazor/etc.) already call /api/account-admin/..., then switching the gateway from Ocelot to YARP with the route above will be transparent.
    • If you had any custom upstream path mapping in Ocelot (different upstream vs downstream), then you’d replicate that in YARP with Match.Path + Transforms (but in what you shared, upstream == downstream, so no transform is needed).

Sources:

  • https://abp.io/docs/latest/solution-templates/microservice/api-gateways
  • https://abp.io/docs/10.2/solution-templates/microservice/api-gateways

This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

Showing 271 to 280 of 1374 entries
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.8.0-preview. Updated on October 21, 2026, 11:09
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.