text:
// Copyright 2014 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.skylark;

import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Ordering;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.Root;
import com.google.devtools.build.lib.analysis.ActionsProvider;
import com.google.devtools.build.lib.analysis.AliasProvider;
import com.google.devtools.build.lib.analysis.AnalysisUtils;
import com.google.devtools.build.lib.analysis.ConfigurationMakeVariableContext;
import com.google.devtools.build.lib.analysis.DefaultInfo;
import com.google.devtools.build.lib.analysis.FilesToRunProvider;
import com.google.devtools.build.lib.analysis.LabelExpander;
import com.google.devtools.build.lib.analysis.LabelExpander.NotUniqueExpansionException;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.config.FragmentCollection;
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.stringtemplate.ExpansionException;
import com.google.devtools.build.lib.analysis.test.InstrumentedFilesCollector;
import com.google.devtools.build.lib.analysis.test.InstrumentedFilesProvider;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.packages.AspectDescriptor;
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition;
import com.google.devtools.build.lib.packages.BuildType;
import com.google.devtools.build.lib.packages.ImplicitOutputsFunction;
import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SkylarkImplicitOutputsFunction;
import com.google.devtools.build.lib.packages.Info;
import com.google.devtools.build.lib.packages.NativeProvider;
import com.google.devtools.build.lib.packages.OutputFile;
import com.google.devtools.build.lib.packages.Package;
import com.google.devtools.build.lib.packages.Provider;
import com.google.devtools.build.lib.packages.RawAttributeMapper;
import com.google.devtools.build.lib.shell.ShellUtils;
import com.google.devtools.build.lib.shell.ShellUtils.TokenizationException;
import com.google.devtools.build.lib.skylarkinterface.Param;
import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
import com.google.devtools.build.lib.syntax.ClassObject;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.FuncallExpression.FuncallException;
import com.google.devtools.build.lib.syntax.Runtime;
import com.google.devtools.build.lib.syntax.SkylarkDict;
import com.google.devtools.build.lib.syntax.SkylarkIndexable;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.syntax.SkylarkSemantics;
import com.google.devtools.build.lib.syntax.SkylarkType;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.syntax.Type.LabelClass;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.annotation.Nullable;

/** A Skylark API for the ruleContext.
 *
 * "This object becomes featureless once the rule implementation function that it was created for
 * has completed. To achieve this, the {@link #nullify()} should be called once the evaluation of
 * the function is completed. The method both frees memory by deleting all significant fields of the
 * object and makes it impossible to accidentally use this object where it's not supposed to be used
 * (such attempts will result in {@link EvalException}s).
 */
@SkylarkModule(
  name = "ctx",
  category = SkylarkModuleCategory.BUILTIN,
  doc =
      "The context of the rule containing helper functions and "
          + "information about attributes, depending targets and outputs. "
          + "You get a ctx object as an argument to the implementation function when "
          + "you create a rule."
)
public final class SkylarkRuleContext implements SkylarkValue {

  private static final String DOC_NEW_FILE_TAIL = "Does not actually create a file on the file "
      + "system, just declares that some action will do so. You must create an action that "
      + "generates the file. If the file should be visible to other rules, declare a rule output "
      + "instead when possible. Doing so enables Blaze to associate a label with the file that "
      + "rules can refer to (allowing finer dependency control) instead of referencing the whole "
      + "rule.";
  public static final String EXECUTABLE_DOC =
      "A struct containing executable files defined in label type "
          + "attributes marked as executable=True. The struct fields correspond "
          + "to the attribute names. Each value in the struct is either a file or "
          + "None. If an optional attribute is not specified in the rule "
          + "then the corresponding struct value is None. If a label type is not "
          + "marked as executable=True, no corresponding struct field is generated.";
  public static final String FILES_DOC =
      "A struct containing files defined in label or label list "
          + "type attributes. The struct fields correspond to the attribute names. The struct "
          + "values are list of files. If an optional attribute is "
          + "not specified in the rule, an empty list is generated. "
          + "It is a shortcut for:"
          + "
[f for t in ctx.attr.<ATTR> for f in t.files]
";
  public static final String FILE_DOC =
      "A struct containing files defined in label type "
          + "attributes marked as single_file=True. The struct fields correspond "
          + "to the attribute names. The struct value is always a file or "
          + "None. If an optional attribute is not specified in the rule "
          + "then the corresponding struct value is None. If a label type is not "
          + "marked as single_file=True, no corresponding struct field is generated. "
          + "It is a shortcut for:"
          + "
list(ctx.attr.<ATTR>.files)[0]
";
  public static final String ATTR_DOC =
      "A struct to access the values of the attributes. The values are provided by "
          + "the user (if not, a default value is used).";
  public static final String SPLIT_ATTR_DOC =
      "A struct to access the values of attributes with split configurations. If the attribute is "
          + "a label list, the value of split_attr is a dict of the keys of the split (as strings) "
          + "to lists of the ConfiguredTargets in that branch of the split. If the attribute is a "
          + "label, then the value of split_attr is a dict of the keys of the split (as strings) "
          + "to single ConfiguredTargets. Attributes with split configurations still appear in the "
          + "attr struct, but their values will be single lists with all the branches of the split "
          + "merged together.";
  public static final String OUTPUTS_DOC =
      "A pseudo-struct containing all the pre-declared output files."
          + " It is generated the following way:
"
          + "
" + ""
          + "
For every entry in the rule's outputs dict an attr is generated with "
          + "the same name and the corresponding file value."
          + "
For every output type attribute a struct attribute is generated with the "
          + "same name and the corresponding file value or None, "
          + "if no value is specified in the rule."
          + "
For every output list type attribute a struct attribute is generated with the "
          + "same name and corresponding list of files value "
          + "(an empty list if no value is specified in the rule).
"
          + "
DEPRECATED: If the rule is marked as executable=True, a field "
          + "\"executable\" can be accessed. That will declare the rule's default executable "
          + "File value. The recommended alternative is to declare an executable with "
          + "ctx.actions.declare_file "
          + "and return it as the executable field of the rule's "
          + "DefaultInfo provider."
          + "
";
  public static final Function<Attribute, Object> ATTRIBUTE_VALUE_EXTRACTOR_FOR_ASPECT =
      new Function<Attribute, Object>() {
        @Nullable
        @Override
        public Object apply(Attribute attribute) {
          return attribute.getDefaultValue(null);
        }
      };
  public static final String EXECUTABLE_OUTPUT_NAME = "executable";

  // This field is a copy of the info from ruleContext, stored separately so it can be accessed
  // after this object has been nullified.
  private final String ruleLabelCanonicalName;

  private final boolean isForAspect;

  private final SkylarkActionFactory actionFactory;

  // The fields below intended to be final except that they can be cleared by calling `nullify()`
  // when the object becomes featureless.
  private RuleContext ruleContext;
  private FragmentCollection fragments;
  private FragmentCollection hostFragments;
  private AspectDescriptor aspectDescriptor;
  private final SkylarkSemantics skylarkSemantics;

  private SkylarkDict<String, String> makeVariables;
  private SkylarkRuleAttributesCollection attributesCollection;
  private SkylarkRuleAttributesCollection ruleAttributesCollection;
  private Info splitAttributes;

  // TODO(bazel-team): we only need this because of the css_binary rule.
  private ImmutableMap<Artifact, Label> artifactsLabelMap;
  private Outputs outputsObject;

