From 40ea2656f072e23bbbccd22c39fb29a36390fa3a Mon Sep 17 00:00:00 2001
From: Micah <micah@leap.se>
Date: Tue, 12 Jul 2016 16:46:08 -0400
Subject: git subrepo clone https://leap.se/git/puppet_stdlib
 puppet/modules/stdlib

subrepo:
  subdir:   "puppet/modules/stdlib"
  merged:   "7112363"
upstream:
  origin:   "https://leap.se/git/puppet_stdlib"
  branch:   "master"
  commit:   "7112363"
git-subrepo:
  version:  "0.3.0"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "1e79595"

Change-Id: I032e3e7c2984bf53b717373df495c039bb6f41b3
---
 puppet/modules/stdlib/lib/facter/facter_dot_d.rb   | 202 +++++++++++++++++++++
 .../stdlib/lib/facter/netmask_cidr_interface.rb    |  22 +++
 puppet/modules/stdlib/lib/facter/pe_version.rb     |  53 ++++++
 puppet/modules/stdlib/lib/facter/puppet_vardir.rb  |  26 +++
 puppet/modules/stdlib/lib/facter/root_home.rb      |  32 ++++
 .../stdlib/lib/facter/util/puppet_settings.rb      |  21 +++
 .../modules/stdlib/lib/puppet/functions/type_of.rb |  17 ++
 .../stdlib/lib/puppet/parser/functions/abs.rb      |  36 ++++
 .../lib/puppet/parser/functions/any2array.rb       |  33 ++++
 .../stdlib/lib/puppet/parser/functions/base64.rb   |  37 ++++
 .../stdlib/lib/puppet/parser/functions/basename.rb |  34 ++++
 .../stdlib/lib/puppet/parser/functions/bool2num.rb |  26 +++
 .../stdlib/lib/puppet/parser/functions/bool2str.rb |  27 +++
 .../lib/puppet/parser/functions/camelcase.rb       |  33 ++++
 .../lib/puppet/parser/functions/capitalize.rb      |  33 ++++
 .../stdlib/lib/puppet/parser/functions/chomp.rb    |  34 ++++
 .../stdlib/lib/puppet/parser/functions/chop.rb     |  36 ++++
 .../stdlib/lib/puppet/parser/functions/concat.rb   |  41 +++++
 .../stdlib/lib/puppet/parser/functions/count.rb    |  22 +++
 .../lib/puppet/parser/functions/deep_merge.rb      |  44 +++++
 .../puppet/parser/functions/defined_with_params.rb |  35 ++++
 .../stdlib/lib/puppet/parser/functions/delete.rb   |  49 +++++
 .../lib/puppet/parser/functions/delete_at.rb       |  49 +++++
 .../puppet/parser/functions/delete_undef_values.rb |  34 ++++
 .../lib/puppet/parser/functions/delete_values.rb   |  26 +++
 .../lib/puppet/parser/functions/difference.rb      |  36 ++++
 .../stdlib/lib/puppet/parser/functions/dirname.rb  |  15 ++
 .../stdlib/lib/puppet/parser/functions/downcase.rb |  32 ++++
 .../stdlib/lib/puppet/parser/functions/empty.rb    |  27 +++
 .../lib/puppet/parser/functions/ensure_packages.rb |  35 ++++
 .../lib/puppet/parser/functions/ensure_resource.rb |  46 +++++
 .../stdlib/lib/puppet/parser/functions/flatten.rb  |  33 ++++
 .../stdlib/lib/puppet/parser/functions/floor.rb    |  25 +++
 .../lib/puppet/parser/functions/fqdn_rotate.rb     |  45 +++++
 .../lib/puppet/parser/functions/get_module_path.rb |  17 ++
 .../stdlib/lib/puppet/parser/functions/getparam.rb |  35 ++++
 .../stdlib/lib/puppet/parser/functions/getvar.rb   |  29 +++
 .../stdlib/lib/puppet/parser/functions/grep.rb     |  33 ++++
 .../puppet/parser/functions/has_interface_with.rb  |  68 +++++++
 .../lib/puppet/parser/functions/has_ip_address.rb  |  25 +++
 .../lib/puppet/parser/functions/has_ip_network.rb  |  25 +++
 .../stdlib/lib/puppet/parser/functions/has_key.rb  |  28 +++
 .../stdlib/lib/puppet/parser/functions/hash.rb     |  41 +++++
 .../lib/puppet/parser/functions/intersection.rb    |  34 ++++
 .../stdlib/lib/puppet/parser/functions/is_array.rb |  22 +++
 .../stdlib/lib/puppet/parser/functions/is_bool.rb  |  22 +++
 .../lib/puppet/parser/functions/is_domain_name.rb  |  50 +++++
 .../stdlib/lib/puppet/parser/functions/is_float.rb |  30 +++
 .../parser/functions/is_function_available.rb      |  26 +++
 .../stdlib/lib/puppet/parser/functions/is_hash.rb  |  22 +++
 .../lib/puppet/parser/functions/is_integer.rb      |  45 +++++
 .../lib/puppet/parser/functions/is_ip_address.rb   |  32 ++++
 .../lib/puppet/parser/functions/is_mac_address.rb  |  27 +++
 .../lib/puppet/parser/functions/is_numeric.rb      |  75 ++++++++
 .../lib/puppet/parser/functions/is_string.rb       |  26 +++
 .../stdlib/lib/puppet/parser/functions/join.rb     |  41 +++++
 .../puppet/parser/functions/join_keys_to_values.rb |  47 +++++
 .../stdlib/lib/puppet/parser/functions/keys.rb     |  26 +++
 .../stdlib/lib/puppet/parser/functions/loadyaml.rb |  20 ++
 .../stdlib/lib/puppet/parser/functions/lstrip.rb   |  32 ++++
 .../stdlib/lib/puppet/parser/functions/max.rb      |  21 +++
 .../stdlib/lib/puppet/parser/functions/member.rb   |  62 +++++++
 .../stdlib/lib/puppet/parser/functions/merge.rb    |  34 ++++
 .../stdlib/lib/puppet/parser/functions/min.rb      |  21 +++
 .../stdlib/lib/puppet/parser/functions/num2bool.rb |  43 +++++
 .../lib/puppet/parser/functions/obfuscate_email.rb |  16 ++
 .../lib/puppet/parser/functions/parsejson.rb       |  24 +++
 .../lib/puppet/parser/functions/parseyaml.rb       |  24 +++
 .../stdlib/lib/puppet/parser/functions/pick.rb     |  29 +++
 .../lib/puppet/parser/functions/pick_default.rb    |  35 ++++
 .../stdlib/lib/puppet/parser/functions/prefix.rb   |  45 +++++
 .../stdlib/lib/puppet/parser/functions/private.rb  |  29 +++
 .../stdlib/lib/puppet/parser/functions/range.rb    |  88 +++++++++
 .../stdlib/lib/puppet/parser/functions/reject.rb   |  31 ++++
 .../stdlib/lib/puppet/parser/functions/reverse.rb  |  27 +++
 .../stdlib/lib/puppet/parser/functions/rstrip.rb   |  31 ++++
 .../stdlib/lib/puppet/parser/functions/shuffle.rb  |  45 +++++
 .../stdlib/lib/puppet/parser/functions/size.rb     |  48 +++++
 .../stdlib/lib/puppet/parser/functions/sort.rb     |  27 +++
 .../stdlib/lib/puppet/parser/functions/squeeze.rb  |  36 ++++
 .../stdlib/lib/puppet/parser/functions/str2bool.rb |  46 +++++
 .../lib/puppet/parser/functions/str2saltedsha1.rb  |  32 ++++
 .../puppet/parser/functions/str2saltedsha512.rb    |  32 ++++
 .../puppet/parser/functions/str2sha1_and_salt.rb   |  36 ++++
 .../puppet/parser/functions/str_and_salt2sha1.rb   |  32 ++++
 .../stdlib/lib/puppet/parser/functions/strftime.rb | 107 +++++++++++
 .../stdlib/lib/puppet/parser/functions/strip.rb    |  38 ++++
 .../stdlib/lib/puppet/parser/functions/suffix.rb   |  45 +++++
 .../stdlib/lib/puppet/parser/functions/swapcase.rb |  38 ++++
 .../stdlib/lib/puppet/parser/functions/time.rb     |  49 +++++
 .../stdlib/lib/puppet/parser/functions/to_bytes.rb |  31 ++++
 .../stdlib/lib/puppet/parser/functions/type.rb     |  19 ++
 .../stdlib/lib/puppet/parser/functions/type3x.rb   |  51 ++++++
 .../stdlib/lib/puppet/parser/functions/union.rb    |  34 ++++
 .../stdlib/lib/puppet/parser/functions/unique.rb   |  50 +++++
 .../stdlib/lib/puppet/parser/functions/upcase.rb   |  40 ++++
 .../lib/puppet/parser/functions/uriescape.rb       |  34 ++++
 .../parser/functions/validate_absolute_path.rb     |  69 +++++++
 .../lib/puppet/parser/functions/validate_array.rb  |  33 ++++
 .../lib/puppet/parser/functions/validate_augeas.rb |  83 +++++++++
 .../lib/puppet/parser/functions/validate_bool.rb   |  34 ++++
 .../lib/puppet/parser/functions/validate_cmd.rb    |  63 +++++++
 .../lib/puppet/parser/functions/validate_hash.rb   |  33 ++++
 .../parser/functions/validate_ipv4_address.rb      |  48 +++++
 .../parser/functions/validate_ipv6_address.rb      |  49 +++++
 .../lib/puppet/parser/functions/validate_re.rb     |  40 ++++
 .../puppet/parser/functions/validate_slength.rb    |  71 ++++++++
 .../lib/puppet/parser/functions/validate_string.rb |  38 ++++
 .../stdlib/lib/puppet/parser/functions/values.rb   |  39 ++++
 .../lib/puppet/parser/functions/values_at.rb       |  99 ++++++++++
 .../stdlib/lib/puppet/parser/functions/zip.rb      |  39 ++++
 .../stdlib/lib/puppet/provider/file_line/ruby.rb   |  85 +++++++++
 puppet/modules/stdlib/lib/puppet/type/anchor.rb    |  46 +++++
 puppet/modules/stdlib/lib/puppet/type/file_line.rb |  75 ++++++++
 114 files changed, 4548 insertions(+)
 create mode 100644 puppet/modules/stdlib/lib/facter/facter_dot_d.rb
 create mode 100644 puppet/modules/stdlib/lib/facter/netmask_cidr_interface.rb
 create mode 100644 puppet/modules/stdlib/lib/facter/pe_version.rb
 create mode 100644 puppet/modules/stdlib/lib/facter/puppet_vardir.rb
 create mode 100644 puppet/modules/stdlib/lib/facter/root_home.rb
 create mode 100644 puppet/modules/stdlib/lib/facter/util/puppet_settings.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/functions/type_of.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/abs.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/any2array.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/base64.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/basename.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/bool2num.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/bool2str.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/camelcase.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/capitalize.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/chomp.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/chop.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/concat.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/count.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/deep_merge.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/defined_with_params.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/delete.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/delete_at.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/delete_undef_values.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/delete_values.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/difference.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/dirname.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/downcase.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/empty.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/ensure_packages.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/ensure_resource.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/flatten.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/floor.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/fqdn_rotate.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/get_module_path.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/getparam.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/getvar.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/grep.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/has_interface_with.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/has_ip_address.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/has_ip_network.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/has_key.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/hash.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/intersection.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/is_array.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/is_bool.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/is_domain_name.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/is_float.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/is_function_available.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/is_hash.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/is_integer.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/is_ip_address.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/is_mac_address.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/is_numeric.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/is_string.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/join.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/join_keys_to_values.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/keys.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/loadyaml.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/lstrip.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/max.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/member.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/merge.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/min.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/num2bool.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/obfuscate_email.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/parsejson.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/parseyaml.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/pick.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/pick_default.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/prefix.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/private.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/range.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/reject.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/reverse.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/rstrip.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/shuffle.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/size.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/sort.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/squeeze.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/str2bool.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/str2saltedsha1.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/str2saltedsha512.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/str2sha1_and_salt.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/str_and_salt2sha1.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/strftime.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/strip.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/suffix.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/swapcase.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/time.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/to_bytes.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/type.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/type3x.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/union.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/unique.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/upcase.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/uriescape.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/validate_absolute_path.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/validate_array.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/validate_augeas.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/validate_bool.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/validate_cmd.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/validate_hash.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/validate_ipv4_address.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/validate_ipv6_address.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/validate_re.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/validate_slength.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/validate_string.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/values.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/values_at.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/parser/functions/zip.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/provider/file_line/ruby.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/type/anchor.rb
 create mode 100644 puppet/modules/stdlib/lib/puppet/type/file_line.rb

(limited to 'puppet/modules/stdlib/lib')

