text:
// Copyright 2015 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.lib.analysis;

import static com.google.common.collect.MoreCollectors.onlyElement;
import static com.google.common.truth.Truth.assertThat;
import static com.google.devtools.build.lib.analysis.BaseRuleClasses.ACTION_LISTENER;
import static com.google.devtools.build.lib.packages.Attribute.attr;
import static com.google.devtools.build.lib.packages.BuildType.LABEL;
import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
import static org.junit.Assert.assertThrows;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.eventbus.EventBus;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
import com.google.devtools.build.lib.actions.util.ActionsTestUtil.NullAction;
import com.google.devtools.build.lib.analysis.config.ExecutionTransitionFactory;
import com.google.devtools.build.lib.analysis.test.InstrumentedFilesInfo;
import com.google.devtools.build.lib.analysis.util.AnalysisTestCase;
import com.google.devtools.build.lib.analysis.util.MockRule;
import com.google.devtools.build.lib.analysis.util.TestAspects;
import com.google.devtools.build.lib.analysis.util.TestAspects.AspectApplyingToFiles;
import com.google.devtools.build.lib.analysis.util.TestAspects.AspectInfo;
import com.google.devtools.build.lib.analysis.util.TestAspects.DummyRuleFactory;
import com.google.devtools.build.lib.analysis.util.TestAspects.ExtraAttributeAspect;
import com.google.devtools.build.lib.analysis.util.TestAspects.RuleInfo;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
import com.google.devtools.build.lib.cmdline.RepositoryName;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.events.EventKind;
import com.google.devtools.build.lib.events.OutputFilter.RegexOutputFilter;
import com.google.devtools.build.lib.packages.AspectDefinition;
import com.google.devtools.build.lib.packages.AspectParameters;
import com.google.devtools.build.lib.packages.Attribute.LateBoundDefault;
import com.google.devtools.build.lib.packages.NativeAspectClass;
import com.google.devtools.build.lib.packages.Provider;
import com.google.devtools.build.lib.packages.StarlarkProvider;
import com.google.devtools.build.lib.packages.StructImpl;
import com.google.devtools.build.lib.skyframe.AspectKeyCreator.AspectKey;
import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData;
import com.google.devtools.build.lib.testutil.MoreAsserts;
import com.google.devtools.build.lib.testutil.TestConstants;
import com.google.devtools.build.lib.vfs.ModifiedFileSet;
import com.google.devtools.build.lib.vfs.Root;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import net.starlark.java.eval.StarlarkInt;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/**
 * Tests for aspect creation and merging with configured targets.
 *
 * <p>Uses the complete analysis machinery and depends on custom rules so that behaviors related to
 * aspects can be tested even if they aren't used by regular rules.
 */
@RunWith(JUnit4.class)
public class AspectTest extends AnalysisTestCase {

  private void pkg(String name, String... contents) throws Exception {
    scratch.file(name + "/BUILD", contents);
  }