  /**
   * Creates a new SkylarkRuleContext using ruleContext.
   * @param aspectDescriptor aspect for which the context is created, or null
   *        if it is for a rule.
   * @throws InterruptedException
   */
  public SkylarkRuleContext(RuleContext ruleContext,
      @Nullable AspectDescriptor aspectDescriptor,
      SkylarkSemantics skylarkSemantics)
      throws EvalException, InterruptedException {
    this.actionFactory = new SkylarkActionFactory(this, skylarkSemantics, ruleContext);
    this.ruleContext = Preconditions.checkNotNull(ruleContext);
    this.ruleLabelCanonicalName = ruleContext.getLabel().getCanonicalForm();
    this.fragments = new FragmentCollection(ruleContext, ConfigurationTransition.NONE);
    this.hostFragments = new FragmentCollection(ruleContext, ConfigurationTransition.HOST);
    this.aspectDescriptor = aspectDescriptor;
    this.skylarkSemantics = skylarkSemantics;

    if (aspectDescriptor == null) {
      this.isForAspect = false;
      Collection<Attribute> attributes = ruleContext.getRule().getAttributes();
      Outputs outputs = new Outputs(this);

      ImplicitOutputsFunction implicitOutputsFunction =
          ruleContext.getRule().getImplicitOutputsFunction();

      if (implicitOutputsFunction instanceof SkylarkImplicitOutputsFunction) {
        SkylarkImplicitOutputsFunction func =
            (SkylarkImplicitOutputsFunction) implicitOutputsFunction;
        for (Map.Entry<String, String> entry :
            func.calculateOutputs(RawAttributeMapper.of(ruleContext.getRule())).entrySet()) {
          outputs.addOutput(
              entry.getKey(),
              ruleContext.getImplicitOutputArtifact(entry.getValue()));
        }
      }

      Builder<Artifact, Label> artifactLabelMapBuilder = ImmutableMap.builder();
      for (Attribute a : attributes) {
        String attrName = a.getName();
        Type<?> type = a.getType();
        if (type.getLabelClass() != LabelClass.OUTPUT) {
          continue;
        }
        ImmutableList.Builder<Artifact> artifactsBuilder = ImmutableList.builder();
        for (OutputFile outputFile : ruleContext.getRule().getOutputFileMap().get(attrName)) {
          Artifact artifact = ruleContext.createOutputArtifact(outputFile);
          artifactsBuilder.add(artifact);
          artifactLabelMapBuilder.put(artifact, outputFile.getLabel());
        }
        ImmutableList<Artifact> artifacts = artifactsBuilder.build();

        if (type == BuildType.OUTPUT) {
          if (artifacts.size() == 1) {
            outputs.addOutput(attrName, Iterables.getOnlyElement(artifacts));
          } else {
            outputs.addOutput(attrName, Runtime.NONE);
          }
        } else if (type == BuildType.OUTPUT_LIST) {
          outputs.addOutput(attrName, SkylarkList.createImmutable(artifacts));
        } else {
          throw new IllegalArgumentException(
              "Type of " + attrName + "(" + type + ") is not output type ");
        }
      }

      this.artifactsLabelMap = artifactLabelMapBuilder.build();
      this.outputsObject = outputs;

      this.attributesCollection =
          buildAttributesCollection(
              this, attributes, ruleContext, attributeValueExtractorForRule(ruleContext));
      this.splitAttributes = buildSplitAttributeInfo(attributes, ruleContext);
      this.ruleAttributesCollection = null;
    } else { // ASPECT
      this.isForAspect = true;
      this.artifactsLabelMap = ImmutableMap.of();
      this.outputsObject = null;
      this.attributesCollection =
          buildAttributesCollection(
              this,
              ruleContext.getAspectAttributes().values(),
              ruleContext,
              ATTRIBUTE_VALUE_EXTRACTOR_FOR_ASPECT);
      this.splitAttributes = null;
      this.ruleAttributesCollection =
          buildAttributesCollection(
              this,
              ruleContext.getRule().getAttributes(),
              ruleContext,
              attributeValueExtractorForRule(ruleContext));
    }

    makeVariables = ruleContext.getConfigurationMakeVariableContext().collectMakeVariables();
  }

  /**
   * Represents `ctx.outputs`.
   *
   *
A {@link ClassObject} (struct-like data structure) with "executable" field created
   * lazily on-demand.
   *
   *
Note: There is only one {@code Outputs} object per rule context, so default
   * (object identity) equals and hashCode suffice.
   */
  private static class Outputs implements ClassObject, SkylarkValue {
    private final Map<String, Object> outputs;
    private final SkylarkRuleContext context;
    private boolean executableCreated = false;

    public Outputs(SkylarkRuleContext context) {
      this.outputs = new LinkedHashMap<>();
      this.context = context;
    }

    private void addOutput(String key, Object value)
        throws EvalException {
      Preconditions.checkState(!context.isImmutable(),
          "Cannot add outputs to immutable Outputs object");
      if (outputs.containsKey(key)
          || (context.isExecutable() && EXECUTABLE_OUTPUT_NAME.equals(key))) {
        throw new EvalException(null, "Multiple outputs with the same key: " + key);
      }
      outputs.put(key, value);
    }

    @Override
    public boolean isImmutable() {
      return context.isImmutable();
    }

    @Override
    public ImmutableCollection<String> getKeys() throws EvalException {
      checkMutable();
      ImmutableList.Builder<String> result = ImmutableList.builder();
      if (context.isExecutable() && executableCreated) {
        result.add(EXECUTABLE_OUTPUT_NAME);
      }
      result.addAll(outputs.keySet());
      return result.build();
    }

    @Nullable
    @Override
    public Object getValue(String name) throws EvalException {
      checkMutable();
      if (context.isExecutable() && EXECUTABLE_OUTPUT_NAME.equals(name)) {
        executableCreated = true;
        // createOutputArtifact() will cache the created artifact.
        return context.ruleContext.createOutputArtifact();
      }

      return outputs.get(name);
    }

    @Nullable
    @Override
    public String errorMessage(String name) {
      return String.format(
          "No attribute '%s' in outputs. Make sure you declared a rule output with this name.",
          name);
    }

    @Override
    public void repr(SkylarkPrinter printer) {
      if (isImmutable()) {
        printer.append("ctx.outputs(for ");
        printer.append(context.ruleLabelCanonicalName);
        printer.append(")");
        return;
      }
      boolean first = true;
      printer.append("ctx.outputs(");
      // Sort by key to ensure deterministic output.
      try {
        for (String key : Ordering.natural().sortedCopy(getKeys())) {
          if (!first) {
            printer.append(", ");
          }
          first = false;
          printer.append(key);
          printer.append(" = ");
          printer.repr(getValue(key));
        }
        printer.append(")");
      } catch (EvalException e) {
        throw new AssertionError("mutable ctx.outputs should not throw", e);
      }
    }

    private void checkMutable() throws EvalException {
      if (isImmutable()) {
        throw new EvalException(
            null,
            String.format(
                "cannot access outputs of rule '%s' outside of its own "
                    + "rule implementation function",
                context.ruleLabelCanonicalName));
      }
    }

  }

  public boolean isExecutable() {
    return ruleContext.getRule().getRuleClassObject().isExecutableSkylark();
  }

  public boolean isDefaultExecutableCreated() {
    return this.outputsObject.executableCreated;
  }

  /**
   * Nullifies fields of the object when it's not supposed to be used anymore to free unused memory
   * and to make sure this object is not accessed when it's not supposed to (after the corresponding
   * rule implementation function has exited).
   */
  public void nullify() {
    actionFactory.nullify();
    ruleContext = null;
    fragments = null;
    hostFragments = null;
    aspectDescriptor = null;
    makeVariables = null;
    attributesCollection = null;
    ruleAttributesCollection = null;
    splitAttributes = null;
    artifactsLabelMap = null;
    outputsObject = null;
  }

  public void checkMutable(String attrName) throws EvalException {
    if (isImmutable()) {
      throw new EvalException(null, String.format(
          "cannot access field or method '%s' of rule context for '%s' outside of its own rule "
              + "implementation function", attrName, ruleLabelCanonicalName));
    }
  }

  @Nullable
  public AspectDescriptor getAspectDescriptor() {
    return aspectDescriptor;
  }

  private Function<Attribute, Object> attributeValueExtractorForRule(
      final RuleContext ruleContext) {
    return new Function<Attribute, Object>() {
      @Nullable
      @Override
      public Object apply(Attribute attribute) {
        return ruleContext.attributes().get(attribute.getName(), attribute.getType());
      }
    };
  }

