anchor.diff:      listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))
     );
   
  +  # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
  +  range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1);
  +
  +  # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
  +  stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
  +
  +  # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
  +  stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
  +  concatStrings = builtins.concatStringsSep "";
  +
     # fetchTarball version that is compatible between all the versions of Nix
  -  builtins_fetchTarball = { url, sha256 }@attrs:
  +  builtins_fetchTarball = { url, name, sha256 }@attrs:
       let
         inherit (builtins) lessThan nixVersion fetchTarball;
       in
         if lessThan nixVersion "1.12" then
  -        fetchTarball { inherit url; }
  +        fetchTarball { inherit name url; }
         else
           fetchTarball attrs;
   
  
positive.code:         then abort
            "The values in sources.json should not have an 'outPath' attribute"
          else
            spec // { outPath = fetch config.pkgs name spec; }
      ) config.sources;
  
    # The "config" used by the fetchers
    mkConfig =
      { sourcesFile ? ./sources.json
      , sources ? builtins.fromJSON (builtins.readFile sourcesFile)
      , pkgs ? mkPkgs sources
      }: rec {
        # The sources, i.e. the attribute set of spec name to spec
  
negative.code:       # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
        inherit pkgs;
      };
  
  in
  mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); }
  