  @Test
  public void testAspectAppliedToAliasWithSelect() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.ASPECT_REQUIRING_RULE);
    pkg("a",
        "aspect(name='a', foo=[':b'])",
        "alias(name='b', actual=select({'//conditions:default': ':c'}))",
        "base(name='c')");
    ConfiguredTarget a = getConfiguredTarget("//a:a");
    assertThat(a.getProvider(RuleInfo.class).getData().toList())
        .containsExactly("aspect //a:c", "rule //a:a");
  }

  @Test
  public void testAspectAppliedToChainedAliases() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.ASPECT_REQUIRING_RULE);
    pkg("a",
        "aspect(name='a', foo=[':b'])",
        "alias(name='b', actual=':c')",
        "alias(name='c', actual=':d')",
        "alias(name='d', actual=':e')",
        "base(name='e')");

    ConfiguredTarget a = getConfiguredTarget("//a:a");
    assertThat(a.getProvider(RuleInfo.class).getData().toList())
        .containsExactly("aspect //a:e", "rule //a:a");
  }

  @Test
  public void testAspectAppliedToChainedAliasesAndSelect() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.ASPECT_REQUIRING_RULE);
    pkg("a",
        "aspect(name='a', foo=[':b'])",
        "alias(name='b', actual=select({'//conditions:default': ':c'}))",
        "alias(name='c', actual=select({'//conditions:default': ':d'}))",
        "base(name='d')");
    ConfiguredTarget a = getConfiguredTarget("//a:a");
    assertThat(a.getProvider(RuleInfo.class).getData().toList())
        .containsExactly("aspect //a:d", "rule //a:a");
  }

  @Test
  public void providersOfAspectAreMergedIntoDependency() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.ASPECT_REQUIRING_RULE);
    pkg("a",
        "aspect(name='a', foo=[':b'])",
        "aspect(name='b', foo=[])");

    ConfiguredTarget a = getConfiguredTarget("//a:a");
    assertThat(a.getProvider(RuleInfo.class).getData().toList())
        .containsExactly("aspect //a:b", "rule //a:a");
  }

  @Test
  public void aspectIsNotCreatedIfAdvertisedProviderIsNotPresent() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.LIAR_RULE,
        TestAspects.ASPECT_REQUIRING_PROVIDER_RULE);

    pkg("a",
        "aspect_requiring_provider(name='a', foo=[':b'])",
        "liar(name='b', foo=[])");

    ConfiguredTarget a = getConfiguredTarget("//a:a");
    assertThat(a.getProvider(RuleInfo.class).getData().toList()).containsExactly("rule //a:a");
  }

  @Test
  public void aspectIsNotCreatedIfAdvertisedProviderIsNotPresentWithAlias() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.LIAR_RULE,
        TestAspects.ASPECT_REQUIRING_PROVIDER_RULE);

    pkg("a",
        "aspect_requiring_provider(name='a', foo=[':b'])",
        "alias(name = 'b_alias', actual = ':b')",
        "liar(name='b', foo=[])");

    ConfiguredTarget a = getConfiguredTarget("//a:a");
    assertThat(a.getProvider(RuleInfo.class).getData().toList()).containsExactly("rule //a:a");
  }

  @Test
  public void aspectIsNotPropagatedThroughLiars() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.LIAR_RULE,
        TestAspects.HONEST_RULE, TestAspects.ASPECT_REQUIRING_PROVIDER_RULE);

    pkg("a",
        "aspect_requiring_provider(name='a', foo=[':b_alias'])",
        "alias(name = 'b_alias', actual = ':b')",
        "liar(name='b', foo=[':c'])",
        "honest(name = 'c', foo = [])"
    );

    ConfiguredTarget a = getConfiguredTarget("//a:a");
    assertThat(a.getProvider(RuleInfo.class).getData().toList()).containsExactly("rule //a:a");
  }

  @Test
  public void aspectPropagatedThroughAliasRule() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.HONEST_RULE,
        TestAspects.ASPECT_REQUIRING_PROVIDER_RULE);

    pkg("a",
        "aspect_requiring_provider(name='a', foo=[':b_alias'])",
        "alias(name = 'b_alias', actual = ':b')",
        "honest(name='b', foo=[])");

    ConfiguredTarget a = getConfiguredTarget("//a:a");
    assertThat(a.getProvider(RuleInfo.class).getData().toList())
        .containsExactly("rule //a:a", "aspect //a:b");
  }

  @Test
  public void aspectPropagatedThroughAliasRuleAndHonestRules() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.HONEST_RULE,
        TestAspects.ASPECT_REQUIRING_PROVIDER_RULE);

    pkg("a",
        "aspect_requiring_provider(name='a', foo=[':b'])",
        "alias(name = 'b_alias', actual = ':b')",
        "honest(name='b', foo=[':c'])",
        "honest(name='c', foo=[])"
    );

    ConfiguredTarget a = getConfiguredTarget("//a:a");
    assertThat(a.getProvider(RuleInfo.class).getData().toList())
        .containsExactly("rule //a:a", "aspect //a:b", "aspect //a:c");
  }

  @Test
  public void aspectCreationWorksThroughBind() throws Exception {
    if (getInternalTestExecutionMode() != TestConstants.InternalTestExecutionMode.NORMAL) {
      // TODO(b/67651960): fix or justify disabling.
      return;
    }
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.HONEST_RULE,
        TestAspects.ASPECT_REQUIRING_PROVIDER_RULE);
    pkg("a",
        "aspect_requiring_provider(name='a', foo=['//external:b'])",
        "honest(name='b', foo=[])");

    scratch.overwriteFile("WORKSPACE",
        new ImmutableList.Builder<String>()
            .addAll(analysisMock.getWorkspaceContents(mockToolsConfig))
            .add("bind(name='b', actual='//a:b')")
            .build());

    skyframeExecutor.invalidateFilesUnderPathForTesting(
        reporter, ModifiedFileSet.EVERYTHING_MODIFIED, Root.fromPath(rootDirectory));

    ConfiguredTarget a = getConfiguredTarget("//a:a");
    assertThat(a.getProvider(RuleInfo.class).getData().toList())
        .containsExactly("rule //a:a", "aspect //a:b");
  }

  @Test
  public void aspectCreatedIfAdvertisedProviderIsPresent() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.HONEST_RULE,
        TestAspects.ASPECT_REQUIRING_PROVIDER_RULE);

    pkg("a",
        "aspect_requiring_provider(name='a', foo=[':b'])",
        "honest(name='b', foo=[])");

    ConfiguredTarget a = getConfiguredTarget("//a:a");
    assertThat(a.getProvider(RuleInfo.class).getData().toList())
        .containsExactly("rule //a:a", "aspect //a:b");
  }

  @Test
  public void aspectCreatedIfAtLeastOneSetOfAdvertisedProvidersArePresent() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.HONEST_RULE,
        TestAspects.HONEST_RULE_2, TestAspects.ASPECT_REQUIRING_PROVIDER_SETS_RULE);

    pkg("a",
        "aspect_requiring_provider_sets(name='a', foo=[':b', ':c'])",
        "honest(name='b', foo=[])",
        "honest2(name='c', foo=[])");

    ConfiguredTarget a = getConfiguredTarget("//a:a");
    assertThat(a.getProvider(RuleInfo.class).getData().toList())
        .containsExactly("rule //a:a", "aspect //a:b", "aspect //a:c");
  }

  @Test
  public void aspectWithParametrizedDefinition() throws Exception {
    setRulesAvailableInTests(
        TestAspects.BASE_RULE,
        TestAspects.HONEST_RULE,
        TestAspects.PARAMETERIZED_DEFINITION_ASPECT_RULE);

    pkg(
        "a",
        "honest(name='q', foo=[])",
        "parametrized_definition_aspect(name='a', foo=[':b'], baz='//a:q')",
        "honest(name='c', foo=[])",
        "honest(name='b', foo=[':c'])");

    ConfiguredTarget a = getConfiguredTarget("//a:a");
    assertThat(a.getProvider(TestAspects.RuleInfo.class).getData().toList())
        .containsExactly(
            "rule //a:a",
            "aspect //a:b data //a:q $dep:[ //a:q]",
            "aspect //a:c data //a:q $dep:[ //a:q]");
  }

  @Test
  public void aspectInError() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.ERROR_ASPECT_RULE,
        TestAspects.SIMPLE_RULE);

    pkg("a",
        "simple(name='a', foo=[':b'])",
        "error_aspect(name='b', foo=[':c'])",
        "simple(name='c')");

    reporter.removeHandler(failFastHandler);
    // getConfiguredTarget() uses a separate code path that does not hit
    // SkyframeBuildView#configureTargets
    assertThrows(ViewCreationFailedException.class, () -> update("//a:a"));
    assertContainsEvent("Aspect error");
  }

  @Test
  public void transitiveAspectInError() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.ERROR_ASPECT_RULE,
        TestAspects.SIMPLE_RULE);

    pkg("a",
        "error_aspect(name='a', foo=[':b'])",
        "error_aspect(name='b', bar=[':c'])",
        "error_aspect(name='c', bar=[':d'])",
        "error_aspect(name='d')");

    reporter.removeHandler(failFastHandler);
    // getConfiguredTarget() uses a separate code path that does not hit
    // SkyframeBuildView#configureTargets
    assertThrows(ViewCreationFailedException.class, () -> update("//a:a"));
    assertContainsEvent("Aspect error");
  }

  @Test
  public void aspectDependenciesDontShowDeprecationWarnings() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.EXTRA_ATTRIBUTE_ASPECT_RULE);

    pkg("extra", "base(name='extra', deprecation='bad aspect')");

    pkg("a",
        "rule_with_extra_deps_aspect(name='a', foo=[':b'])",
        "base(name='b')");

    getConfiguredTarget("//a:a");
    assertContainsEventWithFrequency("bad aspect", 0);
  }

  @Test
  public void aspectDependsOnPackageGroup() throws Exception {
    setRulesAvailableInTests(
        TestAspects.BASE_RULE, TestAspects.PACKAGE_GROUP_ATTRIBUTE_ASPECT_RULE);
    pkg("extra", "package_group(name='extra')");
    pkg("a", "rule_with_package_group_deps_aspect(name='a', foo=[':b'])", "base(name='b')");

    getConfiguredTarget("//a:a");
    assertContainsEventWithFrequency("bad aspect", 0);
  }

  @Test
  public void aspectWithComputedAttribute() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.COMPUTED_ATTRIBUTE_ASPECT_RULE);

    pkg("a", "rule_with_computed_deps_aspect(name='a', foo=[':b'])", "base(name='b')");

    getConfiguredTarget("//a:a");
  }

  @Test
  public void ruleDependencyDeprecationWarningsAbsentDuringAspectEvaluations() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.ASPECT_REQUIRING_RULE);

    pkg("a", "aspect(name='a', foo=['//b:b'])");
    pkg("b", "aspect(name='b', bar=['//d:d'])");
    pkg("d", "base(name='d', deprecation='bad rule')");

    getConfiguredTarget("//a:a");
    assertContainsEventWithFrequency("bad rule", 1);
  }

  @Test
  public void aspectWarningsFilteredByOutputFiltersForAssociatedRules() throws Exception {
    if (getInternalTestExecutionMode() != TestConstants.InternalTestExecutionMode.NORMAL) {
      // TODO(b/67651960): fix or justify disabling.
      return;
    }
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.WARNING_ASPECT_RULE);
    pkg("a", "warning_aspect(name='a', foo=['//b:b', '//c:c'])");
    pkg("b", "base(name='b')");
    pkg("c", "base(name='c')");

    reporter.setOutputFilter(RegexOutputFilter.forPattern(Pattern.compile("^//b:")));

    getConfiguredTarget("//a:a");
    assertContainsEventWithFrequency("Aspect warning on //b:b", 1);
    assertContainsEventWithFrequency("Aspect warning on //c:c", 0);
  }

  @Test
  public void sameTargetInDifferentAttributes() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.ASPECT_REQUIRING_RULE,
        TestAspects.SIMPLE_RULE);
    pkg("a",
        "aspect(name='a', foo=[':b'], bar=[':b'])",
        "aspect(name='b', foo=[])");

    ConfiguredTarget a = getConfiguredTarget("//a:a");
    assertThat(a.getProvider(RuleInfo.class).getData().toList())
        .containsExactly("aspect //a:b", "rule //a:a");
  }

  @Test
  public void sameTargetInDifferentAttributesWithDifferentAspects() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.MULTI_ASPECT_RULE,
        TestAspects.SIMPLE_RULE);
    pkg("a",
        "multi_aspect(name='a', foo=':b', bar=':b')",
        "simple(name='b')");

    ConfiguredTarget a = getConfiguredTarget("//a:a");
    assertThat(a.getProvider(RuleInfo.class).getData().toList()).containsExactly("foo", "bar");
  }

  @Test
  public void informationFromBaseRulePassedToAspect() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.HONEST_RULE,
        TestAspects.ASPECT_REQUIRING_PROVIDER_RULE);
    pkg("a",
        "aspect_requiring_provider(name='a', foo=[':b'], baz='hello')",
        "honest(name='b', foo=[])");

    ConfiguredTarget a = getConfiguredTarget("//a:a");
    assertThat(a.getProvider(RuleInfo.class).getData().toList())
        .containsExactly("rule //a:a", "aspect //a:b data hello");
  }

  /**
   * Rule definitions to be used in emptyAspectAttributesAreAvailableInRuleContext().
   */
  public static class EmptyAspectAttributesAreAvailableInRuleContext {
    public static final MockRule TEST_RULE =
        () ->
            MockRule.ancestor(TestAspects.BASE_RULE.getClass())
                .factory(DummyRuleFactory.class)
                .define(
                    "testrule",
                    (builder, env) ->
                        builder.add(
                            attr("foo", LABEL_LIST)
                                .legacyAllowAnyFileType()
                                .aspect(AspectWithEmptyLateBoundAttribute.INSTANCE)));

    public static class AspectWithEmptyLateBoundAttribute extends NativeAspectClass
      implements ConfiguredAspectFactory {
      static final AspectWithEmptyLateBoundAttribute INSTANCE =
          new AspectWithEmptyLateBoundAttribute();

      private AspectWithEmptyLateBoundAttribute() {}

      @Override
      public AspectDefinition getDefinition(AspectParameters params) {
        return new AspectDefinition.Builder(this)
            .add(attr(":late", LABEL).value(LateBoundDefault.alwaysNull()))
            .build();
      }

      @Override
      public ConfiguredAspect create(
          ConfiguredTargetAndData ctadBase,
          RuleContext ruleContext,
          AspectParameters parameters,
          RepositoryName toolsRepository)
          throws InterruptedException, ActionConflictException {
        Object lateBoundPrereq = ruleContext.getPrerequisite(":late");
        return new ConfiguredAspect.Builder(ruleContext)
            .addProvider(
                AspectInfo.class,
                new AspectInfo(
                    NestedSetBuilder.create(
                        Order.STABLE_ORDER, lateBoundPrereq != null ? "non-empty" : "empty")))
            .build();
      }
    }
  }

  /**
   * An Aspect has a late-bound attribute with no value (that is, a LateBoundDefault whose
   * getDefault() returns `null`). Test that this attribute is available in the RuleContext which is
   * provided to the Aspect's `create()` method.
   */
  @Test
  public void emptyAspectAttributesAreAvailableInRuleContext() throws Exception {
    setRulesAndAspectsAvailableInTests(
        ImmutableList.of(
            TestAspects.SIMPLE_ASPECT,
            EmptyAspectAttributesAreAvailableInRuleContext.AspectWithEmptyLateBoundAttribute
                .INSTANCE),
        ImmutableList.of(
            TestAspects.BASE_RULE, EmptyAspectAttributesAreAvailableInRuleContext.TEST_RULE));
    pkg("a",
        "testrule(name='a', foo=[':b'])",
        "testrule(name='b')");
    ConfiguredTarget a = getConfiguredTarget("//a:a");
    assertThat(a.getProvider(RuleInfo.class).getData().toList()).contains("empty");
  }

  /**
   * Rule definitions to be used in extraActionsAreEmitted().
   */
  public static class ExtraActionsAreEmitted {
    public static final MockRule TEST_RULE =
        () ->
            MockRule.ancestor(TestAspects.BASE_RULE.getClass())
                .factory(DummyRuleFactory.class)
                .define(
                    "testrule",
                    (builder, env) ->
                        builder
                            .add(
                                attr("foo", LABEL_LIST)
                                    .legacyAllowAnyFileType()
                                    .aspect(AspectThatRegistersAction.INSTANCE))
                            .add(
                                attr(":action_listener", LABEL_LIST)
                                    .cfg(ExecutionTransitionFactory.create())
                                    .value(ACTION_LISTENER)));

    public static class AspectThatRegistersAction extends NativeAspectClass
      implements ConfiguredAspectFactory {

      static final AspectThatRegistersAction INSTANCE = new AspectThatRegistersAction();

      private AspectThatRegistersAction() {}

      @Override
      public AspectDefinition getDefinition(AspectParameters params) {
        return new AspectDefinition.Builder(this).build();
      }

      @Override
      public ConfiguredAspect create(
          ConfiguredTargetAndData ctadBase,
          RuleContext ruleContext,
          AspectParameters parameters,
          RepositoryName toolsRepository)
          throws InterruptedException, ActionConflictException {
        ruleContext.registerAction(new NullAction(ruleContext.createOutputArtifact()));
        return new ConfiguredAspect.Builder(ruleContext).build();
      }
    }
  }

  /**
   * Test that actions registered in an Aspect are reported as extra-actions on the attached rule.
   * AspectThatRegistersAction registers a NullAction, whose mnemonic is "Null". We have an
   * action_listener that targets that mnemonic, which makes sure the Aspect machinery will expose
   * an ExtraActionArtifactsProvider.
   * The rule //a:a doesn't have an aspect, so the only action we get is the one on //a:b
   * (which does have an aspect).
   */
  @Test
  public void extraActionsAreEmitted() throws Exception {
    setRulesAndAspectsAvailableInTests(
        ImmutableList.of(
            TestAspects.SIMPLE_ASPECT, ExtraActionsAreEmitted.AspectThatRegistersAction.INSTANCE),
        ImmutableList.of(TestAspects.BASE_RULE, ExtraActionsAreEmitted.TEST_RULE));
    useConfiguration("--experimental_action_listener=//extra_actions:listener");
    scratch.file(
        "extra_actions/BUILD",
        "extra_action(name='xa', cmd='echo dont-care')",
        "action_listener(name='listener', mnemonics=['Null'], extra_actions=[':xa'])");
    pkg("a",
        "testrule(name='a', foo=[':b'])",
        "testrule(name='b')");
    update();

    ConfiguredTarget a = getConfiguredTarget("//a:a");
    NestedSet<Artifact.DerivedArtifact> extraActionArtifacts =
        a.getProvider(ExtraActionArtifactsProvider.class).getTransitiveExtraActionArtifacts();
    for (Artifact artifact : extraActionArtifacts.toList()) {
      assertThat(artifact.getOwnerLabel()).isEqualTo(Label.create("@//a", "b"));
    }
  }

  @Test
  public void aspectPropagatesToAllAttributes() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.SIMPLE_RULE,
        TestAspects.ALL_ATTRIBUTES_ASPECT_RULE);
    pkg("a",
        "simple(name='a', foo=[':b'], foo1=':c', txt='some text')",
        "simple(name='b', foo=[], txt='some text')",
        "simple(name='c', foo=[], txt='more text')",
        "all_attributes_aspect(name='x', foo=[':a'])");

    ConfiguredTarget a = getConfiguredTarget("//a:x");
    assertThat(a.getProvider(RuleInfo.class).getData().toList())
        .containsExactly("aspect //a:a", "aspect //a:b", "aspect //a:c", "rule //a:x");
  }

  /**
   * Tests that when --experimental_extra_action_top_level_only, Blaze reports extra-actions for
   * actions registered by Aspects injected by a top-level rule. Because we can't know whether an
   * aspect was injected by a top-level target or one of its children, we approximate it by only
   * reporting extra-actions from Aspects that the top-level target could have injected.
   *
   * <p>Here, injector1() and injector2() inject aspects into their children. null_rule() just
   * passes the aspects to its children. The test makes sure that actions registered by aspect1
   * (injected by injector1()) are reported to the extra-action mechanism. Actions registered by
   * aspect2 (from injector2) are not reported, because the target under test (//x:a) doesn't inject
   * aspect2.
   */
  @Test
  public void extraActionsAreEmitted_topLevel() throws Exception {
    useConfiguration(
        "--experimental_action_listener=//pkg1:listener",
        "--experimental_extra_action_top_level_only");

    scratch.file(
        "x/BUILD",
        "load(':extension.bzl', 'injector1', 'injector2', 'null_rule')",
        "injector1(name='a', deps=[':b'])",
        "null_rule(name='b', deps=[':c'])",
        "null_rule(name='c', deps=[':d'])",
        "injector2(name = 'd', extra_deps=[':e'])",
        "null_rule(name = 'e')");

    scratch.file(
        "x/extension.bzl",
        "def _aspect_impl(target, ctx):",
        "  ctx.actions.do_nothing(mnemonic='Mnemonic')",
        "  return []",
        "aspect1 = aspect(_aspect_impl, attr_aspects=['deps'])",
        "aspect2 = aspect(_aspect_impl, attr_aspects=['extra_deps'])",
        "def _rule_impl(ctx):",
        "  return []",
        "injector1 = rule(_rule_impl, attrs = { 'deps' : attr.label_list(aspects = [aspect1]) })",
        "null_rule = rule(_rule_impl, attrs = { 'deps' : attr.label_list() })",
        "injector2 = rule(",
        "  _rule_impl, attrs = { 'extra_deps' : attr.label_list(aspects = [aspect2]) })");

    scratch.file(
        "pkg1/BUILD",
        "extra_action(name='xa', cmd='echo dont-care')",
        "action_listener(name='listener', mnemonics=['Mnemonic'], extra_actions=[':xa'])");

    // Check: //x:d injects an aspect which produces some extra-action.
    {
      AnalysisResult analysisResult = update("//x:d");

      // Get owners of all extra-action artifacts.
      List<Label> extraArtifactOwners = new ArrayList<>();
      for (Artifact artifact : analysisResult.getArtifactsToBuild()) {
        if (artifact.getRootRelativePathString().endsWith(".xa")) {
          extraArtifactOwners.add(artifact.getOwnerLabel());
        }
      }
      assertThat(extraArtifactOwners).containsExactly(Label.create("@//x", "e"));
    }

    // Actual test: //x:a reports actions registered by the aspect it injects.
    {
      AnalysisResult analysisResult = update("//x:a");

      // Get owners of all extra-action artifacts.
      List<Label> extraArtifactOwners = new ArrayList<>();
      for (Artifact artifact : analysisResult.getArtifactsToBuild()) {
        if (artifact.getRootRelativePathString().endsWith(".xa")) {
          extraArtifactOwners.add(artifact.getOwnerLabel());
        }
      }
      assertThat(extraArtifactOwners)
          .containsExactly(
              Label.create("@//x", "b"), Label.create("@//x", "c"), Label.create("@//x", "d"));
    }
  }

  @Test
  public void extraActionsFromDifferentAspectsDontConflict() throws Exception {
    useConfiguration(
        "--experimental_action_listener=//pkg1:listener",
        "--experimental_extra_action_top_level_only");

    scratch.file(
        "x/BUILD",
        "load(':extension.bzl', 'injector1', 'injector2', 'null_rule')",
        "injector2(name='i2_a', deps = [':i1_a'])",
        "injector1(name='i1_a', deps=[':n'], param = 'a')",
        "injector1(name='i1_b', deps=[':n'], param = 'b')",
        "injector2(name='i2', deps=[':n'])",
        "null_rule(name = 'n')");

    scratch.file(
        "x/extension.bzl",
        "def _aspect_impl(target, ctx):",
        "  ctx.actions.do_nothing(mnemonic='Mnemonic')",
        "  return []",
        "aspect1 = aspect(_aspect_impl, attr_aspects=['deps'], attrs =",
        "    {'param': attr.string(values = ['a', 'b'])})",
        "aspect2 = aspect(_aspect_impl, attr_aspects=['deps'])",
        "def _rule_impl(ctx):",
        "  return []",
        "injector1 = rule(_rule_impl, attrs =",
        "    { 'deps' : attr.label_list(aspects = [aspect1]), 'param' : attr.string() })",
        "injector2 = rule(_rule_impl, attrs = { 'deps' : attr.label_list(aspects = [aspect2]) })",
        "null_rule = rule(_rule_impl, attrs = { 'deps' : attr.label_list() })");

    scratch.file(
        "pkg1/BUILD",
        "extra_action(name='xa', cmd='echo dont-care')",
        "action_listener(name='listener', mnemonics=['Mnemonic'], extra_actions=[':xa'])");

    update("//x:i1_a", "//x:i1_b", "//x:i2", "//x:i2_a");

    // Implicitly check that update() didn't throw an exception because of two actions producing
    // the same outputs.
  }

  @Test
  public void sharedArtifactsInAspect() throws Exception {
    scratch.file(
        "foo/shared_aspect.bzl",
        "def _shared_aspect_impl(target, ctx):",
        "  shared_file = ctx.actions.declare_file('shared_file')",
        "  ctx.actions.write(output=shared_file, content='Shared content')",
        "  lib = ctx.rule.attr.lib",
        "  if lib:",
        "    result = depset([shared_file], transitive=[ctx.rule.attr.lib.prov])",
        "  else:",
        "    result = depset([shared_file])",
        "  return struct(prov=result)",
        "",
        "shared_aspect = aspect(implementation = _shared_aspect_impl,",
        "                       attr_aspects = ['lib'])",
        "",
        "def _rule_impl(ctx):",
        "  pass",
        "",
        "simple_rule = rule(",
        "    implementation=_rule_impl,",
        "    attrs = {'lib': attr.label(providers = ['prov'],",
        "                               aspects=[shared_aspect])})");
    scratch.file(
        "foo/BUILD",
        "load(':shared_aspect.bzl', 'shared_aspect', 'simple_rule')",
        "",
        "simple_rule(name = 'top_rule', lib = ':first_dep')",
        "simple_rule(name = 'first_dep', lib = ':second_dep')",
        "simple_rule(name = 'second_dep')");
    // Confirm that load is successful and doesn't crash.
    update("//foo:top_rule");
  }

  @Test
  public void aspectPropagatesToAllAttributesImplicit() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.SIMPLE_RULE,
        TestAspects.IMPLICIT_DEP_RULE, TestAspects.ALL_ATTRIBUTES_ASPECT_RULE);
    scratch.file(
        "extra/BUILD",
        "simple(name ='extra')"
    );
    pkg("a",
        "simple(name='a', foo=[':b'], foo1=':c', txt='some text')",
        "simple(name='b', foo=[], txt='some text')",
        "implicit_dep(name='c')",
        "all_attributes_aspect(name='x', foo=[':a'])");
    update();

    ConfiguredTarget a = getConfiguredTarget("//a:x");
    assertThat(a.getProvider(RuleInfo.class).getData().toList())
        .containsExactly(
            "aspect //a:a", "aspect //a:b", "aspect //a:c", "aspect //extra:extra", "rule //a:x");
  }

  @Test
  public void aspectPropagatesToAllAttributesLateBound() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.SIMPLE_RULE,
        TestAspects.LATE_BOUND_DEP_RULE, TestAspects.ALL_ATTRIBUTES_ASPECT_RULE);

    scratch.file(
        "extra/BUILD",
        "simple(name ='extra')"
    );
    pkg("a",
        "simple(name='a', foo=[':b'], foo1=':c', txt='some text')",
        "simple(name='b', foo=[], txt='some text')",
        "late_bound_dep(name='c')",
        "all_attributes_aspect(name='x', foo=[':a'])");
    useConfiguration("--plugin=//extra:extra");
    update();

    ConfiguredTarget a = getConfiguredTarget("//a:x");
    assertThat(a.getProvider(RuleInfo.class).getData().toList())
        .containsExactly(
            "aspect //a:a", "aspect //a:b", "aspect //a:c", "aspect //extra:extra", "rule //a:x");
  }

  /**
   * Ensures an aspect with attr = '*' doesn't try to propagate to its own implicit attributes.
   * Doing so leads to a dependency cycle.
   */
  @Test
  public void aspectWithAllAttributesDoesNotPropagateToOwnImplicitAttributes() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.SIMPLE_RULE,
        TestAspects.ALL_ATTRIBUTES_WITH_TOOL_ASPECT_RULE);
    pkg(
        "a",
        "simple(name='tool')",
        "simple(name='a')",
        "all_attributes_with_tool_aspect(name='x', foo=[':a'])");

    ConfiguredTarget a = getConfiguredTarget("//a:x");
    assertThat(a.getProvider(RuleInfo.class).getData().toList())
        .containsExactly("aspect //a:a", "rule //a:x");
  }

  /**
   * Makes sure the aspect *will* propagate to its implicit attributes if there is a "regular"
   * dependency path to it (i.e. not through its own implicit attributes).
   */
  @Test
  public void aspectWithAllAttributesPropagatesToItsToolIfThereIsPath() throws Exception {
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.SIMPLE_RULE,
        TestAspects.ALL_ATTRIBUTES_WITH_TOOL_ASPECT_RULE);
    pkg(
        "a",
        "simple(name='tool')",
        "simple(name='a', foo=[':b'], foo1=':c', txt='some text')",
        "simple(name='b', foo=[], txt='some text')",
        "simple(name='c', foo=[':tool'], txt='more text')",
        "all_attributes_with_tool_aspect(name='x', foo=[':a'])");

    ConfiguredTarget a = getConfiguredTarget("//a:x");
    assertThat(a.getProvider(RuleInfo.class).getData().toList())
        .containsExactly(
            "aspect //a:a", "aspect //a:b", "aspect //a:c", "aspect //a:tool", "rule //a:x");
  }

  @Test
  public void aspectTruthInAdvertisement() throws Exception {
    reporter.removeHandler(failFastHandler); // expect errors
    setRulesAvailableInTests(TestAspects.BASE_RULE, TestAspects.SIMPLE_RULE,
        TestAspects.FALSE_ADVERTISEMENT_ASPECT_RULE);
    pkg(
        "a",
        "simple(name = 's')",
        "false_advertisement_aspect(name = 'x', deps = [':s'])"
    );
    try {
      update("//a:x");
    } catch (ViewCreationFailedException e) {
      // expected.
    }
    assertContainsEvent(
        "Aspect 'FalseAdvertisementAspect', applied to '//a:s',"
            + " does not provide advertised provider 'RequiredProvider'");
    assertContainsEvent(
        "Aspect 'FalseAdvertisementAspect', applied to '//a:s',"
            + " does not provide advertised provider 'advertised_provider'");
  }

  @Test
  public void aspectApplyingToFiles() throws Exception {
    AspectApplyingToFiles aspectApplyingToFiles = new AspectApplyingToFiles();
    setRulesAndAspectsAvailableInTests(ImmutableList.of(aspectApplyingToFiles), ImmutableList.of());
    pkg(
        "a",
        "java_binary(name = 'x', main_class = 'x.FooBar', srcs = ['x.java'])"
    );
    AnalysisResult analysisResult = update(new EventBus(), defaultFlags(),
        ImmutableList.of(aspectApplyingToFiles.getName()),
        "//a:x_deploy.jar");
    ConfiguredAspect aspect = Iterables.getOnlyElement(analysisResult.getAspectsMap().values());
    AspectApplyingToFiles.Provider provider =
        aspect.getProvider(AspectApplyingToFiles.Provider.class);
    assertThat(provider.getLabel())
        .isEqualTo(Label.parseAbsoluteUnchecked("//a:x_deploy.jar"));
  }

  @Test
  public void aspectApplyingToSourceFilesIgnored() throws Exception {
    AspectApplyingToFiles aspectApplyingToFiles = new AspectApplyingToFiles();
    setRulesAndAspectsAvailableInTests(ImmutableList.of(aspectApplyingToFiles), ImmutableList.of());
    pkg(
        "a",
        "java_binary(name = 'x', main_class = 'x.FooBar', srcs = ['x.java'])"
    );
    scratch.file("a/x.java", "");
    AnalysisResult analysisResult = update(new EventBus(), defaultFlags(),
        ImmutableList.of(aspectApplyingToFiles.getName()),
        "//a:x.java");
    ConfiguredAspect aspect = Iterables.getOnlyElement(analysisResult.getAspectsMap().values());
    assertThat(aspect.getProvider(AspectApplyingToFiles.Provider.class)).isNull();
  }

  @Test
  public void duplicateTopLevelAspects_duplicateAspectsNotAllowed() throws Exception {
    AspectApplyingToFiles aspectApplyingToFiles = new AspectApplyingToFiles();
    setRulesAndAspectsAvailableInTests(ImmutableList.of(aspectApplyingToFiles), ImmutableList.of());
    pkg("a", "java_binary(name = 'x', main_class = 'x.FooBar', srcs = ['x.java'])");
    reporter.removeHandler(failFastHandler);

    assertThrows(
        ViewCreationFailedException.class,
        () ->
            update(
                new EventBus(),
                defaultFlags(),
                ImmutableList.of(aspectApplyingToFiles.getName(), aspectApplyingToFiles.getName()),
                "//a:x_deploy.jar"));
    assertContainsEvent("Aspect AspectApplyingToFiles has already been added");
  }

  @Test
  public void aspectWithExtraAttribute_ignoredForOutputFile() throws Exception {
    ExtraAttributeAspect aspect =
        new ExtraAttributeAspect("//nonexistent", /*applyToFiles=*/ false);
    setRulesAndAspectsAvailableInTests(ImmutableList.of(aspect), ImmutableList.of());
    scratch.file("a/BUILD", "genrule(name='gen_a', outs=['a'], cmd='touch $@')");

    AnalysisResult analysisResult =
        update(new EventBus(), defaultFlags(), ImmutableList.of(aspect.getName()), "//a");

    ConfiguredAspect configuredAspect =
        Iterables.getOnlyElement(analysisResult.getAspectsMap().values());
    assertThat(configuredAspect.getProvider(ExtraAttributeAspect.Provider.class)).isNull();
  }

  @Test
  public void aspectWithExtraAttributeApplyToFiles_outputFile_hasResolvedAttribute()
      throws Exception {
    ExtraAttributeAspect aspect = new ExtraAttributeAspect("//extra", /*applyToFiles=*/ true);
    setRulesAndAspectsAvailableInTests(
        ImmutableList.of(aspect), ImmutableList.of(TestAspects.BASE_RULE, TestAspects.SIMPLE_RULE));
    scratch.file("extra/BUILD", "simple(name='extra')");
    scratch.file("a/BUILD", "genrule(name='gen_a', outs=['a'], cmd='touch $@')");

    AnalysisResult analysisResult =
        update(new EventBus(), defaultFlags(), ImmutableList.of(aspect.getName()), "//a");

    ConfiguredAspect configuredAspect =
        Iterables.getOnlyElement(analysisResult.getAspectsMap().values());
    ExtraAttributeAspect.Provider provider =
        configuredAspect.getProvider(ExtraAttributeAspect.Provider.class);
    assertThat(provider.label()).isEqualTo("//extra:extra");
  }

  @Test
  public void aspectWithExtraAttributeApplyToFiles_ignoredForSourceFile() throws Exception {
    ExtraAttributeAspect aspect = new ExtraAttributeAspect("//nonexistent", /*applyToFiles=*/ true);
    setRulesAndAspectsAvailableInTests(ImmutableList.of(aspect), ImmutableList.of());
    scratch.file("a/BUILD", "exports_files(['a.txt'])");
    scratch.file("a/a.txt", "hello");

    AnalysisResult analysisResult =
        update(new EventBus(), defaultFlags(), ImmutableList.of(aspect.getName()), "//a:a.txt");

    ConfiguredAspect configuredAspect =
        Iterables.getOnlyElement(analysisResult.getAspectsMap().values());
    assertThat(configuredAspect.getProvider(ExtraAttributeAspect.Provider.class)).isNull();
  }

  @Test
  public void aspectWithExtraAttributeApplyToFilesAndNot_outputFile_onlyApplyToFilesIsResolved()
      throws Exception {
    ExtraAttributeAspect aspectApplies =
        new ExtraAttributeAspect("//extra", /*applyToFiles=*/ true);
    ExtraAttributeAspect aspectDoesNotApply =
        new ExtraAttributeAspect("//nonexistent", /*applyToFiles=*/ false);
    setRulesAndAspectsAvailableInTests(
        ImmutableList.of(aspectApplies, aspectDoesNotApply),
        ImmutableList.of(TestAspects.BASE_RULE, TestAspects.SIMPLE_RULE));
    scratch.file("extra/BUILD", "simple(name='extra')");
    scratch.file("a/BUILD", "genrule(name='gen_a', outs=['a'], cmd='touch $@')");

    AnalysisResult analysisResult =
        update(
            new EventBus(),
            defaultFlags(),
            ImmutableList.of(aspectApplies.getName(), aspectDoesNotApply.getName()),
            "//a");

    assertThat(analysisResult.getAspectsMap()).hasSize(2);
    ExtraAttributeAspect.Provider provider =
        getAspectByName(analysisResult.getAspectsMap(), aspectApplies.getName())
            .getProvider(ExtraAttributeAspect.Provider.class);
    assertThat(provider.label()).isEqualTo("//extra:extra");
    assertThat(
            getAspectByName(analysisResult.getAspectsMap(), aspectDoesNotApply.getName())
                .getProviders()
                .getProviderCount())
        .isEqualTo(0);
  }

  @Test
  public void aspectWithExtraAttributeDependsOnNotApplicable_usesAttributeFromDependentAspect()
      throws Exception {
    ExtraAttributeAspect aspectApplies =
        new ExtraAttributeAspect(
            "//extra", /*applyToFiles=*/ true, ExtraAttributeAspect.Provider.class);
    ExtraAttributeAspect aspectDoesNotApply =
        new ExtraAttributeAspect("//extra:extra2", /*applyToFiles=*/ false);
    setRulesAndAspectsAvailableInTests(
        ImmutableList.of(aspectApplies, aspectDoesNotApply),
        ImmutableList.of(TestAspects.BASE_RULE, TestAspects.SIMPLE_RULE));
    scratch.file("extra/BUILD", "simple(name='extra')", "simple(name='extra2')");
    scratch.file("a/BUILD", "genrule(name='gen_a', outs=['a'], cmd='touch $@')");

    AnalysisResult analysisResult =
        update(
            new EventBus(),
            defaultFlags(),
            ImmutableList.of(aspectDoesNotApply.getName(), aspectApplies.getName()),
            "//a");

    assertThat(analysisResult.getAspectsMap()).hasSize(2);
    ExtraAttributeAspect.Provider provider =
        getAspectByName(analysisResult.getAspectsMap(), aspectApplies.getName())
            .getProvider(ExtraAttributeAspect.Provider.class);
    assertThat(provider.label()).isEqualTo("//extra:extra2");
    assertThat(
            getAspectByName(analysisResult.getAspectsMap(), aspectDoesNotApply.getName())
                .getProviders()
                .getProviderCount())
        .isEqualTo(0);
  }

  @Test
  public void sameConfiguredAttributeOnAspectAndRule() throws Exception {
    scratch.file(
        "a/a.bzl",
        "def _a_impl(t, ctx):",
        "  return [DefaultInfo()]",
        "def _r_impl(ctx):",
        "  return [DefaultInfo()]",
        "a = aspect(",
        "  implementation = _a_impl,",
        "  attrs = {'_f': attr.label(",
        "                   default = configuration_field(",
        "                     fragment = 'cpp', name = 'cc_toolchain'))})",
        "r = rule(",
        "  implementation = _r_impl,",
        "  attrs = {'_f': attr.label(",
        "                   default = configuration_field(",
        "                     fragment = 'cpp', name = 'cc_toolchain')),",
        "           'dep': attr.label(aspects=[a])})");

    scratch.file("a/BUILD", "load(':a.bzl', 'r')", "r(name='r')");

    setRulesAndAspectsAvailableInTests(ImmutableList.of(), ImmutableList.of());
    getConfiguredTarget("//a:r");
  }

  @Test
  public void topLevelConflictDetected() throws Exception {
    String bzlFileTemplate =
        String.join(
            "\n",
            "def _aspect1_impl(target, ctx):",
            "  outfile = ctx.actions.declare_file('aspect.out')",
            "  ctx.actions.run_shell(",
            "    outputs = [outfile],",
            "    progress_message = 'Action for aspect 1',",
            "    command = 'echo \"1\" > ' + outfile.path,",
            "  )",
            "  return [OutputGroupInfo(files = [outfile])]",
            "def _aspect2_impl(target, ctx):",
            "  outfile = ctx.actions.declare_file('aspect.out')",
            "  ctx.actions.run_shell(",
            "    outputs = [outfile],",
            "    progress_message = 'Action for aspect 2',",
            "    command = 'echo \"%s\" > ' + outfile.path,",
            "  )",
            "  return [OutputGroupInfo(files = [outfile])]",
            "aspect1 = aspect(implementation = _aspect1_impl)",
            "aspect2 = aspect(implementation = _aspect2_impl)");
    scratch.file("foo/aspect.bzl", String.format(bzlFileTemplate, "2"));
    scratch.file("foo/BUILD", "sh_library(name = 'foo', srcs = ['foo.sh'])");
    // Expect errors.
    reporter.removeHandler(failFastHandler);
    ViewCreationFailedException exception =
        assertThrows(
            ViewCreationFailedException.class,
            () ->
                update(
                    new EventBus(),
                    defaultFlags(),
                    ImmutableList.of("//foo:aspect.bzl%aspect1", "//foo:aspect.bzl%aspect2"),
                    "//foo:foo"));
    assertThat(exception)
        .hasMessageThat()
        .containsMatch(
            "ConflictException: for foo/aspect.out, previous action: action 'Action for aspect .',"
                + " attempted action: action 'Action for aspect .'");
    MoreAsserts.assertContainsEvent(
        eventCollector,
        Pattern.compile(
            "Aspects: \\[//foo:aspect.bzl%aspect[12]], \\[//foo:aspect.bzl%aspect[12]]"),
        EventKind.ERROR);

    // Fix bzl file so actions are shared: analysis should succeed now.
    scratch.overwriteFile("foo/aspect.bzl", String.format(bzlFileTemplate, "1"));
    reporter.addHandler(failFastHandler);
    AnalysisResult result =
        update(
            new EventBus(),
            defaultFlags(),
            ImmutableList.of("//foo:aspect.bzl%aspect1", "//foo:aspect.bzl%aspect2"),
            "//foo:foo");
    assertThat(result.getAspectsMap()).hasSize(2);

    // Break bzl file again: we should notice.
    scratch.overwriteFile("foo/aspect.bzl", String.format(bzlFileTemplate, "2"));
    // Expect errors.
    reporter.removeHandler(failFastHandler);
    exception =
        assertThrows(
            ViewCreationFailedException.class,
            () ->
                update(
                    new EventBus(),
                    defaultFlags(),
                    ImmutableList.of("//foo:aspect.bzl%aspect1", "//foo:aspect.bzl%aspect2"),
                    "//foo:foo"));
    assertThat(exception)
        .hasMessageThat()
        .containsMatch(
            "ConflictException: for foo/aspect.out, previous action: action 'Action for aspect .',"
                + " attempted action: action 'Action for aspect .'");
  }

  @Test
  public void conflictBetweenTargetAndAspect() throws Exception {
    scratch.file(
        "foo/aspect.bzl",
        "def _aspect_impl(target, ctx):",
        "  outfile = ctx.actions.declare_file('conflict.out')",
        "  ctx.actions.run_shell(",
        "    outputs = [outfile],",
        "    progress_message = 'Action for aspect',",
        "    command = 'echo \"aspect\" > ' + outfile.path,",
        "  )",
        "  return [OutputGroupInfo(files = [outfile])]",
        "",
        "def _rule_impl(ctx):",
        "  outfile = ctx.actions.declare_file('conflict.out')",
        "  ctx.actions.run_shell(",
        "    outputs = [outfile],",
        "    progress_message = 'Action for target',",
        "    command = 'echo \"target\" > ' + outfile.path,",
        "  )",
        "  return [DefaultInfo(files = depset([outfile]))]",
        "my_aspect = aspect(implementation = _aspect_impl)",
        "my_rule = rule(implementation = _rule_impl, attrs = {'deps' : attr.label_list(aspects ="
            + " [my_aspect])})");
    scratch.file(
        "foo/BUILD",
        "load('//foo:aspect.bzl', 'my_aspect', 'my_rule')",
        "my_rule(name = 'foo', deps = [':dep'])",
        "sh_library(name = 'dep', srcs = ['dep.sh'])");
    // Expect errors.
    reporter.removeHandler(failFastHandler);
    ViewCreationFailedException exception =
        assertThrows(ViewCreationFailedException.class, () -> update("//foo:foo"));
    assertThat(exception).hasMessageThat().containsMatch("ConflictException: for foo/conflict.out");
    MoreAsserts.assertContainsEvent(
        eventCollector,
        Pattern.compile(
            "Aspects: (\\[], \\[//foo:aspect.bzl%my_aspect]|\\[//foo:aspect.bzl%my_aspect], \\[])"),
        EventKind.ERROR);
  }

  @Test
  public void aspectDuplicatesRuleProviderError() throws Exception {
    setRulesAndAspectsAvailableInTests(ImmutableList.of(), ImmutableList.of());
    scratch.file(
        "aspect/build_defs.bzl",
        "def _aspect_impl(target, ctx):",
        "    return [DefaultInfo()]",
        "",
        "returns_default_info_aspect = aspect(implementation = _aspect_impl)",
        "",
        "def _rule_impl(ctx):",
        "    pass",
        "",
        "duplicate_provider_aspect_applying_rule = rule(",
        "    implementation = _rule_impl,",
        "    attrs = {'to': attr.label(aspects = [returns_default_info_aspect])},",
        ")");
    scratch.file(
        "aspect/BUILD",
        "load('build_defs.bzl', 'duplicate_provider_aspect_applying_rule')",
        "cc_library(name = 'rule_target')",
        "duplicate_provider_aspect_applying_rule(name='applies_aspect', to=':rule_target')");
    assertThat(
            assertThrows(
                AssertionError.class, () -> getConfiguredTarget("//aspect:applies_aspect")))
        .hasMessageThat()
        .contains("Provider DefaultInfo provided twice");
  }

  @Test
  public void instrumentedFilesInfoFromBaseRuleAndAspectUsesAspect() throws Exception {
    scratch.file(
        "aspect/build_defs.bzl",
        "def _instrumented_files_info_aspect_impl(target, ctx):",
        "    return [coverage_common.instrumented_files_info(ctx, source_attributes=['a'])]",
        "",
        "instrumented_files_info_aspect = aspect(",
        "    implementation = _instrumented_files_info_aspect_impl,",
        ")",
        "",
        "def _no_instrumented_files_info_aspect_impl(target, ctx):",
        "    return []",
        "",
        "no_instrumented_files_info_aspect = aspect(",
        "    implementation = _no_instrumented_files_info_aspect_impl,",
        ")",
        "",
        "def _applies_aspect_impl(ctx):",
        "    return coverage_common.instrumented_files_info(ctx, dependency_attributes=['to'])",
        "",
        "instrumented_files_info_aspect_rule = rule(",
        "    implementation = _applies_aspect_impl,",
        "    attrs = {'to': attr.label(aspects = [instrumented_files_info_aspect])},",
        ")",
        "",
        "no_instrumented_files_info_aspect_rule = rule(",
        "    implementation = _applies_aspect_impl,",
        "    attrs = {'to': attr.label(aspects = [no_instrumented_files_info_aspect])},",
        ")",
        "",
        "def _base_rule_impl(ctx):",
        "    return [coverage_common.instrumented_files_info(ctx, source_attributes=['b'])]",
        "",
        "base_rule = rule(",
        "    implementation = _base_rule_impl,",
        "    attrs = {'a': attr.label(allow_files=True), 'b': attr.label(allow_files=True)},",
        ")",
        "",
        "def _base_rule_no_coverage_impl(ctx):",
        "    return []",
        "",
        "base_rule_no_coverage = rule(",
        "    implementation = _base_rule_no_coverage_impl,",
        "    attrs = {'a': attr.label(allow_files=True), 'b': attr.label(allow_files=True)},",
        ")");
    scratch.file(
        "aspect/BUILD",
        "load(",
        "    'build_defs.bzl',",
        "    'base_rule',",
        "    'base_rule_no_coverage',",
        "    'instrumented_files_info_aspect_rule',",
        "    'no_instrumented_files_info_aspect_rule',",
        ")",
        "",
        "base_rule(",
        "    name = 'rule_target',",
        // Ends up in coverage sources when instrumented_files_info_aspect is applied
        "    a = 'a',",
        // Ends up in coverage sources for the base rule's InstrumentedFilesInfo is used
        "    b = 'b',",
        ")",
        "",
        "instrumented_files_info_aspect_rule(",
        "    name='duplicate_instrumented_file_info',",
        "    to=':rule_target',",
        ")",
        "",
        "no_instrumented_files_info_aspect_rule(",
        "    name='instrumented_file_info_from_base_target',",
        "    to=':rule_target',",
        ")",
        "",
        "base_rule_no_coverage(",
        "    name = 'rule_target_no_coverage',",
        // Ends up in coverage sources when instrumented_files_info_aspect is applied
        "    a = 'a',",
        // Ends up in coverage sources never
        "    b = 'b',",
        ")",
        "",
        "instrumented_files_info_aspect_rule(",
        "    name='instrumented_files_info_only_from_aspect',",
        "    to=':rule_target_no_coverage',",
        ")",
        "",
        "no_instrumented_files_info_aspect_rule(",
        "    name='no_instrumented_files_info',",
        "    to=':rule_target_no_coverage',",
        ")");
    useConfiguration("--collect_code_coverage", "--instrumentation_filter=.*");
    update();
    assertThat(getInstrumentedFiles("//aspect:rule_target")).containsExactly("b");
    assertThat(getInstrumentedFiles("//aspect:duplicate_instrumented_file_info"))
        .containsExactly("a");
    assertThat(getInstrumentedFiles("//aspect:instrumented_file_info_from_base_target"))
        .containsExactly("b");
    assertThat(getInstrumentedFiles("//aspect:rule_target_no_coverage")).isEmpty();
    assertThat(getInstrumentedFiles("//aspect:instrumented_files_info_only_from_aspect"))
        .containsExactly("a");
    assertThat(getInstrumentedFiles("//aspect:no_instrumented_files_info")).isEmpty();
  }

  private List<String> getInstrumentedFiles(String label) throws InterruptedException {
    return ActionsTestUtil.baseArtifactNames(
        getConfiguredTarget(label)
            .get(InstrumentedFilesInfo.STARLARK_CONSTRUCTOR)
            .getInstrumentedFiles());
  }

  @Test
  public void aspectSeesAspectHintsAttributeOnNativeRule() throws Exception {
    useConfiguration("--experimental_enable_aspect_hints");
    setupAspectHints();
    scratch.file(
        "aspect_hints/BUILD",
        "load('//aspect_hints:hints_counter.bzl', 'count_hints')",
        "load('//aspect_hints:hints.bzl', 'hint')",
        "",
        "hint(name = 'my_hint', hints_cnt = 3)",
        "cc_library(name = 'lib1', deps = [':lib2'])",
        "cc_library(name = 'lib2', aspect_hints = [':my_hint'])",
        "count_hints(name = 'cnt', deps = [':lib1'])");
    update();

    ConfiguredTarget a = getConfiguredTarget("//aspect_hints:cnt");
    StarlarkInt info = (StarlarkInt) getHintsCntInfo(a).getValue("cnt");

    assertThat(info.truncateToInt()).isEqualTo(3);
  }

  @Test
  public void aspectSeesAspectHintsAttributeOnStarlarkRule() throws Exception {
    useConfiguration("--experimental_enable_aspect_hints");
    setupAspectHints();
    setupStarlarkRule();
    scratch.file(
        "aspect_hints/BUILD",
        "load('//aspect_hints:hints_counter.bzl', 'count_hints')",
        "load('//aspect_hints:custom_rule.bzl', 'custom_rule')",
        "load('//aspect_hints:hints.bzl', 'hint')",
        "",
        "hint(name = 'my_hint', hints_cnt = 2)",
        "custom_rule(name = 'lib1', deps = [':lib2'])",
        "custom_rule(name = 'lib2', aspect_hints = [':my_hint'])",
        "count_hints(name = 'cnt', deps = [':lib1'])");
    update();

    ConfiguredTarget a = getConfiguredTarget("//aspect_hints:cnt");
    StarlarkInt info = (StarlarkInt) getHintsCntInfo(a).getValue("cnt");

    assertThat(info.truncateToInt()).isEqualTo(2);
  }

  private void setupAspectHints() throws Exception {
    scratch.file(
        "aspect_hints/hints.bzl",
        "HintInfo = provider(fields = ['hints_cnt'])",
        "def _hint_impl(ctx):",
        "    return [HintInfo(hints_cnt = ctx.attr.hints_cnt)]",
        "",
        "hint = rule(",
        "    implementation = _hint_impl,",
        "    attrs = {'hints_cnt': attr.int(default=0)},",
        ")");
    scratch.file(
        "aspect_hints/hints_counter.bzl",
        "load('//aspect_hints:hints.bzl', 'HintInfo')",
        "HintsCntInfo = provider(fields = ['cnt'])",
        "",
        "def _my_aspect_impl(target, ctx):",
        "    transitive_hints = 0",
        "    for dep in ctx.rule.attr.deps:",
        "        transitive_hints = transitive_hints + dep[HintsCntInfo].cnt",
        "",
        "    hints = 0",
        "    for hint in ctx.rule.attr.aspect_hints:",
        "        hints = hints + hint[HintInfo].hints_cnt",
        "",
        "    return [HintsCntInfo(cnt = hints + transitive_hints)]",
        "",
        "my_aspect = aspect(",
        "    implementation = _my_aspect_impl,",
        "    attr_aspects = ['deps'],",
        ")",
        "",
        "def _count_hints_impl(ctx):",
        "    hints = 0",
        "    for dep in ctx.attr.deps:",
        "        hints = hints + dep[HintsCntInfo].cnt",
        "    return [HintsCntInfo(cnt = hints)]",
        "",
        "count_hints = rule(",
        "    implementation = _count_hints_impl,",
        "    attrs = {",
        "        'deps': attr.label_list(aspects = [my_aspect])",
        "    }",
        ")");
  }

  private void setupStarlarkRule() throws Exception {
    scratch.file(
        "aspect_hints/custom_rule.bzl",
        "def _custom_rule_impl(ctx):",
        "    return []",
        "",
        "custom_rule = rule(",
        "    implementation = _custom_rule_impl,",
        "    attrs = {",
        "        'deps': attr.label_list(),",
        "    },",
        ")");
  }

  private static StructImpl getHintsCntInfo(ConfiguredTarget configuredTarget)
      throws LabelSyntaxException {
    Provider.Key key =
        new StarlarkProvider.Key(
            Label.parseAbsolute("//aspect_hints:hints_counter.bzl", ImmutableMap.of()),
            "HintsCntInfo");
    return (StructImpl) configuredTarget.get(key);
  }

  private static ConfiguredAspect getAspectByName(
      ImmutableMap<AspectKey, ConfiguredAspect> aspectMap, String name) {
    return aspectMap.entrySet().stream()
        .filter(e -> e.getKey().getAspectName().equals(name))
        .map(Map.Entry::getValue)
        .collect(onlyElement());
  }
}