  private static SkylarkRuleAttributesCollection buildAttributesCollection(
      SkylarkRuleContext skylarkRuleContext,
      Collection<Attribute> attributes,
      RuleContext ruleContext,
      Function<Attribute, Object> attributeValueExtractor) {
    Builder<String, Object> attrBuilder = new Builder<>();
    Builder<String, Object> executableBuilder = new Builder<>();
    Builder<Artifact, FilesToRunProvider> executableRunfilesbuilder = new Builder<>();
    Builder<String, Object> fileBuilder = new Builder<>();
    Builder<String, Object> filesBuilder = new Builder<>();
    HashSet<Artifact> seenExecutables = new HashSet<>();
    for (Attribute a : attributes) {
      Type<?> type = a.getType();
      Object val = attributeValueExtractor.apply(a);
      // TODO(mstaib): Remove the LABEL_DICT_UNARY special case of this conditional
      // LABEL_DICT_UNARY was previously not treated as a dependency-bearing type, and was put into
      // Skylark as a Map<String, Label>; this special case preserves that behavior temporarily.
      if (type.getLabelClass() != LabelClass.DEPENDENCY || type == BuildType.LABEL_DICT_UNARY) {
        attrBuilder.put(a.getPublicName(), val == null ? Runtime.NONE
            // Attribute values should be type safe
            : SkylarkType.convertToSkylark(val, null));
        continue;
      }
      String skyname = a.getPublicName();
      if (a.isExecutable()) {
        // In Skylark only label (not label list) type attributes can have the Executable flag.
        FilesToRunProvider provider =
            ruleContext.getExecutablePrerequisite(a.getName(), Mode.DONT_CHECK);
        if (provider != null && provider.getExecutable() != null) {
          Artifact executable = provider.getExecutable();
          executableBuilder.put(skyname, executable);
          if (!seenExecutables.contains(executable)) {
            // todo(dslomov,laurentlb): In general, this is incorrect.
            // We associate the first encountered FilesToRunProvider with
            // the executable (this provider is later used to build the spawn).
            // However ideally we should associate a provider with the attribute name,
            // and pass the correct FilesToRunProvider to the spawn depending on
            // what attribute is used to access the executable.
            executableRunfilesbuilder.put(executable, provider);
            seenExecutables.add(executable);
          }
        } else {
          executableBuilder.put(skyname, Runtime.NONE);
        }
      }
      if (a.isSingleArtifact()) {
        // In Skylark only label (not label list) type attributes can have the SingleArtifact flag.
        Artifact artifact = ruleContext.getPrerequisiteArtifact(a.getName(), Mode.DONT_CHECK);
        if (artifact != null) {
          fileBuilder.put(skyname, artifact);
        } else {
          fileBuilder.put(skyname, Runtime.NONE);
        }
      }
      filesBuilder.put(
          skyname, ruleContext.getPrerequisiteArtifacts(a.getName(), Mode.DONT_CHECK).list());

      if (type == BuildType.LABEL && !a.hasSplitConfigurationTransition()) {
        Object prereq = ruleContext.getPrerequisite(a.getName(), Mode.DONT_CHECK);
        if (prereq == null) {
          prereq = Runtime.NONE;
        }
        attrBuilder.put(skyname, prereq);
      } else if (type == BuildType.LABEL_LIST
          || (type == BuildType.LABEL && a.hasSplitConfigurationTransition())) {
        List<?> allPrereq = ruleContext.getPrerequisites(a.getName(), Mode.DONT_CHECK);
        attrBuilder.put(skyname, SkylarkList.createImmutable(allPrereq));
      } else if (type == BuildType.LABEL_KEYED_STRING_DICT) {
        ImmutableMap.Builder<TransitiveInfoCollection, String> builder =
            new ImmutableMap.Builder<>();
        Map original = BuildType.LABEL_KEYED_STRING_DICT.cast(val);
        List<? extends TransitiveInfoCollection> allPrereq =
            ruleContext.getPrerequisites(a.getName(), Mode.DONT_CHECK);
        for (TransitiveInfoCollection prereq : allPrereq) {
          builder.put(prereq, original.get(AliasProvider.getDependencyLabel(prereq)));
        }
        attrBuilder.put(skyname, SkylarkType.convertToSkylark(builder.build(), null));
      } else if (type == BuildType.LABEL_DICT_UNARY) {
        Map prereqsByLabel = new LinkedHashMap<>();
        for (TransitiveInfoCollection target
              : ruleContext.getPrerequisites(a.getName(), Mode.DONT_CHECK)) {
          prereqsByLabel.put(target.getLabel(), target);
        }
        ImmutableMap.Builder<String, TransitiveInfoCollection> attrValue =
            new ImmutableMap.Builder<>();
        for (Map.Entry<String, Label> entry : ((Map<String, Label>) val).entrySet()) {
          attrValue.put(entry.getKey(), prereqsByLabel.get(entry.getValue()));
        }
        attrBuilder.put(skyname, attrValue.build());
      } else {
        throw new IllegalArgumentException(
            "Can't transform attribute " + a.getName() + " of type " + type
            + " to a Skylark object");
      }
    }

    return new SkylarkRuleAttributesCollection(
        skylarkRuleContext,
        ruleContext.getRule().getRuleClass(),
        attrBuilder.build(),
        executableBuilder.build(),
        fileBuilder.build(),
        filesBuilder.build(),
        executableRunfilesbuilder.build());
  }

  private static Info buildSplitAttributeInfo(
      Collection<Attribute> attributes, RuleContext ruleContext) {

    ImmutableMap.Builder<String, Object> splitAttrInfos = ImmutableMap.builder();
    for (Attribute attr : attributes) {

      if (attr.hasSplitConfigurationTransition()) {

        Map<Optional<String>, ? extends List<? extends TransitiveInfoCollection>> splitPrereqs =
            ruleContext.getSplitPrerequisites(attr.getName());

        Map<Object, Object> splitPrereqsMap = new LinkedHashMap<>();
        for (Entry<Optional<String>, ? extends List<? extends TransitiveInfoCollection>> splitPrereq
            : splitPrereqs.entrySet()) {

          Object value;
          if (attr.getType() == BuildType.LABEL) {
            Preconditions.checkState(splitPrereq.getValue().size() == 1);
            value = splitPrereq.getValue().get(0);
          } else {
            // BuildType.LABEL_LIST
            value = SkylarkList.createImmutable(splitPrereq.getValue());
          }

          if (splitPrereq.getKey().isPresent()) {
            splitPrereqsMap.put(splitPrereq.getKey().get(), value);
          } else {
            // If the split transition is not in effect, then the key will be missing since there's
            // nothing to key on because the dependencies aren't split and getSplitPrerequisites()
            // behaves like getPrerequisites(). This also means there should be only one entry in
            // the map. Use None in Skylark to represent this.
            Preconditions.checkState(splitPrereqs.size() == 1);
            splitPrereqsMap.put(Runtime.NONE, value);
          }
        }

        splitAttrInfos.put(attr.getPublicName(), SkylarkDict.copyOf(null, splitPrereqsMap));
      }
    }

    return NativeProvider.STRUCT.create(
        splitAttrInfos.build(),
        "No attribute '%s' in split_attr. Make sure that this attribute is defined with a "
            + "split configuration.");
  }

  @SkylarkModule(
    name = "rule_attributes",
    category = SkylarkModuleCategory.NONE,
    doc = "Information about attributes of a rule an aspect is applied to."
  )
  private static class SkylarkRuleAttributesCollection implements SkylarkValue {
    private final SkylarkRuleContext skylarkRuleContext;
    private final Info attrObject;
    private final Info executableObject;
    private final Info fileObject;
    private final Info filesObject;
    private final ImmutableMap<Artifact, FilesToRunProvider> executableRunfilesMap;
    private final String ruleClassName;

    private SkylarkRuleAttributesCollection(
        SkylarkRuleContext skylarkRuleContext,
        String ruleClassName, ImmutableMap<String, Object> attrs,
        ImmutableMap<String, Object> executables,
        ImmutableMap<String, Object> singleFiles,
        ImmutableMap<String, Object> files,
        ImmutableMap<Artifact, FilesToRunProvider> executableRunfilesMap) {
      this.skylarkRuleContext = skylarkRuleContext;
      this.ruleClassName = ruleClassName;
      attrObject =
          NativeProvider.STRUCT.create(
              attrs,
              "No attribute '%s' in attr. Make sure you declared a rule attribute with this name.");
      executableObject =
          NativeProvider.STRUCT.create(
              executables,
              "No attribute '%s' in executable. Make sure there is a label type attribute marked "
                  + "as 'executable' with this name");
      fileObject =
          NativeProvider.STRUCT.create(
              singleFiles,
              "No attribute '%s' in file. Make sure there is a label type attribute marked "
                  + "as 'single_file' with this name");
      filesObject =
          NativeProvider.STRUCT.create(
              files,
              "No attribute '%s' in files. Make sure there is a label or label_list type attribute "
                  + "with this name");
      this.executableRunfilesMap = executableRunfilesMap;
    }

    private void checkMutable(String attrName) throws EvalException {
      skylarkRuleContext.checkMutable("rule." + attrName);
    }

    @SkylarkCallable(name = "attr", structField = true, doc = ATTR_DOC)
    public Info getAttr() throws EvalException {
      checkMutable("attr");
      return attrObject;
    }

    @SkylarkCallable(name = "executable", structField = true, doc = EXECUTABLE_DOC)
    public Info getExecutable() throws EvalException {
      checkMutable("executable");
      return executableObject;
    }

    @SkylarkCallable(name = "file", structField = true, doc = FILE_DOC)
    public Info getFile() throws EvalException {
      checkMutable("file");
      return fileObject;
    }

    @SkylarkCallable(name = "files", structField = true, doc = FILES_DOC)
    public Info getFiles() throws EvalException {
      checkMutable("files");
      return filesObject;
    }

    @SkylarkCallable(name = "kind", structField = true, doc =
        "The kind of a rule, such as 'cc_library'")
    public String getRuleClassName() throws EvalException {
      checkMutable("kind");
      return ruleClassName;
    }

    public ImmutableMap<Artifact, FilesToRunProvider> getExecutableRunfilesMap() {
      return executableRunfilesMap;
    }

    @Override
    public boolean isImmutable() {
      return skylarkRuleContext.isImmutable();
    }

    @Override
    public void repr(SkylarkPrinter printer) {
      printer.append("<rule collection for " + skylarkRuleContext.ruleLabelCanonicalName + ">");
    }
  }

  @Override
  public boolean isImmutable() {
    return ruleContext == null;
  }

  @Override
  public void repr(SkylarkPrinter printer) {
    if (isForAspect) {
      printer.append("<aspect context for " + ruleLabelCanonicalName + ">");
    } else {
      printer.append("<rule context for " + ruleLabelCanonicalName + ">");
    }
  }

  /**
   * Returns the original ruleContext.
   */
  public RuleContext getRuleContext() {
    return ruleContext;
  }

  @SkylarkCallable(
    name = "default_provider",
    structField = true,
    doc = "Deprecated. Use DefaultInfo instead."
  )
  public static Provider getDefaultProvider() {
    return DefaultInfo.PROVIDER;
  }

  @SkylarkCallable(
      name = "actions",
      structField = true,
      doc = "Functions to declare files and create actions."
  )
  public SkylarkActionFactory actions() {
    return actionFactory;
  }

  @SkylarkCallable(name = "created_actions",
      doc = "For rules with _skylark_testable"
          + " set to True, this returns an "
          + "Actions provider representing all actions "
          + "created so far for the current rule. For all other rules, returns None. "
          + "Note that the provider is not updated when subsequent actions are created, so you "
          + "will have to call this function again if you wish to inspect them. "
          + "

"
          + "This is intended to help write tests for rule-implementation helper functions, which "
          + "may take in a ctx object and create actions on it.")
  public SkylarkValue createdActions() throws EvalException {
    checkMutable("created_actions");
    if (ruleContext.getRule().getRuleClassObject().isSkylarkTestable()) {
      return ActionsProvider.create(
          ruleContext.getAnalysisEnvironment().getRegisteredActions());
    } else {
      return Runtime.NONE;
    }
  }

