anchor.diff:          (l + (if l=="" then "" else ".") + s) (builtins.getAttr s attrs)))
           (builtins.attrNames attrs)));
   
  -        
  +  /* Option Properties */
  +  # Generalize the problem of delayable properties.  Any property can be created
  +
  +
  +  # Tell that nothing is defined.  When properties are evaluated, this type
  +  # is used to remove an entry.  Thus if your property evaluation semantic
  +  # implies that you have to mute the content of an attribute, then your
  +  # property should produce this value.
  +  isNotdef = attrs: (typeOf attrs) == "notdef";
  +  mkNotdef = {_type = "notdef";};
  +
  +  # General property type, it has a property attribute and a content
  +  # attribute.  The property attribute refer to an attribute set which
  +  # contains a _type attribute and a list of functions which are used to
  +  # evaluate this property.  The content attribute is used to stack property
  +  # on top of each other.
  +  # 
  +  # The optional functions which may be contained in the property attribute
  +  # are:
  +  #  - onDelay: run on a copied property.
  +  #  - onGlobalDelay: run on all copied properties.
  +  #  - onEval: run on an evaluated property.
  +  #  - onGlobalEval: run on a list of property stack on top of their values.
  +  isProperty = attrs: (typeOf attrs) == "property";
  +  mkProperty = p@{property, content, ...}: p // {
  +    _type = "property";
  +  };
  +
  +  # Go throw the stack of properties and apply the function `op' on all
  +  # property and call the function `nul' on the final value which is not a
  +  # property.  The stack is traversed in reversed order.  The `op' function
  +  # should expect a property with a content which have been modified.
  +  # 
  +  # Warning: The `op' function expects only one argument in order to avoid
  +  # calls to mkProperties as the argument is already a valid property which
  +  # contains the result of the folding inside the content attribute.
  +  foldProperty = op: nul: attrs:
  +    if isProperty attrs then
  +      op (attrs // {
  +        content = foldProperty op nul attrs.content;
  +      })
  +    else
  +      nul attrs;
  +
  +  # Simple function which can be used as the `op' argument of the
  +  # foldProperty function.  Properties that you don't want to handle can be
  +  # ignored with the `id' function.  `isSearched' is a function which should
  +  # check the type of a property and return a boolean value.  `thenFun' and
  +  # `elseFun' are functions which behave as the `op' argument of the
  +  # foldProperty function.
  +  foldFilter = isSearched: thenFun: elseFun: attrs:
  +    if isSearched attrs.property then
  +      thenFun attrs
  +    else
  +      elseFun attrs;
  +
  +
  +  # Move properties from the current attribute set to the attribute
  +  # contained in this attribute set.  This trigger property handlers called
  +  # `onDelay' and `onGlobalDelay'.
  +  delayProperties = attrs:
  +    let cleanAttrs = rmProperties attrs; in
  +    if cleanAttrs != attrs then
  +      lib.mapAttrs (a: v:
  +        lib.addErrorContext "while moving properties on the attribute `${a}'." (
  +          triggerPropertiesGlobalDelay a (
  +            triggerPropertiesDelay a (
  +              copyProperties attrs v
  +      )))) cleanAttrs
  +    else
  +      attrs;
  +
  +  # Call onDelay functions.
  +  triggerPropertiesDelay = name: attrs:
  +    let
  +      callOnDelay = p@{property, ...}:
  +        lib.addErrorContext "while calling a onDelay function." (
  +          if property ? onDelay then
  +            property.onDelay name p
  +          else
  +            p
  +        );
  +    in
  +      foldProperty callOnDelay id attrs;
  +
  +  # Call onGlobalDelay functions.
  +  triggerPropertiesGlobalDelay = name: attrs:
  +    let
  +      globalDelayFuns = uniqListExt {
  +        getter = property: property._type;
  +        inputList = foldProperty (p@{property, content, ...}:
  +          if property ? onGlobalDelay then
  +            [ property ] ++ content
  +          else
  +            content
  +        ) (a: []) attrs;
  +      };
  +
  +      callOnGlobalDelay = property: content:
  +        lib.addErrorContext "while calling a onGlobalDelay function." (
  +          property.onGlobalDelay name content
  +        );
  +    in
  +      fold callOnGlobalDelay attrs globalDelayFuns;
  +
  +  # Expect a list of values which may have properties and return the same
  +  # list of values where all properties have been evaluated and where all
  +  # ignored values are removed.  This trigger property handlers called
  +  # `onEval' and `onGlobalEval'.
  +  evalProperties = valList:
  +    if valList != [] then
  +      filter (x: !isNotdef x) (
  +        lib.addErrorContext "while evaluating properties an attribute." (
  +          triggerPropertiesGlobalEval (
  +            map triggerPropertiesEval valList
  +      )))
  +    else
  +      valList;
  +
  +  # Call onEval function
  +  triggerPropertiesEval = val:
  +    foldProperty (p@{property, ...}:
  +      lib.addErrorContext "while calling a onEval function." (
  +        if property ? onEval then
  +          property.onEval p
  +        else
  +          p
  +      )
  +    ) id val;
  +
  +  # Call onGlobalEval function
  +  triggerPropertiesGlobalEval = valList:
  +    let
  +      globalEvalFuns = uniqListExt {
  +        getter = property: property._type;
  +        inputList =
  +          fold (attrs: list:
  +            foldProperty (p@{property, content, ...}:
  +              if property ? onGlobalEval then
  +                [ property ] ++ content
  +              else
  +                content
  +            ) (a: list) attrs
  +          ) [] valList;
  +      };
  +
  +      callOnGlobalEval = property: valList:
  +        lib.addErrorContext "while calling a onGlobalEval function." (
  +          property.onGlobalEval valList
  +        );
  +    in
  +      fold callOnGlobalEval valList globalEvalFuns;
  +
  +  # Remove all properties on top of a value and return the value.
  +  rmProperties =
  +    foldProperty (p@{content, ...}: content) id;
  +
  +  # Copy properties defined on a value on another value.
  +  copyProperties = attrs: newAttrs:
  +    foldProperty id (x: newAttrs) attrs;
  +
     /* If. ThenElse. Always. */
  -  # !!! cleanup needed
   
     # create "if" statement that can be dealyed on sets until a "then-else" or
     # "always" set is reached.  When an always set is reached the condition
     # is ignore.
   
  +  # Create a "If" property which only contains a condition.
     isIf = attrs: (typeOf attrs) == "if";
  -  mkIf = condition: thenelse:
  -    if isIf thenelse then
  -      mkIf (condition && thenelse.condition) thenelse.thenelse
  -    else {
  +  mkIf = condition: content: mkProperty {
  +    property = {
         _type = "if";
  -      inherit condition thenelse;
  +      onGlobalDelay = onIfGlobalDelay;
  +      onEval = onIfEval;
  +      inherit condition;
       };
  -
  -
  -  isNotdef = attrs: (typeOf attrs) == "notdef";
  -  mkNotdef = {_type = "notdef";};
  -
  -
  +    inherit content;
  +  };
  +
  +  # Create a "ThenElse" property which contains choices which can choosed by
  +  # the evaluation of an "If" statement.
     isThenElse = attrs: (typeOf attrs) == "then-else";
     mkThenElse = attrs:
       assert attrs ? thenPart && attrs ? elsePart;
  -    attrs // { _type = "then-else"; };
  -
  -
  +    mkProperty {
  +      property = {
  +        _type = "then-else";
  +        onEval = val: throw "Missing mkIf statement.";
  +        inherit (attrs) thenPart elsePart;
  +      };
  +      content = mkNotdef;
  +    };
  +
  +  # Create an "Always" property remove ignore all "If" statement.
     isAlways = attrs: (typeOf attrs) == "always";
  -  mkAlways = value: { inherit value; _type = "always"; };
  -
  -  pushIf = f: attrs:
  -    if isIf attrs then pushIf f (
  -      let val = attrs.thenelse; in
  -      # evaluate the condition.
  -      if isThenElse val then
  -        if attrs.condition then
  -          val.thenPart
  +  mkAlways = value:
  +    mkProperty {
  +      property = {
  +        _type = "always";
  +        onEval = p@{content, ...}: content;
  +        inherit value;
  +      };
  +      content = mkNotdef;
  +    };
  +
  +  # Remove all "If" statement defined on a value.
  +  rmIf = foldProperty (
  +      foldFilter isIf
  +        ({content, ...}: content)
  +        id
  +    ) id;
  +
  +  # Evaluate the "If" statements when either "ThenElse" or "Always"
  +  # statement is encounter.  Otherwise it remove multiple If statement and
  +  # replace them by one "If" staement where the condition is the list of all
  +  # conditions joined with a "and" operation.
  +  onIfGlobalDelay = name: content:
  +    let
  +      # extract if statements and non-if statements and repectively put them
  +      # in the attribute list and attrs.
  +      ifProps =
  +        foldProperty
  +          (foldFilter (p: isIf p || isThenElse p || isAlways p)
  +            # then, push the codition inside the list list
  +            (p@{property, content, ...}:
  +              { inherit (content) attrs;
  +                list = [property] ++ content.list;
  +              }
  +            )
  +            # otherwise, add the propertie.
  +            (p@{property, content, ...}:
  +              { inherit (content) list;
  +                attrs = p // { content = content.attrs; };
  +              }
  +            )
  +          )
  +          (attrs: { list = []; inherit attrs; })
  +          content;
  +
  +      # compute the list of if statements.
  +      evalIf = content: condition: list:
  +        if list == [] then
  +          mkIf condition content
           else
  -          val.elsePart
  -      # ignore the condition.
  -      else if isAlways val then
  -        val.value
  -      # otherwise
  +          let p = head list; in
  +
  +          # evaluate the condition.
  +          if isThenElse p then
  +            if condition then
  +              foldProperty (a: p.thenPart) id content
  +            else
  +              foldProperty (a: p.elsePart) id content
  +          # ignore the condition.
  +          else if isAlways p then
  +            foldProperty (a: p.value) id content
  +          # otherwise (isIf)
  +          else
  +            evalIf content (condition && p.condition) (tail list);
  +    in
  +      evalIf ifProps.attrs true ifProps.list;
  +
  +  # Evaluate the condition of the "If" statement to either get the value or
  +  # to ignore the value.
  +  onIfEval = p@{property, content, ...}:
  +    if property.condition then
  +      content
  +    else
  +      mkNotdef;
  +
  +  /* mkOverride */
  +
  +  # Create an "Override" statement which allow the user to define
  +  # prioprities between values.  The default priority is 100 and the lowest
  +  # priorities are kept.  The template argument must reproduce the same
  +  # attribute set hierachy to override leaves of the hierarchy.
  +  isOverride = attrs: (typeOf attrs) == "override";
  +  mkOverride = priority: template: content: mkProperty {
  +    property = {
  +      _type = "override";
  +      onDelay = onOverrideDelay;
  +      onGlobalEval = onOverrideGlobalEval;
  +      inherit priority template;
  +    };
  +    inherit content;
  +  };
  +
  +  # Make the template traversal in function of the property traversal.  If
  +  # the template define a non-empty attribute set, then the property is
  +  # copied only on all mentionned attributes inside the template.
  +  # Otherwise, the property is kept on all sub-attribute definitions.
  +  onOverrideDelay = name: p@{property, content, ...}:
  +    let inherit (property) template; in
  +    if builtins.isAttrs template && template != {} then
  +      if builtins.hasAttr name template then
  +        p // {
  +          property = p.property // {
  +            template = builtins.getAttr name template;
  +          };
  +        }
  +      # Do not override the attribute \name\
         else
  -        f attrs.condition val)
  +        content
  +    # Override values defined inside the attribute \name\.
       else
  -      attrs;
  -
  -  # take care otherwise you will have to handle this by hand.
  -  rmIf = pushIf (condition: val: val);
  -
  -  evalIf = pushIf (condition: val:
  -    if condition then val else mkNotdef
  -  );
  -
  -  delayIf = pushIf (condition: val:
  -    # rewrite the condition on sub-attributes.
  -    lib.mapAttrs (name: mkIf condition) val
  -  );
  +      p;
  +
  +  # Ignore all values which have a higher value of the priority number.
  +  onOverrideGlobalEval = valList:
  +    let
  +      defaultPrio = 100;
  +
  +      inherit (builtins) lessThan;
  +
  +      getPrioVal =
  +        foldProperty
  +          (foldFilter isOverride
  +            (p@{property, content, ...}:
  +              if lessThan content.priority property.priority then
  +                content
  +              else
  +                content // {
  +                  inherit (property) priority;
  +                }
  +            )
  +            (p@{property, content, ...}:
  +              content // {
  +                value = p // { content = content.value; };
  +              }
  +            )
  +          ) (value: { priority = defaultPrio; inherit value; });
  +
  +      prioValList = map getPrioVal valList;
  +
  +      higherPrio = fold (x: y:
  +        if lessThan x.priority y then
  +          x.priority
  +        else
  +          y
  +      ) defaultPrio prioValList;
  +    in
  +      map (x:
  +        if x.priority == higherPrio then
  +          x.value
  +        else
  +          mkNotdef
  +      ) prioValList;
   
   }
positive.code:           } // (head decls);
  
            # Return the list of option sets.
            optAttrs = map delayIf defs;
  
            # return the list of option values.
            # Remove undefined values that are coming from evalIf.
            optValues = filter (x: !isNotdef x) (map evalIf defs);
          in
            if decls == [] then handleOptionSets optionHandler name optAttrs
            else lib.addErrorContext "while evaluating the option ${name}:" (
  
negative.code: let lib = import ./default.nix; in
  
  with { inherit (builtins) head tail; };
  with import ./trivial.nix;
  with import ./lists.nix;
  with import ./misc.nix;
  with import ./attrsets.nix;
  
  rec {
  