redpajama_set_name: RedPajamaGithub


This film released in 2017, along with Guardians of the Galaxy Vol. 2 (2017) and Spider-Man: Homecoming (2017). This marked the first time the Marvel Cinematic Universe has released three films in the same year.


Marietta mother, Rachel Goldschein, will honor her 5-year-old son with apraxia, Sammy Goldschein, at the second annual Walk for Children with Apraxia of Speech event on Saturday, May 4, in East Cobb Park. Last year more than 300 residents participated in the walk that helped bring local awareness to the motor speech disorder and raised over $20,000 to benefit the Childhood Apraxia of Speech Association of North America (CASANA).
"I am passionate about apraxia since first receiving my son's diagnosis," said Goldschein, who is coordinating this Walk for her second year in the Greater Atlanta area. Goldschein's son was diagnosed with childhood apraxia of speech three years ago.
The 2013 Greater Atlanta Area Walk for Children with Apraxia of Speech is open to all adults and children. On-site registration, check-in, and children's activities will begin at 8:30 AM, with the Walk starting promptly at 10:00 AM. Anyone interested in participating should contact Goldschein at savyrach@hotmail.com OR visit the website at http://secure.apraxia-kids.org/greateratlantawalk for more information, to register, or to make a donation.


text:
Labelexpo India attracts nearly 8,000 to New Delhi
7,927 visitors attended the seventh edition of Labelexpo India which took place 29 October – 1 November at Pragati Maidan, New Delhi. With just under 200 exhibitors taking part, the show floor was busy with product launches and news of many installations being agreed as numerous deals were signed on-site.
Aimed at label and package printers, brand owners and label designers, 2014's show saw the leading Indian and international manufacturers showcasing their cutting edge technology. Product launch highlights included new flexographic plate and equipment from DuPont Packaging Graphics, HP Indigo's WS 6800 digital press, Multitec's two new narrow-web label printing presses - Ecoflex VSi Servo and Ecosmart, Nilpeter's Indian-made FB3300S press with gravure unit, Omet's XFlex X4 8-color all-servo press and Rotatek's Smartflex UV flexo press.
2014's edition also saw the successful debut of the Brand Innovation Summit. Held in partnership with HP Indigo, the half day conference program was attended by several top brands including ACG Pharma, Cipla, Coca Cola, Dabur, GSK, ITC, Morepen, Nestle, Reckitt Benckiser and Siemens amongst others. The insightful session focused specifically on the role and importance of label and package printing in a brand's design and ultimate sales performance in the Indian marketplace.
Jade Grace, event director said: "There was a good buzz about this year's Labelexpo India and our exhibitors reported excellent visitor engagement with revisit numbers up 42%. This is not purely a numbers game however and attracting the right sort of visitor is crucial, so we are delighted to report an increase in senior decision makers attending the show. We've been really satisfied with the anecdotal feedback from our exhibitors with many of them securing large orders and generating strong leads. We look forward to returning in 2016."
Quotes from exhibitors:
Luc Dehandschutter, Arets Graphics: "Arets Graphics and Toyo Ink India, both subsidiaries of Toyo Ink Group, introduced a new series of UV flexo inks at Labelexpo India 2014. The new series, Steraflex, is designed to address the high-end needs of UV flexo customers. This is an ideal product, for customers who are looking for high strength and yet low viscosity, maintaining high curing speeds for quality and productivity. Steraflex is a high strength, fast curing UV flexo ink system ideally suited for label and flexible packaging markets. With the launch, Arets hopes to improve its share of UV flexo ink market in India."
Jitesh Mehta, Avery Dennison: "Labelexpo India has been very successful for Avery Dennison. A large number of customers visited our booth who were keen to know about our offerings in durable, home and personal care and pharma segments. The 14 innovations we showcased this time earned the spotlight at the exhibition. Labelexpo gives us a platform to demonstrate to customers how we can help them grow."
Martin Kugler, GEW: "Once again GEW participated as an exhibitor in this year's Labelexpo India to demo the latest product developments. For GEW the show was an international platform to announce the availability of the RHINO electronic power supply for UV-printing systems that was launched in production following three years of intensive development and rigorous testing. RHINO sets the new benchmark in effective UV technology and includes a series of innovative features with reliability and energy efficiency at the top of the list. Visiting the GEW stand, existing customers and new prospects alike were excited about the benefits of 24x7 reliability, energy savings, ease of use and embedded service support. The combination of the rugged RHINO power unit and the E2C UV-lamphead has made an extremely favorable impact and customers are insisting that OEMs incorporate these systems from GEW in their scope of supply."
A Appadurai, HP India: "Labelexpo India was the ideal platform to showcase the new HP Indigo WS 6800 digital press for the first time in India. One of the major attractions at our booth was the digital supermarket, where visitors could see first-hand, the various application possibilities for label and packaging converters. Our key highlight was the Brand Innovation Summit, where we were able to share insights with brand managers and owners, helping them understand the challenges and opportunities of the label industry. We were thoroughly pleased with the visitor engagement we had at the expo."
Ashish Anand, LinkSmart Technologies: "Labelexpo India was a successful event for introducing smartDNA based new technology and solution for tamper-evidence, anti-counterfeit coupled with track & trace. Our fundamental differentiator of insider threat protection was something of great interest for visitors and other exhibitors as well. LinkSmart witnessed interest for various end-customer applications and at least three licensing opportunities in multiple geographies. Similarly our reusable tamper-evident, duplication-evident and remote-monitorable flexible packaging again based on smartDNA was received with great enthusiasm. To summarize there were more opportunities at Labelexpo than we had expected while doing ground-up architecture, design and development of smartDNA labeling technology."
Atul Gandhi, Macart: "This is the first time we have participated at Labelexpo India and we are very much satisfied with the inquiries generated. We got visitors from all over India and also some international visitors."
Sanjeev Chada, Memory Repro Systems: "This was our first participation at Labelexpo as for the past four decades we've been in pre-press and post press in offset printing. We got tremendous response to our flexo cleaning machine because printers were really looking for one such machine. Labelexpo India gave us exposure and we are sure to gain out of it. Our rough estimate is to get business worth 3-4 million. The enquiries that have gone into the pipeline are serious and we will turn them into orders in the near future."
Ajay Metha, SMI Coated Products: "SMI Coated Products Private Limited has its roots truly entrenched in India. Despite the growth in exports, India has been the centre of our focus and Labelexpo India is a fantastic opportunity to showcase our products, firm commitment and gratitude to the Indian label industry. The four days at the show were very busy and extremely fruitful. Over the period of years the show has progressively improved and the quality of the large number of visitors is truly amazing. Our friends in the industry evinced keen interest in our ever expanding wide range of products as well as the new tools we have introduced at the show. Our new specification sheets, curved diameter indicator and brochures for the seven different types of industry are path breaking tools to help the industry. And last but definitely not the least; Labelexpo has truly made the show of an international standard and hats off to them!?"
Pravin Varshney UPM Raflatac: "We enjoyed the four extremely busy days at Labelexpo India. The atmosphere was great and we had a pleasure to host a successful gala dinner for over 300 customers, industry partners and other stakeholders. Labelexpo is definitely is the best place to meet the people working in the labeling industry and to see where the business is moving. We are seeing overall healthy organic growth in India and across South Asia due to a rapid increase in pre-packaged food products, pharma sector growth and the massive appetite for personal care products. In addition, Indian companies are increasingly becoming aware of environmental issues and that's why our Label Life concept was of interest to both label printers and end-users. We're proud to work in India along the same principles of world-class technology, quality and performance, environmental sustainability and top class customer service as we do everywhere else."
All Labelexpo
Etiquetas: All Labelexpo