  @SkylarkCallable(name = "attr", structField = true, doc = ATTR_DOC)
  public Info getAttr() throws EvalException {
    checkMutable("attr");
    return attributesCollection.getAttr();
  }

  @SkylarkCallable(name = "split_attr", structField = true, doc = SPLIT_ATTR_DOC)
  public Info getSplitAttr() throws EvalException {
    checkMutable("split_attr");
    if (splitAttributes == null) {
      throw new EvalException(
          Location.BUILTIN, "'split_attr' is available only in rule implementations");
    }
    return splitAttributes;
  }

  /** See {@link RuleContext#getExecutablePrerequisite(String, Mode)}. */
  @SkylarkCallable(name = "executable", structField = true, doc = EXECUTABLE_DOC)
  public Info getExecutable() throws EvalException {
    checkMutable("executable");
    return attributesCollection.getExecutable();
  }

  /** See {@link RuleContext#getPrerequisiteArtifact(String, Mode)}. */
  @SkylarkCallable(name = "file", structField = true, doc = FILE_DOC)
  public Info getFile() throws EvalException {
    checkMutable("file");
    return attributesCollection.getFile();
  }

  /** See {@link RuleContext#getPrerequisiteArtifacts(String, Mode)}. */
  @SkylarkCallable(name = "files", structField = true, doc = FILES_DOC)
  public Info getFiles() throws EvalException {
    checkMutable("files");
    return attributesCollection.getFiles();
  }

  @SkylarkCallable(name = "workspace_name", structField = true,
      doc = "Returns the workspace name as defined in the WORKSPACE file.")
  public String getWorkspaceName() throws EvalException {
    checkMutable("workspace_name");
    return ruleContext.getWorkspaceName();
  }

  @SkylarkCallable(name = "label", structField = true, doc = "The label of this rule.")
  public Label getLabel() throws EvalException {
    checkMutable("label");
    return ruleContext.getLabel();
  }

  @SkylarkCallable(name = "fragments", structField = true,
      doc = "Allows access to configuration fragments in target configuration.")
  public FragmentCollection getFragments() throws EvalException {
    checkMutable("fragments");
    return fragments;
  }

  @SkylarkCallable(name = "host_fragments", structField = true,
      doc = "Allows access to configuration fragments in host configuration.")
  public FragmentCollection getHostFragments() throws EvalException {
    checkMutable("host_fragments");
    return hostFragments;
  }

  @SkylarkCallable(name = "configuration", structField = true,
      doc = "Returns the default configuration. See the "
          + "configuration type for more details.")
  public BuildConfiguration getConfiguration() throws EvalException {
    checkMutable("configuration");
    return ruleContext.getConfiguration();
  }

  @SkylarkCallable(name = "host_configuration", structField = true,
      doc = "Returns the host configuration. See the "
          + "configuration type for more details.")
  public BuildConfiguration getHostConfiguration() throws EvalException {
    checkMutable("host_configuration");
    return ruleContext.getHostConfiguration();
  }

  @SkylarkCallable(name = "coverage_instrumented",
    doc = "Returns whether code coverage instrumentation should be generated when performing "
        + "compilation actions for this rule or, if target is provided, the rule "
        + "specified by that Target. (If a non-rule or a Skylark rule Target is provided, this "
        + "returns False.) Checks if the sources of the current rule (if no Target is provided) or"
        + "the sources of Target should be instrumented based on the --instrumentation_filter and"
        + "--instrument_test_targets config settings. "
        + "This differs from coverage_enabled in the "
        + "configuration, which notes whether coverage data collection is enabled for the "
        + "entire run, but not whether a specific target should be instrumented.",
    parameters = {
      @Param(
          name = "target",
          type = TransitiveInfoCollection.class,
          defaultValue = "None",
          noneable = true,
          named = true,
          doc = "A Target specifying a rule. If not provided, defaults to the current rule.")
    })
  public boolean instrumentCoverage(Object targetUnchecked) throws EvalException {
    checkMutable("coverage_instrumented");
    BuildConfiguration config = ruleContext.getConfiguration();
    if (!config.isCodeCoverageEnabled()) {
      return false;
    }
    if (targetUnchecked == Runtime.NONE) {
      return InstrumentedFilesCollector.shouldIncludeLocalSources(ruleContext);
    }
    TransitiveInfoCollection target = (TransitiveInfoCollection) targetUnchecked;
    return (target.getProvider(InstrumentedFilesProvider.class) != null)
        && InstrumentedFilesCollector.shouldIncludeLocalSources(config, target);
  }

  @SkylarkCallable(name = "features", structField = true,
      doc = "Returns the set of features that are enabled for this rule."
  )
  public ImmutableList<String> getFeatures() throws EvalException {
    checkMutable("features");
    return ImmutableList.copyOf(ruleContext.getFeatures());
  }

  @SkylarkCallable(name = "bin_dir", structField = true,
      doc = "The root corresponding to bin directory.")
  public Root getBinDirectory() throws EvalException {
    checkMutable("bin_dir");
    return getConfiguration().getBinDirectory(ruleContext.getRule().getRepository());
  }

  @SkylarkCallable(name = "genfiles_dir", structField = true,
      doc = "The root corresponding to genfiles directory.")
  public Root getGenfilesDirectory() throws EvalException {
    checkMutable("genfiles_dir");
    return getConfiguration().getGenfilesDirectory(ruleContext.getRule().getRepository());
  }

  @SkylarkCallable(structField = true, doc = OUTPUTS_DOC)
  public ClassObject outputs() throws EvalException {
    checkMutable("outputs");
    if (outputsObject == null) {
      throw new EvalException(Location.BUILTIN, "'outputs' is not defined");
    }
    return outputsObject;
  }

  @SkylarkCallable(structField = true,
      doc = "Returns rule attributes descriptor for the rule that aspect is applied to."
          + " Only available in aspect implementation functions.")
  public SkylarkRuleAttributesCollection rule() throws EvalException {
    checkMutable("rule");
    if (!isForAspect) {
      throw new EvalException(
          Location.BUILTIN, "'rule' is only available in aspect implementations");
    }
    return ruleAttributesCollection;
  }

  @SkylarkCallable(structField = true,
      name = "aspect_ids",
      doc = "Returns a list ids for all aspects applied to the target."
      + " Only available in aspect implementation functions.")
  public ImmutableList<String> aspectIds() throws EvalException {
    checkMutable("aspect_ids");
    if (!isForAspect) {
      throw new EvalException(
          Location.BUILTIN, "'aspect_ids' is only available in aspect implementations");
    }

    ImmutableList.Builder<String> result = ImmutableList.builder();
    for (AspectDescriptor descriptor : ruleContext.getAspectDescriptors()) {
      result.add(descriptor.getDescription());
    }
    return result.build();
  }

  @SkylarkCallable(
    structField = true,
    doc = "Dictionary (String to String) of configuration variables."
  )
  public SkylarkDict<String, String> var() throws EvalException {
    checkMutable("var");
    return makeVariables;
  }

  @SkylarkCallable(structField = true, doc = "Toolchains required for this rule.")
  public SkylarkIndexable toolchains() throws EvalException {
    checkMutable("toolchains");
    return ruleContext.getToolchainContext().getResolvedToolchainProviders();
  }

  @Override
  public String toString() {
    return ruleLabelCanonicalName;
  }

  @SkylarkCallable(doc = "Splits a shell command to a list of tokens.", documented = false)
  public SkylarkList<String> tokenize(String optionString) throws FuncallException, EvalException {
    checkMutable("tokenize");
    List<String> options = new ArrayList<>();
    try {
      ShellUtils.tokenize(options, optionString);
    } catch (TokenizationException e) {
      throw new FuncallException(e.getMessage() + " while tokenizing '" + optionString + "'");
    }
    return SkylarkList.createImmutable(options);
  }

  @SkylarkCallable(
    doc =
        "Expands all references to labels embedded within a string for all files using a mapping "
          + "from definition labels (i.e. the label in the output type attribute) to files. "
          + "Deprecated.",
    documented = false
  )
  public String expand(
      @Nullable String expression, SkylarkList<Object> artifacts, Label labelResolver)
      throws EvalException, FuncallException {
    checkMutable("expand");
    try {
      Map<Label, Iterable<Artifact>> labelMap = new HashMap<>();
      for (Artifact artifact : artifacts.getContents(Artifact.class, "artifacts")) {
        labelMap.put(artifactsLabelMap.get(artifact), ImmutableList.of(artifact));
      }
      return LabelExpander.expand(expression, labelMap, labelResolver);
    } catch (NotUniqueExpansionException e) {
      throw new FuncallException(e.getMessage() + " while expanding '" + expression + "'");
    }
  }

  boolean isForAspect() {
    return isForAspect;
  }