diff --git a/puppet/modules/stdlib/lib/facter/facter_dot_d.rb b/puppet/modules/stdlib/lib/facter/facter_dot_d.rb
new file mode 100644
index 00000000..b0584370
--- /dev/null
+++ b/puppet/modules/stdlib/lib/facter/facter_dot_d.rb
@@ -0,0 +1,202 @@
+# A Facter plugin that loads facts from /etc/facter/facts.d
+# and /etc/puppetlabs/facter/facts.d.
+#
+# Facts can be in the form of JSON, YAML or Text files
+# and any executable that returns key=value pairs.
+#
+# In the case of scripts you can also create a file that
+# contains a cache TTL.  For foo.sh store the ttl as just
+# a number in foo.sh.ttl
+#
+# The cache is stored in /tmp/facts_cache.yaml as a mode
+# 600 file and will have the end result of not calling your
+# fact scripts more often than is needed
+
+class Facter::Util::DotD
+  require 'yaml'
+
+  def initialize(dir="/etc/facts.d", cache_file=File.join(Puppet[:libdir], "facts_dot_d.cache"))
+    @dir = dir
+    @cache_file = cache_file
+    @cache = nil
+    @types = {".txt" => :txt, ".json" => :json, ".yaml" => :yaml}
+  end
+
+  def entries
+    Dir.entries(@dir).reject { |f| f =~ /^\.|\.ttl$/ }.sort.map { |f| File.join(@dir, f) }
+  rescue
+    []
+  end
+
+  def fact_type(file)
+    extension = File.extname(file)
+
+    type = @types[extension] || :unknown
+
+    type = :script if type == :unknown && File.executable?(file)
+
+    return type
+  end
+
+  def txt_parser(file)
+    File.readlines(file).each do |line|
+      if line =~ /^([^=]+)=(.+)$/
+        var = $1; val = $2
+
+        Facter.add(var) do
+          setcode { val }
+        end
+      end
+    end
+  rescue Exception => e
+    Facter.warn("Failed to handle #{file} as text facts: #{e.class}: #{e}")
+  end
+
+  def json_parser(file)
+    begin
+      require 'json'
+    rescue LoadError
+      retry if require 'rubygems'
+      raise
+    end
+
+    JSON.load(File.read(file)).each_pair do |f, v|
+      Facter.add(f) do
+        setcode { v }
+      end
+    end
+  rescue Exception => e
+    Facter.warn("Failed to handle #{file} as json facts: #{e.class}: #{e}")
+  end
+
+  def yaml_parser(file)
+    require 'yaml'
+
+    YAML.load_file(file).each_pair do |f, v|
+      Facter.add(f) do
+        setcode { v }
+      end
+    end
+  rescue Exception => e
+    Facter.warn("Failed to handle #{file} as yaml facts: #{e.class}: #{e}")
+  end
+
+  def script_parser(file)
+    result = cache_lookup(file)
+    ttl = cache_time(file)
+
+    unless result
+      result = Facter::Util::Resolution.exec(file)
+
+      if ttl > 0
+        Facter.debug("Updating cache for #{file}")
+        cache_store(file, result)
+        cache_save!
+      end
+    else
+      Facter.debug("Using cached data for #{file}")
+    end
+
+    result.split("\n").each do |line|
+      if line =~ /^(.+)=(.+)$/
+        var = $1; val = $2
+
+        Facter.add(var) do
+          setcode { val }
+        end
+      end
+    end
+  rescue Exception => e
+    Facter.warn("Failed to handle #{file} as script facts: #{e.class}: #{e}")
+    Facter.debug(e.backtrace.join("\n\t"))
+  end
+
+  def cache_save!
+    cache = load_cache
+    File.open(@cache_file, "w", 0600) { |f| f.write(YAML.dump(cache)) }
+  rescue
+  end
+
+  def cache_store(file, data)
+    load_cache
+
+    @cache[file] = {:data => data, :stored => Time.now.to_i}
+  rescue
+  end
+
+  def cache_lookup(file)
+    cache = load_cache
+
+    return nil if cache.empty?
+
+    ttl = cache_time(file)
+
+    if cache[file]
+      now = Time.now.to_i
+
+      return cache[file][:data] if ttl == -1
+      return cache[file][:data] if (now - cache[file][:stored]) <= ttl
+      return nil
+    else
+      return nil
+    end
+  rescue
+    return nil
+  end
+
+  def cache_time(file)
+    meta = file + ".ttl"
+
+    return File.read(meta).chomp.to_i
+  rescue
+    return 0
+  end
+
+  def load_cache
+    unless @cache
+      if File.exist?(@cache_file)
+        @cache = YAML.load_file(@cache_file)
+      else
+        @cache = {}
+      end
+    end
+
+    return @cache
+  rescue
+    @cache = {}
+    return @cache
+  end
+
+  def create
+    entries.each do |fact|
+      type = fact_type(fact)
+      parser = "#{type}_parser"
+
+      if respond_to?("#{type}_parser")
+        Facter.debug("Parsing #{fact} using #{parser}")
+
+        send(parser, fact)
+      end
+    end
+  end
+end
+
+
+mdata = Facter.version.match(/(\d+)\.(\d+)\.(\d+)/)
+if mdata
+  (major, minor, patch) = mdata.captures.map { |v| v.to_i }
+  if major < 2
+    # Facter 1.7 introduced external facts support directly
+    unless major == 1 and minor > 6
+      Facter::Util::DotD.new("/etc/facter/facts.d").create
+      Facter::Util::DotD.new("/etc/puppetlabs/facter/facts.d").create
+
+      # Windows has a different configuration directory that defaults to a vendor
+      # specific sub directory of the %COMMON_APPDATA% directory.
+      if Dir.const_defined? 'COMMON_APPDATA' then
+        windows_facts_dot_d = File.join(Dir::COMMON_APPDATA, 'PuppetLabs', 'facter', 'facts.d')
+        Facter::Util::DotD.new(windows_facts_dot_d).create
+      end
+    end
+  end
+end
diff --git a/puppet/modules/stdlib/lib/facter/netmask_cidr_interface.rb b/puppet/modules/stdlib/lib/facter/netmask_cidr_interface.rb
new file mode 100644
index 00000000..d628d08c
--- /dev/null
+++ b/puppet/modules/stdlib/lib/facter/netmask_cidr_interface.rb
@@ -0,0 +1,22 @@
+# adds netmask facts for each interface in cidr notation
+# i.e.:
+# ...
+# netmask_cidr_eth2 => 24
+# netmask_cidr_lo => 8
+# netmask_cidr_tun0 => 32
+# netmask_cidr_virbr0 => 24
+# ...
+
+require 'facter/util/ip'
+
+Facter::Util::IP.get_interfaces.each do |interface|
+  netmask = Facter.value("netmask_#{interface}")
+  if netmask != nil
+    Facter.add("netmask_cidr_" + interface ) do
+      setcode do
+        cidr_netmask=IPAddr.new(netmask).to_i.to_s(2).count("1")
+        cidr_netmask
+      end
+    end
+  end
+end
diff --git a/puppet/modules/stdlib/lib/facter/pe_version.rb b/puppet/modules/stdlib/lib/facter/pe_version.rb
new file mode 100644
index 00000000..0cc0f64e
--- /dev/null
+++ b/puppet/modules/stdlib/lib/facter/pe_version.rb
@@ -0,0 +1,53 @@
+# Fact: is_pe, pe_version, pe_major_version, pe_minor_version, pe_patch_version
+#
+# Purpose: Return various facts about the PE state of the system
+#
+# Resolution: Uses a regex match against puppetversion to determine whether the
+#   machine has Puppet Enterprise installed, and what version (overall, major,
+#   minor, patch) is installed.
+#
+# Caveats:
+#
+Facter.add("pe_version") do
+  setcode do
+    pe_ver = Facter.value("puppetversion").match(/Puppet Enterprise (\d+\.\d+\.\d+)/)
+    pe_ver[1] if pe_ver
+  end
+end
+
+Facter.add("is_pe") do
+  setcode do
+    if Facter.value(:pe_version).to_s.empty? then
+      false
+    else
+      true
+    end
+  end
+end
+
+Facter.add("pe_major_version") do
+  confine :is_pe => true
+  setcode do
+    if pe_version = Facter.value(:pe_version)
+      pe_version.to_s.split('.')[0]
+    end
+  end
+end
+
+Facter.add("pe_minor_version") do
+  confine :is_pe => true
+  setcode do
+    if pe_version = Facter.value(:pe_version)
+      pe_version.to_s.split('.')[1]
+    end
+  end
+end
+
+Facter.add("pe_patch_version") do
+  confine :is_pe => true
+  setcode do
+    if pe_version = Facter.value(:pe_version)
+      pe_version.to_s.split('.')[2]
+    end
+  end
+end
diff --git a/puppet/modules/stdlib/lib/facter/puppet_vardir.rb b/puppet/modules/stdlib/lib/facter/puppet_vardir.rb
new file mode 100644
index 00000000..0e6af40e
--- /dev/null
+++ b/puppet/modules/stdlib/lib/facter/puppet_vardir.rb
@@ -0,0 +1,26 @@
+# This facter fact returns the value of the Puppet vardir setting for the node
+# running puppet or puppet agent.  The intent is to enable Puppet modules to
+# automatically have insight into a place where they can place variable data,
+# regardless of the node's platform.
+#
+# The value should be directly usable in a File resource path attribute.
+
+
+begin
+  require 'facter/util/puppet_settings'
+rescue LoadError => e
+  # puppet apply does not add module lib directories to the $LOAD_PATH (See
+  # #4248). It should (in the future) but for the time being we need to be
+  # defensive which is what this rescue block is doing.
+  rb_file = File.join(File.dirname(__FILE__), 'util', 'puppet_settings.rb')
+  load rb_file if File.exists?(rb_file) or raise e
+end
+
+Facter.add(:puppet_vardir) do
+  setcode do
+    # This will be nil if Puppet is not available.
+    Facter::Util::PuppetSettings.with_puppet do
+      Puppet[:vardir]
+    end
+  end
+end
diff --git a/puppet/modules/stdlib/lib/facter/root_home.rb b/puppet/modules/stdlib/lib/facter/root_home.rb
new file mode 100644
index 00000000..b4f87ff2
--- /dev/null
+++ b/puppet/modules/stdlib/lib/facter/root_home.rb
@@ -0,0 +1,32 @@
+# A facter fact to determine the root home directory.
+# This varies on PE supported platforms and may be
+# reconfigured by the end user.
+
+module Facter::Util::RootHome
+  class << self
+  def get_root_home
+    root_ent = Facter::Util::Resolution.exec("getent passwd root")
+    # The home directory is the sixth element in the passwd entry
+    # If the platform doesn't have getent, root_ent will be nil and we should
+    # return it straight away.
+    root_ent && root_ent.split(":")[5]
+  end
+  end
+end
+
+Facter.add(:root_home) do
+  setcode { Facter::Util::RootHome.get_root_home }
+end
+
+Facter.add(:root_home) do
+  confine :kernel => :darwin
+  setcode do
+    str = Facter::Util::Resolution.exec("dscacheutil -q user -a name root")
+    hash = {}
+    str.split("\n").each do |pair|
+      key,value = pair.split(/:/)
+      hash[key] = value
+    end
+    hash['dir'].strip
+  end
+end
diff --git a/puppet/modules/stdlib/lib/facter/util/puppet_settings.rb b/puppet/modules/stdlib/lib/facter/util/puppet_settings.rb
new file mode 100644
index 00000000..1ad94521
--- /dev/null
+++ b/puppet/modules/stdlib/lib/facter/util/puppet_settings.rb
@@ -0,0 +1,21 @@
+module Facter
+  module Util
+    module PuppetSettings
+      # This method is intended to provide a convenient way to evaluate a
+      # Facter code block only if Puppet is loaded.  This is to account for the
+      # situation where the fact happens to be in the load path, but Puppet is
+      # not loaded for whatever reason.  Perhaps the user is simply running
+      # facter without the --puppet flag and they happen to be working in a lib
+      # directory of a module.
+      def self.with_puppet
+        begin
+          Module.const_get("Puppet")
+        rescue NameError
+          nil
+        else
+          yield
+        end
+      end
+    end
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/functions/type_of.rb b/puppet/modules/stdlib/lib/puppet/functions/type_of.rb
new file mode 100644
index 00000000..02cdd4db
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/functions/type_of.rb
@@ -0,0 +1,17 @@
+# Returns the type when passed a value.
+#
+# @example how to compare values' types
+#   # compare the types of two values
+#   if type_of($first_value) != type_of($second_value) { fail("first_value and second_value are different types") }
+# @example how to compare against an abstract type
+#   unless type_of($first_value) <= Numeric { fail("first_value must be Numeric") }
+#   unless type_of{$first_value) <= Collection[1] { fail("first_value must be an Array or Hash, and contain at least one element") }
+#
+# See the documentation for "The Puppet Type System" for more information about types.
+# See the `assert_type()` function for flexible ways to assert the type of a value.
+#
+Puppet::Functions.create_function(:type_of) do
+  def type_of(value)
+    Puppet::Pops::Types::TypeCalculator.infer_set(value)
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/abs.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/abs.rb
new file mode 100644
index 00000000..11d2d7fe
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/abs.rb
@@ -0,0 +1,36 @@
+#
+# abs.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:abs, :type => :rvalue, :doc => <<-EOS
+    Returns the absolute value of a number, for example -34.56 becomes
+    34.56. Takes a single integer and float value as an argument.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "abs(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+
+    # Numbers in Puppet are often string-encoded which is troublesome ...
+    if value.is_a?(String)
+      if value.match(/^-?(?:\d+)(?:\.\d+){1}$/)
+        value = value.to_f
+      elsif value.match(/^-?\d+$/)
+        value = value.to_i
+      else
+        raise(Puppet::ParseError, 'abs(): Requires float or ' +
+          'integer to work with')
+      end
+    end
+
+    # We have numeric value to handle ...
+    result = value.abs
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/any2array.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/any2array.rb
new file mode 100644
index 00000000..e71407e8
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/any2array.rb
@@ -0,0 +1,33 @@
+#
+# any2array.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:any2array, :type => :rvalue, :doc => <<-EOS
+This converts any object to an array containing that object. Empty argument
+lists are converted to an empty array. Arrays are left untouched. Hashes are
+converted to arrays of alternating keys and values.
+    EOS
+  ) do |arguments|
+
+    if arguments.empty?
+        return []
+    end
+
+    if arguments.length == 1
+        if arguments[0].kind_of?(Array)
+            return arguments[0]
+        elsif arguments[0].kind_of?(Hash)
+            result = []
+            arguments[0].each do |key, value|
+                result << key << value
+            end
+            return result
+        end
+    end
+
+    return arguments
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/base64.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/base64.rb
new file mode 100644
index 00000000..617ba31b
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/base64.rb
@@ -0,0 +1,37 @@
+module Puppet::Parser::Functions
+
+  newfunction(:base64, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
+
+    Base64 encode or decode a string based on the command and the string submitted
+
+    Usage:
+
+      $encodestring = base64('encode','thestring')
+      $decodestring = base64('decode','dGhlc3RyaW5n')
+
+    ENDHEREDOC
+
+    require 'base64'
+
+    raise Puppet::ParseError, ("base64(): Wrong number of arguments (#{args.length}; must be = 2)") unless args.length == 2
+
+    actions = ['encode','decode']
+
+    unless actions.include?(args[0])
+      raise Puppet::ParseError, ("base64(): the first argument must be one of 'encode' or 'decode'")
+    end
+
+    unless args[1].is_a?(String)
+      raise Puppet::ParseError, ("base64(): the second argument must be a string to base64")
+    end
+
+    case args[0]
+      when 'encode'
+        result = Base64.encode64(args[1])
+      when 'decode'
+        result = Base64.decode64(args[1])
+    end
+
+    return result
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/basename.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/basename.rb
new file mode 100644
index 00000000..f7e44384
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/basename.rb
@@ -0,0 +1,34 @@
+module Puppet::Parser::Functions
+  newfunction(:basename, :type => :rvalue, :doc => <<-EOS
+    Strips directory (and optional suffix) from a filename
+    EOS
+  ) do |arguments|
+
+    if arguments.size < 1 then
+      raise(Puppet::ParseError, "basename(): No arguments given")
+    elsif arguments.size > 2 then
+      raise(Puppet::ParseError, "basename(): Too many arguments given (#{arguments.size})")
+    else
+
+      unless arguments[0].is_a?(String)
+        raise(Puppet::ParseError, 'basename(): Requires string as first argument')
+      end
+
+      if arguments.size == 1 then
+        rv = File.basename(arguments[0])
+      elsif arguments.size == 2 then
+
+        unless arguments[1].is_a?(String)
+          raise(Puppet::ParseError, 'basename(): Requires string as second argument')
+        end
+
+        rv = File.basename(arguments[0], arguments[1])
+      end
+
+    end
+
+    return rv
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/bool2num.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/bool2num.rb
new file mode 100644
index 00000000..6ad6cf4e
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/bool2num.rb
@@ -0,0 +1,26 @@
+#
+# bool2num.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:bool2num, :type => :rvalue, :doc => <<-EOS
+    Converts a boolean to a number. Converts the values:
+      false, f, 0, n, and no to 0
+      true, t, 1, y, and yes to 1
+    Requires a single boolean or string as an input.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "bool2num(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = function_str2bool([arguments[0]])
+
+    # We have real boolean values as well ...
+    result = value ? 1 : 0
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/bool2str.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/bool2str.rb
new file mode 100644
index 00000000..fcd37917
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/bool2str.rb
@@ -0,0 +1,27 @@
+#
+# bool2str.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:bool2str, :type => :rvalue, :doc => <<-EOS
+    Converts a boolean to a string.
+    Requires a single boolean as an input.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "bool2str(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+    klass = value.class
+
+    # We can have either true or false, and nothing else
+    unless [FalseClass, TrueClass].include?(klass)
+      raise(Puppet::ParseError, 'bool2str(): Requires a boolean to work with')
+    end
+
+    return value.to_s
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/camelcase.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/camelcase.rb
new file mode 100644
index 00000000..d7f43f7a
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/camelcase.rb
@@ -0,0 +1,33 @@
+#
+#  camelcase.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:camelcase, :type => :rvalue, :doc => <<-EOS
+Converts the case of a string or all strings in an array to camel case.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "camelcase(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+    klass = value.class
+
+    unless [Array, String].include?(klass)
+      raise(Puppet::ParseError, 'camelcase(): Requires either ' +
+        'array or string to work with')
+    end
+
+    if value.is_a?(Array)
+      # Numbers in Puppet are often string-encoded which is troublesome ...
+      result = value.collect { |i| i.is_a?(String) ? i.split('_').map{|e| e.capitalize}.join : i }
+    else
+      result = value.split('_').map{|e| e.capitalize}.join
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/capitalize.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/capitalize.rb
new file mode 100644
index 00000000..98b2d16c
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/capitalize.rb
@@ -0,0 +1,33 @@
+#
+#  capitalize.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:capitalize, :type => :rvalue, :doc => <<-EOS
+    Capitalizes the first letter of a string or array of strings.
+    Requires either a single string or an array as an input.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "capitalize(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+
+    unless value.is_a?(Array) || value.is_a?(String)
+      raise(Puppet::ParseError, 'capitalize(): Requires either ' +
+        'array or string to work with')
+    end
+
+    if value.is_a?(Array)
+      # Numbers in Puppet are often string-encoded which is troublesome ...
+      result = value.collect { |i| i.is_a?(String) ? i.capitalize : i }
+    else
+      result = value.capitalize
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/chomp.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/chomp.rb
new file mode 100644
index 00000000..c55841e3
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/chomp.rb
@@ -0,0 +1,34 @@
+#
+#  chomp.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:chomp, :type => :rvalue, :doc => <<-'EOS'
+    Removes the record separator from the end of a string or an array of
+    strings, for example `hello\n` becomes `hello`.
+    Requires a single string or array as an input.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "chomp(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+
+    unless value.is_a?(Array) || value.is_a?(String)
+      raise(Puppet::ParseError, 'chomp(): Requires either ' +
+        'array or string to work with')
+    end
+
+    if value.is_a?(Array)
+      # Numbers in Puppet are often string-encoded which is troublesome ...
+      result = value.collect { |i| i.is_a?(String) ? i.chomp : i }
+    else
+      result = value.chomp
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/chop.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/chop.rb
new file mode 100644
index 00000000..b24ab785
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/chop.rb
@@ -0,0 +1,36 @@
+#
+#  chop.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:chop, :type => :rvalue, :doc => <<-'EOS'
+    Returns a new string with the last character removed. If the string ends
+    with `\r\n`, both characters are removed. Applying chop to an empty
+    string returns an empty string. If you wish to merely remove record
+    separators then you should use the `chomp` function.
+    Requires a string or array of strings as input.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "chop(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+
+    unless value.is_a?(Array) || value.is_a?(String)
+      raise(Puppet::ParseError, 'chop(): Requires either an ' +
+        'array or string to work with')
+    end
+
+    if value.is_a?(Array)
+      # Numbers in Puppet are often string-encoded which is troublesome ...
+      result = value.collect { |i| i.is_a?(String) ? i.chop : i }
+    else
+      result = value.chop
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/concat.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/concat.rb
new file mode 100644
index 00000000..618e62d4
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/concat.rb
@@ -0,0 +1,41 @@
+#
+# concat.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:concat, :type => :rvalue, :doc => <<-EOS
+Appends the contents of multiple arrays into array 1.
+
+*Example:*
+
+    concat(['1','2','3'],['4','5','6'],['7','8','9'])
+
+Would result in:
+
+  ['1','2','3','4','5','6','7','8','9']
+    EOS
+  ) do |arguments|
+
+    # Check that more than 2 arguments have been given ...
+    raise(Puppet::ParseError, "concat(): Wrong number of arguments " +
+      "given (#{arguments.size} for < 2)") if arguments.size < 2
+
+    a = arguments[0]
+
+    # Check that the first parameter is an array
+    unless a.is_a?(Array)
+      raise(Puppet::ParseError, 'concat(): Requires array to work with')
+    end
+
+    result = a
+    arguments.shift
+
+    arguments.each do |x|
+      result = result + Array(x)
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/count.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/count.rb
new file mode 100644
index 00000000..52de1b8a
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/count.rb
@@ -0,0 +1,22 @@
+module Puppet::Parser::Functions
+  newfunction(:count, :type => :rvalue, :arity => -2, :doc => <<-EOS
+Takes an array as first argument and an optional second argument.
+Count the number of elements in array that matches second argument.
+If called with only an array it counts the number of elements that are not nil/undef.
+    EOS
+  ) do |args|
+
+    if (args.size > 2) then
+      raise(ArgumentError, "count(): Wrong number of arguments "+
+        "given #{args.size} for 1 or 2.")
+    end
+
+    collection, item = args
+
+    if item then
+      collection.count item
+    else
+      collection.count { |obj| obj != nil && obj != :undef && obj != '' }
+    end
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/deep_merge.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/deep_merge.rb
new file mode 100644
index 00000000..6df32e9c
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/deep_merge.rb
@@ -0,0 +1,44 @@
+module Puppet::Parser::Functions
+  newfunction(:deep_merge, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
+    Recursively merges two or more hashes together and returns the resulting hash.
+
+    For example:
+
+        $hash1 = {'one' => 1, 'two' => 2, 'three' => { 'four' => 4 } }
+        $hash2 = {'two' => 'dos', 'three' => { 'five' => 5 } }
+        $merged_hash = deep_merge($hash1, $hash2)
+        # The resulting hash is equivalent to:
+        # $merged_hash = { 'one' => 1, 'two' => 'dos', 'three' => { 'four' => 4, 'five' => 5 } }
+
+    When there is a duplicate key that is a hash, they are recursively merged.
+    When there is a duplicate key that is not a hash, the key in the rightmost hash will "win."
+
+    ENDHEREDOC
+
+    if args.length < 2
+      raise Puppet::ParseError, ("deep_merge(): wrong number of arguments (#{args.length}; must be at least 2)")
+    end
+
+    deep_merge = Proc.new do |hash1,hash2|
+      hash1.merge(hash2) do |key,old_value,new_value|
+        if old_value.is_a?(Hash) && new_value.is_a?(Hash)
+          deep_merge.call(old_value, new_value)
+        else
+          new_value
+        end
+      end
+    end
+
+    result = Hash.new
+    args.each do |arg|
+      next if arg.is_a? String and arg.empty? # empty string is synonym for puppet's undef
+      # If the argument was not a hash, skip it.
+      unless arg.is_a?(Hash)
+        raise Puppet::ParseError, "deep_merge: unexpected argument type #{arg.class}, only expects hash arguments"
+      end
+
+      result = deep_merge.call(result, arg)
+    end
+    return( result )
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/defined_with_params.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/defined_with_params.rb
new file mode 100644
index 00000000..d7df306c
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/defined_with_params.rb
@@ -0,0 +1,35 @@
+# Test whether a given class or definition is defined
+require 'puppet/parser/functions'
+
+Puppet::Parser::Functions.newfunction(:defined_with_params,
+                                      :type => :rvalue,
+                                      :doc => <<-'ENDOFDOC'
+Takes a resource reference and an optional hash of attributes.
+
+Returns true if a resource with the specified attributes has already been added
+to the catalog, and false otherwise.
+
+    user { 'dan':
+      ensure => present,
+    }
+
+    if ! defined_with_params(User[dan], {'ensure' => 'present' }) {
+      user { 'dan': ensure => present, }
+    }
+ENDOFDOC
+) do |vals|
+  reference, params = vals
+  raise(ArgumentError, 'Must specify a reference') unless reference
+  if (! params) || params == ''
+    params = {}
+  end
+  ret = false
+  if resource = findresource(reference.to_s)
+    matches = params.collect do |key, value|
+      resource[key] == value
+    end
+    ret = params.empty? || !matches.include?(false)
+  end
+  Puppet.debug("Resource #{reference} was not determined to be defined")
+  ret
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/delete.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/delete.rb
new file mode 100644
index 00000000..f548b444
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/delete.rb
@@ -0,0 +1,49 @@
+#
+# delete.rb
+#
+
+# TODO(Krzysztof Wilczynski): We need to add support for regular expression ...
+
+module Puppet::Parser::Functions
+  newfunction(:delete, :type => :rvalue, :doc => <<-EOS
+Deletes all instances of a given element from an array, substring from a
+string, or key from a hash.
+
+*Examples:*
+
+    delete(['a','b','c','b'], 'b')
+    Would return: ['a','c']
+
+    delete({'a'=>1,'b'=>2,'c'=>3}, 'b')
+    Would return: {'a'=>1,'c'=>3}
+
+    delete({'a'=>1,'b'=>2,'c'=>3}, ['b','c'])
+    Would return: {'a'=>1}
+
+    delete('abracadabra', 'bra')
+    Would return: 'acada'
+  EOS
+  ) do |arguments|
+
+    if (arguments.size != 2) then
+      raise(Puppet::ParseError, "delete(): Wrong number of arguments "+
+                                  "given #{arguments.size} for 2.")
+    end
+
+    collection = arguments[0].dup
+    Array(arguments[1]).each do |item|
+      case collection
+        when Array, Hash
+          collection.delete item
+        when String
+          collection.gsub! item, ''
+        else
+          raise(TypeError, "delete(): First argument must be an Array, " +
+                             "String, or Hash. Given an argument of class #{collection.class}.")
+      end
+    end
+    collection
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/delete_at.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/delete_at.rb
new file mode 100644
index 00000000..3eb4b537
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/delete_at.rb
@@ -0,0 +1,49 @@
+#
+# delete_at.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:delete_at, :type => :rvalue, :doc => <<-EOS
+Deletes a determined indexed value from an array.
+
+*Examples:*
+
+    delete_at(['a','b','c'], 1)
+
+Would return: ['a','c']
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "delete_at(): Wrong number of arguments " +
+      "given (#{arguments.size} for 2)") if arguments.size < 2
+
+    array = arguments[0]
+
+    unless array.is_a?(Array)
+      raise(Puppet::ParseError, 'delete_at(): Requires array to work with')
+    end
+
+    index = arguments[1]
+
+    if index.is_a?(String) and not index.match(/^\d+$/)
+      raise(Puppet::ParseError, 'delete_at(): You must provide ' +
+        'non-negative numeric index')
+    end
+
+    result = array.clone
+
+    # Numbers in Puppet are often string-encoded which is troublesome ...
+    index = index.to_i
+
+    if index > result.size - 1 # First element is at index 0 is it not?
+      raise(Puppet::ParseError, 'delete_at(): Given index ' +
+        'exceeds size of array given')
+    end
+
+    result.delete_at(index) # We ignore the element that got deleted ...
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/delete_undef_values.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/delete_undef_values.rb
new file mode 100644
index 00000000..f94d4da8
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/delete_undef_values.rb
@@ -0,0 +1,34 @@
+module Puppet::Parser::Functions
+  newfunction(:delete_undef_values, :type => :rvalue, :doc => <<-EOS
+Returns a copy of input hash or array with all undefs deleted.
+
+*Examples:*
+
+    $hash = delete_undef_values({a=>'A', b=>'', c=>undef, d => false})
+
+Would return: {a => 'A', b => '', d => false}
+
+    $array = delete_undef_values(['A','',undef,false])
+
+Would return: ['A','',false]
+
+      EOS
+    ) do |args|
+
+    raise(Puppet::ParseError,
+          "delete_undef_values(): Wrong number of arguments given " +
+          "(#{args.size})") if args.size < 1
+
+    unless args[0].is_a? Array or args[0].is_a? Hash
+      raise(Puppet::ParseError,
+            "delete_undef_values(): expected an array or hash, got #{args[0]} type  #{args[0].class} ")
+    end
+    result = args[0].dup
+    if result.is_a?(Hash)
+      result.delete_if {|key, val| val.equal? :undef}
+    elsif result.is_a?(Array)
+      result.delete :undef
+    end
+    result
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/delete_values.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/delete_values.rb
new file mode 100644
index 00000000..f6c8c0e6
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/delete_values.rb
@@ -0,0 +1,26 @@
+module Puppet::Parser::Functions
+  newfunction(:delete_values, :type => :rvalue, :doc => <<-EOS
+Deletes all instances of a given value from a hash.
+
+*Examples:*
+
+    delete_values({'a'=>'A','b'=>'B','c'=>'C','B'=>'D'}, 'B')
+
+Would return: {'a'=>'A','c'=>'C','B'=>'D'}
+
+      EOS
+    ) do |arguments|
+
+    raise(Puppet::ParseError,
+          "delete_values(): Wrong number of arguments given " +
+          "(#{arguments.size} of 2)") if arguments.size != 2
+
+    hash, item = arguments
+
+    if not hash.is_a?(Hash)
+      raise(TypeError, "delete_values(): First argument must be a Hash. " + \
+                       "Given an argument of class #{hash.class}.")
+    end
+    hash.dup.delete_if { |key, val| item == val }
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/difference.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/difference.rb
new file mode 100644
index 00000000..cd258f75
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/difference.rb
@@ -0,0 +1,36 @@
+#
+# difference.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:difference, :type => :rvalue, :doc => <<-EOS
+This function returns the difference between two arrays.
+The returned array is a copy of the original array, removing any items that
+also appear in the second array.
+
+*Examples:*
+
+    difference(["a","b","c"],["b","c","d"])
+
+Would return: ["a"]
+    EOS
+  ) do |arguments|
+
+    # Two arguments are required
+    raise(Puppet::ParseError, "difference(): Wrong number of arguments " +
+      "given (#{arguments.size} for 2)") if arguments.size != 2
+
+    first = arguments[0]
+    second = arguments[1]
+
+    unless first.is_a?(Array) && second.is_a?(Array)
+      raise(Puppet::ParseError, 'difference(): Requires 2 arrays')
+    end
+
+    result = first - second
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/dirname.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/dirname.rb
new file mode 100644
index 00000000..ea8cc1e0
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/dirname.rb
@@ -0,0 +1,15 @@
+module Puppet::Parser::Functions
+  newfunction(:dirname, :type => :rvalue, :doc => <<-EOS
+    Returns the dirname of a path.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "dirname(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    path = arguments[0]
+    return File.dirname(path)
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/downcase.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/downcase.rb
new file mode 100644
index 00000000..040b84f5
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/downcase.rb
@@ -0,0 +1,32 @@
+#
+#  downcase.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:downcase, :type => :rvalue, :doc => <<-EOS
+Converts the case of a string or all strings in an array to lower case.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "downcase(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+
+    unless value.is_a?(Array) || value.is_a?(String)
+      raise(Puppet::ParseError, 'downcase(): Requires either ' +
+        'array or string to work with')
+    end
+
+    if value.is_a?(Array)
+      # Numbers in Puppet are often string-encoded which is troublesome ...
+      result = value.collect { |i| i.is_a?(String) ? i.downcase : i }
+    else
+      result = value.downcase
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/empty.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/empty.rb
new file mode 100644
index 00000000..cca620fa
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/empty.rb
@@ -0,0 +1,27 @@
+#
+# empty.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:empty, :type => :rvalue, :doc => <<-EOS
+Returns true if the variable is empty.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "empty(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+
+    unless value.is_a?(Array) || value.is_a?(Hash) || value.is_a?(String)
+      raise(Puppet::ParseError, 'empty(): Requires either ' +
+        'array, hash or string to work with')
+    end
+
+    result = value.empty?
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/ensure_packages.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/ensure_packages.rb
new file mode 100644
index 00000000..f1da4aaa
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/ensure_packages.rb
@@ -0,0 +1,35 @@
+#
+# ensure_packages.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:ensure_packages, :type => :statement, :doc => <<-EOS
+Takes a list of packages and only installs them if they don't already exist.
+It optionally takes a hash as a second parameter that will be passed as the
+third argument to the ensure_resource() function.
+    EOS
+  ) do |arguments|
+
+    if arguments.size > 2 or arguments.size == 0
+      raise(Puppet::ParseError, "ensure_packages(): Wrong number of arguments " +
+        "given (#{arguments.size} for 1 or 2)")
+    elsif arguments.size == 2 and !arguments[1].is_a?(Hash) 
+      raise(Puppet::ParseError, 'ensure_packages(): Requires second argument to be a Hash')
+    end
+
+    packages = Array(arguments[0])
+
+    if arguments[1]
+      defaults = { 'ensure' => 'present' }.merge(arguments[1])
+    else
+      defaults = { 'ensure' => 'present' }
+    end
+
+    Puppet::Parser::Functions.function(:ensure_resource)
+    packages.each { |package_name|
+      function_ensure_resource(['package', package_name, defaults ])
+    }
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/ensure_resource.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/ensure_resource.rb
new file mode 100644
index 00000000..1ba6a447
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/ensure_resource.rb
@@ -0,0 +1,46 @@
+# Test whether a given class or definition is defined
+require 'puppet/parser/functions'
+
+Puppet::Parser::Functions.newfunction(:ensure_resource,
+                                      :type => :statement,
+                                      :doc => <<-'ENDOFDOC'
+Takes a resource type, title, and a list of attributes that describe a
+resource.
+
+    user { 'dan':
+      ensure => present,
+    }
+
+This example only creates the resource if it does not already exist:
+
+    ensure_resource('user', 'dan', {'ensure' => 'present' })
+
+If the resource already exists but does not match the specified parameters,
+this function will attempt to recreate the resource leading to a duplicate
+resource definition error.
+
+An array of resources can also be passed in and each will be created with
+the type and parameters specified if it doesn't already exist.
+
+    ensure_resource('user', ['dan','alex'], {'ensure' => 'present'})
+
+ENDOFDOC
+) do |vals|
+  type, title, params = vals
+  raise(ArgumentError, 'Must specify a type') unless type
+  raise(ArgumentError, 'Must specify a title') unless title
+  params ||= {}
+
+  items = [title].flatten
+
+  items.each do |item|
+    Puppet::Parser::Functions.function(:defined_with_params)
+    if function_defined_with_params(["#{type}[#{item}]", params])
+      Puppet.debug("Resource #{type}[#{item}] with params #{params} not created because it already exists")
+    else
+      Puppet.debug("Create new resource #{type}[#{item}] with params #{params}")
+      Puppet::Parser::Functions.function(:create_resources)
+      function_create_resources([type.capitalize, { item => params }])
+    end
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/flatten.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/flatten.rb
new file mode 100644
index 00000000..a1ed1832
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/flatten.rb
@@ -0,0 +1,33 @@
+#
+# flatten.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:flatten, :type => :rvalue, :doc => <<-EOS
+This function flattens any deeply nested arrays and returns a single flat array
+as a result.
+
+*Examples:*
+
+    flatten(['a', ['b', ['c']]])
+
+Would return: ['a','b','c']
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "flatten(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size != 1
+
+    array = arguments[0]
+
+    unless array.is_a?(Array)
+      raise(Puppet::ParseError, 'flatten(): Requires array to work with')
+    end
+
+    result = array.flatten
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/floor.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/floor.rb
new file mode 100644
index 00000000..9a6f014d
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/floor.rb
@@ -0,0 +1,25 @@
+module Puppet::Parser::Functions
+  newfunction(:floor, :type => :rvalue, :doc => <<-EOS
+    Returns the largest integer less or equal to the argument.
+    Takes a single numeric value as an argument.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "floor(): Wrong number of arguments " +
+          "given (#{arguments.size} for 1)") if arguments.size != 1
+
+    begin
+      arg = Float(arguments[0])
+    rescue TypeError, ArgumentError => e
+      raise(Puppet::ParseError, "floor(): Wrong argument type " +
+            "given (#{arguments[0]} for Numeric)")
+    end
+
+    raise(Puppet::ParseError, "floor(): Wrong argument type " +
+          "given (#{arg.class} for Numeric)") if arg.is_a?(Numeric) == false
+
+    arg.floor
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/fqdn_rotate.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/fqdn_rotate.rb
new file mode 100644
index 00000000..7f4d37d0
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/fqdn_rotate.rb
@@ -0,0 +1,45 @@
+#
+# fqdn_rotate.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:fqdn_rotate, :type => :rvalue, :doc => <<-EOS
+Rotates an array a random number of times based on a nodes fqdn.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "fqdn_rotate(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+    require 'digest/md5'
+
+    unless value.is_a?(Array) || value.is_a?(String)
+      raise(Puppet::ParseError, 'fqdn_rotate(): Requires either ' +
+        'array or string to work with')
+    end
+
+    result = value.clone
+
+    string = value.is_a?(String) ? true : false
+
+    # Check whether it makes sense to rotate ...
+    return result if result.size <= 1
+
+    # We turn any string value into an array to be able to rotate ...
+    result = string ? result.split('') : result
+
+    elements = result.size
+
+    srand(Digest::MD5.hexdigest([lookupvar('::fqdn'),arguments].join(':')).hex)
+    rand(elements).times {
+       result.push result.shift
+    }
+
+    result = string ? result.join : result
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/get_module_path.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/get_module_path.rb
new file mode 100644
index 00000000..1421b91f
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/get_module_path.rb
@@ -0,0 +1,17 @@
+module Puppet::Parser::Functions
+  newfunction(:get_module_path, :type =>:rvalue, :doc => <<-EOT
+    Returns the absolute path of the specified module for the current
+    environment.
+
+    Example:
+      $module_path = get_module_path('stdlib')
+  EOT
+  ) do |args|
+    raise(Puppet::ParseError, "get_module_path(): Wrong number of arguments, expects one") unless args.size == 1
+    if module_path = Puppet::Module.find(args[0], compiler.environment.to_s)
+      module_path.path
+    else
+      raise(Puppet::ParseError, "Could not find module #{args[0]} in environment #{compiler.environment}")
+    end
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/getparam.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/getparam.rb
new file mode 100644
index 00000000..6d510069
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/getparam.rb
@@ -0,0 +1,35 @@
+# Test whether a given class or definition is defined
+require 'puppet/parser/functions'
+
+Puppet::Parser::Functions.newfunction(:getparam,
+                                      :type => :rvalue,
+                                      :doc => <<-'ENDOFDOC'
+Takes a resource reference and name of the parameter and
+returns value of resource's parameter.
+
+*Examples:*
+
+    define example_resource($param) {
+    }
+
+    example_resource { "example_resource_instance":
+        param => "param_value"
+    }
+
+    getparam(Example_resource["example_resource_instance"], "param")
+
+Would return: param_value
+ENDOFDOC
+) do |vals|
+  reference, param = vals
+  raise(ArgumentError, 'Must specify a reference') unless reference
+  raise(ArgumentError, 'Must specify name of a parameter') unless param and param.instance_of? String
+
+  return '' if param.empty?
+
+  if resource = findresource(reference.to_s)
+    return resource[param] if resource[param]
+  end
+
+  return ''
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/getvar.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/getvar.rb
new file mode 100644
index 00000000..fb336b6a
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/getvar.rb
@@ -0,0 +1,29 @@
+module Puppet::Parser::Functions
+
+  newfunction(:getvar, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
+    Lookup a variable in a remote namespace.
+
+    For example:
+
+        $foo = getvar('site::data::foo')
+        # Equivalent to $foo = $site::data::foo
+
+    This is useful if the namespace itself is stored in a string:
+
+        $datalocation = 'site::data'
+        $bar = getvar("${datalocation}::bar")
+        # Equivalent to $bar = $site::data::bar
+    ENDHEREDOC
+
+    unless args.length == 1
+      raise Puppet::ParseError, ("getvar(): wrong number of arguments (#{args.length}; must be 1)")
+    end
+
+    begin
+      self.lookupvar("#{args[0]}")
+    rescue Puppet::ParseError # Eat the exception if strict_variables = true is set
+    end
+
+  end
+
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/grep.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/grep.rb
new file mode 100644
index 00000000..ceba9ecc
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/grep.rb
@@ -0,0 +1,33 @@
+#
+# grep.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:grep, :type => :rvalue, :doc => <<-EOS
+This function searches through an array and returns any elements that match
+the provided regular expression.
+
+*Examples:*
+
+    grep(['aaa','bbb','ccc','aaaddd'], 'aaa')
+
+Would return:
+
+    ['aaa','aaaddd']
+    EOS
+  ) do |arguments|
+
+    if (arguments.size != 2) then
+      raise(Puppet::ParseError, "grep(): Wrong number of arguments "+
+        "given #{arguments.size} for 2")
+    end
+
+    a = arguments[0]
+    pattern = Regexp.new(arguments[1])
+
+    a.grep(pattern)
+
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/has_interface_with.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/has_interface_with.rb
new file mode 100644
index 00000000..36915246
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/has_interface_with.rb
@@ -0,0 +1,68 @@
+#
+# has_interface_with
+#
+
+module Puppet::Parser::Functions
+  newfunction(:has_interface_with, :type => :rvalue, :doc => <<-EOS
+Returns boolean based on kind and value:
+  * macaddress
+  * netmask
+  * ipaddress
+  * network
+
+has_interface_with("macaddress", "x:x:x:x:x:x")
+has_interface_with("ipaddress", "127.0.0.1")    => true
+etc.
+
+If no "kind" is given, then the presence of the interface is checked:
+has_interface_with("lo")                        => true
+    EOS
+  ) do |args|
+
+    raise(Puppet::ParseError, "has_interface_with(): Wrong number of arguments " +
+          "given (#{args.size} for 1 or 2)") if args.size < 1 or args.size > 2
+
+    interfaces = lookupvar('interfaces')
+
+    # If we do not have any interfaces, then there are no requested attributes
+    return false if (interfaces == :undefined || interfaces.nil?)
+
+    interfaces = interfaces.split(',')
+
+    if args.size == 1
+      return interfaces.member?(args[0])
+    end
+
+    kind, value = args
+
+    # Bug with 3.7.1 - 3.7.3  when using future parser throws :undefined_variable
+    # https://tickets.puppetlabs.com/browse/PUP-3597
+    factval = nil
+    catch :undefined_variable do
+      factval = lookupvar(kind)
+    end
+    if factval == value
+      return true
+    end
+
+    result = false
+    interfaces.each do |iface|
+      iface.downcase!
+      factval = nil
+      begin
+        # Bug with 3.7.1 - 3.7.3 when using future parser throws :undefined_variable
+        # https://tickets.puppetlabs.com/browse/PUP-3597
+        catch :undefined_variable do
+          factval = lookupvar("#{kind}_#{iface}")
+        end
+      rescue Puppet::ParseError # Eat the exception if strict_variables = true is set
+      end
+      if value == factval
+        result = true
+        break
+      end
+    end
+
+    result
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/has_ip_address.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/has_ip_address.rb
new file mode 100644
index 00000000..842c8ec6
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/has_ip_address.rb
@@ -0,0 +1,25 @@
+#
+# has_ip_address
+#
+
+module Puppet::Parser::Functions
+  newfunction(:has_ip_address, :type => :rvalue, :doc => <<-EOS
+Returns true if the client has the requested IP address on some interface.
+
+This function iterates through the 'interfaces' fact and checks the
+'ipaddress_IFACE' facts, performing a simple string comparison.
+    EOS
+  ) do |args|
+
+    raise(Puppet::ParseError, "has_ip_address(): Wrong number of arguments " +
+          "given (#{args.size} for 1)") if args.size != 1
+
+    Puppet::Parser::Functions.autoloader.load(:has_interface_with) \
+      unless Puppet::Parser::Functions.autoloader.loaded?(:has_interface_with)
+
+    function_has_interface_with(['ipaddress', args[0]])
+
+  end
+end
+
+# vim:sts=2 sw=2
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/has_ip_network.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/has_ip_network.rb
new file mode 100644
index 00000000..9ccf9024
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/has_ip_network.rb
@@ -0,0 +1,25 @@
+#
+# has_ip_network
+#
+
+module Puppet::Parser::Functions
+  newfunction(:has_ip_network, :type => :rvalue, :doc => <<-EOS
+Returns true if the client has an IP address within the requested network.
+
+This function iterates through the 'interfaces' fact and checks the
+'network_IFACE' facts, performing a simple string comparision.
+    EOS
+  ) do |args|
+
+    raise(Puppet::ParseError, "has_ip_network(): Wrong number of arguments " +
+          "given (#{args.size} for 1)") if args.size != 1
+
+    Puppet::Parser::Functions.autoloader.load(:has_interface_with) \
+      unless Puppet::Parser::Functions.autoloader.loaded?(:has_interface_with)
+
+    function_has_interface_with(['network', args[0]])
+
+  end
+end
+
+# vim:sts=2 sw=2
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/has_key.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/has_key.rb
new file mode 100644
index 00000000..4657cc29
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/has_key.rb
@@ -0,0 +1,28 @@
+module Puppet::Parser::Functions
+
+  newfunction(:has_key, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
+    Determine if a hash has a certain key value.
+
+    Example:
+
+        $my_hash = {'key_one' => 'value_one'}
+        if has_key($my_hash, 'key_two') {
+          notice('we will not reach here')
+        }
+        if has_key($my_hash, 'key_one') {
+          notice('this will be printed')
+        }
+
+    ENDHEREDOC
+
+    unless args.length == 2
+      raise Puppet::ParseError, ("has_key(): wrong number of arguments (#{args.length}; must be 2)")
+    end
+    unless args[0].is_a?(Hash)
+      raise Puppet::ParseError, "has_key(): expects the first argument to be a hash, got #{args[0].inspect} which is of type #{args[0].class}"
+    end
+    args[0].has_key?(args[1])
+
+  end
+
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/hash.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/hash.rb
new file mode 100644
index 00000000..8cc4823b
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/hash.rb
@@ -0,0 +1,41 @@
+#
+# hash.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:hash, :type => :rvalue, :doc => <<-EOS
+This function converts an array into a hash.
+
+*Examples:*
+
+    hash(['a',1,'b',2,'c',3])
+
+Would return: {'a'=>1,'b'=>2,'c'=>3}
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "hash(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    array = arguments[0]
+
+    unless array.is_a?(Array)
+      raise(Puppet::ParseError, 'hash(): Requires array to work with')
+    end
+
+    result = {}
+
+    begin
+      # This is to make it compatible with older version of Ruby ...
+      array  = array.flatten
+      result = Hash[*array]
+    rescue Exception
+      raise(Puppet::ParseError, 'hash(): Unable to compute ' +
+        'hash from array given')
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/intersection.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/intersection.rb
new file mode 100644
index 00000000..48f02e9d
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/intersection.rb
@@ -0,0 +1,34 @@
+#
+# intersection.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:intersection, :type => :rvalue, :doc => <<-EOS
+This function returns an array an intersection of two.
+
+*Examples:*
+
+    intersection(["a","b","c"],["b","c","d"])
+
+Would return: ["b","c"]
+    EOS
+  ) do |arguments|
+
+    # Two arguments are required
+    raise(Puppet::ParseError, "intersection(): Wrong number of arguments " +
+      "given (#{arguments.size} for 2)") if arguments.size != 2
+
+    first = arguments[0]
+    second = arguments[1]
+
+    unless first.is_a?(Array) && second.is_a?(Array)
+      raise(Puppet::ParseError, 'intersection(): Requires 2 arrays')
+    end
+
+    result = first & second
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/is_array.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/is_array.rb
new file mode 100644
index 00000000..b39e184a
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/is_array.rb
@@ -0,0 +1,22 @@
+#
+# is_array.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:is_array, :type => :rvalue, :doc => <<-EOS
+Returns true if the variable passed to this function is an array.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "is_array(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    type = arguments[0]
+
+    result = type.is_a?(Array)
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/is_bool.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/is_bool.rb
new file mode 100644
index 00000000..8bbdbc8a
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/is_bool.rb
@@ -0,0 +1,22 @@
+#
+# is_bool.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:is_bool, :type => :rvalue, :doc => <<-EOS
+Returns true if the variable passed to this function is a boolean.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "is_bool(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size != 1
+
+    type = arguments[0]
+
+    result = type.is_a?(TrueClass) || type.is_a?(FalseClass)
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/is_domain_name.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/is_domain_name.rb
new file mode 100644
index 00000000..b3fee965
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/is_domain_name.rb
@@ -0,0 +1,50 @@
+#
+# is_domain_name.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:is_domain_name, :type => :rvalue, :doc => <<-EOS
+Returns true if the string passed to this function is a syntactically correct domain name.
+    EOS
+  ) do |arguments|
+
+    if (arguments.size != 1) then
+      raise(Puppet::ParseError, "is_domain_name(): Wrong number of arguments "+
+        "given #{arguments.size} for 1")
+    end
+
+    domain = arguments[0]
+
+    # Limits (rfc1035, 3.1)
+    domain_max_length=255
+    label_min_length=1
+    label_max_length=63
+
+    # Only allow string types
+    return false unless domain.is_a?(String)
+
+    # Allow ".", it is the top level domain
+    return true if domain == '.'
+
+    # Remove the final dot, if present.
+    domain.chomp!('.')
+
+    # Check the whole domain
+    return false if domain.empty?
+    return false if domain.length > domain_max_length
+
+    # Check each label in the domain
+    labels = domain.split('.')
+    vlabels = labels.each do |label|
+      break if label.length < label_min_length
+      break if label.length > label_max_length
+      break if label[-1..-1] == '-'
+      break if label[0..0] == '-'
+      break unless /^[a-z\d-]+$/i.match(label)
+    end
+    return vlabels == labels
+
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/is_float.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/is_float.rb
new file mode 100644
index 00000000..a2da9438
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/is_float.rb
@@ -0,0 +1,30 @@
+#
+# is_float.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:is_float, :type => :rvalue, :doc => <<-EOS
+Returns true if the variable passed to this function is a float.
+    EOS
+  ) do |arguments|
+
+    if (arguments.size != 1) then
+      raise(Puppet::ParseError, "is_float(): Wrong number of arguments "+
+        "given #{arguments.size} for 1")
+    end
+
+    value = arguments[0]
+
+    # Only allow Numeric or String types
+    return false unless value.is_a?(Numeric) or value.is_a?(String)
+
+    if value != value.to_f.to_s and !value.is_a? Float then
+      return false
+    else
+      return true
+    end
+
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/is_function_available.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/is_function_available.rb
new file mode 100644
index 00000000..6da82c8c
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/is_function_available.rb
@@ -0,0 +1,26 @@
+#
+# is_function_available.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:is_function_available, :type => :rvalue, :doc => <<-EOS
+This function accepts a string as an argument, determines whether the
+Puppet runtime has access to a function by that name.  It returns a
+true if the function exists, false if not.
+    EOS
+  ) do |arguments|
+
+    if (arguments.size != 1) then
+      raise(Puppet::ParseError, "is_function_available?(): Wrong number of arguments "+
+        "given #{arguments.size} for 1")
+    end
+
+    # Only allow String types
+    return false unless arguments[0].is_a?(String)
+
+    function = Puppet::Parser::Functions.function(arguments[0].to_sym)
+    function.is_a?(String) and not function.empty?
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/is_hash.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/is_hash.rb
new file mode 100644
index 00000000..ad907f08
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/is_hash.rb
@@ -0,0 +1,22 @@
+#
+# is_hash.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:is_hash, :type => :rvalue, :doc => <<-EOS
+Returns true if the variable passed to this function is a hash.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "is_hash(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size != 1
+
+    type = arguments[0]
+
+    result = type.is_a?(Hash)
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/is_integer.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/is_integer.rb
new file mode 100644
index 00000000..c03d28df
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/is_integer.rb
@@ -0,0 +1,45 @@
+#
+# is_integer.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:is_integer, :type => :rvalue, :doc => <<-EOS
+Returns true if the variable passed to this function is an Integer or
+a decimal (base 10) integer in String form. The string may
+start with a '-' (minus). A value of '0' is allowed, but a leading '0' digit may not
+be followed by other digits as this indicates that the value is octal (base 8).
+
+If given any other argument `false` is returned.
+    EOS
+  ) do |arguments|
+
+    if (arguments.size != 1) then
+      raise(Puppet::ParseError, "is_integer(): Wrong number of arguments "+
+        "given #{arguments.size} for 1")
+    end
+
+    value = arguments[0]
+
+    # Regex is taken from the lexer of puppet
+    # puppet/pops/parser/lexer.rb but modified to match also
+    # negative values and disallow numbers prefixed with multiple
+    # 0's
+    #
+    # TODO these parameter should be a constant but I'm not sure
+    # if there is no risk to declare it inside of the module
+    # Puppet::Parser::Functions
+
+    # Integer numbers like
+    # -1234568981273
+    # 47291
+    numeric = %r{^-?(?:(?:[1-9]\d*)|0)$}
+
+    if value.is_a? Integer or (value.is_a? String and value.match numeric)
+      return true
+    else
+      return false
+    end
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/is_ip_address.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/is_ip_address.rb
new file mode 100644
index 00000000..a90adabe
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/is_ip_address.rb
@@ -0,0 +1,32 @@
+#
+# is_ip_address.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:is_ip_address, :type => :rvalue, :doc => <<-EOS
+Returns true if the string passed to this function is a valid IP address.
+    EOS
+  ) do |arguments|
+
+    require 'ipaddr'
+
+    if (arguments.size != 1) then
+      raise(Puppet::ParseError, "is_ip_address(): Wrong number of arguments "+
+        "given #{arguments.size} for 1")
+    end
+
+    begin
+      ip = IPAddr.new(arguments[0])
+    rescue ArgumentError
+      return false
+    end
+
+    if ip.ipv4? or ip.ipv6? then
+      return true
+    else
+      return false
+    end
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/is_mac_address.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/is_mac_address.rb
new file mode 100644
index 00000000..1b3088a2
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/is_mac_address.rb
@@ -0,0 +1,27 @@
+#
+# is_mac_address.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:is_mac_address, :type => :rvalue, :doc => <<-EOS
+Returns true if the string passed to this function is a valid mac address.
+    EOS
+  ) do |arguments|
+
+    if (arguments.size != 1) then
+      raise(Puppet::ParseError, "is_mac_address(): Wrong number of arguments "+
+        "given #{arguments.size} for 1")
+    end
+
+    mac = arguments[0]
+
+    if /^[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}$/.match(mac) then
+      return true
+    else
+      return false
+    end
+
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/is_numeric.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/is_numeric.rb
new file mode 100644
index 00000000..e7e1d2a7
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/is_numeric.rb
@@ -0,0 +1,75 @@
+#
+# is_numeric.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:is_numeric, :type => :rvalue, :doc => <<-EOS
+Returns true if the given argument is a Numeric (Integer or Float),
+or a String containing either a valid integer in decimal base 10 form, or
+a valid floating point string representation.
+
+The function recognizes only decimal (base 10) integers and float but not
+integers in hex (base 16) or octal (base 8) form.
+
+The string representation may start with a '-' (minus). If a decimal '.' is used,
+it must be followed by at least one digit.
+
+Valid examples:
+
+  77435
+  10e-12
+  -8475
+  0.2343
+  -23.561e3
+    EOS
+  ) do |arguments|
+
+    if (arguments.size != 1) then
+      raise(Puppet::ParseError, "is_numeric(): Wrong number of arguments "+
+        "given #{arguments.size} for 1")
+    end
+
+    value = arguments[0]
+
+    # Regex is taken from the lexer of puppet
+    # puppet/pops/parser/lexer.rb but modified to match also
+    # negative values and disallow invalid octal numbers or
+    # numbers prefixed with multiple 0's (except in hex numbers)
+    #
+    # TODO these parameters should be constants but I'm not sure
+    # if there is no risk to declare them inside of the module
+    # Puppet::Parser::Functions
+
+    # TODO decide if this should be used
+    # HEX numbers like
+    # 0xaa230F
+    # 0X1234009C
+    # 0x0012
+    # -12FcD
+    #numeric_hex = %r{^-?0[xX][0-9A-Fa-f]+$}
+
+    # TODO decide if this should be used
+    # OCTAL numbers like
+    # 01234567
+    # -045372
+    #numeric_oct = %r{^-?0[1-7][0-7]*$}
+
+    # Integer/Float numbers like
+    # -0.1234568981273
+    # 47291
+    # 42.12345e-12
+    numeric = %r{^-?(?:(?:[1-9]\d*)|0)(?:\.\d+)?(?:[eE]-?\d+)?$}
+
+    if value.is_a? Numeric or (value.is_a? String and (
+      value.match(numeric) #or
+    #  value.match(numeric_hex) or
+    #  value.match(numeric_oct)
+    ))
+      return true
+    else
+      return false
+    end
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/is_string.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/is_string.rb
new file mode 100644
index 00000000..f5bef045
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/is_string.rb
@@ -0,0 +1,26 @@
+#
+# is_string.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:is_string, :type => :rvalue, :doc => <<-EOS
+Returns true if the variable passed to this function is a string.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "is_string(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    type = arguments[0]
+
+    result = type.is_a?(String)
+
+    if result and (type == type.to_f.to_s or type == type.to_i.to_s) then
+      return false
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/join.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/join.rb
new file mode 100644
index 00000000..6c0a6ba0
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/join.rb
@@ -0,0 +1,41 @@
+#
+# join.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:join, :type => :rvalue, :doc => <<-EOS
+This function joins an array into a string using a separator.
+
+*Examples:*
+
+    join(['a','b','c'], ",")
+
+Would result in: "a,b,c"
+    EOS
+  ) do |arguments|
+
+    # Technically we support two arguments but only first is mandatory ...
+    raise(Puppet::ParseError, "join(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    array = arguments[0]
+
+    unless array.is_a?(Array)
+      raise(Puppet::ParseError, 'join(): Requires array to work with')
+    end
+
+    suffix = arguments[1] if arguments[1]
+
+    if suffix
+      unless suffix.is_a?(String)
+        raise(Puppet::ParseError, 'join(): Requires string to work with')
+      end
+    end
+
+    result = suffix ? array.join(suffix) : array.join
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/join_keys_to_values.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/join_keys_to_values.rb
new file mode 100644
index 00000000..e9924fe2
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/join_keys_to_values.rb
@@ -0,0 +1,47 @@
+#
+# join.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:join_keys_to_values, :type => :rvalue, :doc => <<-EOS
+This function joins each key of a hash to that key's corresponding value with a
+separator. Keys and values are cast to strings. The return value is an array in
+which each element is one joined key/value pair.
+
+*Examples:*
+
+    join_keys_to_values({'a'=>1,'b'=>2}, " is ")
+
+Would result in: ["a is 1","b is 2"]
+    EOS
+  ) do |arguments|
+
+    # Validate the number of arguments.
+    if arguments.size != 2
+      raise(Puppet::ParseError, "join_keys_to_values(): Takes exactly two " +
+            "arguments, but #{arguments.size} given.")
+    end
+
+    # Validate the first argument.
+    hash = arguments[0]
+    if not hash.is_a?(Hash)
+      raise(TypeError, "join_keys_to_values(): The first argument must be a " +
+            "hash, but a #{hash.class} was given.")
+    end
+
+    # Validate the second argument.
+    separator = arguments[1]
+    if not separator.is_a?(String)
+      raise(TypeError, "join_keys_to_values(): The second argument must be a " +
+            "string, but a #{separator.class} was given.")
+    end
+
+    # Join the keys to their values.
+    hash.map do |k,v|
+      String(k) + separator + String(v)
+    end
+
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/keys.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/keys.rb
new file mode 100644
index 00000000..f0d13b64
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/keys.rb
@@ -0,0 +1,26 @@
+#
+# keys.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:keys, :type => :rvalue, :doc => <<-EOS
+Returns the keys of a hash as an array.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "keys(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    hash = arguments[0]
+
+    unless hash.is_a?(Hash)
+      raise(Puppet::ParseError, 'keys(): Requires hash to work with')
+    end
+
+    result = hash.keys
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/loadyaml.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/loadyaml.rb
new file mode 100644
index 00000000..10c40050
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/loadyaml.rb
@@ -0,0 +1,20 @@
+module Puppet::Parser::Functions
+
+  newfunction(:loadyaml, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
+    Load a YAML file containing an array, string, or hash, and return the data
+    in the corresponding native data type.
+
+    For example:
+
+        $myhash = loadyaml('/etc/puppet/data/myhash.yaml')
+    ENDHEREDOC
+
+    unless args.length == 1
+      raise Puppet::ParseError, ("loadyaml(): wrong number of arguments (#{args.length}; must be 1)")
+    end
+
+    YAML.load_file(args[0])
+
+  end
+
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/lstrip.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/lstrip.rb
new file mode 100644
index 00000000..624e4c84
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/lstrip.rb
@@ -0,0 +1,32 @@
+#
+#  lstrip.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:lstrip, :type => :rvalue, :doc => <<-EOS
+Strips leading spaces to the left of a string.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "lstrip(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+
+    unless value.is_a?(Array) || value.is_a?(String)
+      raise(Puppet::ParseError, 'lstrip(): Requires either ' +
+        'array or string to work with')
+    end
+
+    if value.is_a?(Array)
+      # Numbers in Puppet are often string-encoded which is troublesome ...
+      result = value.collect { |i| i.is_a?(String) ? i.lstrip : i }
+    else
+      result = value.lstrip
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/max.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/max.rb
new file mode 100644
index 00000000..60fb94ac
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/max.rb
@@ -0,0 +1,21 @@
+module Puppet::Parser::Functions
+  newfunction(:max, :type => :rvalue, :doc => <<-EOS
+    Returns the highest value of all arguments.
+    Requires at least one argument.
+    EOS
+  ) do |args|
+
+    raise(Puppet::ParseError, "max(): Wrong number of arguments " +
+          "need at least one") if args.size == 0
+
+    # Sometimes we get numbers as numerics and sometimes as strings.
+    # We try to compare them as numbers when possible
+    return args.max do |a,b|
+      if a.to_s =~ /\A-?\d+(.\d+)?\z/ and b.to_s =~ /\A-?\d+(.\d+)?\z/ then
+        a.to_f <=> b.to_f
+      else
+        a.to_s <=> b.to_s
+      end
+    end
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/member.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/member.rb
new file mode 100644
index 00000000..88609ce5
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/member.rb
@@ -0,0 +1,62 @@
+#
+# member.rb
+#
+
+# TODO(Krzysztof Wilczynski): We need to add support for regular expression ...
+# TODO(Krzysztof Wilczynski): Support for strings and hashes too ...
+
+module Puppet::Parser::Functions
+  newfunction(:member, :type => :rvalue, :doc => <<-EOS
+This function determines if a variable is a member of an array.
+The variable can be a string, fixnum, or array.
+
+*Examples:*
+
+    member(['a','b'], 'b')
+
+Would return: true
+
+    member(['a', 'b', 'c'], ['a', 'b'])
+
+would return: true
+
+    member(['a','b'], 'c')
+
+Would return: false
+
+    member(['a', 'b', 'c'], ['d', 'b'])
+
+would return: false
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "member(): Wrong number of arguments " +
+      "given (#{arguments.size} for 2)") if arguments.size < 2
+
+    array = arguments[0]
+
+    unless array.is_a?(Array)
+      raise(Puppet::ParseError, 'member(): Requires array to work with')
+    end
+
+    unless arguments[1].is_a? String or arguments[1].is_a? Fixnum or arguments[1].is_a? Array
+      raise(Puppet::ParseError, 'member(): Item to search for must be a string, fixnum, or array')
+    end
+
+    if arguments[1].is_a? String or arguments[1].is_a? Fixnum
+      item = Array(arguments[1])
+    else
+      item = arguments[1]
+    end
+
+
+    raise(Puppet::ParseError, 'member(): You must provide item ' +
+      'to search for within array given') if item.respond_to?('empty?') && item.empty?
+
+    result = (item - array).empty?
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/merge.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/merge.rb
new file mode 100644
index 00000000..1b39f206
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/merge.rb
@@ -0,0 +1,34 @@
+module Puppet::Parser::Functions
+  newfunction(:merge, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
+    Merges two or more hashes together and returns the resulting hash.
+
+    For example:
+
+        $hash1 = {'one' => 1, 'two', => 2}
+        $hash2 = {'two' => 'dos', 'three', => 'tres'}
+        $merged_hash = merge($hash1, $hash2)
+        # The resulting hash is equivalent to:
+        # $merged_hash =  {'one' => 1, 'two' => 'dos', 'three' => 'tres'}
+
+    When there is a duplicate key, the key in the rightmost hash will "win."
+
+    ENDHEREDOC
+
+    if args.length < 2
+      raise Puppet::ParseError, ("merge(): wrong number of arguments (#{args.length}; must be at least 2)")
+    end
+
+    # The hash we accumulate into
+    accumulator = Hash.new
+    # Merge into the accumulator hash
+    args.each do |arg|
+      next if arg.is_a? String and arg.empty? # empty string is synonym for puppet's undef
+      unless arg.is_a?(Hash)
+        raise Puppet::ParseError, "merge: unexpected argument type #{arg.class}, only expects hash arguments"
+      end
+      accumulator.merge!(arg)
+    end
+    # Return the fully merged hash
+    accumulator
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/min.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/min.rb
new file mode 100644
index 00000000..6bd6ebf2
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/min.rb
@@ -0,0 +1,21 @@
+module Puppet::Parser::Functions
+  newfunction(:min, :type => :rvalue, :doc => <<-EOS
+    Returns the lowest value of all arguments.
+    Requires at least one argument.
+    EOS
+  ) do |args|
+
+    raise(Puppet::ParseError, "min(): Wrong number of arguments " +
+          "need at least one") if args.size == 0
+
+    # Sometimes we get numbers as numerics and sometimes as strings.
+    # We try to compare them as numbers when possible
+    return args.min do |a,b|
+      if a.to_s =~ /\A^-?\d+(.\d+)?\z/ and b.to_s =~ /\A-?\d+(.\d+)?\z/ then
+        a.to_f <=> b.to_f
+      else
+        a.to_s <=> b.to_s
+      end
+    end
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/num2bool.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/num2bool.rb
new file mode 100644
index 00000000..af0e6ed7
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/num2bool.rb
@@ -0,0 +1,43 @@
+#
+# num2bool.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:num2bool, :type => :rvalue, :doc => <<-EOS
+This function converts a number or a string representation of a number into a
+true boolean. Zero or anything non-numeric becomes false. Numbers higher then 0
+become true.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "num2bool(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size != 1
+
+    number = arguments[0]
+
+    case number
+    when Numeric
+      # Yay, it's a number
+    when String
+      begin
+        number = Float(number)
+      rescue ArgumentError => ex
+        raise(Puppet::ParseError, "num2bool(): '#{number}' does not look like a number: #{ex.message}")
+      end
+    else
+      begin
+        number = number.to_s
+      rescue NoMethodError => ex
+        raise(Puppet::ParseError, "num2bool(): Unable to parse argument: #{ex.message}")
+      end
+    end
+
+    # Truncate Floats
+    number = number.to_i
+
+    # Return true for any positive number and false otherwise
+    return number > 0
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/obfuscate_email.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/obfuscate_email.rb
new file mode 100644
index 00000000..4e4cb826
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/obfuscate_email.rb
@@ -0,0 +1,16 @@
+module Puppet::Parser::Functions
+  newfunction(:obfuscate_email, :type => :rvalue, :doc => <<-EOS
+Given:
+  a comma seperated email string in form of 'john@doe.com, doe@john.com'
+
+This function will return all emails obfuscated in form of 'john {at} doe {dot} com, doe {at} john {dot} com' 
+Works with multiple email adresses as well as with a single email adress.
+
+    EOS
+  ) do |args|
+      args[0].gsub('@', ' {at} ').gsub('.', ' {dot} ')
+    end
+end
+
+# vim: set ts=2 sw=2 et :
+# encoding: utf-8
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/parsejson.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/parsejson.rb
new file mode 100644
index 00000000..a9a16a45
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/parsejson.rb
@@ -0,0 +1,24 @@
+#
+# parsejson.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:parsejson, :type => :rvalue, :doc => <<-EOS
+This function accepts JSON as a string and converts into the correct Puppet
+structure.
+    EOS
+  ) do |arguments|
+
+    if (arguments.size != 1) then
+      raise(Puppet::ParseError, "parsejson(): Wrong number of arguments "+
+        "given #{arguments.size} for 1")
+    end
+
+    json = arguments[0]
+
+    # PSON is natively available in puppet
+    PSON.load(json)
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/parseyaml.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/parseyaml.rb
new file mode 100644
index 00000000..53d54faf
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/parseyaml.rb
@@ -0,0 +1,24 @@
+#
+# parseyaml.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:parseyaml, :type => :rvalue, :doc => <<-EOS
+This function accepts YAML as a string and converts it into the correct
+Puppet structure.
+    EOS
+  ) do |arguments|
+
+    if (arguments.size != 1) then
+      raise(Puppet::ParseError, "parseyaml(): Wrong number of arguments "+
+        "given #{arguments.size} for 1")
+    end
+
+    require 'yaml'
+
+    YAML::load(arguments[0])
+
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/pick.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/pick.rb
new file mode 100644
index 00000000..fdd0aefd
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/pick.rb
@@ -0,0 +1,29 @@
+module Puppet::Parser::Functions
+ newfunction(:pick, :type => :rvalue, :doc => <<-EOS
+
+This function is similar to a coalesce function in SQL in that it will return
+the first value in a list of values that is not undefined or an empty string
+(two things in Puppet that will return a boolean false value). Typically,
+this function is used to check for a value in the Puppet Dashboard/Enterprise
+Console, and failover to a default value like the following:
+
+  $real_jenkins_version = pick($::jenkins_version, '1.449')
+
+The value of $real_jenkins_version will first look for a top-scope variable
+called 'jenkins_version' (note that parameters set in the Puppet Dashboard/
+Enterprise Console are brought into Puppet as top-scope variables), and,
+failing that, will use a default value of 1.449.
+
+EOS
+) do |args|
+   args = args.compact
+   args.delete(:undef)
+   args.delete(:undefined)
+   args.delete("")
+   if args[0].to_s.empty? then
+     fail Puppet::ParseError, "pick(): must receive at least one non empty value"
+   else
+     return args[0]
+   end
+ end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/pick_default.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/pick_default.rb
new file mode 100644
index 00000000..36e33abf
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/pick_default.rb
@@ -0,0 +1,35 @@
+module Puppet::Parser::Functions
+ newfunction(:pick_default, :type => :rvalue, :doc => <<-EOS
+
+This function is similar to a coalesce function in SQL in that it will return
+the first value in a list of values that is not undefined or an empty string
+(two things in Puppet that will return a boolean false value). If no value is
+found, it will return the last argument.
+
+Typically, this function is used to check for a value in the Puppet
+Dashboard/Enterprise Console, and failover to a default value like the
+following:
+
+  $real_jenkins_version = pick_default($::jenkins_version, '1.449')
+
+The value of $real_jenkins_version will first look for a top-scope variable
+called 'jenkins_version' (note that parameters set in the Puppet Dashboard/
+Enterprise Console are brought into Puppet as top-scope variables), and,
+failing that, will use a default value of 1.449.
+
+Note that, contrary to the pick() function, the pick_default does not fail if
+all arguments are empty. This allows pick_default to use an empty value as
+default.
+
+EOS
+) do |args|
+   fail "Must receive at least one argument." if args.empty?
+   default = args.last
+   args = args[0..-2].compact
+   args.delete(:undef)
+   args.delete(:undefined)
+   args.delete("")
+   args << default
+   return args[0]
+ end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/prefix.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/prefix.rb
new file mode 100644
index 00000000..d02286af
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/prefix.rb
@@ -0,0 +1,45 @@
+#
+# prefix.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:prefix, :type => :rvalue, :doc => <<-EOS
+This function applies a prefix to all elements in an array.
+
+*Examples:*
+
+    prefix(['a','b','c'], 'p')
+
+Will return: ['pa','pb','pc']
+    EOS
+  ) do |arguments|
+
+    # Technically we support two arguments but only first is mandatory ...
+    raise(Puppet::ParseError, "prefix(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    array = arguments[0]
+
+    unless array.is_a?(Array)
+      raise Puppet::ParseError, "prefix(): expected first argument to be an Array, got #{array.inspect}"
+    end
+
+    prefix = arguments[1] if arguments[1]
+
+    if prefix
+      unless prefix.is_a?(String)
+        raise Puppet::ParseError, "prefix(): expected second argument to be a String, got #{prefix.inspect}"
+      end
+    end
+
+    # Turn everything into string same as join would do ...
+    result = array.collect do |i|
+      i = i.to_s
+      prefix ? prefix + i : i
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/private.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/private.rb
new file mode 100644
index 00000000..60210d33
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/private.rb
@@ -0,0 +1,29 @@
+#
+# private.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:private, :doc => <<-'EOS'
+    Sets the current class or definition as private.
+    Calling the class or definition from outside the current module will fail.
+    EOS
+  ) do |args|
+
+    raise(Puppet::ParseError, "private(): Wrong number of arguments "+
+      "given (#{args.size}}) for 0 or 1)") if args.size > 1
+
+    scope = self
+    if scope.lookupvar('module_name') != scope.lookupvar('caller_module_name')
+      message = nil
+      if args[0] and args[0].is_a? String
+        message = args[0]
+      else
+        manifest_name = scope.source.name
+        manifest_type = scope.source.type
+        message = (manifest_type.to_s == 'hostclass') ? 'Class' : 'Definition'
+        message += " #{manifest_name} is private"
+      end
+      raise(Puppet::ParseError, message)
+    end
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/range.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/range.rb
new file mode 100644
index 00000000..49fba21c
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/range.rb
@@ -0,0 +1,88 @@
+#
+# range.rb
+#
+
+# TODO(Krzysztof Wilczynski): We probably need to approach numeric values differently ...
+
+module Puppet::Parser::Functions
+  newfunction(:range, :type => :rvalue, :doc => <<-EOS
+When given range in the form of (start, stop) it will extrapolate a range as
+an array.
+
+*Examples:*
+
+    range("0", "9")
+
+Will return: [0,1,2,3,4,5,6,7,8,9]
+
+    range("00", "09")
+
+Will return: [0,1,2,3,4,5,6,7,8,9] (Zero padded strings are converted to
+integers automatically)
+
+    range("a", "c")
+
+Will return: ["a","b","c"]
+
+    range("host01", "host10")
+
+Will return: ["host01", "host02", ..., "host09", "host10"]
+
+Passing a third argument will cause the generated range to step by that
+interval, e.g.
+
+    range("0", "9", "2")
+
+Will return: [0,2,4,6,8]
+    EOS
+  ) do |arguments|
+
+    # We support more than one argument but at least one is mandatory ...
+    raise(Puppet::ParseError, "range(): Wrong number of " +
+      "arguments given (#{arguments.size} for 1)") if arguments.size < 1
+
+    if arguments.size > 1
+      start = arguments[0]
+      stop  = arguments[1]
+      step  = arguments[2].nil? ? 1 : arguments[2].to_i.abs
+
+      type = '..' # We select simplest type for Range available in Ruby ...
+
+    elsif arguments.size > 0
+      value = arguments[0]
+
+      if m = value.match(/^(\w+)(\.\.\.?|\-)(\w+)$/)
+        start = m[1]
+        stop  = m[3]
+
+        type = m[2]
+
+      elsif value.match(/^.+$/)
+        raise(Puppet::ParseError, 'range(): Unable to compute range ' +
+          'from the value given')
+      else
+        raise(Puppet::ParseError, 'range(): Unknown format of range given')
+      end
+    end
+
+    # Check whether we have integer value if so then make it so ...
+    if start.to_s.match(/^\d+$/)
+      start = start.to_i
+      stop  = stop.to_i
+    else
+      start = start.to_s
+      stop  = stop.to_s
+    end
+
+    range = case type
+      when /^(\.\.|\-)$/ then (start .. stop)
+      when /^(\.\.\.)$/  then (start ... stop) # Exclusive of last element ...
+    end
+
+    result = range.step(step).collect { |i| i } # Get them all ... Pokemon ...
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/reject.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/reject.rb
new file mode 100644
index 00000000..1953ffcf
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/reject.rb
@@ -0,0 +1,31 @@
+#
+# reject.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:reject, :type => :rvalue, :doc => <<-EOS) do |args|
+This function searches through an array and rejects all elements that match
+the provided regular expression.
+
+*Examples:*
+
+    reject(['aaa','bbb','ccc','aaaddd'], 'aaa')
+
+Would return:
+
+    ['bbb','ccc']
+EOS
+
+    if (args.size != 2)
+      raise Puppet::ParseError,
+        "reject(): Wrong number of arguments given #{args.size} for 2"
+    end
+
+    ary = args[0]
+    pattern = Regexp.new(args[1])
+
+    ary.reject { |e| e =~ pattern }
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/reverse.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/reverse.rb
new file mode 100644
index 00000000..7f1018f6
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/reverse.rb
@@ -0,0 +1,27 @@
+#
+# reverse.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:reverse, :type => :rvalue, :doc => <<-EOS
+Reverses the order of a string or array.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "reverse(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+
+    unless value.is_a?(Array) || value.is_a?(String)
+      raise(Puppet::ParseError, 'reverse(): Requires either ' +
+        'array or string to work with')
+    end
+
+    result = value.reverse
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/rstrip.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/rstrip.rb
new file mode 100644
index 00000000..0cf8d222
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/rstrip.rb
@@ -0,0 +1,31 @@
+#
+#  rstrip.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:rstrip, :type => :rvalue, :doc => <<-EOS
+Strips leading spaces to the right of the string.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "rstrip(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+
+    unless value.is_a?(Array) || value.is_a?(String)
+      raise(Puppet::ParseError, 'rstrip(): Requires either ' +
+        'array or string to work with')
+    end
+
+    if value.is_a?(Array)
+      result = value.collect { |i| i.is_a?(String) ? i.rstrip : i }
+    else
+      result = value.rstrip
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/shuffle.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/shuffle.rb
new file mode 100644
index 00000000..30c663db
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/shuffle.rb
@@ -0,0 +1,45 @@
+#
+# shuffle.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:shuffle, :type => :rvalue, :doc => <<-EOS
+Randomizes the order of a string or array elements.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "shuffle(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+
+    unless value.is_a?(Array) || value.is_a?(String)
+      raise(Puppet::ParseError, 'shuffle(): Requires either ' +
+        'array or string to work with')
+    end
+
+    result = value.clone
+
+    string = value.is_a?(String) ? true : false
+
+    # Check whether it makes sense to shuffle ...
+    return result if result.size <= 1
+
+    # We turn any string value into an array to be able to shuffle ...
+    result = string ? result.split('') : result
+
+    elements = result.size
+
+    # Simple implementation of Fisher–Yates in-place shuffle ...
+    elements.times do |i|
+      j = rand(elements - i) + i
+      result[j], result[i] = result[i], result[j]
+    end
+
+    result = string ? result.join : result
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/size.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/size.rb
new file mode 100644
index 00000000..cc207e3f
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/size.rb
@@ -0,0 +1,48 @@
+#
+# size.rb
+#
+
+# TODO(Krzysztof Wilczynski): Support for hashes would be nice too ...
+
+module Puppet::Parser::Functions
+  newfunction(:size, :type => :rvalue, :doc => <<-EOS
+Returns the number of elements in a string or array.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "size(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    item = arguments[0]
+
+    if item.is_a?(String)
+
+      begin
+        #
+        # Check whether your item is a numeric value or not ...
+        # This will take care about positive and/or negative numbers
+        # for both integer and floating-point values ...
+        #
+        # Please note that Puppet has no notion of hexadecimal
+        # nor octal numbers for its DSL at this point in time ...
+        #
+        Float(item)
+
+        raise(Puppet::ParseError, 'size(): Requires either ' +
+          'string or array to work with')
+
+      rescue ArgumentError
+        result = item.size
+      end
+
+    elsif item.is_a?(Array)
+      result = item.size
+    else
+      raise(Puppet::ParseError, 'size(): Unknown type given')
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/sort.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/sort.rb
new file mode 100644
index 00000000..cefbe546
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/sort.rb
@@ -0,0 +1,27 @@
+#
+# sort.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:sort, :type => :rvalue, :doc => <<-EOS
+Sorts strings and arrays lexically.
+    EOS
+  ) do |arguments|
+
+    if (arguments.size != 1) then
+      raise(Puppet::ParseError, "sort(): Wrong number of arguments "+
+        "given #{arguments.size} for 1")
+    end
+
+    value = arguments[0]
+
+    if value.is_a?(Array) then
+      value.sort
+    elsif value.is_a?(String) then
+      value.split("").sort.join("")
+    end
+
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/squeeze.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/squeeze.rb
new file mode 100644
index 00000000..81fadfdb
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/squeeze.rb
@@ -0,0 +1,36 @@
+#
+# squeeze.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:squeeze, :type => :rvalue, :doc => <<-EOS
+Returns a new string where runs of the same character that occur in this set are replaced by a single character.
+    EOS
+  ) do |arguments|
+
+    if ((arguments.size != 2) and (arguments.size != 1)) then
+      raise(Puppet::ParseError, "squeeze(): Wrong number of arguments "+
+        "given #{arguments.size} for 2 or 1")
+    end
+
+    item = arguments[0]
+    squeezeval = arguments[1]
+
+    if item.is_a?(Array) then
+      if squeezeval then
+        item.collect { |i| i.squeeze(squeezeval) }
+      else
+        item.collect { |i| i.squeeze }
+      end
+    else
+      if squeezeval then
+        item.squeeze(squeezeval)
+      else
+        item.squeeze
+      end
+    end
+
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/str2bool.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/str2bool.rb
new file mode 100644
index 00000000..446732ec
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/str2bool.rb
@@ -0,0 +1,46 @@
+#
+# str2bool.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:str2bool, :type => :rvalue, :doc => <<-EOS
+This converts a string to a boolean. This attempt to convert strings that
+contain things like: y, 1, t, true to 'true' and strings that contain things
+like: 0, f, n, false, no to 'false'.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "str2bool(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    string = arguments[0]
+
+    # If string is already Boolean, return it
+    if !!string == string
+      return string
+    end
+
+    unless string.is_a?(String)
+      raise(Puppet::ParseError, 'str2bool(): Requires either ' +
+        'string to work with')
+    end
+
+    # We consider all the yes, no, y, n and so on too ...
+    result = case string
+      #
+      # This is how undef looks like in Puppet ...
+      # We yield false in this case.
+      #
+      when /^$/, '' then false # Empty string will be false ...
+      when /^(1|t|y|true|yes)$/  then true
+      when /^(0|f|n|false|no)$/  then false
+      when /^(undef|undefined)$/ then false # This is not likely to happen ...
+      else
+        raise(Puppet::ParseError, 'str2bool(): Unknown type of boolean given')
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/str2saltedsha1.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/str2saltedsha1.rb
new file mode 100644
index 00000000..e51a861a
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/str2saltedsha1.rb
@@ -0,0 +1,32 @@
+#
+# str2saltedsha1.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:str2saltedsha1, :type => :rvalue, :doc => <<-EOS
+This converts a string to a salted-SHA1 password hash (which is used for
+OS X versions >= 10.7). Given any simple string, you will get a hex version
+of a salted-SHA1 password hash that can be inserted into your Puppet
+manifests as a valid password attribute.
+    EOS
+  ) do |arguments|
+    require 'digest/sha2'
+
+    raise(Puppet::ParseError, "str2saltedsha1(): Wrong number of arguments " +
+      "passed (#{arguments.size} but we require 1)") if arguments.size != 1
+
+    password = arguments[0]
+
+    unless password.is_a?(String)
+      raise(Puppet::ParseError, 'str2saltedsha1(): Requires a ' +
+        "String argument, you passed: #{password.class}")
+    end
+
+    seedint    = rand(2**31 - 1)
+    seedstring = Array(seedint).pack("L")
+    saltedpass = Digest::SHA1.digest(seedstring + password)
+    (seedstring + saltedpass).unpack('H*')[0]
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/str2saltedsha512.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/str2saltedsha512.rb
new file mode 100644
index 00000000..7fe7b012
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/str2saltedsha512.rb
@@ -0,0 +1,32 @@
+#
+# str2saltedsha512.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:str2saltedsha512, :type => :rvalue, :doc => <<-EOS
+This converts a string to a salted-SHA512 password hash (which is used for
+OS X versions >= 10.7). Given any simple string, you will get a hex version
+of a salted-SHA512 password hash that can be inserted into your Puppet
+manifests as a valid password attribute.
+    EOS
+  ) do |arguments|
+    require 'digest/sha2'
+
+    raise(Puppet::ParseError, "str2saltedsha512(): Wrong number of arguments " +
+      "passed (#{arguments.size} but we require 1)") if arguments.size != 1
+
+    password = arguments[0]
+
+    unless password.is_a?(String)
+      raise(Puppet::ParseError, 'str2saltedsha512(): Requires a ' +
+        "String argument, you passed: #{password.class}")
+    end
+
+    seedint    = rand(2**31 - 1)
+    seedstring = Array(seedint).pack("L")
+    saltedpass = Digest::SHA512.digest(seedstring + password)
+    (seedstring + saltedpass).unpack('H*')[0]
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/str2sha1_and_salt.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/str2sha1_and_salt.rb
new file mode 100644
index 00000000..9ec382d0
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/str2sha1_and_salt.rb
@@ -0,0 +1,36 @@
+#
+# str2saltedsha1.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:str2sha1_and_salt, :type => :rvalue, :doc => <<-EOS
+This converts a string to an array containing the salted SHA1 password hash in
+the first field, and the salt itself in second field of the returned array. 
+This combination is used i.e. for couchdb passwords.
+    EOS
+  ) do |arguments|
+    require 'digest/sha1'
+
+    raise(Puppet::ParseError, "str2saltedsha1(): Wrong number of arguments " +
+      "passed (#{arguments.size} but we require 1)") if arguments.size != 1
+
+    password = arguments[0]
+
+    unless password.is_a?(String)
+      raise(Puppet::ParseError, 'str2saltedsha1(): Requires a ' +
+        "String argument, you passed: #{password.class}")
+    end
+
+    seedint    = rand(2**31 - 1)
+    seedstring = Array(seedint).pack("L")
+    salt       = Digest::MD5.hexdigest(seedstring)
+    saltedpass = Digest::SHA1.hexdigest(password + salt)
+
+    array = Array.new
+    array << saltedpass
+    array << salt 
+    return array 
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/str_and_salt2sha1.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/str_and_salt2sha1.rb
new file mode 100644
index 00000000..71d69cf5
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/str_and_salt2sha1.rb
@@ -0,0 +1,32 @@
+#
+# str_and_salt2sha1.rb 
+#
+
+module Puppet::Parser::Functions
+  newfunction(:str_and_salt2sha1, :type => :rvalue, :doc => <<-EOS
+This converts a string to an array containing the salted SHA1 password hash in
+the first field, and the salt itself in second field of the returned array. 
+This combination is used i.e. for couchdb passwords.
+    EOS
+  ) do |arguments|
+    require 'digest/sha1'
+
+    raise(Puppet::ParseError, "str_and_salt2sha1(): Wrong number of arguments " +
+      "passed (#{arguments.size} but we require 1)") if arguments.size != 1
+
+    str_and_salt = arguments[0]
+
+    unless str_and_salt.is_a?(Array)
+      raise(Puppet::ParseError, 'str_and_salt2sha1(): Requires a ' +
+        "Array argument, you passed: #{password.class}")
+    end
+
+    str  = str_and_salt[0]
+    salt = str_and_salt[1]
+    sha1 = Digest::SHA1.hexdigest(str+ salt)
+
+    return sha1
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/strftime.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/strftime.rb
new file mode 100644
index 00000000..0b52adec
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/strftime.rb
@@ -0,0 +1,107 @@
+#
+# strftime.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:strftime, :type => :rvalue, :doc => <<-EOS
+This function returns formatted time.
+
+*Examples:*
+
+To return the time since epoch:
+
+    strftime("%s")
+
+To return the date:
+
+    strftime("%Y-%m-%d")
+
+*Format meaning:*
+
+    %a - The abbreviated weekday name (``Sun'')
+    %A - The  full  weekday  name (``Sunday'')
+    %b - The abbreviated month name (``Jan'')
+    %B - The  full  month  name (``January'')
+    %c - The preferred local date and time representation
+    %C - Century (20 in 2009)
+    %d - Day of the month (01..31)
+    %D - Date (%m/%d/%y)
+    %e - Day of the month, blank-padded ( 1..31)
+    %F - Equivalent to %Y-%m-%d (the ISO 8601 date format)
+    %h - Equivalent to %b
+    %H - Hour of the day, 24-hour clock (00..23)
+    %I - Hour of the day, 12-hour clock (01..12)
+    %j - Day of the year (001..366)
+    %k - hour, 24-hour clock, blank-padded ( 0..23)
+    %l - hour, 12-hour clock, blank-padded ( 0..12)
+    %L - Millisecond of the second (000..999)
+    %m - Month of the year (01..12)
+    %M - Minute of the hour (00..59)
+    %n - Newline (\n)
+    %N - Fractional seconds digits, default is 9 digits (nanosecond)
+            %3N  millisecond (3 digits)
+            %6N  microsecond (6 digits)
+            %9N  nanosecond (9 digits)
+    %p - Meridian indicator (``AM''  or  ``PM'')
+    %P - Meridian indicator (``am''  or  ``pm'')
+    %r - time, 12-hour (same as %I:%M:%S %p)
+    %R - time, 24-hour (%H:%M)
+    %s - Number of seconds since 1970-01-01 00:00:00 UTC.
+    %S - Second of the minute (00..60)
+    %t - Tab character (\t)
+    %T - time, 24-hour (%H:%M:%S)
+    %u - Day of the week as a decimal, Monday being 1. (1..7)
+    %U - Week  number  of the current year,
+            starting with the first Sunday as the first
+            day of the first week (00..53)
+    %v - VMS date (%e-%b-%Y)
+    %V - Week number of year according to ISO 8601 (01..53)
+    %W - Week  number  of the current year,
+            starting with the first Monday as the first
+            day of the first week (00..53)
+    %w - Day of the week (Sunday is 0, 0..6)
+    %x - Preferred representation for the date alone, no time
+    %X - Preferred representation for the time alone, no date
+    %y - Year without a century (00..99)
+    %Y - Year with century
+    %z - Time zone as  hour offset from UTC (e.g. +0900)
+    %Z - Time zone name
+    %% - Literal ``%'' character
+    EOS
+  ) do |arguments|
+
+    # Technically we support two arguments but only first is mandatory ...
+    raise(Puppet::ParseError, "strftime(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    format = arguments[0]
+
+    raise(Puppet::ParseError, 'strftime(): You must provide ' +
+      'format for evaluation') if format.empty?
+
+    # The Time Zone argument is optional ...
+    time_zone = arguments[1] if arguments[1]
+
+    time = Time.new
+
+    # There is probably a better way to handle Time Zone ...
+    if time_zone and not time_zone.empty?
+      original_zone = ENV['TZ']
+
+      local_time = time.clone
+      local_time = local_time.utc
+
+      ENV['TZ'] = time_zone
+
+      time = local_time.localtime
+
+      ENV['TZ'] = original_zone
+    end
+
+    result = time.strftime(format)
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/strip.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/strip.rb
new file mode 100644
index 00000000..3fac47d5
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/strip.rb
@@ -0,0 +1,38 @@
+#
+#  strip.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:strip, :type => :rvalue, :doc => <<-EOS
+This function removes leading and trailing whitespace from a string or from
+every string inside an array.
+
+*Examples:*
+
+    strip("    aaa   ")
+
+Would result in: "aaa"
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "strip(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+
+    unless value.is_a?(Array) || value.is_a?(String)
+      raise(Puppet::ParseError, 'strip(): Requires either ' +
+        'array or string to work with')
+    end
+
+    if value.is_a?(Array)
+      result = value.collect { |i| i.is_a?(String) ? i.strip : i }
+    else
+      result = value.strip
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/suffix.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/suffix.rb
new file mode 100644
index 00000000..f7792d6f
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/suffix.rb
@@ -0,0 +1,45 @@
+#
+# suffix.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:suffix, :type => :rvalue, :doc => <<-EOS
+This function applies a suffix to all elements in an array.
+
+*Examples:*
+
+    suffix(['a','b','c'], 'p')
+
+Will return: ['ap','bp','cp']
+    EOS
+  ) do |arguments|
+
+    # Technically we support two arguments but only first is mandatory ...
+    raise(Puppet::ParseError, "suffix(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    array = arguments[0]
+
+    unless array.is_a?(Array)
+      raise Puppet::ParseError, "suffix(): expected first argument to be an Array, got #{array.inspect}"
+    end
+
+    suffix = arguments[1] if arguments[1]
+
+    if suffix
+      unless suffix.is_a? String
+        raise Puppet::ParseError, "suffix(): expected second argument to be a String, got #{suffix.inspect}"
+      end
+    end
+
+    # Turn everything into string same as join would do ...
+    result = array.collect do |i|
+      i = i.to_s
+      suffix ? i + suffix : i
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/swapcase.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/swapcase.rb
new file mode 100644
index 00000000..eb7fe137
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/swapcase.rb
@@ -0,0 +1,38 @@
+#
+#  swapcase.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:swapcase, :type => :rvalue, :doc => <<-EOS
+This function will swap the existing case of a string.
+
+*Examples:*
+
+    swapcase("aBcD")
+
+Would result in: "AbCd"
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "swapcase(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+
+    unless value.is_a?(Array) || value.is_a?(String)
+      raise(Puppet::ParseError, 'swapcase(): Requires either ' +
+        'array or string to work with')
+    end
+
+    if value.is_a?(Array)
+      # Numbers in Puppet are often string-encoded which is troublesome ...
+      result = value.collect { |i| i.is_a?(String) ? i.swapcase : i }
+    else
+      result = value.swapcase
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/time.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/time.rb
new file mode 100644
index 00000000..0cddaf86
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/time.rb
@@ -0,0 +1,49 @@
+#
+# time.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:time, :type => :rvalue, :doc => <<-EOS
+This function will return the current time since epoch as an integer.
+
+*Examples:*
+
+    time()
+
+Will return something like: 1311972653
+    EOS
+  ) do |arguments|
+
+    # The Time Zone argument is optional ...
+    time_zone = arguments[0] if arguments[0]
+
+    if (arguments.size != 0) and (arguments.size != 1) then
+      raise(Puppet::ParseError, "time(): Wrong number of arguments "+
+        "given #{arguments.size} for 0 or 1")
+    end
+
+    time = Time.new
+
+    # There is probably a better way to handle Time Zone ...
+    if time_zone and not time_zone.empty?
+      original_zone = ENV['TZ']
+
+      local_time = time.clone
+      local_time = local_time.utc
+
+      ENV['TZ'] = time_zone
+
+      time = local_time.localtime
+
+      ENV['TZ'] = original_zone
+    end
+
+    # Calling Time#to_i on a receiver changes it.  Trust me I am the Doctor.
+    result = time.strftime('%s')
+    result = result.to_i
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/to_bytes.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/to_bytes.rb
new file mode 100644
index 00000000..df490ea8
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/to_bytes.rb
@@ -0,0 +1,31 @@
+module Puppet::Parser::Functions
+  newfunction(:to_bytes, :type => :rvalue, :doc => <<-EOS
+    Converts the argument into bytes, for example 4 kB becomes 4096.
+    Takes a single string value as an argument.
+    These conversions reflect a layperson's understanding of
+    1 MB = 1024 KB, when in fact 1 MB = 1000 KB, and 1 MiB = 1024 KiB.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "to_bytes(): Wrong number of arguments " +
+          "given (#{arguments.size} for 1)") if arguments.size != 1
+
+    arg = arguments[0]
+
+    return arg if arg.is_a? Numeric
+
+    value,prefix = */([0-9.e+-]*)\s*([^bB]?)/.match(arg)[1,2]
+
+    value = value.to_f
+    case prefix
+    when '' then return value.to_i
+    when 'k' then return (value*(1<<10)).to_i
+    when 'M' then return (value*(1<<20)).to_i
+    when 'G' then return (value*(1<<30)).to_i
+    when 'T' then return (value*(1<<40)).to_i
+    when 'P' then return (value*(1<<50)).to_i
+    when 'E' then return (value*(1<<60)).to_i
+    else raise Puppet::ParseError, "to_bytes(): Unknown prefix #{prefix}"
+    end
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/type.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/type.rb
new file mode 100644
index 00000000..016529b0
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/type.rb
@@ -0,0 +1,19 @@
+#
+# type.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:type, :type => :rvalue, :doc => <<-EOS
+  DEPRECATED: This function will cease to function on Puppet 4; please use type3x() before upgrading to puppet 4 for backwards-compatibility, or migrate to the new parser's typing system.
+    EOS
+  ) do |args|
+
+    warning("type() DEPRECATED: This function will cease to function on Puppet 4; please use type3x() before upgrading to puppet 4 for backwards-compatibility, or migrate to the new parser's typing system.")
+    if ! Puppet::Parser::Functions.autoloader.loaded?(:type3x)
+      Puppet::Parser::Functions.autoloader.load(:type3x)
+    end
+    function_type3x(args + [false])
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/type3x.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/type3x.rb
new file mode 100644
index 00000000..0800b4a3
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/type3x.rb
@@ -0,0 +1,51 @@
+#
+# type3x.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:type3x, :type => :rvalue, :doc => <<-EOS
+DEPRECATED: This function will be removed when puppet 3 support is dropped; please migrate to the new parser's typing system.
+
+Returns the type when passed a value. Type can be one of:
+
+* string
+* array
+* hash
+* float
+* integer
+* boolean
+    EOS
+  ) do |args|
+    raise(Puppet::ParseError, "type3x(): Wrong number of arguments " +
+      "given (#{args.size} for 1)") if args.size < 1
+
+    value = args[0]
+
+    klass = value.class
+
+    if not [TrueClass, FalseClass, Array, Bignum, Fixnum, Float, Hash, String].include?(klass)
+      raise(Puppet::ParseError, 'type3x(): Unknown type')
+    end
+
+    klass = klass.to_s # Ugly ...
+
+    # We note that Integer is the parent to Bignum and Fixnum ...
+    result = case klass
+      when /^(?:Big|Fix)num$/ then 'integer'
+      when /^(?:True|False)Class$/ then 'boolean'
+      else klass
+    end
+
+    if result == "String" then
+      if value == value.to_i.to_s then
+        result = "Integer"
+      elsif value == value.to_f.to_s then
+        result = "Float"
+      end
+    end
+
+    return result.downcase
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/union.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/union.rb
new file mode 100644
index 00000000..c91bb805
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/union.rb
@@ -0,0 +1,34 @@
+#
+# union.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:union, :type => :rvalue, :doc => <<-EOS
+This function returns a union of two arrays.
+
+*Examples:*
+
+    union(["a","b","c"],["b","c","d"])
+
+Would return: ["a","b","c","d"]
+    EOS
+  ) do |arguments|
+
+    # Two arguments are required
+    raise(Puppet::ParseError, "union(): Wrong number of arguments " +
+      "given (#{arguments.size} for 2)") if arguments.size != 2
+
+    first = arguments[0]
+    second = arguments[1]
+
+    unless first.is_a?(Array) && second.is_a?(Array)
+      raise(Puppet::ParseError, 'union(): Requires 2 arrays')
+    end
+
+    result = first | second
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/unique.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/unique.rb
new file mode 100644
index 00000000..cf770f3b
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/unique.rb
@@ -0,0 +1,50 @@
+#
+# unique.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:unique, :type => :rvalue, :doc => <<-EOS
+This function will remove duplicates from strings and arrays.
+
+*Examples:*
+
+    unique("aabbcc")
+
+Will return:
+
+    abc
+
+You can also use this with arrays:
+
+    unique(["a","a","b","b","c","c"])
+
+This returns:
+
+    ["a","b","c"]
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "unique(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+
+    unless value.is_a?(Array) || value.is_a?(String)
+      raise(Puppet::ParseError, 'unique(): Requires either ' +
+        'array or string to work with')
+    end
+
+    result = value.clone
+
+    string = value.is_a?(String) ? true : false
+
+    # We turn any string value into an array to be able to shuffle ...
+    result = string ? result.split('') : result
+    result = result.uniq # Remove duplicates ...
+    result = string ? result.join : result
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/upcase.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/upcase.rb
new file mode 100644
index 00000000..4302b29e
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/upcase.rb
@@ -0,0 +1,40 @@
+#
+# upcase.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:upcase, :type => :rvalue, :doc => <<-EOS
+Converts a string or an array of strings to uppercase.
+
+*Examples:*
+
+    upcase("abcd")
+
+Will return:
+
+    ASDF
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "upcase(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+
+    unless value.is_a?(Array) || value.is_a?(String)
+      raise(Puppet::ParseError, 'upcase(): Requires either ' +
+        'array or string to work with')
+    end
+
+    if value.is_a?(Array)
+      # Numbers in Puppet are often string-encoded which is troublesome ...
+      result = value.collect { |i| i.is_a?(String) ? i.upcase : i }
+    else
+      result = value.upcase
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/uriescape.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/uriescape.rb
new file mode 100644
index 00000000..a486eee5
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/uriescape.rb
@@ -0,0 +1,34 @@
+#
+#  uriescape.rb
+#
+require 'uri'
+
+module Puppet::Parser::Functions
+  newfunction(:uriescape, :type => :rvalue, :doc => <<-EOS
+    Urlencodes a string or array of strings.
+    Requires either a single string or an array as an input.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "uriescape(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+
+    unless value.is_a?(Array) || value.is_a?(String)
+      raise(Puppet::ParseError, 'uriescape(): Requires either ' +
+        'array or string to work with')
+    end
+
+    if value.is_a?(Array)
+      # Numbers in Puppet are often string-encoded which is troublesome ...
+      result = value.collect { |i| i.is_a?(String) ? URI.escape(i,unsafe) : i }
+    else
+      result = URI.escape(value)
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/validate_absolute_path.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_absolute_path.rb
new file mode 100644
index 00000000..b6966809
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_absolute_path.rb
@@ -0,0 +1,69 @@
+module Puppet::Parser::Functions
+  newfunction(:validate_absolute_path, :doc => <<-'ENDHEREDOC') do |args|
+    Validate the string represents an absolute path in the filesystem.  This function works
+    for windows and unix style paths.
+
+    The following values will pass:
+
+        $my_path = 'C:/Program Files (x86)/Puppet Labs/Puppet'
+        validate_absolute_path($my_path)
+        $my_path2 = '/var/lib/puppet'
+        validate_absolute_path($my_path2)
+        $my_path3 = ['C:/Program Files (x86)/Puppet Labs/Puppet','C:/Program Files/Puppet Labs/Puppet']
+        validate_absolute_path($my_path3)
+        $my_path4 = ['/var/lib/puppet','/usr/share/puppet']
+        validate_absolute_path($my_path4)
+
+    The following values will fail, causing compilation to abort:
+
+        validate_absolute_path(true)
+        validate_absolute_path('../var/lib/puppet')
+        validate_absolute_path('var/lib/puppet')
+        validate_absolute_path([ 'var/lib/puppet', '/var/foo' ])
+        validate_absolute_path([ '/var/lib/puppet', 'var/foo' ])
+        $undefined = undef
+        validate_absolute_path($undefined)
+
+    ENDHEREDOC
+
+    require 'puppet/util'
+
+    unless args.length > 0 then
+      raise Puppet::ParseError, ("validate_absolute_path(): wrong number of arguments (#{args.length}; must be > 0)")
+    end
+
+    args.each do |arg|
+      # put arg to candidate var to be able to replace it
+      candidates = arg
+      # if arg is just a string with a path to test, convert it to an array
+      # to avoid test code duplication
+      unless arg.is_a?(Array) then
+        candidates = Array.new(1,arg)
+      end
+      # iterate over all pathes within the candidates array
+      candidates.each do |path|
+        # This logic was borrowed from
+        # [lib/puppet/file_serving/base.rb](https://github.com/puppetlabs/puppet/blob/master/lib/puppet/file_serving/base.rb)
+        # Puppet 2.7 and beyond will have Puppet::Util.absolute_path? Fall back to a back-ported implementation otherwise.
+        if Puppet::Util.respond_to?(:absolute_path?) then
+          unless Puppet::Util.absolute_path?(path, :posix) or Puppet::Util.absolute_path?(path, :windows)
+            raise Puppet::ParseError, ("#{path.inspect} is not an absolute path.")
+          end
+        else
+          # This code back-ported from 2.7.x's lib/puppet/util.rb Puppet::Util.absolute_path?
+          # Determine in a platform-specific way whether a path is absolute. This
+          # defaults to the local platform if none is specified.
+          # Escape once for the string literal, and once for the regex.
+          slash = '[\\\\/]'
+          name = '[^\\\\/]+'
+          regexes = {
+            :windows => %r!^(([A-Z]:#{slash})|(#{slash}#{slash}#{name}#{slash}#{name})|(#{slash}#{slash}\?#{slash}#{name}))!i,
+            :posix => %r!^/!,
+          }
+          rval = (!!(path =~ regexes[:posix])) || (!!(path =~ regexes[:windows]))
+          rval or raise Puppet::ParseError, ("#{path.inspect} is not an absolute path.")
+        end
+      end
+    end
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/validate_array.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_array.rb
new file mode 100644
index 00000000..34b51182
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_array.rb
@@ -0,0 +1,33 @@
+module Puppet::Parser::Functions
+
+  newfunction(:validate_array, :doc => <<-'ENDHEREDOC') do |args|
+    Validate that all passed values are array data structures. Abort catalog
+    compilation if any value fails this check.
+
+    The following values will pass:
+
+        $my_array = [ 'one', 'two' ]
+        validate_array($my_array)
+
+    The following values will fail, causing compilation to abort:
+
+        validate_array(true)
+        validate_array('some_string')
+        $undefined = undef
+        validate_array($undefined)
+
+    ENDHEREDOC
+
+    unless args.length > 0 then
+      raise Puppet::ParseError, ("validate_array(): wrong number of arguments (#{args.length}; must be > 0)")
+    end
+
+    args.each do |arg|
+      unless arg.is_a?(Array)
+        raise Puppet::ParseError, ("#{arg.inspect} is not an Array.  It looks to be a #{arg.class}")
+      end
+    end
+
+  end
+
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/validate_augeas.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_augeas.rb
new file mode 100644
index 00000000..4ea4fe07
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_augeas.rb
@@ -0,0 +1,83 @@
+require 'tempfile'
+
+module Puppet::Parser::Functions
+  newfunction(:validate_augeas, :doc => <<-'ENDHEREDOC') do |args|
+    Perform validation of a string using an Augeas lens
+    The first argument of this function should be a string to
+    test, and the second argument should be the name of the Augeas lens to use.
+    If Augeas fails to parse the string with the lens, the compilation will
+    abort with a parse error.
+
+    A third argument can be specified, listing paths which should
+    not be found in the file. The `$file` variable points to the location
+    of the temporary file being tested in the Augeas tree.
+
+    For example, if you want to make sure your passwd content never contains
+    a user `foo`, you could write:
+
+        validate_augeas($passwdcontent, 'Passwd.lns', ['$file/foo'])
+
+    Or if you wanted to ensure that no users used the '/bin/barsh' shell,
+    you could use:
+
+        validate_augeas($passwdcontent, 'Passwd.lns', ['$file/*[shell="/bin/barsh"]']
+
+    If a fourth argument is specified, this will be the error message raised and
+    seen by the user.
+
+    A helpful error message can be returned like this:
+
+        validate_augeas($sudoerscontent, 'Sudoers.lns', [], 'Failed to validate sudoers content with Augeas')
+
+    ENDHEREDOC
+    unless Puppet.features.augeas?
+      raise Puppet::ParseError, ("validate_augeas(): this function requires the augeas feature. See http://projects.puppetlabs.com/projects/puppet/wiki/Puppet_Augeas#Pre-requisites for how to activate it.")
+    end
+
+    if (args.length < 2) or (args.length > 4) then
+      raise Puppet::ParseError, ("validate_augeas(): wrong number of arguments (#{args.length}; must be 2, 3, or 4)")
+    end
+
+    msg = args[3] || "validate_augeas(): Failed to validate content against #{args[1].inspect}"
+
+    require 'augeas'
+    aug = Augeas::open(nil, nil, Augeas::NO_MODL_AUTOLOAD)
+    begin
+      content = args[0]
+
+      # Test content in a temporary file
+      tmpfile = Tempfile.new("validate_augeas")
+      begin
+        tmpfile.write(content)
+      ensure
+        tmpfile.close
+      end
+
+      # Check for syntax
+      lens = args[1]
+      aug.transform(
+        :lens => lens,
+        :name => 'Validate_augeas',
+        :incl => tmpfile.path
+      )
+      aug.load!
+
+      unless aug.match("/augeas/files#{tmpfile.path}//error").empty?
+        error = aug.get("/augeas/files#{tmpfile.path}//error/message")
+        msg += " with error: #{error}"
+        raise Puppet::ParseError, (msg)
+      end
+
+      # Launch unit tests
+      tests = args[2] || []
+      aug.defvar('file', "/files#{tmpfile.path}")
+      tests.each do |t|
+        msg += " testing path #{t}"
+        raise Puppet::ParseError, (msg) unless aug.match(t).empty?
+      end
+    ensure
+      aug.close
+      tmpfile.unlink
+    end
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/validate_bool.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_bool.rb
new file mode 100644
index 00000000..59a08056
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_bool.rb
@@ -0,0 +1,34 @@
+module Puppet::Parser::Functions
+
+  newfunction(:validate_bool, :doc => <<-'ENDHEREDOC') do |args|
+    Validate that all passed values are either true or false. Abort catalog
+    compilation if any value fails this check.
+
+    The following values will pass:
+
+        $iamtrue = true
+        validate_bool(true)
+        validate_bool(true, true, false, $iamtrue)
+
+    The following values will fail, causing compilation to abort:
+
+        $some_array = [ true ]
+        validate_bool("false")
+        validate_bool("true")
+        validate_bool($some_array)
+
+    ENDHEREDOC
+
+    unless args.length > 0 then
+      raise Puppet::ParseError, ("validate_bool(): wrong number of arguments (#{args.length}; must be > 0)")
+    end
+
+    args.each do |arg|
+      unless function_is_bool([arg])
+        raise Puppet::ParseError, ("#{arg.inspect} is not a boolean.  It looks to be a #{arg.class}")
+      end
+    end
+
+  end
+
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/validate_cmd.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_cmd.rb
new file mode 100644
index 00000000..5df3c609
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_cmd.rb
@@ -0,0 +1,63 @@
+require 'puppet/util/execution'
+require 'tempfile'
+
+module Puppet::Parser::Functions
+  newfunction(:validate_cmd, :doc => <<-'ENDHEREDOC') do |args|
+    Perform validation of a string with an external command.
+    The first argument of this function should be a string to
+    test, and the second argument should be a path to a test command
+    taking a % as a placeholder for the file path (will default to the end).
+    If the command, launched against a tempfile containing the passed string,
+    returns a non-null value, compilation will abort with a parse error.
+
+    If a third argument is specified, this will be the error message raised and
+    seen by the user.
+
+    A helpful error message can be returned like this:
+
+    Example:
+
+        # Defaults to end of path
+        validate_cmd($sudoerscontent, '/usr/sbin/visudo -c -f', 'Visudo failed to validate sudoers content')
+
+        # % as file location
+        validate_cmd($haproxycontent, '/usr/sbin/haproxy -f % -c', 'Haproxy failed to validate config content')
+
+    ENDHEREDOC
+    if (args.length < 2) or (args.length > 3) then
+      raise Puppet::ParseError, ("validate_cmd(): wrong number of arguments (#{args.length}; must be 2 or 3)")
+    end
+
+    msg = args[2] || "validate_cmd(): failed to validate content with command #{args[1].inspect}"
+
+    content = args[0]
+    checkscript = args[1]
+
+    # Test content in a temporary file
+    tmpfile = Tempfile.new("validate_cmd")
+    begin
+      tmpfile.write(content)
+      tmpfile.close
+
+      if checkscript =~ /\s%(\s|$)/
+        check_with_correct_location = checkscript.gsub(/%/,tmpfile.path)
+      else
+        check_with_correct_location = "#{checkscript} #{tmpfile.path}"
+      end
+
+      if Puppet::Util::Execution.respond_to?('execute')
+        Puppet::Util::Execution.execute(check_with_correct_location)
+      else
+        Puppet::Util.execute(check_with_correct_location)
+      end
+    rescue Puppet::ExecutionFailure => detail
+      msg += "\n#{detail}"
+      raise Puppet::ParseError, msg
+    rescue Exception => detail
+      msg += "\n#{detail.class.name} #{detail}"
+      raise Puppet::ParseError, msg
+    ensure
+      tmpfile.unlink
+    end
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/validate_hash.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_hash.rb
new file mode 100644
index 00000000..9bdd5432
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_hash.rb
@@ -0,0 +1,33 @@
+module Puppet::Parser::Functions
+
+  newfunction(:validate_hash, :doc => <<-'ENDHEREDOC') do |args|
+    Validate that all passed values are hash data structures. Abort catalog
+    compilation if any value fails this check.
+
+    The following values will pass:
+
+        $my_hash = { 'one' => 'two' }
+        validate_hash($my_hash)
+
+    The following values will fail, causing compilation to abort:
+
+        validate_hash(true)
+        validate_hash('some_string')
+        $undefined = undef
+        validate_hash($undefined)
+
+    ENDHEREDOC
+
+    unless args.length > 0 then
+      raise Puppet::ParseError, ("validate_hash(): wrong number of arguments (#{args.length}; must be > 0)")
+    end
+
+    args.each do |arg|
+      unless arg.is_a?(Hash)
+        raise Puppet::ParseError, ("#{arg.inspect} is not a Hash.  It looks to be a #{arg.class}")
+      end
+    end
+
+  end
+
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/validate_ipv4_address.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_ipv4_address.rb
new file mode 100644
index 00000000..fc02748e
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_ipv4_address.rb
@@ -0,0 +1,48 @@
+module Puppet::Parser::Functions
+
+  newfunction(:validate_ipv4_address, :doc => <<-ENDHEREDOC
+    Validate that all values passed are valid IPv4 addresses.
+    Fail compilation if any value fails this check.
+
+    The following values will pass:
+
+    $my_ip = "1.2.3.4"
+    validate_ipv4_address($my_ip)
+    validate_bool("8.8.8.8", "172.16.0.1", $my_ip)
+
+    The following values will fail, causing compilation to abort:
+
+    $some_array = [ 1, true, false, "garbage string", "3ffe:505:2" ]
+    validate_ipv4_address($some_array)
+
+    ENDHEREDOC
+  ) do |args|
+
+    require "ipaddr"
+    rescuable_exceptions = [ ArgumentError ]
+
+    if defined?(IPAddr::InvalidAddressError)
+      rescuable_exceptions << IPAddr::InvalidAddressError
+    end
+
+    unless args.length > 0 then
+      raise Puppet::ParseError, ("validate_ipv4_address(): wrong number of arguments (#{args.length}; must be > 0)")
+    end
+
+    args.each do |arg|
+      unless arg.is_a?(String)
+        raise Puppet::ParseError, "#{arg.inspect} is not a string."
+      end
+
+      begin
+        unless IPAddr.new(arg).ipv4?
+          raise Puppet::ParseError, "#{arg.inspect} is not a valid IPv4 address."
+        end
+      rescue *rescuable_exceptions
+        raise Puppet::ParseError, "#{arg.inspect} is not a valid IPv4 address."
+      end
+    end
+
+  end
+
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/validate_ipv6_address.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_ipv6_address.rb
new file mode 100644
index 00000000..b0f2558d
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_ipv6_address.rb
@@ -0,0 +1,49 @@
+module Puppet::Parser::Functions
+
+  newfunction(:validate_ipv6_address, :doc => <<-ENDHEREDOC
+    Validate that all values passed are valid IPv6 addresses.
+    Fail compilation if any value fails this check.
+
+    The following values will pass:
+
+    $my_ip = "3ffe:505:2"
+    validate_ipv6_address(1)
+    validate_ipv6_address($my_ip)
+    validate_bool("fe80::baf6:b1ff:fe19:7507", $my_ip)
+
+    The following values will fail, causing compilation to abort:
+
+    $some_array = [ true, false, "garbage string", "1.2.3.4" ]
+    validate_ipv6_address($some_array)
+
+    ENDHEREDOC
+  ) do |args|
+
+    require "ipaddr"
+    rescuable_exceptions = [ ArgumentError ]
+
+    if defined?(IPAddr::InvalidAddressError)
+      rescuable_exceptions << IPAddr::InvalidAddressError
+    end
+
+    unless args.length > 0 then
+      raise Puppet::ParseError, ("validate_ipv6_address(): wrong number of arguments (#{args.length}; must be > 0)")
+    end
+
+    args.each do |arg|
+      unless arg.is_a?(String)
+        raise Puppet::ParseError, "#{arg.inspect} is not a string."
+      end
+
+      begin
+        unless IPAddr.new(arg).ipv6?
+          raise Puppet::ParseError, "#{arg.inspect} is not a valid IPv6 address."
+        end
+      rescue *rescuable_exceptions
+        raise Puppet::ParseError, "#{arg.inspect} is not a valid IPv6 address."
+      end
+    end
+
+  end
+
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/validate_re.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_re.rb
new file mode 100644
index 00000000..ca25a702
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_re.rb
@@ -0,0 +1,40 @@
+module Puppet::Parser::Functions
+  newfunction(:validate_re, :doc => <<-'ENDHEREDOC') do |args|
+    Perform simple validation of a string against one or more regular
+    expressions. The first argument of this function should be a string to
+    test, and the second argument should be a stringified regular expression
+    (without the // delimiters) or an array of regular expressions.  If none
+    of the regular expressions match the string passed in, compilation will
+    abort with a parse error.
+
+    If a third argument is specified, this will be the error message raised and
+    seen by the user.
+
+    The following strings will validate against the regular expressions:
+
+        validate_re('one', '^one$')
+        validate_re('one', [ '^one', '^two' ])
+
+    The following strings will fail to validate, causing compilation to abort:
+
+        validate_re('one', [ '^two', '^three' ])
+
+    A helpful error message can be returned like this:
+
+        validate_re($::puppetversion, '^2.7', 'The $puppetversion fact value does not match 2.7')
+
+    ENDHEREDOC
+    if (args.length < 2) or (args.length > 3) then
+      raise Puppet::ParseError, ("validate_re(): wrong number of arguments (#{args.length}; must be 2 or 3)")
+    end
+
+    msg = args[2] || "validate_re(): #{args[0].inspect} does not match #{args[1].inspect}"
+
+    # We're using a flattened array here because we can't call String#any? in
+    # Ruby 1.9 like we can in Ruby 1.8
+    raise Puppet::ParseError, (msg) unless [args[1]].flatten.any? do |re_str|
+      args[0] =~ Regexp.compile(re_str)
+    end
+
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/validate_slength.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_slength.rb
new file mode 100644
index 00000000..7d534f37
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_slength.rb
@@ -0,0 +1,71 @@
+module Puppet::Parser::Functions
+
+  newfunction(:validate_slength, :doc => <<-'ENDHEREDOC') do |args|
+    Validate that the first argument is a string (or an array of strings), and
+    less/equal to than the length of the second argument. An optional third
+    parameter can be given a the minimum length. It fails if the first
+    argument is not a string or array of strings, and if arg 2 and arg 3 are
+    not convertable to a number.
+
+    The following values will pass:
+
+      validate_slength("discombobulate",17)
+      validate_slength(["discombobulate","moo"],17)
+      validate_slength(["discombobulate","moo"],17,3)
+
+    The following valueis will not:
+
+      validate_slength("discombobulate",1)
+      validate_slength(["discombobulate","thermometer"],5)
+      validate_slength(["discombobulate","moo"],17,10)
+
+    ENDHEREDOC
+
+    raise Puppet::ParseError, "validate_slength(): Wrong number of arguments (#{args.length}; must be 2 or 3)" unless args.length == 2 or args.length == 3
+
+    input, max_length, min_length = *args
+
+    begin
+      max_length = Integer(max_length)
+      raise ArgumentError if max_length <= 0
+    rescue ArgumentError, TypeError
+      raise Puppet::ParseError, "validate_slength(): Expected second argument to be a positive Numeric, got #{max_length}:#{max_length.class}"
+    end
+
+    if min_length
+      begin
+        min_length = Integer(min_length)
+        raise ArgumentError if min_length < 0
+    rescue ArgumentError, TypeError
+        raise Puppet::ParseError, "validate_slength(): Expected third argument to be unset or a positive Numeric, got #{min_length}:#{min_length.class}"
+      end
+    else
+      min_length = 0
+    end
+
+    if min_length > max_length
+      raise Puppet::ParseError, "validate_slength(): Expected second argument to be larger than third argument"
+    end
+
+    validator = lambda do |str|
+      unless str.length <= max_length and str.length >= min_length
+        raise Puppet::ParseError, "validate_slength(): Expected length of #{input.inspect} to be between #{min_length} and #{max_length}, was #{input.length}"
+      end
+    end
+
+    case input
+    when String
+      validator.call(input)
+    when Array
+      input.each_with_index do |arg, pos|
+        if arg.is_a? String
+          validator.call(arg)
+        else
+          raise Puppet::ParseError, "validate_slength(): Expected element at array position #{pos} to be a String, got #{arg.class}"
+        end
+      end
+    else
+      raise Puppet::ParseError, "validate_slength(): Expected first argument to be a String or Array, got #{input.class}"
+    end
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/validate_string.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_string.rb
new file mode 100644
index 00000000..c841f6ab
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_string.rb
@@ -0,0 +1,38 @@
+module Puppet::Parser::Functions
+
+  newfunction(:validate_string, :doc => <<-'ENDHEREDOC') do |args|
+    Validate that all passed values are string data structures. Abort catalog
+    compilation if any value fails this check.
+
+    The following values will pass:
+
+        $my_string = "one two"
+        validate_string($my_string, 'three')
+
+    The following values will fail, causing compilation to abort:
+
+        validate_string(true)
+        validate_string([ 'some', 'array' ])
+        
+    Note: validate_string(undef) will not fail in this version of the
+    functions API (incl. current and future parser). Instead, use:
+    
+        if $var == undef {
+          fail('...')
+        }
+    
+    ENDHEREDOC
+
+    unless args.length > 0 then
+      raise Puppet::ParseError, ("validate_string(): wrong number of arguments (#{args.length}; must be > 0)")
+    end
+
+    args.each do |arg|
+      unless arg.is_a?(String)
+        raise Puppet::ParseError, ("#{arg.inspect} is not a string.  It looks to be a #{arg.class}")
+      end
+    end
+
+  end
+
+end
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/values.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/values.rb
new file mode 100644
index 00000000..16067561
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/values.rb
@@ -0,0 +1,39 @@
+#
+# values.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:values, :type => :rvalue, :doc => <<-EOS
+When given a hash this function will return the values of that hash.
+
+*Examples:*
+
+    $hash = {
+      'a' => 1,
+      'b' => 2,
+      'c' => 3,
+    }
+    values($hash)
+
+This example would return:
+
+    [1,2,3]
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "values(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    hash = arguments[0]
+
+    unless hash.is_a?(Hash)
+      raise(Puppet::ParseError, 'values(): Requires hash to work with')
+    end
+
+    result = hash.values
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/values_at.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/values_at.rb
new file mode 100644
index 00000000..f350f539
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/values_at.rb
@@ -0,0 +1,99 @@
+#
+# values_at.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:values_at, :type => :rvalue, :doc => <<-EOS
+Finds value inside an array based on location.
+
+The first argument is the array you want to analyze, and the second element can
+be a combination of:
+
+* A single numeric index
+* A range in the form of 'start-stop' (eg. 4-9)
+* An array combining the above
+
+*Examples*:
+
+    values_at(['a','b','c'], 2)
+
+Would return ['c'].
+
+    values_at(['a','b','c'], ["0-1"])
+
+Would return ['a','b'].
+
+    values_at(['a','b','c','d','e'], [0, "2-3"])
+
+Would return ['a','c','d'].
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "values_at(): Wrong number of " +
+      "arguments given (#{arguments.size} for 2)") if arguments.size < 2
+
+    array = arguments.shift
+
+    unless array.is_a?(Array)
+      raise(Puppet::ParseError, 'values_at(): Requires array to work with')
+    end
+
+    indices = [arguments.shift].flatten() # Get them all ... Pokemon ...
+
+    if not indices or indices.empty?
+      raise(Puppet::ParseError, 'values_at(): You must provide ' +
+        'at least one positive index to collect')
+    end
+
+    result       = []
+    indices_list = []
+
+    indices.each do |i|
+      i = i.to_s
+      if m = i.match(/^(\d+)(\.\.\.?|\-)(\d+)$/)
+        start = m[1].to_i
+        stop  = m[3].to_i
+
+        type = m[2]
+
+        if start > stop
+          raise(Puppet::ParseError, 'values_at(): Stop index in ' +
+            'given indices range is smaller than the start index')
+        elsif stop > array.size - 1 # First element is at index 0 is it not?
+          raise(Puppet::ParseError, 'values_at(): Stop index in ' +
+            'given indices range exceeds array size')
+        end
+
+        range = case type
+          when /^(\.\.|\-)$/ then (start .. stop)
+          when /^(\.\.\.)$/  then (start ... stop) # Exclusive of last element ...
+        end
+
+        range.each { |i| indices_list << i.to_i }
+      else
+        # Only positive numbers allowed in this case ...
+        if not i.match(/^\d+$/)
+          raise(Puppet::ParseError, 'values_at(): Unknown format ' +
+            'of given index')
+        end
+
+        # In Puppet numbers are often string-encoded ...
+        i = i.to_i
+
+        if i > array.size - 1 # Same story.  First element is at index 0 ...
+          raise(Puppet::ParseError, 'values_at(): Given index ' +
+            'exceeds array size')
+        end
+
+        indices_list << i
+      end
+    end
+
+    # We remove nil values as they make no sense in Puppet DSL ...
+    result = indices_list.collect { |i| array[i] }.compact
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/zip.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/zip.rb
new file mode 100644
index 00000000..3074f282
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/parser/functions/zip.rb
@@ -0,0 +1,39 @@
+#
+# zip.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:zip, :type => :rvalue, :doc => <<-EOS
+Takes one element from first array and merges corresponding elements from second array. This generates a sequence of n-element arrays, where n is one more than the count of arguments.
+
+*Example:*
+
+    zip(['1','2','3'],['4','5','6'])
+
+Would result in:
+
+    ["1", "4"], ["2", "5"], ["3", "6"]
+    EOS
+  ) do |arguments|
+
+    # Technically we support three arguments but only first is mandatory ...
+    raise(Puppet::ParseError, "zip(): Wrong number of arguments " +
+      "given (#{arguments.size} for 2)") if arguments.size < 2
+
+    a = arguments[0]
+    b = arguments[1]
+
+    unless a.is_a?(Array) and b.is_a?(Array)
+      raise(Puppet::ParseError, 'zip(): Requires array to work with')
+    end
+
+    flatten = function_str2bool([arguments[2]]) if arguments[2]
+
+    result = a.zip(b)
+    result = flatten ? result.flatten : result
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/puppet/modules/stdlib/lib/puppet/provider/file_line/ruby.rb b/puppet/modules/stdlib/lib/puppet/provider/file_line/ruby.rb
new file mode 100644
index 00000000..ae1a8b3d
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/provider/file_line/ruby.rb
@@ -0,0 +1,85 @@
+Puppet::Type.type(:file_line).provide(:ruby) do
+  def exists?
+    lines.find do |line|
+      line.chomp == resource[:line].chomp
+    end
+  end
+
+  def create
+    if resource[:match]
+      handle_create_with_match
+    elsif resource[:after]
+      handle_create_with_after
+    else
+      append_line
+    end
+  end
+
+  def destroy
+    local_lines = lines
+    File.open(resource[:path],'w') do |fh|
+      fh.write(local_lines.reject{|l| l.chomp == resource[:line] }.join(''))
+    end
+  end
+
+  private
+  def lines
+    # If this type is ever used with very large files, we should
+    #  write this in a different way, using a temp
+    #  file; for now assuming that this type is only used on
+    #  small-ish config files that can fit into memory without
+    #  too much trouble.
+    @lines ||= File.readlines(resource[:path])
+  end
+
+  def handle_create_with_match()
+    regex = resource[:match] ? Regexp.new(resource[:match]) : nil
+    match_count = count_matches(regex)
+    if match_count > 1 && resource[:multiple].to_s != 'true'
+     raise Puppet::Error, "More than one line in file '#{resource[:path]}' matches pattern '#{resource[:match]}'"
+    end
+    File.open(resource[:path], 'w') do |fh|
+      lines.each do |l|
+        fh.puts(regex.match(l) ? resource[:line] : l)
+      end
+
+      if (match_count == 0)
+        fh.puts(resource[:line])
+      end
+    end
+  end
+
+  def handle_create_with_after
+    regex = Regexp.new(resource[:after])
+    count = count_matches(regex)
+    case count
+    when 1 # find the line to put our line after
+      File.open(resource[:path], 'w') do |fh|
+        lines.each do |l|
+          fh.puts(l)
+          if regex.match(l) then
+            fh.puts(resource[:line])
+          end
+        end
+      end
+    when 0 # append the line to the end of the file
+      append_line
+    else
+      raise Puppet::Error, "#{count} lines match pattern '#{resource[:after]}' in file '#{resource[:path]}'.  One or no line must match the pattern."
+    end
+  end
+
+  def count_matches(regex)
+    lines.select{|l| l.match(regex)}.size
+  end
+
+  ##
+  # append the line to the file.
+  #
+  # @api private
+  def append_line
+    File.open(resource[:path], 'a') do |fh|
+      fh.puts resource[:line]
+    end
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/type/anchor.rb b/puppet/modules/stdlib/lib/puppet/type/anchor.rb
new file mode 100644
index 00000000..fe1e5aa1
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/type/anchor.rb
@@ -0,0 +1,46 @@
+Puppet::Type.newtype(:anchor) do
+  desc <<-'ENDOFDESC'
+  A simple resource type intended to be used as an anchor in a composite class.
+
+  In Puppet 2.6, when a class declares another class, the resources in the
+  interior class are not contained by the exterior class. This interacts badly
+  with the pattern of composing complex modules from smaller classes, as it
+  makes it impossible for end users to specify order relationships between the
+  exterior class and other modules.
+
+  The anchor type lets you work around this. By sandwiching any interior
+  classes between two no-op resources that _are_ contained by the exterior
+  class, you can ensure that all resources in the module are contained.
+
+      class ntp {
+        # These classes will have the correct order relationship with each
+        # other. However, without anchors, they won't have any order
+        # relationship to Class['ntp'].
+        class { 'ntp::package': }
+        -> class { 'ntp::config': }
+        -> class { 'ntp::service': }
+
+        # These two resources "anchor" the composed classes within the ntp
+        # class.
+        anchor { 'ntp::begin': } -> Class['ntp::package']
+        Class['ntp::service']    -> anchor { 'ntp::end': }
+      }
+
+  This allows the end user of the ntp module to establish require and before
+  relationships with Class['ntp']:
+
+      class { 'ntp': } -> class { 'mcollective': }
+      class { 'mcollective': } -> class { 'ntp': }
+
+  ENDOFDESC
+
+  newparam :name do
+    desc "The name of the anchor resource."
+  end
+
+  def refresh
+    # We don't do anything with them, but we need this to
+    #   show that we are "refresh aware" and not break the
+    #   chain of propagation.
+  end
+end
diff --git a/puppet/modules/stdlib/lib/puppet/type/file_line.rb b/puppet/modules/stdlib/lib/puppet/type/file_line.rb
new file mode 100644
index 00000000..df263e6a
--- /dev/null
+++ b/puppet/modules/stdlib/lib/puppet/type/file_line.rb
@@ -0,0 +1,75 @@
+Puppet::Type.newtype(:file_line) do
+
+  desc <<-EOT
+    Ensures that a given line is contained within a file.  The implementation
+    matches the full line, including whitespace at the beginning and end.  If
+    the line is not contained in the given file, Puppet will add the line to
+    ensure the desired state.  Multiple resources may be declared to manage
+    multiple lines in the same file.
+
+    Example:
+
+        file_line { 'sudo_rule':
+          path => '/etc/sudoers',
+          line => '%sudo ALL=(ALL) ALL',
+        }
+        file_line { 'sudo_rule_nopw':
+          path => '/etc/sudoers',
+          line => '%sudonopw ALL=(ALL) NOPASSWD: ALL',
+        }
+
+    In this example, Puppet will ensure both of the specified lines are
+    contained in the file /etc/sudoers.
+
+    **Autorequires:** If Puppet is managing the file that will contain the line
+    being managed, the file_line resource will autorequire that file.
+
+  EOT
+
+  ensurable do
+    defaultvalues
+    defaultto :present
+  end
+
+  newparam(:name, :namevar => true) do
+    desc 'An arbitrary name used as the identity of the resource.'
+  end
+
+  newparam(:match) do
+    desc 'An optional regular expression to run against existing lines in the file;\n' +
+        'if a match is found, we replace that line rather than adding a new line.'
+  end
+
+  newparam(:multiple) do
+    desc 'An optional value to determine if match can change multiple lines.'
+    newvalues(true, false)
+  end
+
+  newparam(:after) do
+    desc 'An optional value used to specify the line after which we will add any new lines. (Existing lines are added in place)'
+  end
+
+  newparam(:line) do
+    desc 'The line to be appended to the file located by the path parameter.'
+  end
+
+  newparam(:path) do
+    desc 'The file Puppet will ensure contains the line specified by the line parameter.'
+    validate do |value|
+      unless (Puppet.features.posix? and value =~ /^\//) or (Puppet.features.microsoft_windows? and (value =~ /^.:\// or value =~ /^\/\/[^\/]+\/[^\/]+/))
+        raise(Puppet::Error, "File paths must be fully qualified, not '#{value}'")
+      end
+    end
+  end
+
+  # Autorequire the file resource if it's being managed
+  autorequire(:file) do
+    self[:path]
+  end
+
+  validate do
+    unless self[:line] and self[:path]
+      raise(Puppet::Error, "Both line and path are required attributes")
+    end
+  end
+end
-- 
cgit v1.2.3