redpajama_set_name: RedPajamaCommonCrawl


We are currently looking for a qualified Transport Planner with 5 to 8 years' experience to join our Strategic Transport Business in the Middle East.
The candidate will be degree-qualified in a related professional field and ideally holding a Master's qualification. Experience in leading and delivering transportation projects within a multi-disciplinary technical environment together with knowledge of Middle East and/or International Transport Planning standards and practices is essential. Transport modelling experience is considered an asset, report writing and presentation skills are essential.
Application of technical competencies, as well as sharing these with junior staff.


text:
Instinctif Partners Appoints Rt Hon David Gauke as a senior adviser to its Public Policy practice
Instinctif Partners has appointed Rt Hon David Gauke as a senior public policy adviser, on a part time basis.
David served as Lord Chancellor and Secretary of State for Justice between 8 January 2018 and 24 July 2019. Prior to that, he was Secretary of State for Work and Pensions from June 2017 to January 2018, and Chief Secretary to the Treasury from July 2016 to June 2017. He was also MP for Hertfordshire South West in 2005 to 2019. He will continue in his existing role as head of public policy for law firm Macfarlanes.
Ed Amory, CEO of Instinctif, said: "David was an exceptional political talent, and I'm delighted that he will be joining us in a part time role to provide strategic advice to our clients on navigating the increasingly complex regulatory and political environment. As a senior minister, he played a vital role at the heart of government, while acting with great personal political integrity. He's brilliantly placed to build on our strong public policy practice in the UK, and I look forward to working with him to develop further our offer in this area."
David Gauke, Senior Adviser, commented: "I am very pleased to be joining the Instinctif team at this exciting time in its journey. I look forward to working with both Instinctif's current and future clients in navigating this changing landscape, and with colleagues to support the growth of the public policy practice."
Instinctif Partners is independently owned, with the majority stake held by private equity firm LDC.