  @SkylarkCallable(
    name = "new_file",
    doc =
        "DEPRECATED. Use ctx.actions.declare_file.
"
            + "Creates a file object with the given filename, in the current package. "
            + DOC_NEW_FILE_TAIL,
    parameters = {
      @Param(
        name = "filename",
        type = String.class,
        doc = "The path of the new file, relative to the current package."
      )
    }
  )
  public Artifact newFile(String filename) throws EvalException {
    SkylarkRuleImplementationFunctions.checkDeprecated(
        "ctx.actions.declare_file", "ctx.new_file", null, skylarkSemantics);
    checkMutable("new_file");
    return actionFactory.declareFile(filename, Runtime.NONE);
  }

  // Kept for compatibility with old code.
  @SkylarkCallable(documented = false)
  public Artifact newFile(Root root, String filename) throws EvalException {
    checkMutable("new_file");
    return ruleContext.getPackageRelativeArtifact(filename, root);
  }

  @SkylarkCallable(
      name = "new_file",
      doc =
          "Creates a new file object in the same directory as the original file. "
              + DOC_NEW_FILE_TAIL,
      parameters = {
        @Param(
          name = "sibling_file",
          type = Artifact.class,
          doc = "A file that lives in the same directory as the newly created file."
        ),
        @Param(
          name = "basename",
          type = String.class,
          doc = "The base name of the newly created file."
        )
      }
    )
  public Artifact newFile(Artifact baseArtifact, String newBaseName) throws EvalException {
    SkylarkRuleImplementationFunctions.checkDeprecated(
        "ctx.actions.declare_file", "ctx.new_file", null, skylarkSemantics);
    checkMutable("new_file");
    return actionFactory.declareFile(newBaseName, baseArtifact);
  }

  // Kept for compatibility with old code.
  @SkylarkCallable(documented = false)
  public Artifact newFile(Root root, Artifact baseArtifact, String suffix) throws EvalException {
    checkMutable("new_file");
    PathFragment original = baseArtifact.getRootRelativePath();
    PathFragment fragment = original.replaceName(original.getBaseName() + suffix);
    return ruleContext.getDerivedArtifact(fragment, root);
  }

  @SkylarkCallable(
    name = "experimental_new_directory",
    documented = false,
    parameters = {
      @Param(name = "name", type = String.class),
      @Param(
        name = "sibling",
        type = Artifact.class,
        defaultValue = "None",
        noneable = true,
        named = true
      )
    }
  )
  public Artifact newDirectory(String name, Object siblingArtifactUnchecked) throws EvalException {
    SkylarkRuleImplementationFunctions.checkDeprecated(
        "ctx.actions.declare_directory", "ctx.experimental_new_directory", null, skylarkSemantics);
    checkMutable("experimental_new_directory");
    return actionFactory.declareDirectory(name, siblingArtifactUnchecked);
  }

  @SkylarkCallable(documented = false)
  public NestedSet<Artifact> middleMan(String attribute) throws EvalException {
    checkMutable("middle_man");
    return AnalysisUtils.getMiddlemanFor(ruleContext, attribute, Mode.HOST);
  }

  @SkylarkCallable(documented = false)
  public boolean checkPlaceholders(String template, SkylarkList<Object> allowedPlaceholders)
      throws EvalException {
    checkMutable("check_placeholders");
    List<String> actualPlaceHolders = new LinkedList<>();
    Set<String> allowedPlaceholderSet =
        ImmutableSet.copyOf(allowedPlaceholders.getContents(String.class, "allowed_placeholders"));
    ImplicitOutputsFunction.createPlaceholderSubstitutionFormatString(template, actualPlaceHolders);
    for (String placeholder : actualPlaceHolders) {
      if (!allowedPlaceholderSet.contains(placeholder)) {
        return false;
      }
    }
    return true;
  }

  @SkylarkCallable(doc =
        "Deprecated. Use ctx.var to access the variables instead.
"
      + "Returns a string after expanding all references to \"Make variables\". The variables "
      + "must have the following format: $(VAR_NAME). Also, $$VAR_NAME"
      + " expands to $VAR_NAME. Parameters:"
      + "

The name of the attribute (string). It's only used for error "
      + "reporting.
\n"
      + "
The expression to expand (string). It can contain references to "
      + "\"Make variables\".
\n"
      + "
A mapping of additional substitutions (dict of string : "
      + "string).

\n"
      + "Examples:"
      + "
\n"
      + "ctx.expand_make_variables(\"cmd\", \"$(MY_VAR)\", {\"MY_VAR\": \"Hi\"})  # == \"Hi\"\n"
      + "ctx.expand_make_variables(\"cmd\", \"$$PWD\", {})  # == \"$PWD\"\n"
      + "
"
      + "Additional variables may come from other places, such as configurations. Note that "
      + "this function is experimental.")
  public String expandMakeVariables(String attributeName, String command,
      final Map<String, String> additionalSubstitutions) throws EvalException {
    checkMutable("expand_make_variables");
    ConfigurationMakeVariableContext makeVariableContext =
        new ConfigurationMakeVariableContext(
            // TODO(lberki): This should be removed. But only after either verifying that no one
            // uses it or providing an alternative.
            ruleContext.getMakeVariables(ImmutableList.of(":cc_toolchain")),
            ruleContext.getRule().getPackage(),
            ruleContext.getConfiguration()) {
          @Override
          public String lookupVariable(String variableName) throws ExpansionException {
            if (additionalSubstitutions.containsKey(variableName)) {
              return additionalSubstitutions.get(variableName);
            } else {
              return super.lookupVariable(variableName);
            }
          }
        };
    return ruleContext.getExpander(makeVariableContext).expand(attributeName, command);
  }

  FilesToRunProvider getExecutableRunfiles(Artifact executable) {
    return attributesCollection.getExecutableRunfilesMap().get(executable);
  }

  @SkylarkCallable(
    name = "info_file",
    structField = true,
    documented = false,
    doc =
        "Returns the file that is used to hold the non-volatile workspace status for the "
            + "current build request."
  )
  public Artifact getStableWorkspaceStatus() throws InterruptedException, EvalException {
    checkMutable("info_file");
    return ruleContext.getAnalysisEnvironment().getStableWorkspaceStatusArtifact();
  }

  @SkylarkCallable(
    name = "version_file",
    structField = true,
    documented = false,
    doc =
        "Returns the file that is used to hold the volatile workspace status for the "
            + "current build request."
  )
  public Artifact getVolatileWorkspaceStatus() throws InterruptedException, EvalException {
    checkMutable("version_file");
    return ruleContext.getAnalysisEnvironment().getVolatileWorkspaceStatusArtifact();
  }

  @SkylarkCallable(
    name = "build_file_path",
    structField = true,
    documented = true,
    doc = "Returns path to the BUILD file for this rule, relative to the source root."
  )
  public String getBuildFileRelativePath() throws EvalException {
    checkMutable("build_file_path");
    Package pkg = ruleContext.getRule().getPackage();
    Root root = Root.asSourceRoot(pkg.getSourceRoot(),
        pkg.getPackageIdentifier().getRepository().isMain());
    return pkg.getBuildFile().getPath().relativeTo(root.getPath()).getPathString();
  }
}

redpajama_set_name: RedPajamaGithub


A singular voice of reason in an era defined by bitter politics and economic uncertainty, Joseph E. Stiglitz has time and again diagnosed America's greatest economic challenges, from the Great Recession and its feeble recovery to the yawning gap between the rich and the poor. gathers his most provocative reflections to date on the subject of inequality. As Stiglitz ably argues, a healthy economy and a fairer democracy are within our grasp if we can put aside misguided interests and ideologies and abandon failed policies. Opening with the essay that gave the Occupy Movement its slogan, "We are the 99%," later essays in reveal equality of opportunity as a national myth, show that today's outsized inequality is a matter of choice, and explain reforms that would spur higher growth, more opportunity, and greater equality.


text:
DutchReview's best of January: these are the articles you don't want to miss!
Image: Pexels/Pixabay
If you're reading this – congratulations! You've successfully navigated the first month of 2020 (and to think the Mayans thought we wouldn't make it to 2012!).
So how has the first month been? Well, we saw coronavirus rear its ugly head and make its way to Europe, although thankfully not the Dutch streets.
Speaking of Dutch streets, innovation is already hitting new heights this year. My personal favourite city Utrecht revealed plans for a new completely car-free neighbourhood, and it looks glorious! Meanwhile, if you're in the nation's capital, a TU Delft architect has unveiled his plans for a stunning Living Bridge right over the river IJ, filled with greenery, apartments, and cycleways.
If that's not your style, a quick getaway could be in the works. How does the far north sound? Rumour has it a new train will launch all the way to Scandinavia – gamechanger! It's still in the works though, but if you need something a little sooner maybe it's time to pop over to London for a cup of tea?
You'll need something to read on the train though, so we've dug up some our best articles from January just for you. Enjoy!
7 things the Dutch don't talk about
Image: Rudy and Peter Skitterians/Pixabay
There are some things the Dutch don't talk about that they really really should. What on EARTH is in bitterballen? Why are we a tax haven? This article ranges from the absence of curtains to the unspoken presence of colonialism, but, for your information, it does not talk about Sinterklaas's problematic helper, which the Dutch definitely talk about more than enough.
DutchReview investigates the tourism crisis in Amsterdam (video inside!)
Like many famous locations around the globe, Amsterdam has been hit hard by over-tourism. From tourists peeing in canals to people being disrespectful towards local etiquette, it is clear that Amsterdam needs to find solutions to curb the influx of tourists coming into the city. Our team has gone in-depth to try to understand better this phenomena, so check our very own DutchReview take on the tourism crisis in Amsterdam.
Lunch in the Netherlands: culture, bread and society
mage: Takeaway/Wikimedia Commons
It's your first day at work as an international, and you are about to have lunch with your Dutch colleagues. Especially if you come from a Southern European context, you reach the cafeteria only to be shocked that what is on the menu is, well, just a sandwich. Not only is it just a sandwich, but it doesn't even contain that many ingredients – plus it's weirdly overpriced.
6 things we're looking forward to in 2020 in the Netherlands
2020 is an exciting year for all sorts of reasons. It's the first year of a new decade, it's pleasingly aesthetic to the eye, and you can make jokes about 2020 vision like never before. But here in the Netherlands, we have six very specific reasons to be very excited about 2020.
New to the Netherlands? 7 reasons why bunq is the perfect bank for expats
Image: bunq
What is bunq, and why is this bank special? bunq is on a mission to change the banking industry. Unlike most banks, which will happily offer you a loan, bunq encourages its customers to save up for whatever they want to buy. It refuses to pay out huge bonuses to its staff— which is also unusual in the banking sector. And, finally, it's a completely digital bank, so there is no need for you to ever go to a physical building. Instead, you can do everything you need to do from the comfort of your phone screen- including sign up.
5 best German cities for a weekend escape from the Netherlands
Image: 46173/Pixabay
The winter can be harsh in the Netherlands, especially if you're one of those fierce Dutchies who battle with the cold day in and day out and continue to cycle instead of catch public transport. All that hard work deserves some reward, no? So how about booking a weekend escape!
Wild swimming in the Netherlands and why you should dive in
Wild swimming is exactly that; swimming in natural bodies of water and getting close to nature. I was surprised how addicting it became, despite not describing myself as a water person. Wild swimmers love the spontaneity and invigoration of plunging into an icy body of water and there are many testimonies which advocate for the healing effects of wild swimming.
Exploring Tilburg: a trip to all the hidden gems of 013
Source: Ticket to Tilburg
Tilburg, in the southern province of Noord Brabant, is a super cool, up-and-coming city with so much to offer. A burgeoning music scene, a thriving cultural sector, and beautiful nature in abundance: exploring this Dutch town should be on everyone's to-do list. But often, Tilburg appears on "Hidden Gems of the Netherlands" lists because most people flock to the Randstad when they are here as tourists. Come on the off-the-beaten-track with us! Let's explore the hidden gems of Tilburg!
The complete and unadulterated guide to sex in the Netherlands
What are Dutch attitudes towards sex, how are they educated in schools and really, again, what's up with the red-light districts? How low do the lowlanders drop it (and is it hot)?
Time to find out in our unofficial, but still kind of scientific, guide to sex in the Netherlands.
7 winter escapes from the Netherlands by train
Image: Pixabay/Pexels.
Ugh, January. It makes everyone want to escape their current lives, whether by resolving to be a better person or by physically travelling away from their usual abodes. In this article, we allow you to do both: travel by train, to minimise your impact on the planet, and explore some gorgeous European cities. We have chosen seven winter escapes from the Netherlands by train that you can enjoy in 2020.
What do you think of these ten great articles from DutchReview this month? Think we missed one from the list? Got a great idea for something you want to be covered next month? Let us know in the comments below!
Previous articleThe New Years firework war zone might be banned starting from this year
Next articleDutch ministry says "don't travel to Hubei province" as KLM cancels all flights to China

redpajama_set_name: RedPajamaCommonCrawl


text:
Whip Smart
SADE:
By Maurice Lever
Translated by Arthur Goldhammer
Farrar, Straus and Giroux, 626 pp.
The lives of saints may be morally edifying and spiritually uplifting, but it's the lives of sinners that make for the most engrossing biographies. And what better subject than Euroculture's most notorious and unrepentant degenerate, the man who lent his name to the carnal pleasure of cruelty, Donatien-Alphonse-Francois, Marquis de Sade?
It should be said from the outset that, as repellent as de Sade's libidinous perversions remain, Maurice Lever has spun from the facts of his life a masterful biography. At one and the same time, the book is a nuanced portrait of the complex individual behind the monstrous caricature; a panoramic boudoir's-eye view of the most tumultuous period in France's history, from the fall of the ancien regime through the Terror to the rise of Napoleon; a searing discourse on the evanescence of morality and the hard realities of pathology; and a page-turner as compelling as any best-selling pot-boiler or bodice-ripper on the market.
The book is built from the voluminous correspondence that issued from de Sade's pen and that swirls about him throughout his long life, a good deal of which, through the graces of the marquis's descendants, Lever brings to light for the first time. There are letters to and from his father, his wife, his mother-in-law, his notary, his legions of mistresses. There are police records, court transcripts, ministerial memos, reports on clandestine surveillance, memoirs of his various warders.
And lest one blanch at the thought of wading through pages of antiquated 18th-century prose, be assured that everyone Lever cites is fiendishly literate, from the loftiest minister to the lowliest asylum inmate, and none more so than the author of Justine himself.
From the beginning, the dashing marquis was trouble incarnate. Separated from his mother at the age of five, and already every inch the over-indulged fanfaron, he was raised by his uncle, the licentious Abbé de Sade, and then by Jesuits, who cultivated in him his love of the theatre and the theatrical, even as they enforced their discipline via the rod.
Does this in itself account for his adult deviancies? Lever, to his credit, refrains from faddish psychoanalysis. It is enough that we know where de Sade's passions lay; the task is to understand the man they created, not what created them.
His father, the Comte de Sade, had been the first of his line to leave the family seat in Provence and seek a career amid the finery and treachery of the Parisian court. But the father, like the son, was too much a libertine, a spendthrift and a hothead to truly prosper. By the time Donatien approached manhood, the comte had already smudged the family name and squandered a good deal of his fortune.
Not that the young marquis much cared. As an officer in the King's Carabineers, he distinguished himself by his bravery on the field and his rakishness off. Fearful for his son's prospects, the father married him off advantageously, albeit against his will, to Mlle. de Montreuil, the daughter of a wealthy and well-connected family. Though the couple would come to be passionately devoted to one another – his wife would stand by him throughout his disgrace, separating only after a lifetime of heartache – the marriage set the stage for the mother of all mother-in-law enmities.
His marriage failed to curtail his philandering, but de Sade never inflicted his more profane tastes on his wife or his numberless high-born mistresses. It was what he did with whores and servant girls that led to his infamy and eventual arrest. In 1763, a mere five months after his marriage, he was charged with forcing a prostitute to masturbate with a statue of Christ. Five years later, he was charged with abducting and torturing a beggar woman, an incident that made his name synonymous with aristocratic debauchery.
Though he managed to wriggle off the hook by virtue of his caste and the aid of a mother-in-law desperate to quiet the scandal with hush money, neither brush with disaster cooled his criminal ardor. By 1771 he was having an affair with his sister-in-law, and the following year he was found guilty of sodomizing, whipping and poisoning with Spanish fly two whores in Marseilles. The conviction carried a sentence of death, a situation serious enough for him to take it on the lam to Sardinia.
By this point, however, de Montreuil, his ferociously formidable mother-in-law, had had enough. She began a life-long campaign to have him locked away for the rest of his days by persuading the king of Sardinia to toss him in the citadel of Miolans. This would set in motion a cycle of daring escapes, interludes of debauchery, exile and recapture that would culminate in a 12-year period of imprisonment, from 1778 to 1790, much of it in the Bastille.
Ironically, it was his presence in the Bastille – where, with little to occupy him but his pornographic imagination, he first began to sketch his infamous works – that made the ignoble nobleman a patriot of the Revolution.
On July 2, 1789, while trouble brewed outside on the streets of Paris, de Sade was denied his usual walk in the prison courtyard. In one of his characteristic rages, he took a funnel used to empty his chamber pot into the moat and turned it into a megaphone, screaming from his prison window that the prisoners' throats were being slit, gathering a crowd and exhorting them to storm the Bastille. Ten days later they did just that, but not before de Sade had been spirited to a different jail.
Released by the Revolution, he feigned patriotism so well that he eventually became the president of his Parisian sector, but he had no stomach for the Terror. His fantasies may have been hideous, but as Lever makes clear, the brutality of bureaucratic minds was anathema to him. He even used his position to spare the life of the person he despised most in the world: his mother-in-law, arrested in the witch hunt.
It couldn't last, however, and eventually de Sade himself was arrested, escaping the guillotine by a whisper only when Robespierre's head fell. Free again, but impoverished, he tried to make a living with his quill. When his conventional writing failed, he turned to publishing his pornography anonymously.
But in the puritanism of the Napoleonic reign, he was "outed" as the author of Justine and Juliette and confined to the Charenton lunatic asylum outside Paris, thus earning the distinction of having been imprisoned by the monarchy, the Revolution and Napoleon.
It was at Charenton that he engineered his last scandale, forming his wretched fellow inmates into a theatrical ensemble and mounting plays for the voyeuristic amusement of high society.
More than simply a species of freak, de Sade stands in this remarkable biography at the fulcrum of a turning point in history: a feudal nobleman at the end of feudalism, a libertine at the emergence of libertarian rhetoric, a media celebrity at the dawn of a truly populist press, a prisoner of desire just at the moment when individual desire was becoming a factor on the social stage.
It has been said before, but it's worth repeating: de Sade merits our attention because he is modernity in at least one of its guises.
Montreal Gazette October 16, 1993
Previous: Marshall McLuhan
Next: Conrad Black


text:
Rollo in London By: Jacob Abbott (1803-1879)
ROLLO IN LONDON
JACOB ABBOTT.
BOSTON:
PUBLISHED BY TAGGARD AND THOMPSON
M DCCC LXIV.
JACOB ABBOTT,
In the Clerk's Office of the District Court of the District of Massachusetts.
STEREOTYPED AT THE BOSTON STEREOTYPE FOUNDRY.
RIVERSIDE, CAMBRIDGE:
PRINTED BY H. O. HOUGHTON
[Illustration: LONDON BRIDGE.]
[Illustration: Rollo's Tour in Europe Taggard & Thompson. Publishers Boston.]
ROLLO'S TOUR IN EUROPE.
ORDER OF THE VOLUMES
ROLLO ON THE ATLANTIC. ROLLO IN PARIS. ROLLO IN SWITZERLAND. ROLLO IN LONDON. ROLLO ON THE RHINE. ROLLO IN SCOTLAND. ROLLO IN GENEVA. ROLLO IN HOLLAND. ROLLO IN NAPLES. ROLLO IN ROME.
PRINCIPAL PERSONS OF THE STORY.
ROLLO; twelve years of age.
MR. and MRS. HOLIDAY; Rollo's father and mother, travelling in Europe.
THANNY; Rollo's younger brother.
JANE; Rollo's cousin, adopted by Mr. and Mrs. Holiday.
MR. GEORGE; a young gentleman, Rollo's uncle.
I. CITY AND TOWN, 13
II. LONDON BRIDGE, 20
III. THE RIVER, 45
IV. THE POLICEMAN, 55
V. LODGINGS, 66
VI. BREAKFAST, 74
VII. WESTMINSTER ABBEY, 80
VIII. CALCULATIONS, 98
IX. ST. PAUL'S, 107
X. THE DOME OF ST. PAUL'S, 126
XI. THE ARISTOCRACY, 142
XII. A MISFORTUNE, 159
XIII. PHILOSOPHY, 164
XIV. THE DOCKS, 173
XV. THE EMIGRANTS, 191
XVI. THE TUNNEL AND THE TOWER, 214
ENGRAVINGS.
LONDON BRIDGE, FRONTISPIECE.
THE PARK, 12
MAP OF LONDON, 15
THE FIRST RAGGED SCHOOL, 43
SHOOTING THE BRIDGE, 50
THE ARREST, 58
BREAKFAST, 78
GROUND PLAN OF WESTMINSTER ABBEY, 84
ST. PAUL'S, 119
THE WHISPERING GALLERY, 128
THE LOSS MADE GOOD, 171
SAVED, 176
PLEASANT WEATHER, 196
THE STORM, 198
THE WRECK, 201
SHOPPING IN THE TUNNEL, 220
[Illustration: THE PARK. (See Chap. XI.)]
ROLLO IN LONDON.
CHAPTER I.
CITY AND TOWN.
"Which London shall we visit first?" said Mr. George to Rollo.
"Why," rejoined Rollo, surprised, "are there two of them?"
"Yes," said Mr. George. "We may almost say there are two of them. Or, at any rate, there are two heads to the monster, though the immense mass forms but one body."
While Mr. George was saying these words Rollo had been standing on the step of the railway car and looking in at the window towards his uncle George, who was inside. Just at this time, however, the conversation was interrupted by the sound of the bell, denoting that the train was about to start... Continue reading book >>
Wikipedia – Jacob Abbott
Wikipedia – Rollo in London


The Faery Cairn is a well into the living memory of the land, a meeting point of human and Faery contact & communion, a living classroom and an activated energy center for raising the original Edenic vision of the Earth for Healing and Restoration of our planet.
The Faery Cairn is is a place of offering to the Spirits of the Land and a portal for the Faery and Spirits of the land to interact, co-create, and communicate with humanity and the creatures of this realm. This is a deeply spiritual workshop walking in the footsteps of the ancients giving devoted labor and enduring form to original alliance between humanity and the Cousins, Co-walkers and companions known as the Shining Ones, the Good Neighbors, the Faery.
This event is a rare opportunity to learn the lore, history and design of the HOB Faery Seership stone cairn. This is the first Cairn raised by Orion in over 10 years and this one is a large one, built with an actual ancient well with live water at its center. Usually, the well part of the Cairn is symbolic and energetic but this one is actual which makes it very special and very powerful. Most Cairns are more like piles of stones, but this one has a specific design. There are specific techniques and practices associated with building, activating, empowering and using it. Over the last 25 years Orion has lead the construction of these cairns in Atlanta GA., Artemis PA., Norfolk VA, Beltsville MD, Portland OR, and St. Petersburg FL – each of varying sizes and states of permanence.
2) The physical construction of the Cairn including any last minute preparation of the soil, tamping the soil and adjustments to the contour of the landscape then forming the parts of the Cairn: (a) The rising Crown of the Queen; (b) the Well of Knowing the Faery Well) (c) the Four Roads and the Roots of the Inverted Tree; and (c) the Four Sentinel Stones as gates of Stellar, Lunar, Solar and Planetary mysteries, the 4 holy winds,the 4 provinces, haunted winds etc. The western stone is the Faery Gate to the Stars.
4) Processing and integrating the experiences of the day and a brief teaching on the uses of the Faery Cairn. Then feasting and celebrating our work and the community of co-creation…human and Faery!
This is a semi private event, open to HOB Faery Seership students as well as GMDO students and alumni.
We ask that participants bring something to contribute to a potluck dinner feast!
Also, w ork gloves, an extra wheelbarrow, and biodegradable offerings for the Faery and Dreamland.
Next post Planning for the end of life?