Toby may know where Heinz is.
Not only does Stacey play the harmonica, he plays the guitar, too.
Amir's warned me about that.
I think Tollefsen is hypocritical.
I share everything with Becky.
Elliott is very nice to me.
Amir went out for a breath of fresh air.
Jonathan has a brother in Boston.
Matthew has not been doing very well at work recently.
Shane and Ellen live in different states.
Manjeri chewed on his pencil.
Ramadoss, who was always early, was there already.
This is for you, Sarah.
I know what got Syed rattled.
Oskar finished cleaning the kitchen and then started cleaning the living room.
Hamilton told John to get his shotgun.
Raymond is going to have to try harder.
I'll send a message to Tareq.
Why did Warren want you to talk to Rogue?
Cristina is the new man in charge.
Ami is engaged in medical research.
Mahesh would help you if you asked him to.
I talked with Sandra for over an hour before he said something that made me realize he wasn't a native speaker.
Roy didn't quite understand what was going on.
Rod went out on his bicycle.


text:
Hawley's ridiculous loot box ban is an attack on gaming companies like Activision Blizzard - and an insult to consumers. | Source: Shutterstock
Activision Alums Raise $16 Million to Build EOS-Focused Blockchain Game Studio
October 5, 2020 UTC: 4:32 PM. November 16, 2018 UTC: 11:35 PM. by P. H. Madore
Mythical Games is "a next-generation game technology studio." Their focus is online games where players own the assets they develop or acquire in the game – true digital ownership powered by the blockchain, as opposed to managed digital ownership backed by centralized servers. It's an important difference.
When a player acquires assets in a game like World of Warcraft, Ultima Online, or Runescape, they are at the whim of the company to stay in business and keep servers online. A decentralized game built on the blockchain can keep in operation, with assets retaining value, for as long as users desire them to. Not to mention how much easier it is to transfer assets when blockchain-connected accounts are involved.
The company has yet to release a game, but today announced that it had raised $16 million in funding from five different venture capital firms including Galaxy Digital's EOS VC fund and OKCoin.
A press release reads in part:
"The funding will support the company's first-to-market plans to develop and co-produce a slate of high-quality game titles (on mobile / PC / console) built around new player economies and user-generated content. The investment was led by Galaxy Digital's EOS VC Fund, with significant participation from Javelin Venture Partners as well as DDC, Fenbushi, Noris, and OkCoin joining the round."
Made up of former Blizzard, Activision, and Yahoo! executives and employees, the company will now presumably begin building out its first offerings. According to Galaxy Digital CEO and billionaire crypto bull Mike Novogratz, gaming is an item of keen interest to the VC firm:
"We believe that gaming – and specifically players' interaction with in-game economies and virtual goods – will play a key role in how the masses first discover the true potential of the blockchain. Mythical's experience building rich and immersive game worlds will be invaluable to this mission."
Given that Galaxy Digital's EOS fund is responsible in large part of the $16 million funding round, Mythical will be building products on EOS, a dApp-focused blockchain that aims to allow developers to run blockchain applications at scale.
Mythical's offerings will not be the first blockchain games to enter the space, with Decentraland having dominated headlines in recent times with people being able to take loans on and for virtual properties.
Central Banks of Canada, Singapore and UK Propose CBDCs for Cross-Border Payments
Bank of Thailand Governor: No Central Bank Digital Currency Within 3-5 Years