For almost 150 years, UC has expanded the horizons of what they know about themselves and their world. Their campuses are routinely ranked among the best in the world, but their reach extends beyond campus borders.
Their students, faculty, staff and alumni exchange ideas, make advancements and unlock the secrets and mysteries of the universe every day. They engage with their local governments, serve California schools, protect the environment and push the boundaries of space.
View all online courses, live webinars, and/or on-demand webinars from the University of California by scrolling down and exploring the table below.


Join Lizzie's Fan Club & Email List!
You are here: Home / News / HAPPY INTERNATIONAL WOMEN'S DAY!
Happy INTERNATIONAL WOMEN'S DAY! After my all-girl assembly at Keller Middle School yesterday, I am feeling extra empowered. Ladies, this is YOUR time to SHINE. You are so strong and beautiful and fierce. Be proud to live your life LIKE A GIRL!


Aluminium in vaccines, in our food storage containers and personal products.
Why is Aluminum Exposure Harmful?
It makes sense, research shows aluminum can produce toxic, oxidative stress in the brain and a brain autopsy study of elderly persons found them to have aluminum levels 20+ times higher than a middle-aged group.   The Agency for Toxic Substances and Disease Registry, part of the U.S. Department of Health and Human Services, recognizes aluminum as one of several metals known to affect the neurological system.  As far as aluminum is concerned, the supreme brain-health concern is Alzheimer's disease.
Earn Health Freedom Idaho points!
Earn your spot on the leaderboard.
You earned Health Freedom Idaho points!
You're on your way to the top of the leaderboard!


text:
Ford's Bob Taenaka Looks At EVs' Big Picture
August 27, 2019 • Alternative Energy, Automotive, Battery/Energy Storage, Electric & Hybrid Vehicle Technology Expo – Novi, MI, Science, Sustainability, Technology
Bob Taenaka has been directly involved in every one of Ford's electrified vehicles to date. His Keynote address at The Battery Show will highlight how battery technology is helping to lead the EV market. (Image source: Ford Motor Company)
Bob Taenaka is a Senior Technical Leader in Electrified Vehicle Battery Cells and Systems at Ford Motor Company, responsible for battery cell technology and battery system performance in support of Ford's present and near-term future production hybrid and electric vehicles.
"I'm looking at the big picture—what are the demands of electrified vehicles for the future. Having the electrified vehicles that people really want," Taenaka told Design News. "It's the technology and capability that will pull the vehicles. These are advanced electrified vehicles and not regulatory push that says we need to reduce emissions and increase fuel economy and less dependence on fossil fuels," he added.
Taenaka will provide one of the Keynote Addresses at The Battery Show and Electric & Hybrid Vehicle Technology Expo 2019, in Novi, Michigan. His talk, titled "Gateways to the Future: Delivering on Electrified Vehicle Demands" will be presented on Tuesday, September 10th.
Sitting on a Precipice
"It's actually quite exciting for me because I have been at Ford since 2001, so I've seen electrified vehicles expand to where we are right on a precipice where electric vehicles will really take off in the next decade," said Taenaka. Prior to joining Ford in 2001, Taenaka spent 18 years with Hughes Space & Communications, serving as battery engineer for the Galileo Probe mission to Jupiter, was principal investigator or program manager for several nickel-hydrogen and sodium-sulfur battery development efforts, and held responsibility for in-orbit support on battery usage for satellite customers and ground stations. Rocket science, in other words.
Moving into electrification of transportation will take several steps. "There is a nuance," Taenaka told us. "There are electric vehicles that are either battery or fuel cell—fully electrically powered. Then there are electrified vehicles which include those, but also include hybrid-type vehicles where you have a gas engine and an electric motor," he said.
"A lot of industry experts have different projections. In the next ten years, I'd say, some say that electric vehicles may be 25-50% of the total vehicle market," Taenaka explained to Design News. "As of today, I think the number is maybe around 1-3%, in that ballpark. The battery electric vehicle and also the full hybrid and plug-in hybrids and mild hybrids—a lot of these are geared to help reduce the level of CO2 emissions generated from the transportation sector. I'd say that's where the regulatory push comes from. So not only the push but also the pull from having the performance."
Pull as Important as Push
Taenaka thinks that having the right kind of vehicles will create this consumer-generated pull. "Having an enhanced capability will mean that people will want to purchase these advanced electrified vehicles—not only for the sense of environmental responsibility for the customer that's driving the vehicle, but also having the advanced technology that makes their drive even more enjoyable and exciting," he said.
Many think that reaching significant market penetration for EVs will only occur when there is cost parity with internal combustion engine vehicles. "The combination of vehicle range and vehicle cost has been one of the big obstacles to lot of people wanting to get electric vehicles in the past. The market is increasing, but to get to the level of market where states such as California are mandating, requires the vehicle costs, in particular the battery cost be reduced significantly. There have been tremendous strides that have taken place in the last 20 years on battery technology, and battery cost. Having vehicle cost parity, or even lower vehicle cost compared to conventional internal combustion engine vehicles, that's where you are going to have a big uptick in customer demand," Taenaka told us.
"Having similar range and similar or lower cost, equal or better capability and features—I think that's really what drives the market," he added.
"Since I started at Ford, the vehicle range has always been dictated by how much battery you can fit into the vehicle. And that's another change I see happening in the next decade or so—the energy density of battery cell technology is going to be at the point where the vehicle designs will no longer be constrained by packaging the battery. We'll start making the battery a little bit smaller and start providing other features that will fit into the space that is presently filled up by the batteries." "It's the combination of the range, the charging time, and the battery cost and dimensions," said Taenaka.
Decoupling Demand From the Cost of Oil
Because Taenaka and has played a key role in battery development for each of Ford's production electrified vehicle models launched to date, he has seen the ups and downs in the demand for EVs. "Customer desires are highly dependent upon a number of external factors. In the past, gas prices have tremendously driven the selection of big trucks and SUVs versus smaller fuel-efficient cars. When we had spikes in gas prices, consumers went with smaller cars so that their transportation costs would not be excessive. I think today people are becoming more immune to the fluctuations in gas prices and so we are tending to see more customers wanting larger vehicles," he said.
Interestingly, because oil prices have only a secondary effect on the price of electricity, wider-spread adoption of EVs, particularly larger SUVs and pickup trucks that are on several carmaker horizons, may push buyers further away from small cars. Renewable energy might disconnect the size of the vehicle you choose from the cost of gasoline. "Geothermal, wind, and solar are not so prone to (oil) price fluctuations. I would expect the price (of electricity) to be much more stable than you would ever have with fossil fuels. Having electric vehicles plays right into that."
Taenaka's Keynote Addresses, titled "Gateways to the Future: Delivering on Electrified Vehicle Demands" will cover many of these topics in greater detail. The talk will be presented on Tuesday, September 10th at The Battery Show and Electric & Hybrid Vehicle Technology Expo 2019, in Novi, Michigan.
Senior Editor Kevin Clemens has been writing about energy, automotive, and transportation topics for more than 30 years. He has masters degrees in Materials Engineering and Environmental Education and a doctorate degree in Mechanical Engineering, specializing in aerodynamics. He has set several world land speed records on electric motorcycles that he built in his workshop.
Battery, EV/HV, & Stationary Power All in One Place.
Learn everything you need to know at our in-depth conference program with 70 technical sessions in eight tracks covering topics on battery, electric & hybrid vehicles, and stationary power technologies.
The Battery Show. Sept. 10-12, 2019, in Novi, MI. Register for the event, hosted by Design News' parent company Informa.


Colonial Business Brokerage has fine tuned a multi-step strategy to selling businesses that helps our clients achieve the best possible price for their business and in a timely manner. Colonial Business Brokerage Intermediaries can review these steps with you are available each step of the way to answer any questions you may have along the way.
Understanding your Goals and Strategic Planning – Getting to know your situation and your goals, protecting confidentiality, and developing a plan in motion to achieve of your ideal business transition.
Comprehensive Business Analysis and Market Valuation – CBB will conduct a thorough analysis of your business. Financials, operations, sales and marketing, inventory, personnel, etc.
Marketing and Advertising – Build a potential buyers list and confidentially get your business information in front of thousands of potential buyers.
Buyer Qualification and Coordination – Create competition with the goal being an auction-like environment, question handling and vetting potential buyers, controlling the flow of information.
Offer presentation and Negotiation – Deal structure, due diligence, support, offer/counter offer proposals.
Closing and Transition – Closing, lease assignment, note and lien search/clearance, inventory, transition to new ownership.
Peace of Mind – When this process is complete, you will know that we have searched the world and totally screened and vetted potential buyers to find you the absolute best deal possible for your business.


text:
Air Map is a drone industry company improving low-altitude-airspace infrastructure to help drone operators can fly safely and legally.
Airmap is a California based technology company developing a low-altitude airspace administration platform for Unmanned aircraft Traffic Management (UTM). The technology provides drones with the up-to-date airspace information so that drone operators can plan and adapt flight plans to local events, restrictions, and even changes in weather around them. The company co-operates with local authorities to manage and regulate safe zones and pathways for drone operation. As of June 2019, Airmap has its services deployed in countries like Japan, Germany, United States, and Switzerland.
Airmap's U-Space is a platform with a set of interconnected services that provide digital registration, identification, geo-awareness for drone operators, and airspace authorities. Airmap uses multiple data sources to create geo-fenced markers to represent legally safe and restricted areas for drone operation. AirMap has information about UAV ( Unmanned Air Vehicles) laws in over 20 countries. Restricted areas include populated areas, airports, military bases, and bird sanctuary zones. With registration and identification of drones, it can provide real-time traffic of unmanned vehicles in a selected area.
Airmap develops an application for iOS and Android operating systems for DJI drone operators to check detailed information about their airspace. The map overlay provides an easy to use and detailed view of safe and restricted zones in the area. The application allows drone operators a way to get authorization for drone operation in urban areas. The authorization requests include information like fly zone area, altitude restriction, device, and personal information, and duration of the flight.
The company also operates a web-based interactive map with geo-fenced areas. As of June 2019, the map contains detailed drone airspace safety zones in the United States, Germany, and Switzerland. The map is hosted on app.airmap.io.
Airmap.io visualization
Ben Marcus and Gregory McNeal founded the company on December 1, 2019, and is headquartered in Santa-Monica, California, United States. Lux Capital Management backed the company in 2017.
AirMap announces a $26 million Series B funding round led by Microsoft Ventures, with Lux Capital.
The Series B funding round will bring AirMap's airspace management platform and Unmanned aircraft Traffic Management (UTM) solutions to new markets worldwide
Hon Lung Chu
Airmap Automated Authorization | How To
https://www.youtube.com/watch?v=b5TJ5vvn1yM
U-space Demonstration at the WEF Drone Innovators Network (Short)
https://www.youtube.com/watch?v=x9OAkifpGro
airmap.com
crunchbase.com/organiz...oflyzone
Lux Capital Management
A company, abbreviated 'co.', is a legal entity made up of an association of people, be they natural, legal, or a mixture of both, for carrying on a commercial or industrial enterprise.
Portion of the atmosphere controlled by a country above its territory
Niroj Manandhar
Rebecca Hammond
MA English I HDip Psychology - Following AI, behavioural and educational psychology
Edita Rexha
Third-year student at the University of Prishtina


Do you remember the name Jonathan Cohen? Jonathan, who was negative on Internet stocks in the late '90s, was replaced by none other than Henry Blodget at Merrill Lynch. Henry's $400 call on Amazon.com put him well on his way towards equity research fame or infamy. As I was catching up on my reading and looking at top performing funds for Q3, it was great to see Johnathan Cohen's Royce Technology Fund top the charts. He did it by building positions in technology value stocks which sounds like an oxymoron but made a ton of sense if you began buying in early 2002. Many of these stocks like Maxtor were trading at or near cash at some point in time during the last 2 years.


text:
Beauty dish (z angličtiny beauty = krása, dish = parabolický reflektor) je typ fotografického zařízení sloužícího k osvětlení scény. Využívá parabolický reflektor k usměrnění světla do ohniska. Takto generované světlo je něco mezi přímým bleskem a softboxem, snímku dává "zabalený", kontrastní vzhled s dramatickým efektem. Využívá se při portrétní, modelingové i produktové fotografii.

Zajímavosti
Dodávají se ve velikostech 40, 56 a 70 cm, například s voštinami, difuzérem nebo klapkami. Klapky světlo lépe směrují, voštiny a difuzér světlo změkčují.

Galerie

Odkazy

Externí odkazy

 Beauty Dish po domácku na fotofanda.cz
 Porozumění beauty dish na youtube.com

Světlo ve fotografii
Fotografické blesky
Fotografické vybavení

redpajama_set_name: RedPajamaWikipedia