Thousands took to the streets of Peru Tuesday to protest the presidential candidacy of Keiko Fujimori, daughter of former President Alberto Fujimori.
The former president is currently in prison for authorizing death squads and corruption during his decade in power between 1990 and 2000. Incumbent President Ollanta Humala is ineligible for elections this year due to constitutional term limitations. This leaves the candidacy to Fujimori, 41, and pro-business conservative and former World Bank economist, Pedro Pablo Kuczynski.
Kuczynski was expected to join the protests but canceled the plan in a last-minute decision. Reuters reported Kuczynski as stating that it would be "undemocratic" for him to join calls to stop Fujimori.
In the first round of presidential elections, Fujimori emerged victorious, with Kuczynski, 77, coming in second ahead of leftist congresswoman, Veronika Mendoza.
According to an Ipsos poll released Sunday, Fujimori is shown beating Kuczynski in the runoff election scheduled for June 5, Reuters reported. Fujimori was seen garnering 45.9 percent of votes while Kuczynski was getting 40.6 percent of votes.
Critics reportedly say that a vote for her would be a vote for former President Alberto Fujimori. However, Keiko Fujimori has sought to counter her critics by vowing not to revive the hard-line methods of her father.
Keiko Fujimori's candidacy has been closely linked to her father's time as the leader. The senior Fujimori is still popular with many rural Peruvians for defeating the Maoist-inspired Shining Path rebels. He is credited with taming hyperinflation and bringing about overhauls that laid the foundation for Peru's growth. The poor sections of the society also reportedly support her because of her father's social programs.
However, 45 percent of Peruvians say they will definitely not vote for her. This number is higher than that for Kuczynski, according to a recent Ipsos poll, Reuters reported.
Before voters head to the ballot box, the two leading candidates are scheduled to face off Sunday night in a last televised debate.
This is Fujimori's second run for president. She lost to Humala in the presidential elections of 2011.


text:
North West Division may refer to:

 The North-West Land Division, a cadastral division of Western Australia
 The North West Division of the High Court of South Africa, a superior court of law in Mahikeng, South Africa

redpajama_set_name: RedPajamaWikipedia