commit a7d31e3676225afe83a2c2cdec30e114c7cac774
Author: Rafael J. García Perdigón <root@RafaDebian.gobex.pri>
Date:   Wed Nov 21 09:54:14 2018 +0100

    puppet: Debianized puppet-linex, puppet-linex-common, facter-linex

diff --git a/debian/stretch/facter-linex/debian/changelog b/debian/stretch/facter-linex/debian/changelog
new file mode 100644
index 0000000..e791913
--- /dev/null
+++ b/debian/stretch/facter-linex/debian/changelog
@@ -0,0 +1,5 @@
+linex-arduino (1.0) linex; urgency=medium
+
+  * Collect and display facts about the system. Modified by Linex.
+
+ -- Rafael J. García Perdigón <rafael.garciap@juntaex.es>  Tue, 20 Nov 2018 09:58:07 +0100
diff --git a/debian/stretch/facter-linex/debian/compat b/debian/stretch/facter-linex/debian/compat
new file mode 100644
index 0000000..ec63514
--- /dev/null
+++ b/debian/stretch/facter-linex/debian/compat
@@ -0,0 +1 @@
+9
diff --git a/debian/stretch/facter-linex/debian/control b/debian/stretch/facter-linex/debian/control
new file mode 100644
index 0000000..7efe2d2
--- /dev/null
+++ b/debian/stretch/facter-linex/debian/control
@@ -0,0 +1,23 @@
+Source: facter-linex
+Section: admin
+Priority: optional
+Maintainer: Rafael Jesús García Perdigón <rafael.garciap@juntaex.es>
+Build-Depends: debhelper (>= 8.0.0)
+Standards-Version: 3.9.4
+
+Package: facter-linex
+Architecture: all
+Depends: bind9-host | host, net-tools, ruby-json, ruby | ruby-interpreter
+Recommends: pciutils, dmidecode, virt-what
+Conflicts: facter
+Provides: facter
+Description: Collect and display facts about the system.
+ A cross-platform Ruby library for retrieving facts from operating systems.
+ Supports multiple resolution mechanisms, any of which can be restricted to
+ working only on certain operating systems or environments. Facter is
+ especially useful for retrieving things like operating system names, IP
+ addresses, MAC addresses, and SSH keys.
+ .
+ It is easy to extend Facter to include your own custom facts or to include
+ additional mechanisms for retrieving facts.
+
diff --git a/debian/stretch/facter-linex/debian/install b/debian/stretch/facter-linex/debian/install
new file mode 100644
index 0000000..73752c9
--- /dev/null
+++ b/debian/stretch/facter-linex/debian/install
@@ -0,0 +1 @@
+usr
diff --git a/debian/stretch/facter-linex/usr/bin/facter b/debian/stretch/facter-linex/usr/bin/facter
new file mode 100755
index 0000000..139d11b
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/bin/facter
@@ -0,0 +1,9 @@
+#!/usr/bin/ruby
+
+# For security reasons, ensure that '.' is not on the load path
+# This is primarily for 1.8.7 since 1.9.2+ doesn't put '.' on the load path
+$LOAD_PATH.delete '.'
+
+require 'facter/application'
+
+Facter::Application.run(ARGV)
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter.rb
new file mode 100644
index 0000000..8566f3f
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter.rb
@@ -0,0 +1,261 @@
+# Facter - Host Fact Detection and Reporting
+#
+# Copyright 2011 Puppet Labs Inc
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require 'facter/version'
+
+# Functions as a hash of 'facts' about your system system, such as MAC
+# address, IP address, architecture, etc.
+#
+# @example Retrieve a fact
+#     puts Facter['operatingsystem'].value
+#
+# @example Retrieve all facts
+#   Facter.to_hash
+#    => { "kernel"=>"Linux", "uptime_days"=>0, "ipaddress"=>"10.0.0.1" }
+#
+# @api public
+module Facter
+  # Most core functionality of facter is implemented in `Facter::Util`.
+  # @api public
+  module Util; end
+
+  require 'facter/util/fact'
+  require 'facter/util/collection'
+
+  include Comparable
+  include Enumerable
+
+  require 'facter/core/logging'
+  extend Facter::Core::Logging
+
+  # module methods
+
+  # Accessor for the collection object which holds all the facts
+  # @return [Facter::Util::Collection] the collection of facts
+  #
+  # @api private
+  def self.collection
+    unless defined?(@collection) and @collection
+      @collection = Facter::Util::Collection.new(
+        Facter::Util::Loader.new,
+        Facter::Util::Config.ext_fact_loader)
+    end
+    @collection
+  end
+
+  # Returns whether the JSON "feature" is available.
+  #
+  # @api private
+  def self.json?
+    begin
+      require 'json'
+      true
+    rescue LoadError
+      false
+    end
+  end
+
+  # Returns a fact object by name.  If you use this, you still have to
+  # call {Facter::Util::Fact#value `value`} on it to retrieve the actual
+  # value.
+  #
+  # @param name [String] the name of the fact
+  #
+  # @return [Facter::Util::Fact, nil] The fact object, or nil if no fact
+  #   is found.
+  #
+  # @api public
+  def self.[](name)
+    collection.fact(name)
+  end
+
+  # (see [])
+  def self.fact(name)
+    collection.fact(name)
+  end
+
+  # Flushes cached values for all facts. This does not cause code to be
+  # reloaded; it only clears the cached results.
+  #
+  # @return [void]
+  #
+  # @api public
+  def self.flush
+    collection.flush
+  end
+
+  # Lists all fact names
+  #
+  # @return [Array<String>] array of fact names
+  #
+  # @api public
+  def self.list
+    collection.list
+  end
+
+  # Gets the value for a fact. Returns `nil` if no such fact exists.
+  #
+  # @param name [String] the fact name
+  # @return [Object, nil] the value of the fact, or nil if no fact is
+  #   found
+  #
+  # @api public
+  def self.value(name)
+    collection.value(name)
+  end
+
+  # Gets a hash mapping fact names to their values
+  #
+  # @return [Hash{String => Object}] the hash of fact names and values
+  #
+  # @api public
+  def self.to_hash
+    collection.load_all
+    collection.to_hash
+  end
+
+  # Define a new fact or extend an existing fact.
+  #
+  # @param name [Symbol] The name of the fact to define
+  # @param options [Hash] A hash of options to set on the fact
+  #
+  # @return [Facter::Util::Fact] The fact that was defined
+  #
+  # @api public
+  # @see {Facter::Util::Collection#define_fact}
+  def self.define_fact(name, options = {}, &block)
+    collection.define_fact(name, options, &block)
+  end
+
+  # Adds a {Facter::Util::Resolution resolution} mechanism for a named
+  # fact. This does not distinguish between adding a new fact and adding
+  # a new way to resolve a fact.
+  #
+  # @overload add(name, options = {}, { || ... })
+  # @param name [String] the fact name
+  # @param options [Hash] optional parameters for the fact - attributes
+  #   of {Facter::Util::Fact} and {Facter::Util::Resolution} can be
+  #   supplied here
+  # @option options [Integer] :timeout set the
+  #   {Facter::Util::Resolution#timeout timeout} for this resolution
+  # @param block [Proc] a block defining a fact resolution
+  #
+  # @return [Facter::Util::Fact] the fact object, which includes any previously
+  #   defined resolutions
+  #
+  # @api public
+  def self.add(name, options = {}, &block)
+    collection.add(name, options, &block)
+  end
+
+  # Iterates over fact names and values
+  #
+  # @yieldparam [String] name the fact name
+  # @yieldparam [String] value the current value of the fact
+  #
+  # @return [void]
+  #
+  # @api public
+  def self.each
+    # Make sure all facts are loaded.
+    collection.load_all
+
+    collection.each do |*args|
+      yield(*args)
+    end
+  end
+
+  # Clears all cached values and removes all facts from memory.
+  #
+  # @return [void]
+  #
+  # @api public
+  def self.clear
+    Facter.flush
+    Facter.reset
+  end
+
+  # Removes all facts from memory. Use this when the fact code has
+  # changed on disk and needs to be reloaded.
+  #
+  # @return [void]
+  #
+  # @api public
+  def self.reset
+    @collection = nil
+    reset_search_path!
+  end
+
+  # Loads all facts.
+  #
+  # @return [void]
+  #
+  # @api public
+  def self.loadfacts
+    collection.load_all
+  end
+
+  # Register directories to be searched for facts. The registered directories
+  # must be absolute paths or they will be ignored.
+  #
+  # @param dirs [String] directories to search
+  #
+  # @return [void]
+  #
+  # @api public
+  def self.search(*dirs)
+    @search_path += dirs
+  end
+
+  # Returns the registered search directories.
+  #
+  # @return [Array<String>] An array of the directories searched
+  #
+  # @api public
+  def self.search_path
+    @search_path.dup
+  end
+
+  # Reset the Facter search directories.
+  #
+  # @api private
+  # @return [void]
+  def self.reset_search_path!
+    @search_path = []
+  end
+
+  reset_search_path!
+
+  # Registers directories to be searched for external facts.
+  #
+  # @param dirs [Array<String>] directories to search
+  #
+  # @return [void]
+  #
+  # @api public
+  def self.search_external(dirs)
+    Facter::Util::Config.external_facts_dirs += dirs
+  end
+
+  # Returns the registered search directories.
+  #
+  # @return [Array<String>] An array of the directories searched
+  #
+  # @api public
+  def self.search_external_path
+    Facter::Util::Config.external_facts_dirs.dup
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/Cfkey.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/Cfkey.rb
new file mode 100644
index 0000000..4c032a6
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/Cfkey.rb
@@ -0,0 +1,42 @@
+# Fact: cfkey
+#
+# Purpose: Return the public key(s) for CFengine.
+#
+# Resolution:
+#   Tries each file of standard `localhost.pub` and `cfkey.pub` locations,
+#   checks if they appear to be a public key, and then join them all together.
+#
+# Caveats:
+#
+
+## Cfkey.rb
+## Facts related to cfengine
+##
+
+Facter.add(:Cfkey) do
+  setcode do
+    value = nil
+    ["/usr/local/etc/cfkey.pub",
+      "/etc/cfkey.pub",
+      "/var/cfng/keys/localhost.pub",
+      "/var/cfengine/ppkeys/localhost.pub",
+      "/var/lib/cfengine/ppkeys/localhost.pub",
+      "/var/lib/cfengine2/ppkeys/localhost.pub"
+    ].each do |file|
+      if FileTest.file?(file)
+        File.open(file) { |openfile|
+          value = openfile.readlines.reject { |line|
+            line =~ /PUBLIC KEY/
+          }.collect { |line|
+            line.chomp
+          }.join("")
+        }
+      end
+      if value
+        break
+      end
+    end
+
+    value
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/application.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/application.rb
new file mode 100644
index 0000000..be85f1a
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/application.rb
@@ -0,0 +1,206 @@
+require 'optparse'
+require 'facter'
+require 'facter/util/formatter'
+
+module Facter
+  module Application
+
+    require 'facter/util/nothing_loader'
+
+    def self.create_directory_loader(dir)
+      begin
+        Facter::Util::Config.ext_fact_loader = Facter::Util::DirectoryLoader.loader_for(dir)
+      rescue Facter::Util::DirectoryLoader::NoSuchDirectoryError => error
+        Facter.log_exception(error, "Specified external facts directory #{dir} does not exist.")
+        exit(1)
+      end
+    end
+
+    def self.create_nothing_loader
+      Facter::Util::Config.ext_fact_loader = Facter::Util::NothingLoader.new
+    end
+
+    def self.run(argv)
+      options = parse(argv)
+
+      # Accept fact names to return from the command line
+      names = argv
+
+      # Change location of external facts dir
+      # Check here for valid ext_dir and exit program
+
+      # Create the facts hash that is printed to standard out.
+      unless names.empty?
+        facts = {}
+        names.each do |name|
+          begin
+            facts[name] = Facter.value(name)
+          rescue => error
+            Facter.log_exception(error, "Could not retrieve #{name}: #{error.message}")
+            exit(10)
+          end
+        end
+      end
+
+      # Print everything if they didn't ask for specific facts.
+      facts ||= Facter.to_hash
+
+      output = nil
+
+      if options[:yaml]
+        output = Facter::Util::Formatter.format_yaml(facts)
+      elsif options[:json]
+        output = Facter::Util::Formatter.format_json(facts)
+      elsif options[:plaintext]
+        output = Facter::Util::Formatter.format_plaintext(facts)
+      else
+        output = Facter::Util::Formatter.format_plaintext(facts)
+      end
+
+      puts output
+      exit(0)
+
+    rescue => e
+      Facter.log_exception(e)
+      exit(12)
+    end
+
+    private
+
+    # Parses the given argument array destructively to return an options hash
+    # (and possibly perform side effects such as changing settings).
+    #
+    # @param [Array<String>] argv command line arguments
+    # @return [Hash] options hash
+    def self.parse(argv)
+      options = {}
+      parser = OptionParser.new do |opts|
+        opts.banner = <<-BANNER
+facter(8) -- Gather system information
+======
+
+SYNOPSIS
+--------
+
+Collect and display facts about the system.
+
+USAGE
+-----
+
+    facter [-h|--help] [-t|--timing] [-d|--debug] [-p|--puppet] [-v|--version]
+      [-y|--yaml] [-j|--json] [--plaintext] [--external-dir DIR] [--no-external-dir]
+      [fact] [fact] [...]
+
+DESCRIPTION
+-----------
+
+Collect and display facts about the current system.  The library behind
+Facter is easy to expand, making Facter an easy way to collect information
+about a system from within the shell or within Ruby.
+
+If no facts are specifically asked for, then all facts will be returned.
+
+EXAMPLE
+-------
+
+Display all facts:
+
+    $ facter
+    architecture => amd64
+    blockdevices => sda,sr0
+    domain => example.com
+    fqdn => puppet.example.com
+    hardwaremodel => x86_64
+    [...]
+
+Display a single fact:
+
+    $ facter kernel
+    Linux
+
+Format facts as JSON:
+
+    $ facter --json architecture kernel hardwaremodel
+    {
+      "architecture": "amd64",
+      "kernel": "Linux",
+      "hardwaremodel": "x86_64"
+    }
+
+AUTHOR
+------
+  Luke Kanies
+
+COPYRIGHT
+---------
+  Copyright (c) 2011-2014 Puppet Labs, Inc Licensed under the Apache 2.0 license
+
+OPTIONS
+-------
+        BANNER
+        opts.on("-y",
+                "--yaml",
+                "Emit facts in YAML format.")   { |v| options[:yaml]   = v }
+        opts.on("-j",
+                "--json",
+                "Emit facts in JSON format.")   { |v| options[:json]   = v }
+        opts.on("--plaintext",
+                "Emit facts in plaintext format.") { |v| options[:plaintext] = v }
+        opts.on("--trace",
+                "Enable backtraces.")  { |v| Facter.trace(true) }
+        opts.on("--external-dir DIR",
+                "The directory to use for external facts.") { |v| create_directory_loader(v) }
+        opts.on("--no-external-dir",
+                "Turn off external facts.") { |v| create_nothing_loader }
+        opts.on("-d",
+                "--debug",
+                "Enable debugging.")  { |v| Facter.debugging(1) }
+        opts.on("-t",
+                "--timing",
+                "Enable timing.") { |v| Facter.timing(1) }
+        opts.on("-p",
+                "--puppet",
+                "(Deprecated: use `puppet facts` instead) Load the Puppet libraries, thus allowing Facter to load Puppet-specific facts.") do |v|
+          load_puppet
+        end
+
+        opts.on_tail("-v",
+                     "--version",
+                     "Print the version and exit.") do
+          puts Facter.version
+          exit(0)
+        end
+
+        opts.on_tail("-h",
+                     "--help",
+                     "Print this help message.") do
+          puts parser
+          exit(0)
+        end
+      end
+
+      parser.parse!(argv)
+
+      options
+    rescue OptionParser::InvalidOption => e
+      $stderr.puts e.message
+      exit(12)
+    end
+
+    def self.load_puppet
+      require 'puppet'
+      Puppet.initialize_settings
+
+      # If you've set 'vardir' but not 'libdir' in your
+      # puppet.conf, then the hook to add libdir to $:
+      # won't get triggered.  This makes sure that it's setup
+      # correctly.
+      unless $LOAD_PATH.include?(Puppet[:libdir])
+        $LOAD_PATH << Puppet[:libdir]
+      end
+    rescue LoadError => detail
+      $stderr.puts "Could not load Puppet: #{detail}"
+    end
+
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/architecture.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/architecture.rb
new file mode 100644
index 0000000..72c5755
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/architecture.rb
@@ -0,0 +1,50 @@
+# Fact: architecture
+#
+# Purpose:
+#   Return the CPU hardware architecture.
+#
+# Resolution:
+#   On non-AIX IBM, OpenBSD, Linux, and Debian's kfreebsd, use the hardwaremodel fact.
+#   On AIX get the arch value from `lsattr -El proc0 -a type`.
+#   Gentoo and Debian call "x86_86" "amd64".
+#   Gentoo also calls "i386" "x86".
+#
+# Caveats:
+#
+
+require 'facter/util/architecture'
+
+Facter.add(:architecture) do
+  setcode do
+    model = Facter.value(:hardwaremodel)
+    case model
+      # most linuxen use "x86_64"
+    when /IBM*/
+      case Facter.value(:operatingsystem)
+      when "AIX"
+         arch = Facter::Util::Architecture.lsattr
+         if (match = arch.match /type\s(\S+)\s/)
+           match[1]
+         end
+      else
+        model
+      end
+    when "x86_64"
+      case Facter.value(:operatingsystem)
+      when "Debian", "Gentoo", "GNU/kFreeBSD", "Ubuntu"
+        "amd64"
+      else
+        model
+      end
+    when /(i[3456]86|pentium)/
+      case Facter.value(:operatingsystem)
+      when "Gentoo", "windows"
+        "x86"
+      else
+        "i386"
+      end
+    else
+      model
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/augeasversion.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/augeasversion.rb
new file mode 100644
index 0000000..6239789
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/augeasversion.rb
@@ -0,0 +1,28 @@
+# Fact: augeasversion
+#
+# Purpose: Report the version of the Augeas library.
+#
+# Resolution:
+#   Loads ruby-augeas and reports the value of `/augeas/version`, the version of
+#   the underlying Augeas library.
+#
+# Caveats:
+#   The library version may not indicate the presence of certain lenses,
+#   depending on the system packages updated, nor the version of ruby-augeas
+#   which may affect support for the Puppet Augeas provider.
+#   Versions prior to 0.3.6 cannot be interrogated for their version.
+#
+
+Facter.add(:augeasversion) do
+  setcode do
+    begin
+      require 'augeas'
+      aug = Augeas::open('/', nil, Augeas::NO_MODL_AUTOLOAD)
+      ver = aug.get('/augeas/version')
+      aug.close
+      ver
+    rescue Exception
+      Facter.debug('ruby-augeas not available')
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/blockdevices.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/blockdevices.rb
new file mode 100644
index 0000000..526987a
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/blockdevices.rb
@@ -0,0 +1,105 @@
+# Fact: blockdevice_<devicename>_size
+#
+# Purpose:
+#   Return the size of a block device in bytes.
+#
+# Resolution:
+#   Parse the contents of `/sys/block/<device>/size` to receive the size (multiplying by 512 to correct for blocks-to-bytes).
+#
+# Caveats:
+#   Only supports Linux 2.6+ at this time, due to the reliance on sysfs.
+#
+
+# Fact: blockdevice_<devicename>_vendor
+#
+# Purpose:
+#   Return the vendor name of block devices attached to the system.
+#
+# Resolution:
+#   Parse the contents of `/sys/block/<device>/device/vendor` to retrieve the vendor for a device.
+#
+# Caveats:
+#   Only supports Linux 2.6+ at this time, due to the reliance on sysfs.
+#
+
+# Fact: blockdevice_<devicename>_model
+#
+# Purpose:
+#   Return the model name of block devices attached to the system.
+#
+# Resolution:
+#   Parse the contents of `/sys/block/<device>/device/model` to retrieve the model name/number for a device.
+#
+# Caveats:
+#   Only supports Linux 2.6+ at this time, due to the reliance on sysfs.
+#
+
+
+# Fact: blockdevices
+#
+# Purpose:
+#   Return a comma separated list of block devices.
+#
+# Resolution:
+#   Retrieve the block devices that were identified and iterated over in the creation of the blockdevice_ facts.
+#
+# Caveats:
+#   Block devices must have been identified using sysfs information.
+#
+
+# Author: Jason Gill <jasongill@gmail.com>
+
+require 'facter'
+
+# Only Linux 2.6+ kernels support sysfs which is required to easily get device details
+if Facter.value(:kernel) == 'Linux'
+
+  sysfs_block_directory = '/sys/block/'
+
+  blockdevices = []
+
+  # This should prevent any non-2.6 kernels or odd machines without sysfs support from being investigated further
+  if File.exist?(sysfs_block_directory)
+
+    # Iterate over each file in the /sys/block/ directory and skip ones that do not have a device subdirectory
+    Dir.entries(sysfs_block_directory).each do |device|
+      sysfs_device_directory = sysfs_block_directory + device + "/device"
+      next unless File.exist?(sysfs_device_directory)
+
+      # Add the device to the blockdevices list, which is returned as it's own fact later on
+      blockdevices << device
+
+      sizefile = sysfs_block_directory + device + "/size"
+      vendorfile = sysfs_device_directory + "/vendor"
+      modelfile = sysfs_device_directory + "/model"
+
+      if File.exist?(sizefile)
+        Facter.add("blockdevice_#{device}_size".to_sym) do
+          setcode { IO.read(sizefile).strip.to_i * 512 }
+        end
+      end
+
+      if File.exist?(vendorfile)
+        Facter.add("blockdevice_#{device}_vendor".to_sym) do
+          setcode { IO.read(vendorfile).strip }
+        end
+      end
+
+      if File.exist?(modelfile)
+        Facter.add("blockdevice_#{device}_model".to_sym) do
+          setcode { IO.read(modelfile).strip }
+        end
+      end
+
+    end
+
+  end
+
+  # Return a comma-seperated list of block devices found
+  unless blockdevices.empty?
+    Facter.add(:blockdevices) do
+      setcode { blockdevices.sort.join(',') }
+    end
+  end
+
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/aggregate.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/aggregate.rb
new file mode 100644
index 0000000..775171a
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/aggregate.rb
@@ -0,0 +1,220 @@
+require 'facter'
+require 'facter/core/directed_graph'
+require 'facter/core/suitable'
+require 'facter/core/resolvable'
+require 'facter/util/values'
+
+# Aggregates provide a mechanism for facts to be resolved in multiple steps.
+#
+# Aggregates are evaluated in two parts: generating individual chunks and then
+# aggregating all chunks together. Each chunk is a block of code that generates
+# a value, and may depend on other chunks when it runs. After all chunks have
+# been evaluated they are passed to the aggregate block as Hash<name, result>.
+# The aggregate block converts the individual chunks into a single value that is
+# returned as the final value of the aggregate.
+#
+# @api public
+# @since 2.0.0
+class Facter::Core::Aggregate
+
+  include Facter::Core::Suitable
+  include Facter::Core::Resolvable
+
+  # @!attribute [r] name
+  #   @return [Symbol] The name of the aggregate resolution
+  attr_reader :name
+
+  # @!attribute [r] deps
+  #   @api private
+  #   @return [Facter::Core::DirectedGraph]
+  attr_reader :deps
+
+  # @!attribute [r] confines
+  #   @return [Array<Facter::Core::Confine>] An array of confines restricting
+  #     this to a specific platform
+  #   @see Facter::Core::Suitable
+  attr_reader :confines
+
+  # @!attribute [r] fact
+  # @return [Facter::Util::Fact]
+  # @api private
+  attr_reader :fact
+
+  def initialize(name, fact)
+    @name = name
+    @fact = fact
+
+    @confines = []
+    @chunks = {}
+
+    @aggregate = nil
+    @deps = Facter::Core::DirectedGraph.new
+  end
+
+  def set_options(options)
+    if options[:name]
+      @name = options.delete(:name)
+    end
+
+    if options.has_key?(:timeout)
+      @timeout = options.delete(:timeout)
+    end
+
+    if options.has_key?(:weight)
+      @weight = options.delete(:weight)
+    end
+
+    if not options.keys.empty?
+      raise ArgumentError, "Invalid aggregate options #{options.keys.inspect}"
+    end
+  end
+
+  def evaluate(&block)
+    instance_eval(&block)
+  end
+
+  # Define a new chunk for the given aggregate
+  #
+  # @api public
+  #
+  # @example Defining a chunk with no dependencies
+  #   aggregate.chunk(:mountpoints) do
+  #     # generate mountpoint information
+  #   end
+  #
+  # @example Defining an chunk to add mount options
+  #   aggregate.chunk(:mount_options, :require => [:mountpoints]) do |mountpoints|
+  #     # `mountpoints` is the result of the previous chunk
+  #     # generate mount option information based on the mountpoints
+  #   end
+  #
+  # @param name [Symbol] A name unique to this aggregate describing the chunk
+  # @param opts [Hash]
+  # @options opts [Array<Symbol>, Symbol] :require One or more chunks
+  #   to evaluate and pass to this block.
+  # @yield [*Object] Zero or more chunk results
+  #
+  # @return [void]
+  def chunk(name, opts = {}, &block)
+    if not block_given?
+      raise ArgumentError, "#{self.class.name}#chunk requires a block"
+    end
+
+    deps = Array(opts.delete(:require))
+
+    if not opts.empty?
+      raise ArgumentError, "Unexpected options passed to #{self.class.name}#chunk: #{opts.keys.inspect}"
+    end
+
+    @deps[name] = deps
+    @chunks[name] = block
+  end
+
+  # Define how all chunks should be combined
+  #
+  # @api public
+  #
+  # @example Merge all chunks
+  #   aggregate.aggregate do |chunks|
+  #     final_result = {}
+  #     chunks.each_value do |chunk|
+  #       final_result.deep_merge(chunk)
+  #     end
+  #     final_result
+  #   end
+  #
+  # @example Sum all chunks
+  #   aggregate.aggregate do |chunks|
+  #     total = 0
+  #     chunks.each_value do |chunk|
+  #       total += chunk
+  #     end
+  #     total
+  #   end
+  #
+  # @yield [Hash<Symbol, Object>] A hash containing chunk names and
+  #   chunk values
+  #
+  # @return [void]
+  def aggregate(&block)
+    if block_given?
+      @aggregate = block
+    else
+      raise ArgumentError, "#{self.class.name}#aggregate requires a block"
+    end
+  end
+
+  def resolution_type
+    :aggregate
+  end
+
+  private
+
+  # Evaluate the results of this aggregate.
+  #
+  # @see Facter::Core::Resolvable#value
+  # @return [Object]
+  def resolve_value
+    chunk_results = run_chunks()
+    aggregate_results(chunk_results)
+  end
+
+  # Order all chunks based on their dependencies and evaluate each one, passing
+  # dependent chunks as needed.
+  #
+  # @return [Hash<Symbol, Object>] A hash containing the chunk that
+  #   generated value and the related value.
+  def run_chunks
+    results = {}
+    order_chunks.each do |(name, block)|
+      input = @deps[name].map { |dep_name| results[dep_name] }
+
+      output = block.call(*input)
+      results[name] = Facter::Util::Values.deep_freeze(output)
+    end
+
+    results
+  end
+
+  # Process the results of all chunks with the aggregate block and return the
+  # results. If no aggregate block has been specified, fall back to deep
+  # merging the given data structure
+  #
+  # @param results [Hash<Symbol, Object>] A hash of chunk names and the output
+  #   of that chunk.
+  # @return [Object]
+  def aggregate_results(results)
+    if @aggregate
+      @aggregate.call(results)
+    else
+      default_aggregate(results)
+    end
+  end
+
+  def default_aggregate(results)
+    results.values.inject do |result, current|
+      Facter::Util::Values.deep_merge(result, current)
+    end
+  rescue Facter::Util::Values::DeepMergeError => e
+    raise ArgumentError, "Could not deep merge all chunks (Original error: " +
+      "#{e.message}), ensure that chunks return either an Array or Hash or " +
+      "override the aggregate block", e.backtrace
+  end
+
+  # Order chunks based on their dependencies
+  #
+  # @return [Array<Symbol, Proc>] A list of chunk names and blocks in evaluation order.
+  def order_chunks
+    if not @deps.acyclic?
+      raise DependencyError, "Could not order chunks; found the following dependency cycles: #{@deps.cycles.inspect}"
+    end
+
+    sorted_names = @deps.tsort
+
+    sorted_names.map do |name|
+      [name, @chunks[name]]
+    end
+  end
+
+  class DependencyError < StandardError; end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/directed_graph.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/directed_graph.rb
new file mode 100644
index 0000000..6edcaba
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/directed_graph.rb
@@ -0,0 +1,46 @@
+require 'set'
+require 'tsort'
+
+module Facter
+  module Core
+    class DirectedGraph < Hash
+      include TSort
+
+      def acyclic?
+        cycles.empty?
+      end
+
+      def cycles
+        cycles = []
+        each_strongly_connected_component do |component|
+          cycles << component if component.size > 1
+        end
+        cycles
+      end
+
+      alias tsort_each_node each_key
+
+      def tsort_each_child(node)
+        fetch(node, []).each do |child|
+          yield child
+        end
+      end
+
+      def tsort
+        missing = Set.new(self.values.flatten) - Set.new(self.keys)
+
+        if not missing.empty?
+          raise MissingVertex, "Cannot sort elements; cannot depend on missing elements #{missing.to_a}"
+        end
+
+        super
+
+      rescue TSort::Cyclic
+        raise CycleError, "Cannot sort elements; found the following cycles: #{cycles.inspect}"
+      end
+
+      class CycleError < StandardError; end
+      class MissingVertex < StandardError; end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/execution.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/execution.rb
new file mode 100644
index 0000000..1536851
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/execution.rb
@@ -0,0 +1,123 @@
+require 'facter/util/config'
+
+module Facter
+  module Core
+    module Execution
+
+      require 'facter/core/execution/base'
+      require 'facter/core/execution/windows'
+      require 'facter/core/execution/posix'
+
+      @@impl = if Facter::Util::Config.is_windows?
+                 Facter::Core::Execution::Windows.new
+               else
+                 Facter::Core::Execution::Posix.new
+               end
+
+      def self.impl
+        @@impl
+      end
+
+      module_function
+
+      # Returns the locations to be searched when looking for a binary. This
+      # is currently determined by the +PATH+ environment variable plus
+      # `/sbin` and `/usr/sbin` when run on unix
+      #
+      # @return [Array<String>] the paths to be searched for binaries
+      # @api private
+      def search_paths
+        @@impl.search_paths
+      end
+
+      # Determines the full path to a binary. If the supplied filename does not
+      # already describe an absolute path then different locations (determined
+      # by {search_paths}) will be searched for a match.
+      #
+      # Returns nil if no matching executable can be found otherwise returns
+      # the expanded pathname.
+      #
+      # @param bin [String] the executable to locate
+      # @return [String,nil] the full path to the executable or nil if not
+      #   found
+      #
+      # @api public
+      def which(bin)
+        @@impl.which(bin)
+      end
+
+      # Determine in a platform-specific way whether a path is absolute. This
+      # defaults to the local platform if none is specified.
+      #
+      # @param path [String] the path to check
+      # @param platform [:posix,:windows,nil] the platform logic to use
+      def absolute_path?(path, platform = nil)
+        @@impl.absolute_path?(path, platform)
+      end
+
+      # Given a command line, this returns the command line with the
+      # executable written as an absolute path. If the executable contains
+      # spaces, it has be put in double quotes to be properly recognized.
+      #
+      # @param command [String] the command line
+      #
+      # @return [String, nil] the command line with the executable's path
+      # expanded, or nil if the executable cannot be found.
+      def expand_command(command)
+        @@impl.expand_command(command)
+      end
+
+      # Overrides environment variables within a block of code.  The
+      # specified values will be set for the duration of the block, after
+      # which the original values (if any) will be restored.
+      #
+      # @overload with_env(values, { || ... })
+      #
+      # @param values [Hash<String=>String>] A hash of the environment
+      #   variables to override
+      #
+      # @return [void]
+      #
+      # @api public
+      def with_env(values, &block)
+        @@impl.with_env(values, &block)
+      end
+
+      # Try to execute a command and return the output.
+      #
+      # @param code [String] the program to run
+      #
+      # @return [String] the output of the program, or nil if the command does
+      #   not exist or could not be executed.
+      #
+      # @deprecated Use #{execute} instead
+      # @api public
+      def exec(command)
+        @@impl.execute(command, :on_fail => nil)
+      end
+
+      # Execute a command and return the output of that program.
+      #
+      # @param code [String] the program to run
+      # @param options [Hash]
+      #
+      # @option options [Object] :on_fail How to behave when the command could
+      #   not be run. Specifying :raise will raise an error, anything else will
+      #   return that object on failure. Default is :raise.
+      #
+      # @raise [Facter::Core::Execution::ExecutionFailure] If the command does
+      #   not exist or could not be executed.
+      #
+      # @return [String] the output of the program, or the value of :on_fail if
+      #   command execution failed and :on_fail was specified.
+      #
+      # @api public
+      # @since 2.0.1
+      def execute(command, options = {})
+        @@impl.execute(command, options)
+      end
+
+      class ExecutionFailure < StandardError; end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/execution/base.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/execution/base.rb
new file mode 100644
index 0000000..9c2f58d
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/execution/base.rb
@@ -0,0 +1,81 @@
+class Facter::Core::Execution::Base
+
+  def with_env(values)
+    old = {}
+    values.each do |var, value|
+      # save the old value if it exists
+      if old_val = ENV[var]
+        old[var] = old_val
+      end
+      # set the new (temporary) value for the environment variable
+      ENV[var] = value
+    end
+    # execute the caller's block, capture the return value
+    rv = yield
+  # use an ensure block to make absolutely sure we restore the variables
+  ensure
+    # restore the old values
+    values.each do |var, value|
+      if old.include?(var)
+        ENV[var] = old[var]
+      else
+        # if there was no old value, delete the key from the current environment variables hash
+        ENV.delete(var)
+      end
+    end
+    # return the captured return value
+    rv
+  end
+
+  def execute(command, options = {})
+
+    on_fail = options.fetch(:on_fail, :raise)
+
+    # Set LC_ALL and LANG to force i18n to C for the duration of this exec; this ensures that any code that parses the
+    # output of the command can expect it to be in a consistent / predictable format / locale
+    with_env 'LC_ALL' => 'C', 'LANG' => 'C' do
+
+      expanded_command = expand_command(command)
+
+      if expanded_command.nil?
+        if on_fail == :raise
+          raise Facter::Core::Execution::ExecutionFailure.new, "Could not execute '#{command}': command not found"
+        else
+          return on_fail
+        end
+      end
+
+      out = ''
+
+      begin
+        wait_for_child = true
+        out = %x{#{expanded_command}}.chomp
+        wait_for_child = false
+      rescue => detail
+        if on_fail == :raise
+          raise Facter::Core::Execution::ExecutionFailure.new, "Failed while executing '#{expanded_command}': #{detail.message}"
+        else
+          return on_fail
+        end
+      ensure
+        if wait_for_child
+          # We need to ensure that if this command exits early then any spawned
+          # children will be reaped. Process execution is frequently
+          # terminated using Timeout.timeout but since the timeout isn't in
+          # this scope we can't rescue the raised exception. The best that
+          # we can do is determine if the child has exited, and if it hasn't
+          # then we need to spawn a thread to wait for the child.
+          #
+          # Due to the limitations of Ruby 1.8 there aren't good ways to
+          # asynchronously run a command and grab the PID of that command
+          # using the standard library. The best we can do is blindly wait
+          # on all processes and hope for the best. This issue is described
+          # at https://tickets.puppetlabs.com/browse/FACT-150
+          Thread.new { Process.waitall }
+        end
+      end
+
+      out
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/execution/posix.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/execution/posix.rb
new file mode 100644
index 0000000..4f30467
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/execution/posix.rb
@@ -0,0 +1,50 @@
+class Facter::Core::Execution::Posix < Facter::Core::Execution::Base
+
+  DEFAULT_SEARCH_PATHS = ['/sbin', '/usr/sbin']
+
+  def search_paths
+    # Make sure facter is usable even for non-root users. Most commands
+    # in /sbin (like ifconfig) can be run as non privileged users as
+    # long as they do not modify anything - which we do not do with facter
+    ENV['PATH'].split(File::PATH_SEPARATOR) + DEFAULT_SEARCH_PATHS
+  end
+
+  def which(bin)
+    if absolute_path?(bin)
+      return bin if File.executable?(bin) and File.file?(bin)
+    else
+      search_paths.each do |dir|
+        dest = File.join(dir, bin)
+        return dest if File.executable?(dest) and File.file?(dest)
+      end
+    end
+    nil
+  end
+
+  ABSOLUTE_PATH_REGEX = %r{^/}
+
+  def absolute_path?(path)
+    !! (path =~ ABSOLUTE_PATH_REGEX)
+  end
+
+  DOUBLE_QUOTED_COMMAND = /^"(.+?)"(?:\s+(.*))?/
+  SINGLE_QUOTED_COMMAND = /^'(.+?)'(?:\s+(.*))?/
+
+  def expand_command(command)
+    exe = nil
+    args = nil
+
+    if (match = (command.match(DOUBLE_QUOTED_COMMAND) || command.match(SINGLE_QUOTED_COMMAND)))
+      exe, args = match.captures
+    else
+      exe, args = command.split(/ /,2)
+    end
+
+    if exe and (expanded = which(exe))
+      expanded = "'#{expanded}'" if expanded.match(/\s/)
+      expanded << " #{args}" if args
+
+      return expanded
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/execution/windows.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/execution/windows.rb
new file mode 100644
index 0000000..1fa3ba7
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/execution/windows.rb
@@ -0,0 +1,57 @@
+class Facter::Core::Execution::Windows < Facter::Core::Execution::Base
+
+  def search_paths
+    ENV['PATH'].split(File::PATH_SEPARATOR)
+  end
+
+  DEFAULT_COMMAND_EXTENSIONS = %w[.COM .EXE .BAT .CMD]
+
+  def which(bin)
+    if absolute_path?(bin)
+      return bin if File.executable?(bin)
+    else
+      search_paths.each do |dir|
+        dest = File.join(dir, bin)
+        dest.gsub!(File::SEPARATOR, File::ALT_SEPARATOR)
+        if File.extname(dest).empty?
+          exts = ENV['PATHEXT']
+          exts = exts ? exts.split(File::PATH_SEPARATOR) : DEFAULT_COMMAND_EXTENSIONS
+          exts.each do |ext|
+            destext = dest + ext
+            return destext if File.executable?(destext)
+          end
+        end
+        return dest if File.executable?(dest)
+      end
+    end
+    nil
+  end
+
+  slash = '[\\\\/]'
+  name = '[^\\\\/]+'
+  ABSOLUTE_PATH_REGEX = %r!^(([A-Z]:#{slash})|(#{slash}#{slash}#{name}#{slash}#{name})|(#{slash}#{slash}\?#{slash}#{name}))!i
+
+  def absolute_path?(path)
+    !! (path =~ ABSOLUTE_PATH_REGEX)
+  end
+
+  DOUBLE_QUOTED_COMMAND = /^"(.+?)"(?:\s+(.*))?/
+
+  def expand_command(command)
+    exe = nil
+    args = nil
+
+    if (match = command.match(DOUBLE_QUOTED_COMMAND))
+      exe, args = match.captures
+    else
+      exe, args = command.split(/ /,2)
+    end
+
+    if exe and (expanded = which(exe))
+      expanded = "\"#{expanded}\"" if expanded.match(/\s+/)
+      expanded << " #{args}" if args
+
+      return expanded
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/logging.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/logging.rb
new file mode 100644
index 0000000..58474d6
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/logging.rb
@@ -0,0 +1,197 @@
+require 'facter'
+
+module Facter::Core::Logging
+
+  extend self
+
+  # @api private
+  GREEN = "[0;32m"
+  # @api private
+  RESET = "[0m"
+
+  # @api private
+  @@debug = false
+  # @api private
+  @@timing = false
+  # @api private
+  @@trace = false
+
+  # @api private
+  @@warn_messages = {}
+  # @api private
+  @@debug_messages = {}
+
+  # @api private
+  @@message_callback = nil
+
+  # Used to register a callback that is called when a message is logged.
+  # If a block is given, Facter will not log messages.
+  # If a block is not given, Facter will resume logging messages.
+  # @param block [Proc] the callback to call when a message is logged.
+  #   The first argument to the callback will be a symbol representing a level. The supported
+  #   levels are: :trace, :debug, :info, :warn, :error, and :fatal.
+  #   The second argument to the callback will be a string containing the message
+  #   that was logged.
+  # @api public
+  def on_message(&block)
+    @@message_callback = block
+  end
+
+  # Prints a debug message if debugging is turned on
+  #
+  # @param msg [String] the debug message
+  # @return [void]
+  def debug(msg)
+    if self.debugging?
+      if msg.nil? or msg.empty?
+        invoker = caller[0].slice(/.*:\d+/)
+        self.warn "#{self.class}#debug invoked with invalid message #{msg.inspect}:#{msg.class} at #{invoker}"
+      elsif @@message_callback
+        @@message_callback.call(:debug, msg)
+      else
+        puts GREEN + msg + RESET
+      end
+    end
+  end
+
+  # Prints a debug message only once.
+  #
+  # @note Uniqueness is based on the string, not the specific location
+  #   of the method call.
+  #
+  # @param msg [String] the debug message
+  # @return [void]
+  def debugonce(msg)
+    if msg and not msg.empty? and @@debug_messages[msg].nil?
+      @@debug_messages[msg] = true
+      debug(msg)
+    end
+  end
+
+  # Prints a warning message. The message is only printed if debugging
+  # is enabled.
+  #
+  # @param msg [String] the warning message to be printed
+  #
+  # @return [void]
+  def warn(msg)
+    if msg.nil? or msg.empty?
+      invoker = caller[0].slice(/.*:\d+/)
+      msg = "#{self.class}#debug invoked with invalid message #{msg.inspect}:#{msg.class} at #{invoker}"
+    end
+    if @@message_callback
+      @@message_callback.call(:warn, msg)
+    else
+      Kernel.warn msg
+    end
+  end
+
+  # Prints a warning message only once per process. Each unique string
+  # is printed once.
+  #
+  # @note Unlike {warn} the message will be printed even if debugging is
+  #   not turned on. This behavior is likely to change and should not be
+  #   relied on.
+  #
+  # @param msg [String] the warning message to be printed
+  #
+  # @return [void]
+  def warnonce(msg)
+    if @@warn_messages[msg].nil?
+      self.warn(msg)
+      @@warn_messages[msg] = true
+    end
+  end
+
+  def log_exception(exception, message = :default)
+    self.warn(format_exception(exception, message, @@trace))
+  end
+
+  def format_exception(exception, message, trace)
+    arr = []
+
+    if message == :default
+      arr << exception.message
+    elsif message
+      arr << message
+    end
+
+    if trace
+      arr.concat(exception.backtrace)
+    end
+
+    arr.flatten.join("\n")
+  end
+
+  # Print an exception message, and optionally a backtrace if trace is set
+
+  # Print timing information
+  #
+  # @param string [String] the time to print
+  # @return [void]
+  #
+  # @api private
+  def show_time(string)
+    return unless string && self.timing?
+
+    if @@message_callback
+      @@message_callback.call(:info, string)
+    else
+      $stderr.puts "#{GREEN}#{string}#{RESET}"
+    end
+  end
+
+  # Enable or disable logging of debug messages
+  #
+  # @param bool [true, false]
+  # @return [void]
+  #
+  # @api private
+  def debugging(bool)
+    @@debug = bool
+  end
+
+  # Is debugging enabled?
+  #
+  # @return [true, false]
+  #
+  # @api private
+  def debugging?
+    @@debug
+  end
+
+  # Enable or disable logging of timing information
+  #
+  # @param bool [true, false]
+  # @return [void]
+  #
+  # @api private
+  def timing(bool)
+    @@timing = bool
+  end
+
+  # Returns whether timing output is turned on
+  #
+  # @api private
+  def timing?
+    @@timing
+  end
+
+  def trace(bool)
+    @@trace = bool
+  end
+
+  def trace?
+    @@trace
+  end
+
+  # Clears the seen state of debug and warning messages. See {debugonce} and {warnonce}.
+  #
+  # @return [void]
+  #
+  # @api private
+  def clear_messages
+    @@debug_messages.clear
+    @@warn_messages.clear
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/resolvable.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/resolvable.rb
new file mode 100644
index 0000000..615aebe
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/resolvable.rb
@@ -0,0 +1,94 @@
+require 'timeout'
+
+# The resolvable mixin defines behavior for evaluating and returning fact
+# resolutions.
+#
+# Classes including this mixin should implement at #name method describing
+# the value being resolved and a #resolve_value that actually executes the code
+# to resolve the value.
+module Facter::Core::Resolvable
+
+  # The timeout, in seconds, for evaluating this resolution.
+  # @return [Integer]
+  # @api public
+  attr_accessor :timeout
+
+  # Return the timeout period for resolving a value.
+  # (see #timeout)
+  # @return [Numeric]
+  # @comment requiring 'timeout' stdlib class causes Object#timeout to be
+  #   defined which delegates to Timeout.timeout. This method may potentially
+  #   overwrite the #timeout attr_reader on this class, so we define #limit to
+  #   avoid conflicts.
+  def limit
+    @timeout || 0
+  end
+
+  ##
+  # on_flush accepts a block and executes the block when the resolution's value
+  # is flushed.  This makes it possible to model a single, expensive system
+  # call inside of a Ruby object and then define multiple dynamic facts which
+  # resolve by sending messages to the model instance.  If one of the dynamic
+  # facts is flushed then it can, in turn, flush the data stored in the model
+  # instance to keep all of the dynamic facts in sync without making multiple,
+  # expensive, system calls.
+  #
+  # Please see the Solaris zones fact for an example of how this feature may be
+  # used.
+  #
+  # @see Facter::Util::Fact#flush
+  # @see Facter::Util::Resolution#flush
+  #
+  # @api public
+  def on_flush(&block)
+    @on_flush_block = block
+  end
+
+  ##
+  # flush executes the block, if any, stored by the {on_flush} method
+  #
+  # @see Facter::Util::Fact#flush
+  # @see Facter::Util::Resolution#on_flush
+  #
+  # @api private
+  def flush
+    @on_flush_block.call if @on_flush_block
+  end
+
+  def value
+    result = nil
+
+    with_timing do
+      Timeout.timeout(limit) do
+        result = resolve_value
+      end
+    end
+
+    Facter::Util::Normalization.normalize(result)
+  rescue Timeout::Error => detail
+    Facter.log_exception(detail, "Timed out after #{limit} seconds while resolving #{qualified_name}")
+    return nil
+  rescue Facter::Util::Normalization::NormalizationError => detail
+    Facter.log_exception(detail, "Fact resolution #{qualified_name} resolved to an invalid value: #{detail.message}")
+    return nil
+  rescue => detail
+    Facter.log_exception(detail, "Could not retrieve #{qualified_name}: #{detail.message}")
+    return nil
+  end
+
+  private
+
+  def with_timing
+    starttime = Time.now.to_f
+
+    yield
+
+    finishtime = Time.now.to_f
+    ms = (finishtime - starttime) * 1000
+    Facter.show_time "#{qualified_name}: #{"%.2f" % ms}ms"
+  end
+
+  def qualified_name
+    "fact='#{@fact.name.to_s}', resolution='#{@name || '<anonymous>'}'"
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/suitable.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/suitable.rb
new file mode 100644
index 0000000..0262470
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/core/suitable.rb
@@ -0,0 +1,113 @@
+require 'facter'
+
+# The Suitable mixin provides mechanisms for confining objects to run on
+# certain platforms and determining the run precedence of these objects.
+#
+# Classes that include the Suitable mixin should define a `#confines` method
+# that returns an Array of zero or more Facter::Util::Confine objects.
+module Facter::Core::Suitable
+
+  attr_writer :weight
+
+  # Sets the weight of this resolution. If multiple suitable resolutions
+  # are found, the one with the highest weight will be used.  If weight
+  # is not given, the number of confines set on a resolution will be
+  # used as its weight (so that the most specific resolution is used).
+  #
+  # @param weight [Integer] the weight of this resolution
+  #
+  # @return [void]
+  #
+  # @api public
+  def has_weight(weight)
+    @weight = weight
+  end
+
+  # Sets the conditions for this resolution to be used.  This method accepts
+  # multiple forms of arguments to determine suitability.
+  #
+  # @return [void]
+  #
+  # @api public
+  #
+  # @overload confine(confines)
+  #   Confine a fact to a specific fact value or values.  This form takes a
+  #   hash of fact names and values. Every fact must match the values given for
+  #   that fact, otherwise this resolution will not be considered suitable. The
+  #   values given for a fact can be an array, in which case the value of the
+  #   fact must be in the array for it to match.
+  #   @param [Hash{String,Symbol=>String,Array<String>}] confines set of facts identified by the hash keys whose
+  #     fact value must match the argument value.
+  #   @example Confining to Linux
+  #       Facter.add(:powerstates) do
+  #         # This resolution only makes sense on linux systems
+  #         confine :kernel => "Linux"
+  #         setcode do
+  #           File.read('/sys/power/states')
+  #         end
+  #       end
+  #
+  # @overload confine(confines, &block)
+  #   Confine a fact to a block with the value of a specified fact yielded to
+  #   the block.
+  #   @param [String,Symbol] confines the fact name whose value should be
+  #     yielded to the block
+  #   @param [Proc] block determines the suitability of the fact.  If the block
+  #     evaluates to `false` or `nil` then the confined fact will not be
+  #     evaluated.
+  #   @yield [value] the value of the fact identified by {confines}
+  #   @example Confine the fact to a host with an ipaddress in a specific
+  #     subnet
+  #       confine :ipaddress do |addr|
+  #         require 'ipaddr'
+  #         IPAddr.new('192.168.0.0/16').include? addr
+  #       end
+  #
+  # @overload confine(&block)
+  #   Confine a fact to a block.  The fact will be evaluated only if the block
+  #   evaluates to something other than `false` or `nil`.
+  #   @param [Proc] block determines the suitability of the fact.  If the block
+  #     evaluates to `false` or `nil` then the confined fact will not be
+  #     evaluated.
+  #   @example Confine the fact to systems with a specific file.
+  #       confine { File.exist? '/bin/foo' }
+  def confine(confines = nil, &block)
+    case confines
+    when Hash
+      confines.each do |fact, values|
+        @confines.push Facter::Util::Confine.new(fact, *values)
+      end
+    else
+      if block
+        if confines
+          @confines.push Facter::Util::Confine.new(confines, &block)
+        else
+          @confines.push Facter::Util::Confine.new(&block)
+        end
+      else
+      end
+    end
+  end
+
+  # Returns the importance of this resolution. If the weight was not
+  # given, the number of confines is used instead (so that a more
+  # specific resolution wins over a less specific one).
+  #
+  # @return [Integer] the weight of this resolution
+  #
+  # @api private
+  def weight
+    if @weight
+      @weight
+    else
+      @confines.length
+    end
+  end
+
+  # Is this resolution mechanism suitable on the system in question?
+  #
+  # @api private
+  def suitable?
+    @confines.all? { |confine| confine.true? }
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/dhcp_servers.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/dhcp_servers.rb
new file mode 100644
index 0000000..ac141c4
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/dhcp_servers.rb
@@ -0,0 +1,45 @@
+# Fact: dhcp_servers
+#
+# Purpose:
+#   Return the DHCP server addresses for all interfaces as a hash.
+#   If the interface that is the default gateway is DHCP assigned, there
+#   will also be a `"system"` entry in the hash.
+#
+#   This fact is structured. Values are returned as a group of key-value pairs.
+#
+# Resolution:
+#   Parses the output of `nmcli` to find the DHCP server for the interface if available.
+#
+# Caveats:
+#   Requires `nmcli` to be available and the interface must use network-manager.
+#
+
+require 'facter'
+require 'facter/util/dhcp_servers'
+
+
+Facter.add(:dhcp_servers) do
+  confine :kernel => :linux
+  confine do
+    Facter::Core::Execution.which('nmcli')
+  end
+  confine do
+    s = Facter::Util::DHCPServers.network_manager_state
+    !s.empty? && (s != 'unknown')
+  end
+
+  setcode do
+    gwdev   = Facter::Util::DHCPServers.gateway_device
+    devices = Facter::Util::DHCPServers.devices
+
+    dhcp_servers = {}
+    devices.each do |device|
+      if server = Facter::Util::DHCPServers.device_dhcp_server(device)
+        dhcp_servers['system'] = server if device == gwdev
+        dhcp_servers[device]   = server
+      end
+    end
+
+    dhcp_servers.keys.length > 0 ? dhcp_servers : nil
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/domain.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/domain.rb
new file mode 100644
index 0000000..5ce5d56
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/domain.rb
@@ -0,0 +1,99 @@
+# Fact: domain
+#
+# Purpose:
+#   Return the host's primary DNS domain name.
+#
+# Resolution:
+#   On UNIX (excluding Darwin), first try and use the hostname fact,
+#   which uses the `hostname` system command, and then parse the output
+#   of that.
+#   Failing that, it tries the `dnsdomainname` system command.
+#   Failing that, it uses `/etc/resolv.conf` and takes the domain from that, or as
+#   a final resort, the search from that.
+#   Otherwise returns `nil`.
+#
+#   On Windows uses the win32ole gem and winmgmts to get the DNSDomain value
+#   from the Win32 networking stack.
+#
+# Caveats:
+#
+
+Facter.add(:domain) do
+  setcode do
+    # Get the domain from various sources; the order of these
+    # steps is important
+
+    # In some OS 'hostname -f' will change the hostname to '-f'
+    # We know that Solaris and HP-UX exhibit this behavior
+    # On good OS, 'hostname -f' will return the FQDN which is preferable
+    # Due to dangerous behavior of 'hostname -f' on old OS, we will explicitly opt-in
+    # 'hostname -f' --hkenney May 9, 2012
+    basic_hostname = 'hostname 2> /dev/null'
+    windows_hostname = 'hostname > NUL'
+    full_hostname = 'hostname -f 2> /dev/null'
+    can_do_hostname_f = Regexp.union /Linux/i, /FreeBSD/i, /Darwin/i
+
+    hostname_command = if Facter.value(:kernel) =~ can_do_hostname_f
+                         full_hostname
+                       elsif Facter.value(:kernel) == "windows"
+                         windows_hostname
+                       else
+                         basic_hostname
+                       end
+
+    if name = Facter::Core::Execution.exec(hostname_command) \
+      and name =~ /.*?\.(.+$)/
+
+      return_value = $1
+    elsif Facter.value(:kernel) != "windows" and domain = Facter::Core::Execution.exec('dnsdomainname 2> /dev/null') \
+      and domain =~ /.+/
+
+      return_value = domain
+    elsif FileTest.exists?("/etc/resolv.conf")
+      domain = nil
+      search = nil
+      File.open("/etc/resolv.conf") { |file|
+        file.each { |line|
+          if line =~ /^\s*domain\s+(\S+)/
+            domain = $1
+          elsif line =~ /^\s*search\s+(\S+)/
+            search = $1
+          end
+        }
+      }
+      return_value ||= domain
+      return_value ||= search
+    end
+
+    if return_value
+      return_value.gsub(/\.$/, '')
+    end
+  end
+end
+
+Facter.add(:domain) do
+  confine :kernel => :windows
+  setcode do
+    require 'facter/util/registry'
+
+    domain = nil
+    regvalue = Facter::Util::Registry.hklm_read('SYSTEM\CurrentControlSet\Services\Tcpip\Parameters', 'Domain')
+
+    if regvalue and not regvalue.empty?
+      domain = regvalue
+    else
+      require 'facter/util/wmi'
+      Facter::Util::WMI.execquery("select DNSDomain from Win32_NetworkAdapterConfiguration where IPEnabled = True").each { |nic|
+        if nic.DNSDomain && nic.DNSDomain.length > 0
+          domain = nic.DNSDomain
+          break
+        end
+      }
+    end
+
+
+    if domain
+      domain.gsub(/\.$/, '')
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/ec2.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/ec2.rb
new file mode 100644
index 0000000..94b6120
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/ec2.rb
@@ -0,0 +1,61 @@
+# Fact: ec2_<EC2 INSTANCE DATA>
+#
+# Purpose:
+#   Returns info retrieved in bulk from the EC2 API. The names of these facts
+#   should be self explanatory, and they are otherwise undocumented. The full
+#   list of these facts is: ec2_ami_id, ec2_ami_launch_index,
+#   ec2_ami_manifest_path, ec2_block_device_mapping_ami,
+#   ec2_block_device_mapping_ephemeral0, ec2_block_device_mapping_root,
+#   ec2_hostname, ec2_instance_id, ec2_instance_type, ec2_kernel_id,
+#   ec2_local_hostname, ec2_local_ipv4, ec2_placement_availability_zone,
+#   ec2_profile, ec2_public_hostname, ec2_public_ipv4,
+#   ec2_public_keys_0_openssh_key, ec2_reservation_id, and ec2_security_groups.
+#
+# Resolution:
+#   Directly queries the EC2 metadata endpoint.
+#
+
+require 'facter/ec2/rest' unless defined?(Facter::EC2)
+
+Facter.define_fact(:ec2_metadata) do
+  define_resolution(:rest) do
+    confine do
+      Facter.value(:virtual).match /^(xen|kvm)/
+    end
+
+    @querier = Facter::EC2::Metadata.new
+    confine do
+      @querier.reachable?
+    end
+
+    setcode do
+      @querier.fetch
+    end
+  end
+end
+
+Facter.define_fact(:ec2_userdata) do
+  define_resolution(:rest) do
+    confine do
+      Facter.value(:virtual).match /^(xen|kvm)/
+    end
+
+    @querier = Facter::EC2::Userdata.new
+    confine do
+      @querier.reachable?
+    end
+
+    setcode do
+      @querier.fetch
+    end
+  end
+end
+
+# The flattened version of the EC2 facts are deprecated and will be removed in
+# a future release of Facter.
+if (ec2_metadata = Facter.value(:ec2_metadata))
+  ec2_facts = Facter::Util::Values.flatten_structure("ec2", ec2_metadata)
+  ec2_facts.each_pair do |factname, factvalue|
+    Facter.add(factname, :value => factvalue)
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/ec2/rest.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/ec2/rest.rb
new file mode 100644
index 0000000..5b324cb
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/ec2/rest.rb
@@ -0,0 +1,139 @@
+require 'timeout'
+require 'open-uri'
+
+module Facter
+  module EC2
+    CONNECTION_ERRORS = [
+      Errno::EHOSTDOWN,
+      Errno::EHOSTUNREACH,
+      Errno::ENETUNREACH,
+      Errno::ECONNABORTED,
+      Errno::ECONNREFUSED,
+      Errno::ECONNRESET,
+      Errno::ETIMEDOUT,
+    ]
+
+    # Contains metadata keys that should not be collected
+    FILTERED_KEYS = [
+      'security-credentials/'
+    ].freeze
+
+    class Base
+      def reachable?(retry_limit = 3)
+        timeout = 0.2
+        able_to_connect = false
+        attempts = 0
+
+        begin
+          Timeout.timeout(timeout) do
+            open(@baseurl, :proxy => nil).read
+          end
+          able_to_connect = true
+        rescue OpenURI::HTTPError => e
+          if e.message.match /404 Not Found/i
+            able_to_connect = false
+          else
+            attempts = attempts + 1
+            retry if attempts < retry_limit
+          end
+        rescue Timeout::Error
+          attempts = attempts + 1
+          retry if attempts < retry_limit
+        rescue *CONNECTION_ERRORS
+          attempts = attempts + 1
+          retry if attempts < retry_limit
+        end
+
+        able_to_connect
+      end
+    end
+
+    class Metadata < Base
+
+      DEFAULT_URI = "http://169.254.169.254/latest/meta-data/"
+
+      def initialize(uri = DEFAULT_URI)
+        @baseurl = uri
+      end
+
+      def fetch(path = '')
+        results = {}
+
+        keys = fetch_endpoint(path)
+        keys.each do |key|
+          next if FILTERED_KEYS.include? key
+          if key.match(%r[/$])
+            # If a metadata key is suffixed with '/' then it's a general metadata
+            # resource, so we have to recursively look up all the keys in the given
+            # collection.
+            name = key[0..-2]
+            results[name] = fetch("#{path}#{key}")
+          else
+            # This is a simple key/value pair, we can just query the given endpoint
+            # and store the results.
+            ret = fetch_endpoint("#{path}#{key}")
+            results[key] = ret.size > 1 ? ret : ret.first
+          end
+        end
+
+        results
+      end
+
+      # @param path [String] The path relative to the object base url
+      #
+      # @return [Array, NilClass]
+      def fetch_endpoint(path)
+        uri = @baseurl + path
+        body = open(uri, :proxy => nil).read
+        parse_results(body)
+      rescue OpenURI::HTTPError => e
+        if e.message.match /404 Not Found/i
+          return nil
+        else
+          Facter.log_exception(e, "Failed to fetch ec2 uri #{uri}: #{e.message}")
+          return nil
+        end
+      rescue *CONNECTION_ERRORS => e
+        Facter.log_exception(e, "Failed to fetch ec2 uri #{uri}: #{e.message}")
+        return nil
+      rescue Timeout::Error => e
+        Facter.log_exception(e, "Failed to fetch ec2 uri #{uri}: #{e.message}")
+        return nil
+      end
+
+      private
+
+      def parse_results(body)
+        lines = body.split("\n")
+        lines.map do |line|
+          if (match = line.match(/^(\d+)=.*$/))
+            # Metadata arrays are formatted like '<index>=<associated key>/', so
+            # we need to extract the index from that output.
+            "#{match[1]}/"
+          else
+            line
+          end
+        end
+      end
+    end
+
+    class Userdata < Base
+      DEFAULT_URI = "http://169.254.169.254/latest/user-data/"
+
+      def initialize(uri = DEFAULT_URI)
+        @baseurl = uri
+      end
+
+      def fetch
+        open(@baseurl).read
+      rescue OpenURI::HTTPError => e
+        if e.message.match /404 Not Found/i
+          return nil
+        else
+          Facter.log_exception(e, "Failed to fetch ec2 uri #{uri}: #{e.message}")
+          return nil
+        end
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/facterversion.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/facterversion.rb
new file mode 100644
index 0000000..f46f887
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/facterversion.rb
@@ -0,0 +1,15 @@
+# Fact: facterversion
+#
+# Purpose: Returns the version of the facter module.
+#
+# Resolution: Uses the `Facter.version` method.
+#
+# Caveats:
+#
+
+Facter.add(:facterversion) do
+  setcode do
+    require 'facter/version'
+    Facter.version.to_s
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/filesystems.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/filesystems.rb
new file mode 100644
index 0000000..37b8d7d
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/filesystems.rb
@@ -0,0 +1,45 @@
+# Fact: filesystems
+#
+# Purpose:
+#   This fact provides an alphabetic list of usable file systems that can
+#   be used for block devices like hard drives, media cards, etc.
+#
+# Resolution:
+#   Checks `/proc/filesystems`.
+#
+# Caveats:
+#   Only supports Linux.
+#
+
+Facter.add('filesystems') do
+  confine :kernel => :linux
+  setcode do
+    # fuseblk can't be created and arguably isn't usable here. If you feel this
+    # doesn't match your use-case please raise a bug.
+    exclude = %w(fuseblk)
+
+    # Make regular expression form our patterns ...
+    exclude = Regexp.union(*exclude.collect { |i| Regexp.new(i) })
+
+    # We utilise rely on "cat" for reading values from entries under "/proc".
+    # This is due to some problems with IO#read in Ruby and reading content of
+    # the "proc" file system that was reported more than once in the past ...
+    file_systems = []
+    Facter::Core::Execution.exec('cat /proc/filesystems 2> /dev/null').each_line do |line|
+      # Remove bloat ...
+      line.strip!
+
+      # Line of interest should not start with "nodev" ...
+      next if line.empty? or line.match(/^nodev/)
+
+      # We have something, so let us apply our device type filter ...
+      next if line.match(exclude)
+
+      file_systems << line
+    end
+    file_systems.sort.join(',')
+  end
+end
+
+# vim: set ts=2 sw=2 et :
+# encoding: utf-8
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/fqdn.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/fqdn.rb
new file mode 100644
index 0000000..bf5f5dc
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/fqdn.rb
@@ -0,0 +1,24 @@
+# Fact: fqdn
+#
+# Purpose: Returns the fully-qualified domain name of the host.
+#
+# Resolution: Simply joins the hostname fact with the domain name fact.
+#
+# Caveats: No attempt is made to check that the two facts are accurate or that
+# the two facts go together. At no point is there any DNS resolution made
+# either.
+#
+
+Facter.add(:fqdn) do
+  setcode do
+    host = Facter.value(:hostname)
+    domain = Facter.value(:domain)
+    if host and domain
+      [host, domain].join(".")
+    elsif host
+      host
+    else
+      nil
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/gce.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/gce.rb
new file mode 100644
index 0000000..ef94104
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/gce.rb
@@ -0,0 +1,16 @@
+require 'facter/gce/metadata'
+
+Facter.define_fact(:gce) do
+  define_resolution(:rest) do
+    confine :virtual => 'gce'
+
+    confine do
+      Facter.json?
+    end
+
+    setcode do
+      querier = Facter::GCE::Metadata.new
+      querier.fetch
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/gce/metadata.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/gce/metadata.rb
new file mode 100644
index 0000000..63fbbc4
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/gce/metadata.rb
@@ -0,0 +1,87 @@
+require 'open-uri'
+
+module Facter
+  module GCE
+
+    # @api private
+    class Metadata
+      CONNECTION_ERRORS = [
+        OpenURI::HTTPError,
+        Errno::EHOSTDOWN,
+        Errno::EHOSTUNREACH,
+        Errno::ENETUNREACH,
+        Errno::ECONNABORTED,
+        Errno::ECONNREFUSED,
+        Errno::ECONNRESET,
+        Errno::ETIMEDOUT,
+        Timeout::Error,
+      ]
+
+      METADATA_URL = "http://metadata/computeMetadata/v1beta1/?recursive=true&alt=json"
+
+      def initialize(url = METADATA_URL)
+        @url = url
+      end
+
+      def fetch
+        with_metadata_server do |body|
+          # This will only be reached if the confine associated with this class
+          # was true which means that JSON was required, but it's a bit
+          # questionable that we're relying on JSON being loaded as a side
+          # effect of that.
+          hash = ::JSON.parse(body)
+          transform_metadata!(hash)
+          hash
+        end
+      end
+
+      private
+
+      def with_metadata_server
+        retry_limit = 3
+        timeout = 0.05
+        body = nil
+        attempts = 0
+
+        begin
+          Timeout.timeout(timeout) do
+            body = open(@url).read
+          end
+        rescue *CONNECTION_ERRORS => e
+          attempts = attempts + 1
+          if attempts < retry_limit
+            retry
+          else
+            Facter.log_exception(e, "Unable to fetch metadata from #{@url}: #{e.message}")
+            return nil
+          end
+        end
+
+        if body
+          yield body
+        end
+      end
+
+      # @return [void]
+      def transform_metadata!(data)
+        case data
+        when Hash
+          data.keys.each do |key|
+            value = data[key]
+            if ["image", "machineType", "zone", "network"].include? key
+              data[key] = value.split('/').last
+            elsif key == "sshKeys"
+              data['sshKeys'] = value.split("\n")
+            end
+            transform_metadata!(value)
+          end
+        when Array
+          data.each do |value|
+            transform_metadata!(value)
+          end
+        end
+        nil
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/gid.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/gid.rb
new file mode 100644
index 0000000..aaa23c7
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/gid.rb
@@ -0,0 +1,25 @@
+# Fact: gid
+#
+# Purpose: Return the GID (group identifier) of the user running puppet.
+#
+# Resolution:
+#
+# Caveats:
+#   Not supported in Windows yet.
+#
+
+Facter.add(:gid) do
+  confine do
+    Facter::Core::Execution.which('id') && !["SunOS", "windows"].include?(Facter.value(:kernel))
+  end
+  setcode { Facter::Core::Execution.exec('id -ng') }
+end
+
+Facter.add(:gid) do
+  confine :kernel => :SunOS
+  setcode do
+    if File.exist? '/usr/xpg4/bin/id'
+      Facter::Core::Execution.exec('/usr/xpg4/bin/id -ng')
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/hardwareisa.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/hardwareisa.rb
new file mode 100644
index 0000000..b95dcab
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/hardwareisa.rb
@@ -0,0 +1,20 @@
+# Fact: hardwareisa
+#
+# Purpose:
+#   Returns hardware processor type.
+#
+# Resolution:
+#   On Solaris, AIX, Linux and the BSDs simply uses the output of `uname -p`.
+#   On HP-UX, `uname -m` gives us the same information.
+#
+# Caveats:
+#   Some Linuxes return unknown to `uname -p` with relative ease.
+#
+
+Facter.add(:hardwareisa) do
+  if Facter.value(:kernel) == 'HP-UX'
+    setcode 'uname -m'
+  else
+    setcode 'uname -p'
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/hardwaremodel.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/hardwaremodel.rb
new file mode 100644
index 0000000..67e48cb
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/hardwaremodel.rb
@@ -0,0 +1,67 @@
+# Fact: hardwaremodel
+#
+# Purpose:
+#   Returns the hardware model of the system.
+#
+# Resolution:
+#   Uses purely `uname -m` on all platforms other than AIX and Windows.
+#   On AIX uses the parsed `modelname` output of `lsattr -El sys0 -a modelname`.
+#   On Windows uses the `host_cpu` pulled out of Ruby's config.
+#
+# Caveats:
+#
+
+Facter.add(:hardwaremodel) do
+  setcode 'uname -m'
+end
+
+Facter.add(:hardwaremodel) do
+  confine :operatingsystem => :aix
+  setcode do
+    model = Facter::Core::Execution.exec('lsattr -El sys0 -a modelname')
+    if model =~ /modelname\s(\S+)\s/
+      $1
+    end
+  end
+end
+
+Facter.add(:hardwaremodel) do
+  confine :operatingsystem => :windows
+  setcode do
+    # The cryptic windows cpu architecture models are documented in these places:
+    # http://source.winehq.org/source/include/winnt.h#L568
+    # http://msdn.microsoft.com/en-us/library/windows/desktop/aa394373(v=vs.85).aspx
+    # http://msdn.microsoft.com/en-us/library/windows/desktop/windows.system.processorarchitecture.aspx
+    # http://linux.derkeiler.com/Mailing-Lists/Kernel/2008-05/msg12924.html (anything over 6 is still i686)
+    # Also, arm and neutral are included because they are valid for the upcoming
+    # windows 8 release.  --jeffweiss 23 May 2012
+    require 'facter/util/wmi'
+    model = ""
+    architecture_level = nil
+
+    Facter::Util::WMI.execquery("select Architecture, Level, AddressWidth from Win32_Processor").each do |cpu|
+      architecture_level = (cpu.Level > 5) ? 6 : cpu.Level;
+
+      model =
+        case cpu.Architecture
+        when 11 then 'neutral'        # PROCESSOR_ARCHITECTURE_NEUTRAL
+        when 10 then 'i686'           # PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
+        when 9 then                   # PROCESSOR_ARCHITECTURE_AMD64
+          cpu.AddressWidth == 32 ? "i#{architecture_level}86" : 'x64' # 32 bit OS on 64 bit CPU
+        when 8 then 'msil'            # PROCESSOR_ARCHITECTURE_MSIL
+        when 7 then 'alpha64'         # PROCESSOR_ARCHITECTURE_ALPHA64
+        when 6 then 'ia64'            # PROCESSOR_ARCHITECTURE_IA64
+        when 5 then 'arm'             # PROCESSOR_ARCHITECTURE_ARM
+        when 4 then 'shx'             # PROCESSOR_ARCHITECTURE_SHX
+        when 3 then 'powerpc'         # PROCESSOR_ARCHITECTURE_PPC
+        when 2 then 'alpha'           # PROCESSOR_ARCHITECTURE_ALPHA
+        when 1 then 'mips'            # PROCESSOR_ARCHITECTURE_MIPS
+        when 0 then "i#{architecture_level}86" # PROCESSOR_ARCHITECTURE_INTEL
+        else 'unknown'            # PROCESSOR_ARCHITECTURE_UNKNOWN
+        end
+      break
+    end
+
+    model
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/hostname.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/hostname.rb
new file mode 100644
index 0000000..3ac153c
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/hostname.rb
@@ -0,0 +1,31 @@
+# Fact: hostname
+#
+# Purpose: Return the system's short hostname.
+#
+# Resolution:
+#   On all systems but Darwin, parses the output of the `hostname` system command
+#   to everything before the first period.
+#   On Darwin, uses the system configuration util to get the LocalHostName
+#   variable.
+#
+# Caveats:
+#
+
+Facter.add(:hostname) do
+  setcode do
+    hostname = nil
+    if name = Facter::Core::Execution.execute('hostname')
+      if name =~ /(.*?)\./
+        hostname = $1
+      else
+        hostname = name
+      end
+    end
+    hostname
+  end
+end
+
+Facter.add(:hostname) do
+  confine :kernel => :darwin, :kernelrelease => "R7"
+  setcode '/usr/sbin/scutil --get LocalHostName'
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/id.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/id.rb
new file mode 100644
index 0000000..713703e
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/id.rb
@@ -0,0 +1,21 @@
+# Fact: id
+#
+# Purpose: Internal fact used to specity the program to return the currently
+# running user ID.
+#
+# Resolution:
+#   On all Unixes but Solaris, just returns the output from `whoami`.
+#   On Solaris, parses the output of the `id` command to grab the username,
+#   as Solaris doesn't have the `whoami` command.
+#
+# Caveats:
+#
+
+Facter.add(:id) do
+  setcode "whoami"
+end
+
+Facter.add(:id) do
+  confine :kernel => :SunOS
+  setcode "/usr/xpg4/bin/id -un"
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/interfaces.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/interfaces.rb
new file mode 100644
index 0000000..ab9d9e1
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/interfaces.rb
@@ -0,0 +1,58 @@
+# Fact: interfaces
+#
+# Purpose:
+#   Returns a comma-separated list of the system's network interfaces.
+#
+#   In addition to the main `interfaces` fact, this code will generate the
+#   following facts for each interface:
+#
+#   * `ipaddress_<INTERFACE>`
+#   * `ipaddress6_<INTERFACE>`
+#   * `macaddress_<INTERFACE>`
+#   * `netmask_<INTERFACE>`
+#   * `mtu_<INTERFACE>`
+#
+# Resolution:
+#
+# Caveats:
+#
+
+# interfaces.rb
+# Try to get additional Facts about the machine's network interfaces
+#
+# Original concept Copyright (C) 2007 psychedelys <psychedelys@gmail.com>
+# Update and *BSD support (C) 2007 James Turnbull <james@lovedthanlost.net>
+#
+
+require 'facter/util/ip'
+require 'facter/util/macaddress'
+
+# Note that most of this only works on a fixed list of platforms; notably, Darwin
+# is missing.
+
+Facter.add(:interfaces) do
+  confine :kernel => Facter::Util::IP.supported_platforms
+  setcode do
+    Facter::Util::IP.get_interfaces.collect { |iface| Facter::Util::IP.alphafy(iface) }.join(",")
+  end
+end
+
+Facter::Util::IP.get_interfaces.each do |interface|
+
+  # Make a fact for each detail of each interface.  Yay.
+  #   There's no point in confining these facts, since we wouldn't be able to create
+  # them if we weren't running on a supported platform.
+  %w{ipaddress ipaddress6 macaddress netmask mtu}.each do |label|
+    Facter.add(label + "_" + Facter::Util::IP.alphafy(interface)) do
+      setcode do
+        value = Facter::Util::IP.get_interface_value(interface, label)
+        if label == "macaddress"
+          value = Facter::Util::Macaddress.standardize(value)
+        elsif label == "mtu"
+          value = value.to_i
+        end
+        value
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/ipaddress.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/ipaddress.rb
new file mode 100644
index 0000000..6179a4d
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/ipaddress.rb
@@ -0,0 +1,169 @@
+# Fact: ipaddress
+#
+# Purpose: Return the main IP address for a host.
+#
+# Resolution:
+#   On the Unixes does an ifconfig, and returns the first non 127.0.0.0/8
+#   subnetted IP it finds.
+#   On Windows, it attempts to use the socket library and resolve the machine's
+#   hostname via DNS.
+#
+#   On LDAP based hosts it tries to use either the win32/resolv library to
+#   resolve the hostname to an IP address, or on Unix, it uses the resolv
+#   library.
+#
+#   As a fall back for undefined systems, it tries to run the "host" command to
+#   resolve the machine's hostname using the system DNS.
+#
+# Caveats:
+#   DNS resolution relies on working DNS infrastructure and resolvers on the
+#   host system.
+#   The ifconfig parsing purely takes the first IP address it finds without any
+#   checking this is a useful IP address.
+#
+
+require 'facter/util/ip'
+
+Facter.add(:ipaddress) do
+  confine :kernel => :linux
+  setcode do
+    ip = nil
+    output = Facter::Util::IP.exec_ifconfig(["2>/dev/null"])
+    if output
+      regexp = /inet (?:addr:)?([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/
+      output.split("\n").each do |line|
+        match = regexp.match(line)
+        if match and not /^127\./.match(match[1])
+          ip = match[1]
+          break
+        end
+      end
+    end
+    ip
+  end
+end
+
+Facter.add(:ipaddress) do
+  confine :kernel => %w{FreeBSD OpenBSD Darwin DragonFly}
+  setcode do
+    ip = nil
+    output = Facter::Util::IP.exec_ifconfig
+
+    output.split(/^\S/).each do |str|
+      if str =~ /inet ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/
+        tmp = $1
+        unless tmp =~ /^127\./
+          ip = tmp
+          break
+        end
+      end
+    end
+
+    ip
+  end
+end
+
+Facter.add(:ipaddress) do
+  confine :kernel => %w{NetBSD SunOS}
+  setcode do
+    ip = nil
+    output = Facter::Util::IP.exec_ifconfig(["-a"])
+
+    output.split(/^\S/).each do |str|
+      if str =~ /inet ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/
+        tmp = $1
+        unless tmp =~ /^127\./ or tmp == "0.0.0.0"
+          ip = tmp
+          break
+        end
+      end
+    end
+
+    ip
+  end
+end
+
+Facter.add(:ipaddress) do
+  confine :kernel => %w{AIX}
+  setcode do
+    ip = nil
+
+    default_interface = Facter::Util::IP.exec_netstat(["-rn | grep default | awk '{ print $6 }'"])
+    output = Facter::Util::IP.exec_ifconfig([default_interface])
+
+    output.split(/^\S/).each do |str|
+      if str =~ /inet ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/
+        ip = $1
+      end
+    end
+
+    ip
+  end
+end
+
+Facter.add(:ipaddress) do
+  confine :kernel => %w{windows}
+  setcode do
+    require 'facter/util/ip/windows'
+    ipaddr = nil
+
+    adapters = Facter::Util::IP::Windows.get_preferred_ipv4_adapters
+    adapters.find do |nic|
+      nic.IPAddress.any? do |addr|
+        ipaddr = addr if Facter::Util::IP::Windows.valid_ipv4_address?(addr)
+        ipaddr
+      end
+    end
+
+    ipaddr
+  end
+end
+
+Facter.add(:ipaddress, :timeout => 2) do
+  setcode do
+    if Facter.value(:kernel) == 'windows'
+      require 'win32/resolv'
+    else
+      require 'resolv'
+    end
+
+    begin
+      if hostname = Facter.value(:hostname)
+        if Facter.value(:kernel) == 'windows'
+          ip = Win32::Resolv.get_resolv_info.last[0]
+        else
+          ip = Resolv.getaddress(hostname)
+        end
+        unless ip == "127.0.0.1"
+          ip
+        end
+      else
+        nil
+      end
+    rescue Resolv::ResolvError
+      nil
+    rescue NoMethodError # i think this is a bug in resolv.rb?
+      nil
+    end
+  end
+end
+
+Facter.add(:ipaddress, :timeout => 2) do
+  setcode do
+    if hostname = Facter.value(:hostname)
+      # we need Hostname to exist for this to work
+      host = nil
+      if host = Facter::Core::Execution.execute("host #{hostname}")
+        list = host.chomp.split(/\s/)
+        if defined? list[-1] and
+          list[-1] =~ /[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/
+          list[-1]
+        end
+      else
+        nil
+      end
+    else
+      nil
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/ipaddress6.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/ipaddress6.rb
new file mode 100644
index 0000000..128f3cd
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/ipaddress6.rb
@@ -0,0 +1,82 @@
+# Fact: ipaddress6
+#
+# Purpose: Returns the "main" IPv6 IP address of a system.
+#
+# Resolution:
+#   OS-dependent code that parses the output of various networking
+#   tools and currently not very intelligent. Returns the first
+#   non-loopback and non-linklocal address found in the ouput unless
+#   a default route can be mapped to a routable interface. Guessing
+#   an interface is currently only possible with BSD-type systems;
+#   too many assumptions have to be made on other platforms to make
+#   this work with the current code. Most of this code is ported or
+#   modeled after the ipaddress fact for the sake of similar
+#   functionality and familiar mechanics.
+#
+# Caveats:
+#
+
+# Cody Herriges <c.a.herriges@gmail.com>
+#
+# Used the ipaddress fact that is already part of
+# Facter as a template.
+
+require 'facter/util/ip'
+
+def get_address_after_token(output, token, return_first=false)
+  ip = nil
+
+  String(output).scan(/#{token}\s?((?>[0-9,a-f,A-F]*\:{1,2})+[0-9,a-f,A-F]{0,4})/).each do |match|
+    match = match.first
+    unless match =~ /^fe80.*/ or match == "::1"
+      ip = match
+      break if return_first
+    end
+  end
+
+  ip
+end
+
+Facter.add(:ipaddress6) do
+  confine :kernel => :linux
+  setcode do
+    output = Facter::Util::IP.exec_ifconfig(["2>/dev/null"])
+    get_address_after_token(output, 'inet6(?: addr:)?')
+  end
+end
+
+Facter.add(:ipaddress6) do
+  confine :kernel => %w{SunOS}
+  setcode do
+    output = Facter::Util::IP.exec_ifconfig(["-a"])
+
+    get_address_after_token(output, 'inet6')
+  end
+end
+
+Facter.add(:ipaddress6) do
+  confine :kernel => %w{Darwin FreeBSD OpenBSD}
+  setcode do
+    output = Facter::Util::IP.exec_ifconfig(["-a"])
+
+    get_address_after_token(output, 'inet6', true)
+  end
+end
+
+Facter.add(:ipaddress6) do
+  confine :kernel => :windows
+  setcode do
+    require 'facter/util/ip/windows'
+    ipaddr = nil
+
+    adapters = Facter::Util::IP::Windows.get_preferred_ipv6_adapters
+    adapters.find do |nic|
+      nic.IPAddress.any? do |addr|
+        ipaddr = addr if Facter::Util::IP::Windows.valid_ipv6_address?(addr)
+        ipaddr
+      end
+    end
+
+    ipaddr
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/iphostnumber.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/iphostnumber.rb
new file mode 100644
index 0000000..c0bd1ee
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/iphostnumber.rb
@@ -0,0 +1,29 @@
+# Fact: iphostnumber
+#
+# Purpose: On selected versions of Darwin, returns the host's IP address.
+#
+# Resolution:
+#   Uses either the scutil program to get the localhost name, or parses output
+#   of ifconfig for a MAC address.
+#
+# Caveats:
+#
+
+Facter.add(:iphostnumber) do
+  confine :kernel => :darwin, :kernelrelease => "R6"
+  setcode do
+    %x{/usr/sbin/scutil --get LocalHostName}
+  end
+end
+Facter.add(:iphostnumber) do
+  confine :kernel => :darwin, :kernelrelease => "R6"
+  setcode do
+    ether = nil
+    output = Facter::Util::IP.exec_ifconfig
+
+    output =~ /HWaddr (\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)/
+    ether = $1
+
+    ether
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/kernel.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/kernel.rb
new file mode 100644
index 0000000..84017fe
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/kernel.rb
@@ -0,0 +1,22 @@
+# Fact: kernel
+#
+# Purpose: Returns the operating system's name.
+#
+# Resolution:
+#   Uses Ruby's RbConfig to find host_os, if that is a Windows derivative, then
+#   returns `windows`, otherwise returns the output of `uname -s` verbatim.
+#
+# Caveats:
+#
+
+Facter.add(:kernel) do
+  setcode do
+    require 'facter/util/config'
+
+    if Facter::Util::Config.is_windows?
+      'windows'
+    else
+      Facter::Core::Execution.exec("uname -s")
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/kernelmajversion.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/kernelmajversion.rb
new file mode 100644
index 0000000..5f06fc6
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/kernelmajversion.rb
@@ -0,0 +1,23 @@
+# Fact: kernelmajversion
+#
+# Purpose: Return the operating system's release number's major value.
+#
+# Resolution:
+#   Takes the first two elements of the kernel version as delimited by periods.
+#   Takes the first element of the kernel version on FreeBSD.
+#
+# Caveats:
+#
+
+Facter.add("kernelmajversion") do
+  setcode do
+    Facter.value(:kernelversion).split('.')[0..1].join('.')
+  end
+end
+
+Facter.add("kernelmajversion") do
+  confine :kernel => :FreeBSD
+  setcode do
+    Facter.value(:kernelversion).split('.')[0]
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/kernelrelease.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/kernelrelease.rb
new file mode 100644
index 0000000..7dfd528
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/kernelrelease.rb
@@ -0,0 +1,50 @@
+# Fact: kernelrelease
+#
+# Purpose: Return the operating system's release number.
+#
+# Resolution:
+#   On AIX, returns the output from the `oslevel -s` system command.
+#   On Windows-based systems, uses the win32ole gem to query Windows Management
+#   for the `Win32_OperatingSystem` value.
+#   Otherwise uses the output of `uname -r` system command.
+#
+# Caveats:
+#
+require 'facter/util/posix'
+
+Facter.add(:kernelrelease) do
+  setcode 'uname -r'
+end
+
+Facter.add(:kernelrelease) do
+  confine :kernel => "aix"
+  setcode 'oslevel -s'
+end
+
+Facter.add("kernelrelease") do
+  confine :kernel => :openbsd
+  setcode do
+    Facter::Util::POSIX.sysctl("kern.version").split(' ')[1]
+  end
+end
+
+Facter.add(:kernelrelease) do
+  confine :kernel => "hp-ux"
+  setcode do
+    version = Facter::Core::Execution.execute('uname -r')
+    version[2..-1]
+  end
+end
+
+Facter.add(:kernelrelease) do
+  confine :kernel => "windows"
+  setcode do
+    require 'facter/util/wmi'
+    version = ""
+    Facter::Util::WMI.execquery("SELECT Version from Win32_OperatingSystem").each do |ole|
+      version = "#{ole.Version}"
+      break
+    end
+    version
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/kernelversion.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/kernelversion.rb
new file mode 100644
index 0000000..c3bb83f
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/kernelversion.rb
@@ -0,0 +1,22 @@
+# Fact: kernelversion
+#
+# Purpose: Return the operating system's kernel version.
+#
+# Resolution:
+#   On Solaris and SunOS based machines, returns the output of `uname -v`.
+#   Otherwise returns the kernerlversion fact up to the first `-`. This may be
+#   the entire kernelversion fact in many cases.
+#
+# Caveats:
+#
+
+Facter.add("kernelversion") do
+  setcode do
+    Facter['kernelrelease'].value.split('-')[0]
+  end
+end
+
+Facter.add("kernelversion") do
+  confine :kernel => :sunos
+  setcode 'uname -v'
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/ldom.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/ldom.rb
new file mode 100644
index 0000000..74ab877
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/ldom.rb
@@ -0,0 +1,51 @@
+# Fact: ldom
+#
+# Purpose:
+#   Returns a list of dynamic facts that describe the attributes of
+#   a Solaris logical domain. The facts returned will include: domainrole,
+#   domainname, domainuuid, domaincontrol, and domainchassis.
+#
+# Resolution:
+#   Uses the output of `virtinfo -ap`.
+#
+
+if Facter.value(:kernel) == 'SunOS' &&
+   Facter.value(:hardwareisa) == 'sparc' &&
+   Facter::Core::Execution.which('virtinfo')
+
+  virtinfo = Facter::Core::Execution.exec('virtinfo -ap')
+
+  # Convert virtinfo parseable output format to array of arrays.
+  # DOMAINROLE|impl=LDoms|control=true|io=true|service=true|root=true
+  # DOMAINNAME|name=primary
+  # DOMAINUUID|uuid=8e0d6ec5-cd55-e57f-ae9f-b4cc050999a4
+  # DOMAINCONTROL|name=san-t2k-6
+  # DOMAINCHASSIS|serialno=0704RB0280
+  #
+  # For keys containing multiple value such as domain role:
+  # ldom_{key}_{subkey} = value
+  # Otherwise the fact will simply be:
+  # ldom_{key} = value
+  unless virtinfo.nil?
+    virt_array = virtinfo.split("\n").select{|l| l =~ /^DOMAIN/ }.
+      collect{|l| l.split('|')}
+    virt_array.each do |x|
+      key = x[0]
+      value = x[1..x.size]
+
+      if value.size == 1
+        Facter.add("ldom_#{key.downcase}") do
+          setcode { value.first.split('=')[1] }
+        end
+      else
+        value.each do |y|
+          k = y.split('=')[0]
+          v = y.split('=')[1]
+          Facter.add("ldom_#{key.downcase}_#{k.downcase}") do
+            setcode { v }
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/lsbdistcodename.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/lsbdistcodename.rb
new file mode 100644
index 0000000..97f1c99
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/lsbdistcodename.rb
@@ -0,0 +1,20 @@
+# Fact: lsbdistcodename
+#
+# Purpose: Return Linux Standard Base information for the host.
+#
+# Resolution:
+#   Uses the lsbdistcodename key of the os structured fact, which 
+#   itself uses the `lsb_release` system command.
+#
+# Caveats:
+#   Only works on Linux (and the kfreebsd derivative) systems.
+#   Requires the `lsb_release` program, which may not be installed by default.
+#   Also is as only as accurate as that program outputs.
+
+Facter.add(:lsbdistcodename) do
+  confine do
+    !Facter.value(:os)["lsb"].nil?
+  end
+
+  setcode { Facter.value("os")["lsb"]["distcodename"] }
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/lsbdistdescription.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/lsbdistdescription.rb
new file mode 100644
index 0000000..038f86c
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/lsbdistdescription.rb
@@ -0,0 +1,21 @@
+# Fact: lsbdistdescription
+#
+# Purpose: Return Linux Standard Base information for the host.
+#
+# Resolution:
+#   Uses the lsbdistdescription key of the os structured fact, which itself
+#   uses the `lsb_release` system command.
+#
+# Caveats:
+#   Only works on Linux (and the kfreebsd derivative) systems.
+#   Requires the `lsb_release` program, which may not be installed by default.
+#   Also is as only as accurate as that program outputs.
+#
+
+Facter.add(:lsbdistdescription) do
+  confine do
+    !Facter.value(:os)["lsb"].nil?
+  end
+
+  setcode { Facter.value("os")["lsb"]["distdescription"] }
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/lsbdistid.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/lsbdistid.rb
new file mode 100644
index 0000000..91df1cc
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/lsbdistid.rb
@@ -0,0 +1,20 @@
+# Fact: lsbdistid
+#
+# Purpose: Return Linux Standard Base information for the host.
+#
+# Resolution:
+#   Uses the lsbdistid key of the os structured fact, which itself
+#   uses the `lsb_release` system command.
+#
+# Caveats:
+#   Only works on Linux (and the kfreebsd derivative) systems.
+#   Requires the `lsb_release` program, which may not be installed by default.
+#   Also is as only as accurate as that program outputs.
+
+Facter.add(:lsbdistid) do
+  confine do
+    !Facter.value(:os)["lsb"].nil?
+  end
+
+  setcode { Facter.value("os")["lsb"]["distid"] }
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/lsbdistrelease.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/lsbdistrelease.rb
new file mode 100644
index 0000000..57ac223
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/lsbdistrelease.rb
@@ -0,0 +1,20 @@
+# Fact: lsbdistrelease
+#
+# Purpose: Return Linux Standard Base information for the host.
+#
+# Resolution:
+#   Uses the lsbdistrelease key of the os structured fact, which itself
+#   uses the `lsb_release` system command.
+#
+# Caveats:
+#   Only works on Linux (and the kfreebsd derivative) systems.
+#   Requires the `lsb_release` program, which may not be installed by default.
+#   Also is as only as accurate as that program outputs.
+
+Facter.add(:lsbdistrelease) do
+  confine do
+    !Facter.value(:os)["lsb"].nil?
+  end
+
+  setcode { Facter.value("os")["lsb"]["distrelease"] }
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/lsbmajdistrelease.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/lsbmajdistrelease.rb
new file mode 100644
index 0000000..c0988d7
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/lsbmajdistrelease.rb
@@ -0,0 +1,22 @@
+# Fact: lsbmajdistrelease
+#
+# Purpose: Returns the major version of the operation system version as gleaned
+# from the lsbdistrelease fact.
+#
+# Resolution:
+#   Uses the lsbmajdistrelease key of the os structured fact, which itself
+#   parses the lsbdistrelease fact for numbers followed by a period and
+#   returns those, or just the lsbdistrelease fact if none were found.
+#
+# Caveats:
+#
+
+require 'facter'
+
+Facter.add(:lsbmajdistrelease) do
+  confine do
+    !Facter.value("os")["lsb"].nil?
+  end
+
+  setcode { Facter.value("os")["lsb"]["majdistrelease"] }
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/lsbminordistrelease.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/lsbminordistrelease.rb
new file mode 100644
index 0000000..62d9a67
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/lsbminordistrelease.rb
@@ -0,0 +1,22 @@
+# Fact: lsbminordistrelease
+#
+# Purpose: Returns the minor version of the operation system version as gleaned
+# from the lsbdistrelease fact.
+#
+# Resolution:
+#   Parses the lsbdistrelease fact for x.y and returns y. If y is not present,
+#   the fact is not present.
+#
+#   For both values '1.2.3' and '1.2' of lsbdistrelease, lsbminordistrelease
+#   would return '2'. For the value '1', no fact would be set for
+#   lsbminordistrelease.
+#
+require 'facter'
+
+Facter.add('lsbminordistrelease') do
+  confine do
+    !Facter.value("os")["lsb"].nil?
+  end
+
+  setcode { Facter.value("os")["lsb"]["minordistrelease"] }
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/lsbrelease.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/lsbrelease.rb
new file mode 100644
index 0000000..72ec067
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/lsbrelease.rb
@@ -0,0 +1,20 @@
+# Fact: lsbrelease
+#
+# Purpose: Return Linux Standard Base information for the host.
+#
+# Resolution:
+#   Uses the lsbrelease key of the os structured fact, which itself
+#   uses the `lsb_release` system command.
+#
+# Caveats:
+#   Only works on Linux (and the kfreebsd derivative) systems.
+#   Requires the `lsb_release` program, which may not be installed by default.
+#   Also is as only as accurate as that program outputs.
+
+Facter.add(:lsbrelease) do
+  confine do
+    !Facter.value(:os)["lsb"].nil?
+  end
+
+  setcode { Facter.value("os")["lsb"]["release"] }
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/macaddress.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/macaddress.rb
new file mode 100644
index 0000000..c2cbe65
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/macaddress.rb
@@ -0,0 +1,99 @@
+# Fact: macaddress
+#
+# Purpose:
+#   Returns the MAC address of the primary network interface.
+#
+# Resolution:
+#
+# Caveats:
+#
+
+require 'facter/util/macaddress'
+require 'facter/util/ip'
+
+Facter.add(:macaddress) do
+  confine :kernel => 'Linux'
+  setcode do
+    ether = []
+    output = Facter::Util::IP.exec_ifconfig(["-a","2>/dev/null"])
+
+    String(output).each_line do |s|
+      ether.push($1) if s =~ /(?:ether|HWaddr) ((\w{1,2}:){5,}\w{1,2})/
+    end
+    Facter::Util::Macaddress.standardize(ether[0])
+  end
+end
+
+Facter.add(:macaddress) do
+  confine :kernel => %w{SunOS GNU/kFreeBSD}
+  setcode do
+    ether = []
+    output = Facter::Util::IP.exec_ifconfig(["-a"])
+    output.each_line do |s|
+      ether.push($1) if s =~ /(?:ether|HWaddr) ((\w{1,2}:){5,}\w{1,2})/
+    end
+    Facter::Util::Macaddress.standardize(ether[0])
+  end
+end
+
+Facter.add(:macaddress) do
+  confine :osfamily => "Solaris"
+  setcode do
+    ether = []
+    output = Facter::Core::Execution.exec("/usr/bin/netstat -np")
+    output.each_line do |s|
+      ether.push($1) if s =~ /(?:SPLA)\s+(\w{2}:\w{2}:\w{2}:\w{2}:\w{2}:\w{2})/
+    end
+    Facter::Util::Macaddress.standardize(ether[0])
+  end
+end
+
+Facter.add(:macaddress) do
+  confine :operatingsystem => %w{FreeBSD OpenBSD DragonFly}
+  setcode do
+    ether = []
+    output = Facter::Util::IP.exec_ifconfig
+    output.each_line do |s|
+      if s =~ /(?:ether|lladdr)\s+(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)/
+        ether.push($1)
+      end
+    end
+    Facter::Util::Macaddress.standardize(ether[0])
+  end
+end
+
+Facter.add(:macaddress) do
+  confine :kernel => :darwin
+  setcode { Facter::Util::Macaddress::Darwin.macaddress }
+end
+
+Facter.add(:macaddress) do
+  confine :kernel => %w{AIX}
+  setcode do
+    ether = []
+    ip = nil
+    default_interface = Facter::Util::IP.exec_netstat(["-rn | grep default | awk '{ print $6 }'"])
+    output = Facter::Util::IP.exec_ifconfig([default_interface])
+    output.each_line do |str|
+      if str =~ /([a-z]+\d+): flags=/
+        devname = $1
+        unless devname =~ /lo0/
+          output2 = %x{/usr/bin/entstat #{devname}}
+          output2.each_line do |str2|
+            if str2 =~ /^Hardware Address: (\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2})/
+              ether.push($1)
+            end
+          end
+        end
+      end
+    end
+    Facter::Util::Macaddress.standardize(ether[0])
+  end
+end
+
+Facter.add(:macaddress) do
+  confine :kernel => %w(windows)
+  setcode do
+    Facter::Util::Macaddress::Windows.macaddress
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/macosx.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/macosx.rb
new file mode 100644
index 0000000..fbf9182
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/macosx.rb
@@ -0,0 +1,56 @@
+# Fact: macosx
+#
+# Purpose:
+#   Returns a number of Mac specific facts, from system profiler and
+#   sw_vers.
+#
+# Resolution:
+#   Uses util/macosx.rb to do the fact reconnaissance, then outputs them
+#   preceded by `sp_`
+#
+# Caveats:
+#
+
+#
+# macosx.rb
+# Additional Facts coming from Mac OS X system_profiler command
+#
+# Copyright (C) 2007 Jeff McCune
+# Author: Jeff McCune <jeff.mccune@northstarlabs.net>
+#
+# Jeff McCune
+# There's a lot more information coming out of system_profiler -xml
+# We could add quite a bit more, but I didn't want to overload facter
+# at this point in time.
+# In particular, Installed Software might be an interesting addition.
+
+if Facter.value(:kernel) == "Darwin"
+  require 'facter/util/macosx'
+
+  Facter::Util::Macosx.hardware_overview.each do |fact, value|
+    Facter.add("sp_#{fact}") do
+      confine :kernel => :darwin
+      setcode do
+        value
+      end
+    end
+  end
+
+  Facter::Util::Macosx.os_overview.each do |fact, value|
+    Facter.add("sp_#{fact}") do
+      confine :kernel => :darwin
+      setcode do
+        value
+      end
+    end
+  end
+
+  Facter::Util::Macosx.sw_vers.each do |fact, value|
+    Facter.add(fact) do
+      confine :kernel => :darwin
+      setcode do
+        value
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/manufacturer.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/manufacturer.rb
new file mode 100644
index 0000000..87ee5c6
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/manufacturer.rb
@@ -0,0 +1,68 @@
+# Fact: manufacturer
+#
+# Purpose: Return the hardware manufacturer information about the hardware.
+#
+# Resolution:
+#   On OpenBSD, queries `sysctl` values, via a util class.
+#   On SunOS Sparc, uses `prtdiag` via a util class.
+#   On Windows, queries the system via a util class.
+#   Uses `util/manufacturer.rb` for fallback parsing.
+#
+# Caveats:
+#
+
+# manufacturer.rb
+# Facts related to hardware manufacturer
+#
+#
+
+require 'facter/util/manufacturer'
+
+if Facter.value(:kernel) == "OpenBSD"
+  mfg_keys = {
+    'hw.vendor'   => 'manufacturer',
+    'hw.product'  => 'productname',
+    'hw.serialno' => 'serialnumber'
+  }
+
+  Facter::Manufacturer.sysctl_find_system_info(mfg_keys)
+elsif Facter.value(:kernel) == "Darwin"
+  mfg_keys = {
+    'hw.model'   => 'productname'
+  }
+  Facter::Manufacturer.sysctl_find_system_info(mfg_keys)
+elsif Facter.value(:kernel) == "SunOS" and Facter.value(:hardwareisa) == "sparc"
+  Facter::Manufacturer.prtdiag_sparc_find_system_info()
+elsif Facter.value(:kernel) == "windows"
+  win32_keys = {
+    'manufacturer' => ['Manufacturer', 'Bios'],
+    'serialNumber' => ['Serialnumber', 'Bios'],
+    'productname'  => ['Name', 'ComputerSystemProduct']
+  }
+  Facter::Manufacturer.win32_find_system_info(win32_keys)
+else
+  query = {
+    '[Bb]ase [Bb]oard [Ii]nformation' => [
+      { 'Manufacturer:'    => 'boardmanufacturer' },
+      { 'Product(?: Name)?:' => 'boardproductname' },
+      { 'Serial Number:'   => 'boardserialnumber' }
+    ],
+    '[Bb][Ii][Oo][Ss] [Ii]nformation' => [
+      { '[Vv]endor:' => 'bios_vendor' },
+      { '[Vv]ersion:' => 'bios_version' },
+      { '[Rr]elease [Dd]ate:' => 'bios_release_date' }
+    ],
+    '[Ss]ystem [Ii]nformation' => [
+      { 'Manufacturer:'    => 'manufacturer' },
+      { 'Product(?: Name)?:' => 'productname' },
+      { 'Serial Number:'   => 'serialnumber' },
+      { 'UUID:'   => 'uuid' }
+    ],
+    '(Chassis Information|system enclosure or chassis)' => [
+      { '(?:Chassis )?Type:' => 'type' }
+    ]
+  }
+
+  Facter::Manufacturer.dmi_find_system_info(query)
+end
+
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/memory.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/memory.rb
new file mode 100644
index 0000000..4aa763c
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/memory.rb
@@ -0,0 +1,168 @@
+# Fact: memory
+#
+# Purpose: Return information about memory and swap usage.
+#
+# Resolution:
+#   On Linuxes, uses `Facter::Memory.meminfo_number` from
+#   `facter/util/memory.rb`
+#   On AIX, parses `swap -l` for swap values only.
+#   On OpenBSD, it parses `swapctl -l` for swap values, `vmstat` via a module for
+#   free memory, and `sysctl hw.physmem` for maximum memory.
+#   On FreeBSD, it parses `swapinfo -k` for swap values, and parses `sysctl` for
+#   maximum memory.
+#   On Solaris, use `swap -l` for swap values, and parsing `prtconf` for maximum
+#   memory, and again, the `vmstat` module for free memory.
+#
+# Caveats:
+#   Some BSD platforms aren't covered at all. AIX is missing memory values.
+#
+
+# memory.rb
+# Additional Facts for memory/swap usage
+#
+# Copyright (C) 2006 Mooter Media Ltd
+# Author: Matthew Palmer <matt@solutionsfirst.com.au>
+#
+#
+
+require 'facter/util/memory'
+
+[  "memorysize",
+   "memoryfree",
+   "swapsize",
+   "swapfree"
+].each do |fact|
+  Facter.add(fact) do
+    setcode do
+      name = Facter.fact(fact + "_mb").value
+      Facter::Memory.scale_number(name.to_f, "MB") if name
+    end
+  end
+end
+
+Facter.add("swapsize_mb") do
+  setcode do
+    swaptotal = Facter::Memory.swap_size
+    "%.2f" % [swaptotal] if swaptotal
+  end
+end
+
+Facter.add("swapfree_mb") do
+  setcode do
+    swapfree = Facter::Memory.swap_free
+    "%.2f" % [swapfree] if swapfree
+  end
+end
+
+Facter.add("memorysize_mb") do
+  setcode do
+    memtotal = Facter::Memory.mem_size
+    "%.2f" % [memtotal] if memtotal
+  end
+end
+
+Facter.add("memoryfree_mb") do
+  setcode do
+    memfree = Facter::Memory.mem_free
+    "%.2f" % [memfree] if memfree
+  end
+end
+
+{   :memorysize_mb => "MemTotal",
+    :memoryfree_mb => "MemFree",
+    :swapsize_mb   => "SwapTotal",
+    :swapfree_mb   => "SwapFree"
+}.each do |fact, name|
+  Facter.add(fact) do
+    confine :kernel => [ :linux, :"gnu/kfreebsd" ]
+    setcode do
+      meminfo = Facter::Memory.meminfo_number(name)
+      "%.2f" % [meminfo]
+    end
+  end
+end
+
+Facter.add("SwapEncrypted") do
+  confine :kernel => :openbsd
+  setcode do
+    sysctl_encrypted = Facter::Util::POSIX.sysctl("vm.swapencrypt.enable").to_i
+    !(sysctl_encrypted.zero?)
+  end
+end
+
+Facter.add("SwapEncrypted") do
+  confine :kernel => :Darwin
+  setcode do
+    swap = Facter::Util::POSIX.sysctl('vm.swapusage')
+    encrypted = false
+    if swap =~ /\(encrypted\)/ then encrypted = true; end
+    encrypted
+  end
+end
+
+if Facter.value(:kernel) == "SunOS"
+
+  Facter.add("memorysize_mb") do
+    confine :kernel => :sunos
+    # Total memory size available from prtconf
+    pconf = Facter::Core::Execution.exec('/usr/sbin/prtconf 2>/dev/null')
+    phymem = ""
+    pconf.each_line do |line|
+      if line =~ /^Memory size:\s+(\d+) Megabytes/
+        phymem = $1
+      end
+    end
+    setcode do
+      "%.2f" % [phymem.to_f]
+    end
+  end
+end
+
+if Facter.value(:kernel) == "windows"
+  require 'facter/util/wmi'
+
+  Facter.add("memorysize_mb") do
+    confine :kernel => :windows
+    setcode do
+      mem = 0
+      Facter::Util::WMI.execquery("select TotalPhysicalMemory from Win32_ComputerSystem").each do |comp|
+        mem = comp.TotalPhysicalMemory
+        break
+      end
+      "%.2f" % [(mem.to_f / 1024.0) / 1024.0]
+    end
+  end
+
+  Facter.add("memoryfree_mb") do
+    confine :kernel => :windows
+    setcode do
+      mem = 0
+      Facter::Util::WMI.execquery("select FreePhysicalMemory from Win32_OperatingSystem").each do |os|
+        mem = os.FreePhysicalMemory
+        break
+      end
+      "%.2f" % [mem.to_f / 1024.0]
+    end
+  end
+end
+
+Facter.add("swapsize_mb") do
+  confine :kernel => :dragonfly
+  setcode do
+    page_size = Facter::Util::POSIX.sysctl("hw.pagesize").to_f
+    swaptotal = Facter::Util::POSIX.sysctl("vm.swap_size").to_f * page_size
+    "%.2f" % [(swaptotal.to_f / 1024.0) / 1024.0]
+  end
+end
+
+Facter.add("swapfree_mb") do
+  confine :kernel => :dragonfly
+  setcode do
+    page_size = Facter::Util::POSIX.sysctl("hw.pagesize").to_f
+    swaptotal = Facter::Util::POSIX.sysctl("vm.swap_size").to_f * page_size
+    swap_anon_use = Facter::Util::POSIX.sysctl("vm.swap_anon_use").to_f * page_size
+    swap_cache_use = Facter::Util::POSIX.sysctl("vm.swap_cache_use").to_f * page_size
+    swapfree = swaptotal - swap_anon_use - swap_cache_use
+    "%.2f" % [(swapfree.to_f / 1024.0) / 1024.0]
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/netmask.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/netmask.rb
new file mode 100644
index 0000000..7156714
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/netmask.rb
@@ -0,0 +1,43 @@
+# Fact: netmask
+#
+# Purpose: Returns the netmask for the main interfaces.
+#
+# Resolution: Uses the `facter/util/netmask` library routines.
+#
+# Caveats:
+#
+
+# netmask.rb
+# Find the netmask of the primary ipaddress
+# Copyright (C) 2007 David Schmitt <david@schmitt.edv-bus.at>
+# Copyright (C) 2007 Mark 'phips' Phillips
+#
+# idea and originial source by Mark 'phips' Phillips
+#
+require 'facter/util/netmask'
+
+Facter.add("netmask") do
+  confine :kernel => [ :sunos, :linux, :freebsd, :openbsd, :netbsd, :darwin, :"gnu/kfreebsd", :dragonfly, :AIX ]
+  setcode do
+    Facter::NetMask.get_netmask
+  end
+end
+
+Facter.add(:netmask) do
+  confine :kernel => :windows
+  setcode do
+    require 'facter/util/ip/windows'
+
+    mask = nil
+
+    adapters = Facter::Util::IP::Windows.get_preferred_ipv4_adapters
+    adapters.find do |nic|
+      nic.IPSubnet.any? do |subnet|
+        mask = subnet if Facter::Util::IP::Windows.valid_ipv4_address?(subnet)
+        mask
+      end
+    end
+
+    mask
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/network.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/network.rb
new file mode 100644
index 0000000..38b9315
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/network.rb
@@ -0,0 +1,20 @@
+# Fact: network
+#
+# Purpose:
+#   Get IP, network, and netmask information for available network
+#   interfaces.
+#
+# Resolution:
+#   Uses `facter/util/ip` to enumerate interfaces and return their information.
+#
+# Caveats:
+#
+require 'facter/util/ip'
+
+Facter::Util::IP.get_interfaces.each do |interface|
+  Facter.add("network_" + Facter::Util::IP.alphafy(interface)) do
+    setcode do
+      Facter::Util::IP.get_network_value(interface)
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem.rb
new file mode 100644
index 0000000..fdf9f15
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem.rb
@@ -0,0 +1,24 @@
+# Fact: operatingsystem
+#
+# Purpose: Return the name of the operating system.
+#
+# Resolution:
+#   Uses the name key of the os structured fact, which itself
+#   operates on the following conditions:
+#
+#
+#   If the kernel is a Linux kernel, check for the existence of a selection of
+#   files in `/etc/` to find the specific flavour.
+#   On SunOS based kernels, attempt to determine the flavour, otherwise return Solaris.
+#   On systems other than Linux, use the kernel fact's value.
+#
+# Caveats:
+#
+
+Facter.add(:operatingsystem) do
+  confine do
+    !Facter.value("os")["name"].nil?
+  end
+
+  setcode { Facter.value("os")["name"] }
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/base.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/base.rb
new file mode 100644
index 0000000..facf76c
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/base.rb
@@ -0,0 +1,61 @@
+require 'facter/util/operatingsystem'
+
+module Facter
+  module Operatingsystem
+    class Base
+      def get_operatingsystem
+        @operatingsystem ||= Facter.value(:kernel)
+        @operatingsystem
+      end
+
+      def get_osfamily
+        Facter.value(:kernel)
+      end
+
+      def get_operatingsystemrelease
+        @operatingsystemrelease = Facter.value(:kernelrelease)
+        @operatingsystemrelease
+      end
+
+      def get_operatingsystemmajorrelease
+        if operatingsystemrelease = get_operatingsystemrelease
+          if (releasemajor = operatingsystemrelease.split(".")[0])
+            releasemajor
+          end
+        end
+      end
+
+      def get_operatingsystemminorrelease
+        if operatingsystemrelease = get_operatingsystemrelease
+          if (releaseminor = operatingsystemrelease.split(".")[1])
+            if releaseminor.include? "-"
+              releaseminor.split("-")[0]
+            else
+              releaseminor
+            end
+          end
+        end
+      end
+
+      def get_operatingsystemrelease_hash
+        release_hash = {}
+        if releasemajor = get_operatingsystemmajorrelease
+          release_hash["major"] = releasemajor
+        end
+
+        if releaseminor = get_operatingsystemminorrelease
+          release_hash["minor"] = releaseminor
+        end
+
+        if release = get_operatingsystemrelease
+          release_hash["full"] = release
+        end
+        release_hash
+      end
+
+      def has_lsb?
+        false
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/cumuluslinux.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/cumuluslinux.rb
new file mode 100644
index 0000000..80c6d40
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/cumuluslinux.rb
@@ -0,0 +1,27 @@
+require 'facter/util/operatingsystem'
+require 'facter/operatingsystem/linux'
+
+module Facter
+  module Operatingsystem
+    class CumulusLinux < Linux
+      def get_operatingsystem
+        "CumulusLinux"
+      end
+
+      def get_osfamily
+        "Debian"
+      end
+
+      def get_operatingsystemrelease
+        @operatingsystemrelease ||= Facter::Util::Operatingsystem.os_release['VERSION_ID']
+        @operatingsystemrelease
+      end
+
+      def get_operatingsystemmajrelease
+        if operatingsystemrelease = get_operatingsystemrelease
+          operatingsystemrelease.split(".").first
+        end
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/implementation.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/implementation.rb
new file mode 100644
index 0000000..68596e7
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/implementation.rb
@@ -0,0 +1,33 @@
+require 'facter/operatingsystem/base'
+require 'facter/operatingsystem/osreleaselinux'
+require 'facter/operatingsystem/cumuluslinux'
+require 'facter/operatingsystem/linux'
+require 'facter/operatingsystem/sunos'
+require 'facter/operatingsystem/vmkernel'
+require 'facter/operatingsystem/windows'
+
+module Facter
+  module Operatingsystem
+    def self.implementation(kernel = Facter.value(:kernel))
+      case kernel
+      when "Linux", "GNU/kFreeBSD"
+        release_info = Facter::Util::Operatingsystem.os_release
+        if release_info['NAME'] == "Cumulus Linux"
+          Facter::Operatingsystem::CumulusLinux.new
+        elsif release_info['NAME'] == "CoreOS"
+          Facter::Operatingsystem::OsReleaseLinux.new
+        else
+          Facter::Operatingsystem::Linux.new
+        end
+      when "SunOS"
+        Facter::Operatingsystem::SunOS.new
+      when "VMkernel"
+        Facter::Operatingsystem::VMkernel.new
+      when "windows"
+        Facter::Operatingsystem::Windows.new
+      else
+        Facter::Operatingsystem::Base.new
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/linux.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/linux.rb
new file mode 100644
index 0000000..a9a1ab0
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/linux.rb
@@ -0,0 +1,479 @@
+require 'facter/util/file_read'
+require 'facter/util/operatingsystem'
+require 'facter/operatingsystem/base'
+
+module Facter
+  module Operatingsystem
+    class Linux < Base
+      def get_operatingsystem
+        if Facter.value(:kernel) == "GNU/kFreeBSD"
+          "GNU/kFreeBSD"
+        elsif lsbdistid = get_lsbdistid
+          if lsbdistid == "Ubuntu"
+            @operatingsystem ||= "Ubuntu"
+          elsif lsbdistid == "LinuxMint"
+            @operatingsystem ||= "LinuxMint"
+          else
+            @operatingsystem ||= get_operatingsystem_with_release_files
+          end
+        else
+          @operatingsystem ||= get_operatingsystem_with_release_files
+        end
+      end
+
+      def get_osfamily
+        case get_operatingsystem
+        when "RedHat", "Fedora", "CentOS", "Scientific", "SLC", "Ascendos", "CloudLinux", "PSBM", "OracleLinux", "OVS", "OEL", "Amazon", "XenServer"
+          "RedHat"
+        when "LinuxMint", "Ubuntu", "Debian"
+          "Debian"
+        when "SLES", "SLED", "OpenSuSE", "SuSE"
+          "Suse"
+        when "Gentoo"
+          "Gentoo"
+        when "Archlinux", "Manjarolinux"
+          "Archlinux"
+        when "Mageia", "Mandriva", "Mandrake"
+          "Mandrake"
+        else
+          Facter.value("kernel")
+        end
+      end
+
+      def get_operatingsystemrelease
+        case get_operatingsystem
+        when "Alpine"
+          get_alpine_release_with_release_file
+        when "Amazon"
+          get_amazon_release_with_lsb
+        when "AristaEOS"
+          get_arista_release_with_release_file
+        when "BlueWhite64"
+          get_bluewhite_release_with_release_file
+        when "CentOS", "RedHat", "Scientific", "SLC", "Ascendos", "CloudLinux", "PSBM",
+             "XenServer", "Fedora", "MeeGo", "OracleLinux", "OEL", "oel", "OVS", "ovs"
+          get_redhatish_release_with_release_file
+        when "Debian"
+          get_debian_release_with_release_file
+        when "LinuxMint"
+          get_linux_mint_release_with_release_file
+        when "Mageia"
+          get_mageia_release_with_release_file
+        when "OpenWrt"
+          get_openwrt_release_with_release_file
+        when "Slackware"
+          get_slackware_release_with_release_file
+        when "Slamd64"
+          get_slamd64_release_with_release_file
+       when "SLES", "SLED", "OpenSuSE"
+          get_suse_release_with_release_file
+        when "Ubuntu"
+          get_ubuntu_release_with_release_file
+        when "VMwareESX"
+          get_vmwareESX_release_with_release_file
+        else
+          Facter.value(:kernelrelease)
+        end
+      end
+
+      def get_operatingsystemmajorrelease
+        if operatingsystemrelease = get_operatingsystemrelease
+          if get_operatingsystem == "Ubuntu"
+            if (releasemajor = operatingsystemrelease.split("."))
+              if releasemajor.length >= 2
+                "#{releasemajor[0]}.#{releasemajor[1]}"
+              else
+                releasemajor[0]
+              end
+            end
+          else
+            if (releasemajor = operatingsystemrelease.split(".")[0])
+              releasemajor
+            end
+          end
+        end
+      end
+
+      def get_operatingsystemminorrelease
+        if operatingsystemrelease = get_operatingsystemrelease
+          if get_operatingsystem == "Ubuntu"
+            if (releaseminor = operatingsystemrelease.split(".")[2])
+              releaseminor
+            end
+          else
+            if (releaseminor = operatingsystemrelease.split(".")[1])
+              if releaseminor.include? "-"
+                releaseminor.split("-")[0]
+              else
+                releaseminor
+              end
+            end
+          end
+        end
+      end
+
+      def has_lsb?
+        true
+      end
+
+      def get_lsbdistcodename
+        if (lsb_data = collect_lsb_information)
+          lsb_data["Codename"]
+        end
+      end
+
+      def get_lsbdistid
+        if (lsb_data = collect_lsb_information)
+          lsb_data["Distributor ID"]
+        end
+      end
+
+      def get_lsbdistdescription
+        if (lsb_data = collect_lsb_information)
+          lsb_data["Description"].sub(/^"(.*)"$/,'\1')
+        end
+      end
+
+      def get_lsbrelease
+        if (lsb_data = collect_lsb_information)
+          lsb_data["LSB Version"]
+        end
+      end
+
+      def get_lsbdistrelease
+        if (lsb_data = collect_lsb_information)
+          lsb_data["Release"]
+        end
+      end
+
+      def get_lsbmajdistrelease
+        lsbdistrelease = get_lsbdistrelease
+        if get_operatingsystem == "Ubuntu"
+          if (lsbreleasemajor = lsbdistrelease.split("."))
+            if lsbreleasemajor.length >= 2
+              result = "#{lsbreleasemajor[0]}.#{lsbreleasemajor[1]}"
+            else
+              result = lsbreleasemajor
+            end
+          end
+        else
+          if /(\d*)\./i =~ lsbdistrelease
+            result = $1
+          else
+            result = lsbdistrelease
+          end
+        end
+        result
+      end
+
+      def get_lsbminordistrelease
+        lsbdistrelease = get_lsbdistrelease
+        if get_operatingsystem == "Ubuntu"
+          mdata = /(\d+).(\d+).(\d+)/i.match(lsbdistrelease)
+          if mdata == nil
+            result = nil
+          else
+            result = mdata[3]
+          end
+        else
+          mdata = /(\d+).(\d+)/i.match(lsbdistrelease)
+          if mdata == nil
+            result = nil
+          else
+            result = mdata[2]
+          end
+        end
+        result
+      end
+
+      def get_lsb_facts_hash
+        lsb_hash = {}
+        if lsbdistcodename = get_lsbdistcodename
+          lsb_hash["distcodename"] = lsbdistcodename
+        end
+
+        if lsbdistid = get_lsbdistid
+          lsb_hash["distid"] = lsbdistid
+        end
+
+        if lsbdistdescription = get_lsbdistdescription
+          lsb_hash["distdescription"] = lsbdistdescription
+        end
+
+        if lsbrelease = get_lsbrelease
+          lsb_hash["release"] = lsbrelease
+        end
+
+        if lsbdistrelease = get_lsbdistrelease
+          lsb_hash["distrelease"] = lsbdistrelease
+        end
+
+        if lsbmajdistrelease = get_lsbmajdistrelease
+          lsb_hash["majdistrelease"]  = lsbmajdistrelease
+        end
+
+        if lsbminordistrelease = get_lsbminordistrelease
+          lsb_hash["minordistrelease"]  = lsbminordistrelease
+        end
+        lsb_hash
+      end
+
+      def collect_lsb_information
+        @lsb_data ||= Facter::Core::Execution.exec("lsb_release -cidvr 2>/dev/null")
+        @data_hash = {}
+
+        if @lsb_data && @data_hash.empty?
+          @lsb_data.split("\n").each do |element|
+            lsbvar, value = element.split("\t")
+            lsbvar.gsub!(":", "")
+            @data_hash["#{lsbvar}"] = value
+          end
+        end
+
+        @data_hash unless @data_hash.empty?
+      end
+
+      private
+
+      # Sequentially searches the filesystem for the existence of a release file
+      #
+      # @return [String, NilClass]
+      def get_operatingsystem_with_release_files
+        operatingsystem = nil
+        release_files = {
+          "AristaEOS"   => "/etc/Eos-release",
+          "Debian"      => "/etc/debian_version",
+          "Gentoo"      => "/etc/gentoo-release",
+          "Fedora"      => "/etc/fedora-release",
+          "Mageia"      => "/etc/mageia-release",
+          "Mandriva"    => "/etc/mandriva-release",
+          "Mandrake"    => "/etc/mandrake-release",
+          "MeeGo"       => "/etc/meego-release",
+          "Archlinux"   => "/etc/arch-release",
+          "Manjarolinux"=> "/etc/manjaro-release",
+          "OracleLinux" => "/etc/oracle-release",
+          "OpenWrt"     => "/etc/openwrt_release",
+          "Alpine"      => "/etc/alpine-release",
+          "VMWareESX"   => "/etc/vmware-release",
+          "Bluewhite64" => "/etc/bluewhite64-version",
+          "Slamd64"     => "/etc/slamd64-version",
+          "Slackware"   => "/etc/slackware-version"
+        }
+
+        release_files.each do |os, releasefile|
+          if FileTest.exists?(releasefile)
+            operatingsystem = os
+          end
+        end
+
+        unless operatingsystem
+          if FileTest.exists?("/etc/enterprise-release")
+            if FileTest.exists?("/etc/ovs-release")
+              operatingsystem = "OVS"
+            else
+              operatingsystem = "OEL"
+            end
+          elsif FileTest.exists?("/etc/redhat-release")
+            operatingsystem = get_redhat_operatingsystem_name
+          elsif FileTest.exists?("/etc/SuSE-release")
+            operatingsystem = get_suse_operatingsystem_name
+          elsif FileTest.exists?("/etc/system-release")
+            operatingsystem = "Amazon"
+          end
+        end
+
+        operatingsystem
+      end
+
+      # Uses a regex search on /etc/redhat-release to determine OS
+      #
+      # @return [String]
+      def get_redhat_operatingsystem_name
+        txt = File.read("/etc/redhat-release")
+        matches = {
+          "CentOS"     => "centos",
+          "Scientific" => "Scientific",
+          "CloudLinux" => "^cloudlinux",
+          "PSBM"       => "^Parallels Server Bare Metal",
+          "Ascendos"   => "Ascendos",
+          "XenServer"  => "^XenServer",
+          "XCP"        => "XCP"
+        }
+
+        if txt =~ /CERN/
+          "SLC"
+        else
+          match = regex_search_release_file_for_operatingsystem(matches, txt)
+          match = "RedHat" if match == nil
+
+          match
+        end
+      end
+
+      # Uses a regex search on /etc/SuSE-release to determine OS
+      #
+      # @return [String]
+      def get_suse_operatingsystem_name
+        txt = File.read("/etc/SuSE-release")
+        matches = {
+          "SLES"     => "^SUSE LINUX Enterprise Server",
+          "SLED"     => "^SUSE LINUX Enterprise Desktop",
+          "OpenSuSE" => "^openSUSE"
+        }
+        match = regex_search_release_file_for_operatingsystem(matches, txt)
+        match = "SuSE" if match == nil
+
+        match
+      end
+
+      # Iterates over potential matches from a hash argument and returns
+      # result of search
+      #
+      # @return [String, NilClass]
+      def regex_search_release_file_for_operatingsystem(regex_os_hash, filecontent)
+        match = nil
+        regex_os_hash.each do |os, regex|
+          match = os if filecontent =~ /#{regex}/i
+        end
+
+        match
+      end
+
+      # Read release files to determine operatingsystemrelease
+      #
+      # @return [String]
+      def get_alpine_release_with_release_file
+        if release = Facter::Util::FileRead.read('/etc/alpine-release')
+          release.sub!(/\s*$/, '')
+          release
+        end
+      end
+
+      def get_arista_release_with_release_file
+        if release = Facter::Util::FileRead.read('/etc/Eos-release')
+          if match = /\d+\.\d+(:?\.\d+)?[A-M]?$/.match(release)
+            match[0]
+          end
+        end
+      end
+
+      def get_amazon_release_with_lsb
+        if lsbdistrelease = get_lsbdistrelease
+          lsbdistrelease
+        else
+          if release = Facter::Util::FileRead.read('/etc/system-release')
+            if match = /\d+\.\d+/.match(release)
+              match[0]
+            end
+          end
+        end
+      end
+
+      def get_bluewhite_release_with_release_file
+        if release = Facter::Util::FileRead.read('/etc/bluewhite64-version')
+          if match = /^\s*\w+\s+(\d+)\.(\d+)/.match(release)
+            match[1] + "." + match[2]
+          else
+            "unknown"
+          end
+        end
+      end
+
+      def get_redhatish_release_with_release_file
+        case get_operatingsystem
+        when "CentOS", "RedHat", "Scientific", "SLC", "Ascendos", "CloudLinux", "PSBM", "XenServer"
+          releasefile = "/etc/redhat-release"
+        when "Fedora"
+          releasefile = "/etc/fedora-release"
+        when "MeeGo"
+          releasefile = "/etc/meego-release"
+        when "OracleLinux"
+          releasefile = "/etc/oracle-release"
+        when "OEL", "oel"
+          releasefile = "/etc/enterprise-release"
+        when "OVS", "ovs"
+          releasefile = "/etc/ovs-release"
+        end
+
+        if release = Facter::Util::FileRead.read(releasefile)
+          line = release.split("\n").first.chomp
+          if match = /\(Rawhide\)$/.match(line)
+            "Rawhide"
+          elsif match = /release (\d[\d.]*)/.match(line)
+            match[1]
+          end
+        end
+      end
+
+      def get_debian_release_with_release_file
+        if release = Facter::Util::FileRead.read('/etc/debian_version')
+          release.sub!(/\s*$/, '')
+          release
+        end
+      end
+
+      def get_linux_mint_release_with_release_file
+        regex_search_releasefile_for_release(/RELEASE\=(\d+)/, "/etc/linuxmint/info")
+      end
+
+      def get_mageia_release_with_release_file
+        regex_search_releasefile_for_release(/Mageia release ([0-9.]+)/, "/etc/mageia-release")
+      end
+
+      def get_openwrt_release_with_release_file
+        regex_search_releasefile_for_release(/^(\d+\.\d+.*)/, "/etc/openwrt_version")
+      end
+
+      def get_slackware_release_with_release_file
+        regex_search_releasefile_for_release(/Slackware ([0-9.]+)/, "/etc/slackware-version")
+      end
+
+      def get_slamd64_release_with_release_file
+        regex_search_releasefile_for_release(/^\s*\w+\s+(\d+)\.(\d+)/, "/etc/slamd64-version")
+      end
+
+      def get_ubuntu_release_with_release_file
+        if release = Facter::Util::FileRead.read('/etc/lsb-release')
+          if match = release.match(/DISTRIB_RELEASE=((\d+.\d+)(\.(\d+))?)/)
+            # Return only the major and minor version numbers.  This behavior must
+            # be preserved for compatibility reasons.
+            match[2]
+          end
+        end
+      end
+
+      def get_vmwareESX_release_with_release_file
+        release = Facter::Core::Execution.exec('vmware -v')
+        if match = /VMware ESX .*?(\d.*)/.match(release)
+          match[1]
+        end
+      end
+
+      def get_suse_release_with_release_file
+        if release = Facter::Util::FileRead.read('/etc/SuSE-release')
+          if match = /^VERSION\s*=\s*(\d+)/.match(release)
+            releasemajor = match[1]
+            if match = /^PATCHLEVEL\s*=\s*(\d+)/.match(release)
+              releaseminor = match[1]
+            elsif match = /^VERSION\s=.*.(\d+)/.match(release)
+              releaseminor = match[1]
+            else
+              releaseminor = "0"
+            end
+            releasemajor + "." + releaseminor
+          else
+            "unknown"
+          end
+        end
+      end
+
+      def regex_search_releasefile_for_release(regex, releasefile)
+        if release = Facter::Util::FileRead.read(releasefile)
+          if match = release.match(regex)
+            match[1]
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/osreleaselinux.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/osreleaselinux.rb
new file mode 100644
index 0000000..b44d212
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/osreleaselinux.rb
@@ -0,0 +1,28 @@
+require 'facter/util/operatingsystem'
+require 'facter/operatingsystem/linux'
+
+module Facter
+  module Operatingsystem
+    class OsReleaseLinux < Linux
+      def get_operatingsystem
+        # Native cfacter also uses the NAME field.
+        Facter::Util::Operatingsystem.os_release['NAME']
+      end
+
+      def get_osfamily
+        Facter::Util::Operatingsystem.os_release['NAME']
+      end
+
+      def get_operatingsystemrelease
+        @operatingsystemrelease ||= Facter::Util::Operatingsystem.os_release['VERSION_ID']
+        @operatingsystemrelease
+      end
+
+      def get_operatingsystemmajrelease
+        if operatingsystemrelease = get_operatingsystemrelease
+          operatingsystemrelease.split(".").first
+        end
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/sunos.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/sunos.rb
new file mode 100644
index 0000000..0baed8a
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/sunos.rb
@@ -0,0 +1,54 @@
+require 'facter/util/file_read'
+require 'facter/operatingsystem/base'
+
+module Facter
+  module Operatingsystem
+    class SunOS < Base
+      def get_operatingsystem
+        output = Facter::Core::Execution.exec('uname -v')
+        if output =~ /^joyent_/
+          "SmartOS"
+        elsif output =~ /^oi_/
+          "OpenIndiana"
+        elsif output =~ /^omnios-/
+          "OmniOS"
+        elsif FileTest.exists?("/etc/debian_version")
+          "Nexenta"
+        else
+          "Solaris"
+        end
+      end
+
+      def get_osfamily
+        "Solaris"
+      end
+
+      def get_operatingsystemrelease
+        if release = Facter::Util::FileRead.read('/etc/release')
+          line = release.split("\n").first
+
+          # Solaris 10: Solaris 10 10/09 s10x_u8wos_08a X86
+          # Solaris 11 (old naming scheme): Oracle Solaris 11 11/11 X86
+          # Solaris 11 (new naming scheme): Oracle Solaris 11.1 SPARC
+          if match = /\s+s(\d+)[sx]?(_u\d+)?.*(?:SPARC|X86)/.match(line)
+            match.captures.join('')
+          elsif match = /Solaris ([0-9\.]+(?:\s*[0-9\.\/]+))\s*(?:SPARC|X86)/.match(line)
+            match.captures[0]
+          else
+            Facter[:kernelrelease].value
+          end
+        else
+          Facter[:kernelrelease].value
+        end
+      end
+
+      def get_operatingsystemmajorrelease
+        if get_operatingsystem == "Solaris"
+          if match = get_operatingsystemrelease.match(/^(\d+)/)
+            match.captures[0]
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/vmkernel.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/vmkernel.rb
new file mode 100644
index 0000000..c572e9e
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/vmkernel.rb
@@ -0,0 +1,11 @@
+require 'facter/operatingsystem/base'
+
+module Facter
+  module Operatingsystem
+    class VMkernel < Base
+      def get_operatingsystem
+        "ESXi"
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/windows.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/windows.rb
new file mode 100644
index 0000000..82ffde8
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystem/windows.rb
@@ -0,0 +1,44 @@
+require 'facter/operatingsystem/base'
+
+module Facter
+  module Operatingsystem
+    class Windows < Base
+      def get_operatingsystemrelease
+        require 'facter/util/wmi'
+        result = nil
+        Facter::Util::WMI.execquery("SELECT version, producttype FROM Win32_OperatingSystem").each do |os|
+          result =
+            case os.version
+            when /^6\.4/
+              # As of October 2014, there are no Win server releases with kernel 6.4.x.
+              # This case prevents future releases from resolving to nil before we
+              # can update the fact regexes.
+              os.producttype == 1 ? "10" : Facter[:kernelrelease].value
+            when /^6\.3/
+              os.producttype == 1 ? "8.1" : "2012 R2"
+            when /^6\.2/
+              os.producttype == 1 ? "8" : "2012"
+            when /^6\.1/
+              os.producttype == 1 ? "7" : "2008 R2"
+            when /^6\.0/
+              os.producttype == 1 ? "Vista" : "2008"
+            when /^5\.2/
+              if os.producttype == 1
+                "XP"
+              else
+                begin
+                  os.othertypedescription == "R2" ? "2003 R2" : "2003"
+                rescue NoMethodError
+                  "2003"
+                end
+              end
+            else
+              Facter[:kernelrelease].value
+            end
+          break
+        end
+        result
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystemmajrelease.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystemmajrelease.rb
new file mode 100644
index 0000000..00b8ad4
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystemmajrelease.rb
@@ -0,0 +1,31 @@
+# Fact: operatingsystemmajrelease
+#
+# Purpose: Returns the major release of the operating system.
+#
+# Resolution:
+#   Uses the release['major'] entry of the os structured fact, which itself
+#   attempts to use its own release['full'] entry to determine the major release value.
+#   In RedHat osfamily derivatives and Debian, splits down the release string for a decimal point
+#   and uses the first non-decimal character.
+#   In Solaris, uses the first non-decimal character of the release string.
+#   In Ubuntu, uses the characters before and after the first decimal point, as in '14.04'.
+#   In Windows, uses the full release string in the case of server releases, such as '2012 R2',
+#   and uses the first non-decimal character in the cases of releases such as '8.1'.
+#
+#   This should be the same as lsbmajdistrelease, but on minimal systems there
+#   are too many dependencies to use LSB
+#
+# List of operatingsystems at time of writing:
+#   "Alpine" "Amazon" "Archlinux" "Ascendos" "Bluewhite64" "CentOS" "CloudLinux" 
+#   "Debian" "Fedora" "Gentoo" "Mandrake" "Mandriva" "MeeGo" "OEL" "OpenSuSE" 
+#   "OracleLinux" "OVS" "PSBM" "RedHat" "Scientific" "Slackware" "Slamd64" "SLC"
+#   "SLED" "SLES" "Solaris" "SuSE" "Ubuntu" "VMWareESX"
+#
+
+Facter.add(:operatingsystemmajrelease) do
+  confine do
+    !Facter.value("os")["release"]["major"].nil?
+  end
+
+  setcode { Facter.value("os")["release"]["major"].to_s }
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystemrelease.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystemrelease.rb
new file mode 100644
index 0000000..bb3cde6
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/operatingsystemrelease.rb
@@ -0,0 +1,29 @@
+# Fact: operatingsystemrelease
+#
+# Purpose: Returns the release of the operating system.
+#
+# Resolution:
+#   Uses the release key of the os structured hash, which itself
+#   operates on the following conditions:
+#
+#   On RedHat derivatives, returns their `/etc/<variant>-release` file.
+#   On Debian, returns `/etc/debian_version`.
+#   On Ubuntu, parses `/etc/lsb-release` for the release version.
+#   On Suse, derivatives, parses `/etc/SuSE-release` for a selection of version
+#   information.
+#   On Slackware, parses `/etc/slackware-version`.
+#   On Amazon Linux, returns the `lsbdistrelease` value.
+#   On Mageia, parses `/etc/mageia-release` for the release version.
+#
+#   On all remaining systems, returns the kernelrelease fact's value.
+#
+# Caveats:
+#
+
+Facter.add(:operatingsystemrelease) do
+  confine do
+    !Facter.value("os")["release"]["full"].nil?
+  end
+
+  setcode { Facter.value("os")["release"]["full"].to_s }
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/os.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/os.rb
new file mode 100644
index 0000000..0c41ba4
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/os.rb
@@ -0,0 +1,98 @@
+# Fact: os
+#
+# Purpose:
+#   Return various facts related to the machine's operating system, including:
+#   Name: The name of the operating system.
+#   Family: A mapping of the operating system to an operating system family.
+#   Release: The release version of the operating system. Includes entries for the
+#   major and minor release versions, as well as the full release string.
+#   Lsb: Linux Standard Base information for the system.
+#
+#   This fact is structured. These values are returned as a group of key-value pairs.
+#
+# Resolution:
+#   For the name entry, if the kernel is a Linux kernel, check for the existence of a 
+#   selection of files in `/etc` to find the specific flavor.
+#   On SunOS based kernels, attempt to determine the flavor, otherwise return Solaris.
+#   On systems other than Linux, use the kernel value.
+#
+#   For the family entry, map operating systems to operating system families, such
+#   as linux distribution derivatives. Adds mappings from specific operating systems
+#   to kernels in the case that it is relevant.
+#
+#   For the release entry, on RedHat derivatives, returns `/etc/<variant>-release` file.
+#   On Debian, returns `/etc/debian_version`.
+#   On Ubuntu, parses `/etc/lsb-release` for the release version
+#   On Suse and derivatives, parses `/etc/SuSE-release` for a selection of version
+#   information.
+#   On Slackware, parses `/etc/slackware-version`.
+#   On Amazon Linux, returns the lsbdistrelease fact's value.
+#   On Mageia, parses `/etc/mageia-release` for the release version.
+#   On all remaining systems, returns the kernelrelease fact's value.
+#
+#   For the major version, uses the value of the full release string to determine the major
+#   release version.
+#   In RedHat osfamily derivatives and Debian, splits down the release string for a decimal point
+#   and uses the first non-decimal character.
+#   In Solaris, uses the first non-decimal character of the release string.
+#   In Ubuntu, uses the characters before and after the first decimal point, as in '14.04'.
+#   In Windows, uses the full release string in the case of server releases, such as '2012 R2',
+#   and uses the first non-decimal character in the cases of releases such as '8.1'.
+#
+#   For the minor version, attempts to split the full release version string and return
+#   the value of the character after the first decimal.
+#
+#   For the lsb entries, uses the `lsb_release` system command.
+#
+# Caveats:
+#   The family entry is completely reliant on the name key, and no heuristics are used.
+#
+#   The major and minor release sub-facts of the release entry are not currenty
+#   supported on all platforms.
+#
+#   The lsb entries only work on Linux (and the kfreebsd derivative) systems. Requires
+#   the `lsb_release` program, which may not be installed by default. It is only as 
+#   accurate as the output of `lsb_release`.
+#
+
+require 'facter/operatingsystem/implementation'
+
+Facter.add(:os, :type => :aggregate) do
+  def os
+    @os ||= Facter::Operatingsystem.implementation
+  end
+
+  chunk(:name) do
+    os_hash = {}
+    if (operatingsystem = os.get_operatingsystem)
+      os_hash["name"] = operatingsystem
+      os_hash
+    end
+  end
+
+  chunk(:family) do
+    os_hash = {}
+    if (osfamily = os.get_osfamily)
+      os_hash["family"] = osfamily
+      os_hash
+    end
+  end
+
+  chunk(:release) do
+    os_hash = {}
+    if (releasedata = os.get_operatingsystemrelease_hash)
+      os_hash["release"] = releasedata
+      os_hash unless os_hash["release"].empty?
+    end
+  end
+
+  chunk(:lsb) do
+    os_hash = {}
+    if os.has_lsb?
+      if (lsbdata = os.get_lsb_facts_hash)
+        os_hash["lsb"] = lsbdata
+        os_hash unless os_hash["lsb"].empty?
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/osfamily.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/osfamily.rb
new file mode 100644
index 0000000..db69550
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/osfamily.rb
@@ -0,0 +1,18 @@
+# Fact: osfamily
+#
+# Purpose: Returns the operating system
+#
+# Resolution:
+#   Uses the family key of the os structured fact, which itself
+#   maps operating systems to operating system families, such as Linux
+#   distribution derivatives. Adds mappings from specific operating systems
+#   to kernels in the case that it is relevant.
+#
+# Caveats:
+#   This fact is completely reliant on the operatingsystem fact, and no
+#   heuristics are used.
+#
+
+Facter.add(:osfamily) do
+  setcode { Facter.value("os")["family"] }
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/partitions.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/partitions.rb
new file mode 100644
index 0000000..b487796
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/partitions.rb
@@ -0,0 +1,39 @@
+# Fact: partitions
+#
+# Purpose:
+#   Return the details of the disk partitions.
+#
+#   This fact is structured. Values are returned as a group of key-value pairs.
+#
+# Resolution:
+#   Parse the contents of `/sys/block/<device>/size` to receive the size (multiplying by 512 to correct for blocks-to-bytes).
+#
+# Caveats:
+#   For Linux, only 2.6+ is supported at this time due to the reliance on sysfs.
+#
+
+# Author: Chris Portman <chris@portman.net.au>
+
+require 'facter'
+require 'facter/util/partitions'
+
+Facter.add(:partitions) do
+  confine do
+    Facter::Util::Partitions.available? ? true : nil
+  end
+
+  setcode do
+    partitions = {}
+    Facter::Util::Partitions.list.each do |part|
+      details = {}
+      details['uuid']       = Facter::Util::Partitions.uuid(part)
+      details['size']       = Facter::Util::Partitions.size(part)
+      details['mount']      = Facter::Util::Partitions.mount(part)
+      details['label']      = Facter::Util::Partitions.label(part)
+      details['filesystem'] = Facter::Util::Partitions.filesystem(part)
+      details.reject! {|k,v| v.nil? || v.to_s.empty? }
+      partitions[part] = details
+    end
+    partitions
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/path.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/path.rb
new file mode 100644
index 0000000..0a1d666
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/path.rb
@@ -0,0 +1,14 @@
+# Fact: path
+#
+# Purpose: Returns the `$PATH` variable.
+#
+# Resolution: Gets `$PATH` from the environment.
+#
+# Caveats:
+#
+
+Facter.add(:path) do
+  setcode do
+    ENV['PATH']
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/physicalprocessorcount.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/physicalprocessorcount.rb
new file mode 100644
index 0000000..b60d069
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/physicalprocessorcount.rb
@@ -0,0 +1,27 @@
+# Fact: physicalprocessorcount
+#
+# Purpose: Return the number of physical processors.
+#
+# Resolution:
+#   Uses the physicalprocessorcount key of the processors structured
+#   fact, which itself attempts to use sysfs to get the physical IDs of
+#   the processors and falls back to `/proc/cpuinfo` and `physical id` if
+#   sysfs is not available.
+#
+# Caveats:
+#
+
+Facter.add('physicalprocessorcount') do
+  confine do
+    !Facter.value(:processors).nil?
+  end
+
+  setcode do
+    processors = Facter.value(:processors)
+    if (physicalprocessorcount = processors["physicalcount"])
+      physicalprocessorcount
+    else
+      nil
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/processor.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/processor.rb
new file mode 100644
index 0000000..48c129c
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/processor.rb
@@ -0,0 +1,52 @@
+# Fact: processor
+#
+# Purpose:
+#   Additional Facts about the machine's CPUs.
+#
+# Resolution:
+#   Utilizes values from the processors structured fact, which itself
+#   uses various methods to collect CPU information, with implementation
+#   dependent upon the OS of the system in question.
+#
+# Caveats:
+#
+
+# processor.rb
+#
+# Copyright (C) 2006 Mooter Media Ltd
+# Author: Matthew Palmer <matt@solutionsfirst.com.au>
+#
+
+
+# We have to enumerate these outside a Facter.add block to get the processorN
+# descriptions iteratively (but we need them inside the Facter.add block above
+# for tests on processorcount to work)
+processors = Facter.value(:processors)
+if processors && (processor_list = processors["models"])
+  processor_list.each_with_index do |processor, i|
+    Facter.add("processor#{i}") do
+      setcode { processor }
+    end
+  end
+end
+
+Facter.add("ProcessorCount") do
+  confine do
+    !Facter.value(:processors).nil?
+  end
+
+  setcode do
+    if (processorcount = processors["count"])
+      processorcount
+    else
+      nil
+    end
+  end
+end
+
+Facter.add("Processor") do
+  confine :kernel => [:dragonfly,:freebsd,:openbsd]
+  setcode do
+    Facter::Util::POSIX.sysctl("hw.model")
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/processors.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/processors.rb
new file mode 100644
index 0000000..9679e56
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/processors.rb
@@ -0,0 +1,66 @@
+# Fact: processors
+#
+# Purpose:
+#   Provide additional facts about the machine's CPUs, including:
+#   Models: A list of processors present on the system.
+#   Count:  The number of hardware threads.
+#   Physicalcount: The number of physical processors.
+#   Speed: The speed of the processors on the system.
+#
+#   This fact is structured. These values are returned as a group of key-value pairs.
+#
+# Resolution:
+#   Linux and kFreeBSD parse `/proc/cpuinfo` for each processor.
+#   AIX parses the output of `lsdev` for its processor section.
+#   Solaris parses the output of `kstat` for each processor.
+#   OpenBSD uses the sysctl variables `hw.model` and `hw.ncpu` for the CPU model
+#   and the CPU count respectively.
+#   Darwin utilizes the system profiler to collect the physical CPU count and speed.
+#
+# Caveats:
+#   The 'speed' sub-fact is not currently supported on all platforms.
+
+require 'facter/processors/os'
+
+Facter.add(:processors, :type => :aggregate) do
+  confine do
+    !os.nil?
+  end
+
+  def os
+    @os ||= Facter::Processors.implementation
+  end
+
+  chunk(:models) do
+    processor_hash = {}
+    processor_list = os.get_processor_list
+    if processor_list.length > 0
+      processor_hash["models"] = processor_list
+      processor_hash
+    end
+  end
+
+  chunk(:count) do
+    processor_hash = {}
+    if (processor_count = os.get_processor_count)
+      processor_hash["count"] = processor_count
+      processor_hash
+    end
+  end
+
+  chunk(:physicalcount) do
+    processor_hash = {}
+    if (physical_processor_count = os.get_physical_processor_count)
+      processor_hash["physicalcount"] = physical_processor_count
+      processor_hash
+    end
+  end
+
+  chunk(:speed) do
+    processor_hash = {}
+    if (processor_speed = os.get_processor_speed)
+      processor_hash["speed"] = processor_speed
+      processor_hash
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/processors/os.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/processors/os.rb
new file mode 100644
index 0000000..e7a7cf8
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/processors/os.rb
@@ -0,0 +1,244 @@
+# Processor OS classes
+#
+# Implements processor data collection with the help
+# of the Util::Processor module.
+
+require 'facter/util/processor'
+require 'facter/util/posix'
+
+module Facter
+  module Processors
+
+    def self.implementation(kernel = Facter.value(:kernel))
+      case kernel
+      when "Linux"
+        Facter::Processors::Linux.new
+      when "GNU/kFreeBSD"
+        Facter::Processors::GNU.new
+      when "Darwin"
+        Facter::Processors::Darwin.new
+      when "AIX"
+        Facter::Processors::AIX.new
+      when "HP-UX"
+        Facter::Processors::HP_UX.new
+      when "DragonFly", "FreeBSD"
+        Facter::Processors::BSD.new
+      when "OpenBSD"
+        Facter::Processors::OpenBSD.new
+      when "SunOS"
+        Facter::Processors::SunOS.new
+      when "windows"
+        Facter::Processors::Windows.new
+      end
+    end
+
+    class Base
+      def get_processor_list
+        Facter::Util::Processor.enum_cpuinfo
+      end
+
+      def get_processor_count
+        get_processor_list.length
+      end
+
+      def get_physical_processor_count
+        nil
+      end
+
+      def get_processor_speed
+        nil
+      end
+    end
+
+    class GNU < Base
+      def get_processor_count
+        processor_list = get_processor_list
+        if processor_list.length != 0
+          processor_list.length
+        else
+          count_cpu_from_sysfs
+        end
+      end
+
+      private
+
+      def count_cpu_from_sysfs
+        sysfs_cpu_directory = "/sys/devices/system/cpu"
+        if File.exists?(sysfs_cpu_directory)
+          lookup_pattern = "#{sysfs_cpu_directory}" + "/cpu[0-9]*"
+          Dir.glob(lookup_pattern).length
+        end
+      end
+    end
+
+    class Linux < GNU
+      def get_physical_processor_count
+        if count = count_physical_cpu_from_sysfs
+          count
+        else
+          count_physical_cpu_from_cpuinfo
+        end
+      end
+
+      private
+
+      def count_physical_cpu_from_sysfs
+        sysfs_cpu_directory = "/sys/devices/system/cpu"
+        if File.exists?(sysfs_cpu_directory)
+          lookup_pattern = "#{sysfs_cpu_directory}" + "/cpu*/topology/physical_package_id"
+          Dir.glob(lookup_pattern).collect { |f| Facter::Core::Execution.exec("cat #{f}")}.uniq.size
+        else
+          nil
+        end
+      end
+
+      def count_physical_cpu_from_cpuinfo
+        str = Facter::Core::Execution.exec("grep 'physical.\+:' /proc/cpuinfo")
+        if str
+          str.scan(/\d+/).uniq.size
+        else
+          nil
+        end
+      end
+    end
+
+    class Windows < Base
+      def initialize
+        require 'facter/util/wmi'
+      end
+
+      def get_processor_list
+        processor_list = []
+        # get each physical processor
+        Facter::Util::WMI.execquery("select * from Win32_Processor").each do |proc|
+          # not supported before 2008
+          if proc.ole_respond_to?(:NumberOfLogicalProcessors)
+            processor_num = proc.NumberOfLogicalProcessors
+          else
+            processor_num = 1
+          end
+
+          processor_num.times do |i|
+            processor_list << proc.Name.squeeze(" ")
+          end
+        end
+        processor_list
+      end
+
+      def get_physical_processor_count
+         Facter::Util::WMI.execquery("select Name from Win32_Processor").Count
+      end
+    end
+
+    class AIX < Base
+      def get_processor_list
+        Facter::Util::Processor.aix_processor_list
+      end
+    end
+
+    class HP_UX < Base
+      def get_processor_list
+        Facter::Util::Processor.hpux_processor_list
+      end
+    end
+
+    class Darwin < Base
+      def initialize
+        require "cfpropertylist"
+        @system_hardware_data = query_system_profiler
+      end
+
+      def get_processor_count
+        Facter::Util::POSIX.sysctl("hw.ncpu").to_i
+      end
+
+      def get_processor_speed
+        @system_hardware_data["current_processor_speed"]
+      end
+
+      private
+
+      def query_system_profiler
+        output = Facter::Core::Execution.exec("/usr/sbin/system_profiler -xml SPHardwareDataType 2>/dev/null")
+        plist  = CFPropertyList::List.new
+        plist.load_str(output)
+        parsed_xml = CFPropertyList.native_types(plist.value)
+        parsed_xml[0]['_items'][0]
+      end
+    end
+
+    class BSD < Base
+      def get_processor_count
+        Facter::Util::POSIX.sysctl("hw.ncpu").to_i
+      end
+    end
+
+    class OpenBSD < BSD
+      def get_physical_processor_count
+        Facter::Util::POSIX.sysctl("hw.ncpufound").to_i
+      end
+
+      def get_processor_speed
+        speed = Facter::Util::POSIX.sysctl("hw.cpuspeed").to_i
+        if speed < 1000
+          "#{speed} MHz"
+        else
+          speed = speed.to_f / 1000
+          "#{(speed * 100).round.to_f / 100.0} GHz"
+        end
+      end
+    end
+
+    class SunOS < Base
+      def initialize
+        kernelrelease = Facter.value(:kernelrelease)
+        @major_version = kernelrelease.split(".")[0].to_i
+        @minor_version = kernelrelease.split(".")[1].to_i
+      end
+
+      def get_processor_list
+        Facter::Util::Processor.enum_kstat
+      end
+
+      def get_processor_count
+        if @major_version < 5 or (@major_version == 5 and @minor_version < 8)
+          if count = count_cpu_with_kstat
+            count
+          else
+            count_cpu_with_psrinfo
+          end
+        else
+          count_cpu_with_psrinfo
+        end
+      end
+
+      def get_physical_processor_count
+        if @major_version > 5 or (@major_version == 5 and @minor_version >= 8)
+          if output = Facter::Core::Execution.exec("/usr/sbin/psrinfo -p")
+            output.to_i
+          end
+        else
+          count_cpu_with_psrinfo
+        end
+      end
+
+      private
+
+      def count_cpu_with_kstat
+        if output = Facter::Core::Execution.exec("/usr/bin/kstat cpu_info")
+          output.scan(/\bcore_id\b\s+\d+/).uniq.length
+        else
+          nil
+        end
+      end
+
+      def count_cpu_with_psrinfo
+        if output = Facter::Core::Execution.exec("/usr/sbin/psrinfo")
+          output.split("\n").length
+        else
+          nil
+        end
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/ps.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/ps.rb
new file mode 100644
index 0000000..9163519
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/ps.rb
@@ -0,0 +1,31 @@
+# Fact: ps
+#
+# Purpose: 
+#   Internal fact for what to use to list all processes. Used by
+#   the Service type in Puppet.
+#
+# Resolution:
+#   Assumes `ps -ef` for all operating systems other than BSD derivatives, where
+#   it uses `ps auxwww`.
+#
+# Caveats:
+#
+
+Facter.add(:ps) do
+  setcode do 'ps -ef' end
+end
+
+Facter.add(:ps) do
+  confine :operatingsystem => :OpenWrt
+  setcode do 'ps www' end
+end
+
+Facter.add(:ps) do
+  confine :operatingsystem => %w{FreeBSD NetBSD OpenBSD Darwin DragonFly}
+  setcode do 'ps auxwww' end
+end
+
+Facter.add(:ps) do
+  confine :operatingsystem => :windows
+  setcode do 'tasklist.exe' end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/puppetversion.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/puppetversion.rb
new file mode 100644
index 0000000..cecf5c1
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/puppetversion.rb
@@ -0,0 +1,20 @@
+# Fact: puppetversion
+#
+# Purpose: Return the version of puppet installed.
+#
+# Resolution:
+#   Requires puppet via Ruby and returns the value of its version constant.
+#
+# Caveats:
+#
+
+Facter.add(:puppetversion) do
+  setcode do
+    begin
+      require 'puppet/version'
+      Puppet.version.to_s
+    rescue LoadError
+      nil
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/rackspace.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/rackspace.rb
new file mode 100644
index 0000000..90d1a57
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/rackspace.rb
@@ -0,0 +1,37 @@
+# Fact: rsc_<RACKSPACE INSTANCE DATA>
+#
+# Purpose: Determine information about Rackspace cloud instances.
+#
+# Resolution:
+#   If this is a Rackspace Cloud instance, populates `rsc_` facts: `is_rsc`, `rsc_region`,
+#   and `rsc_instance_id`.
+#
+# Caveats:
+#   Depends on Xenstore.
+#
+
+Facter.add(:is_rsc) do
+  setcode do
+    result = Facter::Util::Resolution.exec("/usr/bin/xenstore-read vm-data/provider_data/provider 2> /dev/null")
+    if result == "Rackspace"
+      "true"
+    end
+  end
+end
+
+Facter.add(:rsc_region) do
+  confine :is_rsc => "true"
+  setcode do
+    Facter::Util::Resolution.exec("/usr/bin/xenstore-read vm-data/provider_data/region 2> /dev/null")
+  end
+end
+
+Facter.add(:rsc_instance_id) do
+  confine :is_rsc => "true"
+  setcode do
+    result = Facter::Util::Resolution.exec("/usr/bin/xenstore-read name")
+    if result and (match = result.match(/instance-(.*)/))
+      match[1]
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/rubyplatform.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/rubyplatform.rb
new file mode 100644
index 0000000..28a62c4
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/rubyplatform.rb
@@ -0,0 +1,12 @@
+# Fact: rubyplatform
+#
+# Purpose: Returns the platform of Ruby that facter is running under.
+#
+# Resolution: Returns the value of the `RUBY_PLATFORM` constant.
+#
+# Caveats:
+#
+
+Facter.add(:rubyplatform) do
+  setcode { RUBY_PLATFORM.to_s }
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/rubysitedir.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/rubysitedir.rb
new file mode 100644
index 0000000..941a48d
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/rubysitedir.rb
@@ -0,0 +1,15 @@
+# Fact: rubysitedir
+#
+# Purpose: Returns Ruby's site library directory.
+#
+# Resolution:
+#   Uses the RbConfig module.
+#
+
+require 'rbconfig'
+
+Facter.add :rubysitedir do
+  setcode do
+    RbConfig::CONFIG["sitelibdir"]
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/rubyversion.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/rubyversion.rb
new file mode 100644
index 0000000..78915d1
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/rubyversion.rb
@@ -0,0 +1,12 @@
+# Fact: rubyversion
+#
+# Purpose: Returns the version of Ruby that facter is running under.
+#
+# Resolution: Returns the value of the `RUBY_VERSION` constant.
+#
+# Caveats:
+#
+
+Facter.add(:rubyversion) do
+  setcode { RUBY_VERSION.to_s }
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/selinux.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/selinux.rb
new file mode 100644
index 0000000..c52d927
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/selinux.rb
@@ -0,0 +1,154 @@
+# Fact: selinux
+#
+# Purpose:
+#   Determine whether SE Linux is enabled on the node.
+#
+# Resolution:
+#   Checks for the existence of the enforce file under the SE Linux mount
+#   point (e.g. `/selinux/enforce`) and returns true if `/proc/self/attr/current`
+#   does not contain the kernel.
+#
+# Caveats:
+#
+
+# Fact: selinux_config_mode
+#
+# Purpose:
+#   Returns the configured SE Linux mode (e.g., `enforcing`, `permissive`, or `disabled`).
+#
+# Resolution:
+#   Parses the output of `sestatus_cmd` and returns the value of the line beginning
+#   with `Mode from config file:`.
+#
+# Caveats:
+#
+
+# Fact: selinux_config_policy
+#
+# Purpose:
+#   Returns the configured SE Linux policy (e.g., `targeted`, `MLS`, or `minimum`).
+#
+# Resolution:
+#   Parses the output of `sestatus_cmd` and returns the value of the line beginning
+#   with `Policy from config file:`.
+#
+# Caveats:
+#
+
+# Fact: selinux_enforced
+#
+# Purpose:
+#   Returns whether SE Linux is enabled (`true`) or not (`false`).
+#
+# Resolution:
+#   Returns the value found in the `enforce` file under the SE Linux mount
+#   point (e.g. `/selinux/enforce`).
+#
+# Caveats:
+#
+
+# Fact: selinux_policyversion
+#
+# Purpose:
+#   Returns the current SE Linux policy version.
+#
+# Resolution:
+#   Reads the content of the `policyvers` file found under the SE Linux mount point,
+#   e.g. `/selinux/policyvers`.
+#
+# Caveats:
+#
+
+# Fact for SElinux
+# Written by immerda admin team (admin(at)immerda.ch)
+
+sestatus_cmd = '/usr/sbin/sestatus'
+
+# This supports the fact that the selinux mount point is not always in the
+# same location -- the selinux mount point is operating system specific.
+def selinux_mount_point
+  path = "/selinux"
+  if FileTest.exists?('/proc/self/mounts')
+    # Centos 5 shows an error in which having ruby use File.read to read
+    # /proc/self/mounts combined with the puppet agent run with --listen causes
+    # a hang. Reading from other parts of /proc does not seem to cause this problem.
+    # The work around is to read the file in another process.
+    # -- andy Fri Aug 31 2012
+    selinux_line = Facter::Core::Execution.exec('cat /proc/self/mounts').each_line.find { |line| line =~ /selinuxfs/ }
+    if selinux_line
+      path = selinux_line.split[1]
+    end
+  end
+  path
+end
+
+Facter.add("selinux") do
+  confine :kernel => :linux
+  setcode do
+    result = false
+    if FileTest.exists?("#{selinux_mount_point}/enforce")
+      if FileTest.exists?("/proc/self/attr/current")
+        begin
+          if (File.read("/proc/self/attr/current") != "kernel\0")
+            result = true
+          end
+        rescue
+        end
+      end
+    end
+    result
+  end
+end
+
+Facter.add("selinux_enforced") do
+  confine :selinux => true
+  setcode do
+    result = false
+    if FileTest.exists?("#{selinux_mount_point}/enforce") and
+       File.read("#{selinux_mount_point}/enforce") =~ /1/i
+      result = true
+    end
+    result
+  end
+end
+
+Facter.add("selinux_policyversion") do
+  confine :selinux => true
+  setcode do
+    result = 'unknown'
+    if FileTest.exists?("#{selinux_mount_point}/policyvers")
+      result = File.read("#{selinux_mount_point}/policyvers").chomp
+    end
+    result
+  end
+end
+
+Facter.add("selinux_current_mode") do
+  confine :selinux => true
+  setcode do
+    result = 'unknown'
+    mode = Facter::Core::Execution.exec(sestatus_cmd)
+    mode.each_line { |l| result = $1 if l =~ /^Current mode\:\s+(\w+)$/i }
+    result.chomp
+  end
+end
+
+Facter.add("selinux_config_mode") do
+  confine :selinux => true
+  setcode do
+    result = 'unknown'
+    mode = Facter::Core::Execution.exec(sestatus_cmd)
+    mode.each_line { |l| result = $1 if l =~ /^Mode from config file\:\s+(\w+)$/i }
+    result.chomp
+  end
+end
+
+Facter.add("selinux_config_policy") do
+  confine :selinux => true
+  setcode do
+    result = 'unknown'
+    mode = Facter::Core::Execution.exec(sestatus_cmd)
+    mode.each_line { |l| result = $2 if l =~ /^(Policy from config file|Loaded policy name)\:\s+(\w+)$/i }
+    result.chomp
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/ssh.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/ssh.rb
new file mode 100644
index 0000000..1c12451
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/ssh.rb
@@ -0,0 +1,73 @@
+# Fact: ssh
+#
+# Purpose:
+#   Gather facts related to SSH.
+#
+# Resolution:
+#
+# Caveats:
+#
+
+## ssh.rb
+## Facts related to SSH
+##
+
+{"SSHDSAKey" => { :file => "ssh_host_dsa_key.pub", :sshfprrtype => 2 },
+ "SSHRSAKey" => { :file => "ssh_host_rsa_key.pub", :sshfprrtype => 1 },
+ "SSHECDSAKey" => { :file => "ssh_host_ecdsa_key.pub", :sshfprrtype => 3 },
+ "SSHED25519Key" => { :file => "ssh_host_ed25519_key.pub", :sshfprrtype => 4 } }.each do |name,key|
+
+  Facter.add(name) do
+    setcode do
+      value = nil
+      
+      [ "/etc/ssh",
+        "/usr/local/etc/ssh",
+        "/etc",
+        "/usr/local/etc",
+        "/etc/opt/ssh",
+      ].each do |dir|
+      
+        filepath = File.join(dir,key[:file])
+      
+        if FileTest.file?(filepath)
+          begin
+            value = File.read(filepath).chomp.split(/\s+/)[1]
+            break
+          rescue
+            value = nil
+          end
+        end
+      end
+      
+      value
+    end
+  end
+  
+  Facter.add('SSHFP_' + name[3..-4]) do
+    setcode do
+      ssh = Facter.fact(name).value
+      value = nil
+      
+      if ssh && key[:sshfprrtype]
+        begin
+          require 'digest/sha1'
+          require 'base64'
+          digest = Base64.decode64(ssh)
+          value = 'SSHFP ' + key[:sshfprrtype].to_s + ' 1 ' + Digest::SHA1.hexdigest(digest)
+          begin
+            require 'digest/sha2'
+            value += "\nSSHFP " + key[:sshfprrtype].to_s + ' 2 ' + Digest::SHA256.hexdigest(digest)
+          rescue
+          end
+        rescue
+          value = nil
+        end
+      end
+      
+      value
+    end
+    
+  end
+  
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/system32.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/system32.rb
new file mode 100644
index 0000000..96d95ec
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/system32.rb
@@ -0,0 +1,21 @@
+# Fact: system32
+#
+# Purpose: Returns the directory of the native system32 directory.
+# For 32-bit ruby on 32-bit Windows, typically: 'C:\Windows\system32'.
+# For 32-bit ruby on 64-bit Windows, typically: 'C:\Windows\sysnative'.
+# For 64-bit ruby on 64-bit Windows, typically: 'C:\Windows\system32'.
+#
+# Resolution: Checks for the existence of the `sysnative` directory, otherwise
+# uses `system32`
+#
+
+Facter.add(:system32) do
+  confine :kernel => :windows
+  setcode do
+    if File.exist?("#{ENV['SYSTEMROOT']}\\sysnative")
+      "#{ENV['SYSTEMROOT']}\\sysnative"
+    else
+      "#{ENV['SYSTEMROOT']}\\system32"
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/system_uptime.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/system_uptime.rb
new file mode 100644
index 0000000..e693ca2
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/system_uptime.rb
@@ -0,0 +1,44 @@
+# Fact: system_uptime
+#
+# Purpose:
+#   Return the system uptime in a hash in the forms of
+#   seconds, hours, days and a general, human
+#   readable uptime.
+#
+#   This fact is structured. These values are returned as a group of key-value pairs.
+#
+# Resolution:
+#   Does basic math on the get_uptime_seconds utility
+#   to calculate seconds, hours and days.
+#
+# Caveats:
+#
+
+require 'facter/util/uptime'
+
+Facter.add(:system_uptime) do
+  setcode do
+    system_uptime = {}
+    if Facter.value(:kernel) == 'windows'
+      seconds = Facter::Util::Uptime.get_uptime_seconds_win
+    else
+      seconds = Facter::Util::Uptime.get_uptime_seconds_unix
+    end
+
+    if seconds
+      system_uptime['seconds'] = seconds
+      minutes                  = seconds / 60 % 60
+      system_uptime['hours']   = seconds / (60 * 60)
+      system_uptime['days']    = system_uptime['hours'] / 24
+
+      case system_uptime['days']
+      when 0 then system_uptime['uptime'] = "#{system_uptime['hours']}:#{"%02d" % minutes} hours"
+      when 1 then system_uptime['uptime'] = "1 day"
+      else system_uptime['uptime']        = "#{system_uptime['days']} days"
+      end
+    else
+      system_uptime['uptime']  = 'unknown'
+    end
+    system_uptime
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/timezone.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/timezone.rb
new file mode 100644
index 0000000..da008c1
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/timezone.rb
@@ -0,0 +1,14 @@
+# Fact: timezone
+#
+# Purpose: Return the machine's time zone.
+#
+# Resolution: Uses Ruby's Time module.
+#
+# Caveats:
+#
+
+Facter.add("timezone") do
+  setcode do
+    Time.new.zone
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/uniqueid.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/uniqueid.rb
new file mode 100644
index 0000000..df2ed87
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/uniqueid.rb
@@ -0,0 +1,4 @@
+Facter.add(:uniqueid) do
+  setcode 'hostid'
+  confine :kernel => %w{SunOS Linux AIX GNU/kFreeBSD}
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/uptime.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/uptime.rb
new file mode 100644
index 0000000..cc3e715
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/uptime.rb
@@ -0,0 +1,16 @@
+# Fact: uptime
+#
+# Purpose: Return the system uptime in a human-readable format.
+#
+# Resolution:
+#   Uses the structured system_uptime fact, which does basic math
+#   on the number of seconds of uptime to return a count of days
+#   and hours of uptime.
+#
+# Caveats:
+#
+
+Facter.add(:uptime) do
+  setcode { Facter.value(:system_uptime)['uptime'] }
+end
+
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/uptime_days.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/uptime_days.rb
new file mode 100644
index 0000000..a34599d
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/uptime_days.rb
@@ -0,0 +1,13 @@
+# Fact: uptime_days
+#
+# Purpose: Return just the number of days of uptime.
+#
+# Resolution: Uses the "days" key of the system_uptime fact, which divides
+#   its own "hours" key by 24
+#
+# Caveats:
+#
+
+Facter.add(:uptime_days) do
+  setcode { Facter.value(:system_uptime)['days'] }
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/uptime_hours.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/uptime_hours.rb
new file mode 100644
index 0000000..89037ca
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/uptime_hours.rb
@@ -0,0 +1,13 @@
+# Fact: uptime_hours
+#
+# Purpose: Return just the number of hours of uptime.
+#
+# Resolution: Uses the "hours" key of the system_uptime fact, which divides
+#   its own 'seconds' key by 3600.
+#
+# Caveats:
+#
+
+Facter.add(:uptime_hours) do
+  setcode { Facter.value(:system_uptime)['hours'] }
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/uptime_seconds.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/uptime_seconds.rb
new file mode 100644
index 0000000..e175048
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/uptime_seconds.rb
@@ -0,0 +1,20 @@
+# Fact: uptime_seconds
+#
+# Purpose: Return just the number of seconds of uptime.
+#
+# Resolution:
+#   Acquires the uptime in seconds via the 'seconds' key of the system_uptime fact,
+#   which uses the `facter/util/uptime.rb` module to try a variety of methods to acquire
+#   the uptime on Unix.
+#
+#   On Windows, the module calculates the uptime by the `LastBootupTime` Windows
+#   management value.
+#
+# Caveats:
+#
+
+require 'facter/util/uptime'
+
+Facter.add(:uptime_seconds) do
+  setcode { Facter.value(:system_uptime)['seconds'] }
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/architecture.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/architecture.rb
new file mode 100644
index 0000000..1aeebbd
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/architecture.rb
@@ -0,0 +1,19 @@
+# A module to help test architecture facts on non-AIX test hardware
+
+module Facter::Util::Architecture
+  ##
+  # lsattr is intended to directly delegate to Facter::Core::Execution.exec in
+  # an effort to make the processorX facts easier to test.  See also the
+  # {lsdev} method.
+  def self.lsattr(command="lsattr -El proc0 -a type")
+    Facter::Core::Execution.exec(command)
+  end
+
+  ##
+  # kernel_fact_value is intended to directly delegate to Facter.value(:kernel)
+  # to make it easier to stub the kernel fact without affecting the entire
+  # system.
+  def self.kernel_fact_value
+    Facter.value(:kernel)
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/collection.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/collection.rb
new file mode 100644
index 0000000..be3f6f8
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/collection.rb
@@ -0,0 +1,161 @@
+require 'facter'
+require 'facter/util/fact'
+require 'facter/util/loader'
+
+# Manage which facts exist and how we access them.  Largely just a wrapper
+# around a hash of facts.
+#
+# @api private
+class Facter::Util::Collection
+
+  def initialize(internal_loader, external_loader)
+    @facts = Hash.new
+    @internal_loader = internal_loader
+    @external_loader = external_loader
+  end
+
+  # Return a fact object by name.
+  def [](name)
+    value(name)
+  end
+
+  # Define a new fact or extend an existing fact.
+  #
+  # @param name [Symbol] The name of the fact to define
+  # @param options [Hash] A hash of options to set on the fact
+  #
+  # @return [Facter::Util::Fact] The fact that was defined
+  def define_fact(name, options = {}, &block)
+    fact = create_or_return_fact(name, options)
+
+    if block_given?
+      fact.instance_eval(&block)
+    end
+
+    fact
+  rescue => e
+    Facter.log_exception(e, "Unable to add fact #{name}: #{e}")
+  end
+
+  # Add a resolution mechanism for a named fact.  This does not distinguish
+  # between adding a new fact and adding a new way to resolve a fact.
+  #
+  # @param name [Symbol] The name of the fact to define
+  # @param options [Hash] A hash of options to set on the fact and resolution
+  #
+  # @return [Facter::Util::Fact] The fact that was defined
+  def add(name, options = {}, &block)
+    fact = create_or_return_fact(name, options)
+
+    fact.add(options, &block)
+
+    return fact
+  end
+
+  include Enumerable
+
+  # Iterate across all of the facts.
+  def each
+    load_all
+    @facts.each do |name, fact|
+      value = fact.value
+      unless value.nil?
+        yield name.to_s, value
+      end
+    end
+  end
+
+  # Return a fact by name.
+  def fact(name)
+    name = canonicalize(name)
+
+    # Try to load the fact if necessary
+    load(name) unless @facts[name]
+
+    # Try HARDER
+    internal_loader.load_all unless @facts[name]
+
+    if @facts.empty?
+      Facter.warnonce("No facts loaded from #{internal_loader.search_path.join(File::PATH_SEPARATOR)}")
+    end
+
+    @facts[name]
+  end
+
+  # Flush all cached values.
+  def flush
+    @facts.each { |name, fact| fact.flush }
+    @external_facts_loaded = nil
+  end
+
+  # Return a list of all of the facts.
+  def list
+    load_all
+    return @facts.keys
+  end
+
+  def load(name)
+    internal_loader.load(name)
+    load_external_facts
+  end
+
+  # Load all known facts.
+  def load_all
+    internal_loader.load_all
+    load_external_facts
+  end
+
+  def internal_loader
+    @internal_loader
+  end
+
+  def external_loader
+    @external_loader
+  end
+
+  # Return a hash of all of our facts.
+  def to_hash
+    @facts.inject({}) do |h, ary|
+      value = ary[1].value
+      if ! value.nil?
+        # For backwards compatibility, convert the fact name to a string.
+        h[ary[0].to_s] = value
+      end
+      h
+    end
+  end
+
+  def value(name)
+    if fact = fact(name)
+      fact.value
+    end
+  end
+
+  private
+
+  def create_or_return_fact(name, options)
+    name = canonicalize(name)
+
+    fact = @facts[name]
+
+    if fact.nil?
+      fact = Facter::Util::Fact.new(name, options)
+      @facts[name] = fact
+    else
+      fact.extract_ldapname_option!(options)
+    end
+
+    fact
+  end
+
+  def canonicalize(name)
+    name.to_s.downcase.to_sym
+  end
+
+  def load_external_facts
+    if ! @external_facts_loaded
+      @external_facts_loaded = true
+      external_loader.load(self)
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/composite_loader.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/composite_loader.rb
new file mode 100644
index 0000000..eb7de37
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/composite_loader.rb
@@ -0,0 +1,12 @@
+# A composite loader that allows for more than one
+# default directory loader
+
+class Facter::Util::CompositeLoader
+  def initialize(loaders)
+    @loaders = loaders
+  end
+
+  def load(collection)
+    @loaders.each { |loader| loader.load(collection) }
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/config.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/config.rb
new file mode 100644
index 0000000..12ed74a
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/config.rb
@@ -0,0 +1,88 @@
+require 'rbconfig'
+
+# A module to return config related data
+#
+module Facter::Util::Config
+
+  def self.ext_fact_loader
+    @ext_fact_loader || Facter::Util::DirectoryLoader.default_loader
+  end
+
+  def self.ext_fact_loader=(loader)
+    @ext_fact_loader = loader
+  end
+
+  def self.is_mac?
+    RbConfig::CONFIG['host_os'] =~ /darwin/i
+  end
+
+  # Returns true if OS is windows
+  def self.is_windows?
+    RbConfig::CONFIG['host_os'] =~ /mswin|win32|dos|mingw|cygwin/i
+  end
+
+  def self.windows_data_dir
+    if Dir.const_defined? 'COMMON_APPDATA' then
+      Dir::COMMON_APPDATA
+    else
+      nil
+    end
+  end
+
+  def self.external_facts_dirs=(dir)
+    @external_facts_dirs = dir
+  end
+
+  def self.external_facts_dirs
+    @external_facts_dirs
+  end
+
+  def self.setup_default_ext_facts_dirs
+    if Facter::Util::Root.root?
+      windows_dir = windows_data_dir
+      if windows_dir.nil? then
+        # Note: Beginning with Facter 3, /opt/puppetlabs/facter/facts.d will be the only
+        # default external fact directory.
+        @external_facts_dirs = ["/opt/puppetlabs/facter/facts.d",
+                                "/etc/facter/facts.d",
+                                "/etc/puppetlabs/facter/facts.d"]
+      else
+        @external_facts_dirs = [File.join(windows_dir, 'PuppetLabs', 'facter', 'facts.d')]
+      end
+    elsif ENV['HOME']
+      # Note: Beginning with Facter 3, ~/.puppetlabs/opt/facter/facts.d will be the only
+      # default external fact directory.
+      @external_facts_dirs = [File.expand_path(File.join(ENV['HOME'], ".puppetlabs", "opt", "facter", "facts.d")),
+                              File.expand_path(File.join(ENV['HOME'], ".facter", "facts.d"))]
+    else
+      @external_facts_dirs = []
+    end
+  end
+
+  if Facter::Util::Config.is_windows?
+    require 'win32/dir'
+    require 'facter/util/windows_root'
+  else
+    require 'facter/util/unix_root'
+  end
+
+  setup_default_ext_facts_dirs
+
+  def self.override_binary_dir=(dir)
+    @override_binary_dir = dir
+  end
+
+  def self.override_binary_dir
+    @override_binary_dir
+  end
+
+  def self.setup_default_override_binary_dir
+    if Facter::Util::Config.is_windows?
+      @override_binary_dir = nil
+    else
+      @override_binary_dir = "/opt/puppetlabs/puppet/bin"
+    end
+  end
+
+  setup_default_override_binary_dir
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/confine.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/confine.rb
new file mode 100644
index 0000000..eac539c
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/confine.rb
@@ -0,0 +1,66 @@
+# A restricting tag for fact resolution mechanisms.  The tag must be true
+# for the resolution mechanism to be suitable.
+
+require 'facter/util/values'
+
+class Facter::Util::Confine
+  attr_accessor :fact, :values
+
+  include Facter::Util::Values
+
+  # Add the restriction.  Requires the fact name, an operator, and the value
+  # we're comparing to.
+  #
+  # @param fact [Symbol] Name of the fact
+  # @param values [Array] One or more values to match against.
+  #   They can be any type that provides a === method.
+  # @param block [Proc] Alternatively a block can be supplied as a check.  The fact
+  #   value will be passed as the argument to the block.  If the block returns
+  #   true then the fact will be enabled, otherwise it will be disabled.
+  def initialize(fact = nil, *values, &block)
+    raise ArgumentError, "The fact name must be provided" unless fact or block_given?
+    if values.empty? and not block_given?
+      raise ArgumentError, "One or more values or a block must be provided"
+    end
+    @fact = fact
+    @values = values
+    @block = block
+  end
+
+  def to_s
+    return @block.to_s if @block
+    return "'%s' '%s'" % [@fact, @values.join(",")]
+  end
+
+  # Evaluate the fact, returning true or false.
+  # if we have a block paramter then we only evaluate that instead
+  def true?
+    if @block and not @fact then
+      begin
+        return !! @block.call
+      rescue StandardError => error
+        Facter.debug "Confine raised #{error.class} #{error}"
+        return false
+      end
+    end
+
+    unless fact = Facter[@fact]
+      Facter.debug "No fact for %s" % @fact
+      return false
+    end
+    value = convert(fact.value)
+
+    return false if value.nil?
+
+    if @block then
+      begin
+        return !! @block.call(value)
+      rescue StandardError => error
+        Facter.debug "Confine raised #{error.class} #{error}"
+        return false
+      end
+    end
+
+    return @values.any? do |v| convert(v) === value end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/dhcp_servers.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/dhcp_servers.rb
new file mode 100644
index 0000000..b2764f7
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/dhcp_servers.rb
@@ -0,0 +1,58 @@
+require 'facter/util/file_read'
+
+module Facter::Util::DHCPServers
+  def self.gateway_device
+    interface = nil
+    if routes = Facter::Util::FileRead.read('/proc/net/route')
+      routes.each_line do |line|
+        device, destination = line.split(' ')
+        if destination == '00000000'
+          interface = device
+          break
+        end
+      end
+    end
+    interface
+  end
+
+  def self.devices
+    if Facter::Core::Execution.which('nmcli')
+      Facter::Core::Execution.exec("nmcli d").split("\n").select {|d| d =~ /\sconnected/i }.collect{ |line| line.split[0] }
+    else
+      []
+    end
+  end
+
+  def self.device_dhcp_server(device)
+    if Facter::Core::Execution.which('nmcli')
+      # If the version is >= 0.9.9, use show instead of list
+      if is_newer_nmcli?
+        Facter::Core::Execution.exec("nmcli -f all d show #{device}").scan(/dhcp_server_identifier.*?(\d+\.\d+\.\d+\.\d+)$/).flatten.first
+      else
+        Facter::Core::Execution.exec("nmcli -f all d list iface #{device}").scan(/dhcp_server_identifier.*?(\d+\.\d+\.\d+\.\d+)$/).flatten.first
+      end
+    end
+  end
+
+  def self.network_manager_state
+    # If the version is >= 0.9.9, use g instead of nm
+    if is_newer_nmcli?
+      output = Facter::Core::Execution.exec('nmcli -t -f STATE g 2>/dev/null')
+    else
+      output = Facter::Core::Execution.exec('nmcli -t -f STATE nm 2>/dev/null')
+    end
+    return nil unless output
+    output.strip
+  end
+
+  def self.nmcli_version
+    if version = Facter::Core::Execution.exec("nmcli --version")
+      version.scan(/version\s(\d+)\.?(\d+)?\.?(\d+)?\.?(\d+)?/).flatten.map(&:to_i)
+    end
+  end
+
+  def self.is_newer_nmcli?
+    version = nmcli_version
+    version && (version[0] > 0 || version[1] > 9 || (version[1] == 9 && version[2] >= 9))
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/directory_loader.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/directory_loader.rb
new file mode 100644
index 0000000..e547dcb
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/directory_loader.rb
@@ -0,0 +1,88 @@
+# A Facter plugin that loads external facts.
+#
+# Default Unix Directories:
+# /opt/puppetlabs/facter/facts.d, /etc/facter/facts.d, /etc/puppetlabs/facter/facts.d
+#
+# Beginning with Facter 3, only /opt/puppetlabs/facter/facts.d will be a default external fact
+# directory in Unix.
+#
+# Default Windows Direcotires:
+# C:\ProgramData\Puppetlabs\facter\facts.d (2008)
+# C:\Documents and Settings\All Users\Application Data\Puppetlabs\facter\facts.d (2003)
+#
+# Can also load from command-line specified directory
+#
+# Facts can be in the form of JSON, YAML or Text files
+# and any executable that returns key=value pairs.
+
+require 'facter'
+require 'facter/util/config'
+require 'facter/util/composite_loader'
+require 'facter/util/parser'
+require 'yaml'
+
+class Facter::Util::DirectoryLoader
+
+  class NoSuchDirectoryError < Exception
+  end
+
+  # This value makes it highly likely that external facts will take
+  # precedence over all other facts
+  EXTERNAL_FACT_WEIGHT = 10000
+
+  # Directory for fact loading
+  attr_reader :directory
+
+  def initialize(dir, weight = nil)
+    @directory = dir
+    @weight = weight || EXTERNAL_FACT_WEIGHT
+  end
+
+  def self.loader_for(dir)
+    if File.directory?(dir)
+      Facter::Util::DirectoryLoader.new(dir)
+    else
+      raise NoSuchDirectoryError
+    end
+  end
+
+  def self.default_loader
+    loaders = Facter::Util::Config.external_facts_dirs.collect do |dir|
+      Facter::Util::DirectoryLoader.new(dir)
+    end
+    Facter::Util::CompositeLoader.new(loaders)
+  end
+
+  # Load facts from files in fact directory using the relevant parser classes to
+  # parse them.
+  def load(collection)
+    weight = @weight
+    entries.each do |file|
+      parser = Facter::Util::Parser.parser_for(file)
+      if parser == nil
+        next
+      end
+
+      data = parser.results
+      if data == false
+        Facter.warn "Could not interpret fact file #{file}"
+      elsif data == {} or data == nil
+        Facter.warn "Fact file #{file} was parsed but returned an empty data set"
+      else
+        data.each { |p,v| collection.add(p, :value => v) { has_weight(weight) } }
+      end
+    end
+  end
+
+private
+
+  def entries
+    Dir.entries(directory).find_all { |f| should_parse?(f) }.sort.map { |f| File.join(directory, f) }
+  rescue Errno::ENOENT => detail
+    []
+  end
+
+  def should_parse?(file)
+    not file =~ /^\./
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/ec2.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/ec2.rb
new file mode 100644
index 0000000..b81c8fe
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/ec2.rb
@@ -0,0 +1,106 @@
+require 'timeout'
+require 'open-uri'
+
+# Provide a set of utility static methods that help with resolving the EC2
+# fact.
+module Facter::Util::EC2
+  class << self
+    # Test if we can connect to the EC2 api. Return true if able to connect.
+    # On failure this function fails silently and returns false.
+    #
+    # The +wait_sec+ parameter provides you with an adjustable timeout.
+    #
+    def can_connect?(wait_sec=2)
+      Facter.warnonce("#{self}.#{__method__} is deprecated; see the Facter::EC2 classes instead")
+      url = "http://169.254.169.254:80/"
+      Timeout::timeout(wait_sec) {open(url)}
+      return true
+    rescue Timeout::Error
+      return false
+    rescue
+      return false
+    end
+
+    # Test if this host has a mac address used by Eucalyptus clouds, which
+    # normally is +d0:0d+.
+    def has_euca_mac?
+      Facter.warnonce("#{self}.#{__method__} is deprecated; see the Facter::EC2 classes instead")
+      !!(Facter.value(:macaddress) =~ %r{^[dD]0:0[dD]:})
+    end
+
+    # Test if this host has a mac address used by OpenStack, which
+    # normally starts with FA:16:3E (older versions of OpenStack
+    # may generate mac addresses starting with 02:16:3E)
+    def has_openstack_mac?
+      Facter.warnonce("#{self}.#{__method__} is deprecated; see the Facter::EC2 classes instead")
+      !!(Facter.value(:macaddress) =~ %r{^(02|[fF][aA]):16:3[eE]})
+    end
+
+    # Test if the host has an arp entry in its cache that matches the EC2 arp,
+    # which is normally +fe:ff:ff:ff:ff:ff+.
+    def has_ec2_arp?
+      Facter.warnonce("#{self}.#{__method__} is deprecated; see the Facter::EC2 classes instead")
+      kernel = Facter.value(:kernel)
+
+      mac_address_re = case kernel
+                       when /Windows/i
+                         /fe-ff-ff-ff-ff-ff/i
+                       else
+                         /fe:ff:ff:ff:ff:ff/i
+                       end
+
+      arp_command = case kernel
+                    when /Windows/i, /SunOS/i
+                      "arp -a"
+                    else
+                      "arp -an"
+                    end
+
+      if arp_table = Facter::Core::Execution.exec(arp_command)
+        return true if arp_table.match(mac_address_re)
+      end
+      return false
+    end
+  end
+
+  ##
+  # userdata returns a single string containing the body of the response of the
+  # GET request for the URI http://169.254.169.254/latest/user-data/  If the
+  # metadata server responds with a 404 Not Found error code then this method
+  # retuns `nil`.
+  #
+  # @param version [String] containing the API version for the request.
+  # Defaults to "latest" and other examples are documented at
+  # http://aws.amazon.com/archives/Amazon%20EC2
+  #
+  # @api public
+  #
+  # @return [String] containing the response body or `nil`
+  def self.userdata(version="latest")
+    Facter.warnonce("#{self}.#{__method__} is deprecated; see the Facter::EC2 classes instead")
+    uri = "http://169.254.169.254/#{version}/user-data/"
+    begin
+      read_uri(uri)
+    rescue OpenURI::HTTPError => detail
+      case detail.message
+      when /404 Not Found/i
+        Facter.debug "No user-data present at #{uri}: server responded with #{detail.message}"
+        return nil
+      else
+        raise detail
+      end
+    end
+  end
+
+  ##
+  # read_uri provides a seam method to easily test the HTTP client
+  # functionality of a HTTP based metadata server.
+  #
+  # @api private
+  #
+  # @return [String] containing the body of the response
+  def self.read_uri(uri)
+    open(uri).read
+  end
+  private_class_method :read_uri
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/fact.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/fact.rb
new file mode 100644
index 0000000..304cbf7
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/fact.rb
@@ -0,0 +1,204 @@
+require 'facter'
+require 'facter/util/resolution'
+require 'facter/core/aggregate'
+
+# This class represents a fact. Each fact has a name and multiple
+# {Facter::Util::Resolution resolutions}.
+#
+# Create facts using {Facter.add}
+#
+# @api public
+class Facter::Util::Fact
+  # The name of the fact
+  # @return [String]
+  attr_accessor :name
+
+  # @return [String]
+  # @deprecated
+  attr_accessor :ldapname
+
+  # Creates a new fact, with no resolution mechanisms. See {Facter.add}
+  # for the public API for creating facts.
+  # @param name [String] the fact name
+  # @param options [Hash] optional parameters
+  # @option options [String] :ldapname set the ldapname property on the fact
+  #
+  # @api private
+  def initialize(name, options = {})
+    @name = name.to_s.downcase.intern
+
+    extract_ldapname_option!(options)
+
+    @ldapname ||= @name.to_s
+
+    @resolves = []
+    @searching = false
+
+    @value = nil
+  end
+
+  # Adds a new {Facter::Util::Resolution resolution}.  This requires a
+  # block, which will then be evaluated in the context of the new
+  # resolution.
+  #
+  # @param options [Hash] A hash of options to set on the resolution
+  #
+  # @return [Facter::Util::Resolution]
+  #
+  # @api private
+  def add(options = {}, &block)
+    define_resolution(nil, options, &block)
+  end
+
+  # Define a new named resolution or return an existing resolution with
+  # the given name.
+  #
+  # @param resolution_name [String] The name of the resolve to define or look up
+  # @param options [Hash] A hash of options to set on the resolution
+  # @return [Facter::Util::Resolution]
+  #
+  # @api public
+  def define_resolution(resolution_name, options = {}, &block)
+
+    resolution_type = options.delete(:type) || :simple
+
+    resolve = create_or_return_resolution(resolution_name, resolution_type)
+
+    resolve.set_options(options) unless options.empty?
+    resolve.evaluate(&block) if block
+
+    resolve
+  rescue => e
+    Facter.log_exception(e, "Unable to add resolve #{resolution_name.inspect} for fact #{@name}: #{e.message}")
+  end
+
+  # Retrieve an existing resolution by name
+  #
+  # @param name [String]
+  #
+  # @return [Facter::Util::Resolution, nil] The resolution if exists, nil if
+  #   it doesn't exist or name is nil
+  def resolution(name)
+    return nil if name.nil?
+
+    @resolves.find { |resolve| resolve.name == name }
+  end
+
+  # Flushes any cached values.
+  #
+  # @return [void]
+  #
+  # @api private
+  def flush
+    @resolves.each { |r| r.flush }
+    @value = nil
+  end
+
+  # Returns the value for this fact. This searches all resolutions by
+  # suitability and weight (see {Facter::Util::Resolution}). If no
+  # suitable resolution is found, it returns nil.
+  #
+  # @api public
+  def value
+    return @value if @value
+
+    if @resolves.empty?
+      Facter.debug "No resolves for %s" % @name
+      return nil
+    end
+
+    searching do
+
+      suitable_resolutions = sort_by_weight(find_suitable_resolutions(@resolves))
+      @value = find_first_real_value(suitable_resolutions)
+
+      announce_when_no_suitable_resolution(suitable_resolutions)
+      announce_when_no_value_found(@value)
+
+      @value
+    end
+  end
+
+  # @api private
+  # @deprecated
+  def extract_ldapname_option!(options)
+    if options[:ldapname]
+      Facter.warnonce("ldapname is deprecated and will be removed in a future version")
+      self.ldapname = options.delete(:ldapname)
+    end
+  end
+
+  private
+
+  # Are we in the midst of a search?
+  def searching?
+    @searching
+  end
+
+  # Lock our searching process, so we never ge stuck in recursion.
+  def searching
+    raise RuntimeError, "Caught recursion on #{@name}" if searching?
+
+    # If we've gotten this far, we're not already searching, so go ahead and do so.
+    @searching = true
+    begin
+      yield
+    ensure
+      @searching = false
+    end
+  end
+
+  def find_suitable_resolutions(resolutions)
+    resolutions.find_all{ |resolve| resolve.suitable? }
+  end
+
+  def sort_by_weight(resolutions)
+    resolutions.sort { |a, b| b.weight <=> a.weight }
+  end
+
+  def find_first_real_value(resolutions)
+    resolutions.each do |resolve|
+      value = resolve.value
+      if not value.nil?
+        return value
+      end
+    end
+    nil
+  end
+
+  def announce_when_no_suitable_resolution(resolutions)
+    if resolutions.empty?
+      Facter.debug "Found no suitable resolves of %s for %s" % [@resolves.length, @name]
+    end
+  end
+
+  def announce_when_no_value_found(value)
+    if value.nil?
+      Facter.debug("value for %s is still nil" % @name)
+    end
+  end
+
+  def create_or_return_resolution(resolution_name, resolution_type)
+    resolve = self.resolution(resolution_name)
+
+    if resolve
+      if resolution_type != resolve.resolution_type
+        raise ArgumentError, "Cannot return resolution #{resolution_name} with type" +
+          " #{resolution_type}; already defined as #{resolve.resolution_type}"
+      end
+    else
+      case resolution_type
+      when :simple
+        resolve = Facter::Util::Resolution.new(resolution_name, self)
+      when :aggregate
+        resolve = Facter::Core::Aggregate.new(resolution_name, self)
+      else
+        raise ArgumentError, "Expected resolution type to be one of (:simple, :aggregate) but was #{resolution_type}"
+      end
+
+      @resolves << resolve
+    end
+
+    resolve
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/file_read.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/file_read.rb
new file mode 100644
index 0000000..c92185a
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/file_read.rb
@@ -0,0 +1,37 @@
+module Facter
+module Util
+
+# {Facter::Util::FileRead} is a utility module intended to provide easily
+# mockable methods that delegate to simple file read methods.  The intent is to
+# avoid the need to execute the `cat` system command or `File.read` directly in
+# Ruby, as mocking these behaviors can have wide-ranging effects.
+#
+# All Facter facts are encouraged to use this method instead of File.read or
+# Facter::Core::Execution.exec('cat ...')
+#
+# @api public
+module FileRead
+  # read returns the raw content of a file as a string.  If the file does not
+  # exist, or the process does not have permission to read the file then nil is
+  # returned.
+  #
+  # @api public
+  #
+  # @param path [String] the path to be read
+  #
+  # @return [String, nil] the raw contents of the file or `nil` if the
+  #   file cannot be read because it does not exist or the process does not have
+  #   permission to read the file.
+  def self.read(path)
+    File.read(path)
+  rescue Errno::ENOENT, Errno::EACCES => detail
+    Facter.debug "Could not read #{path}: #{detail.message}"
+    nil
+  end
+
+  def self.read_binary(path)
+    File.open(path, "rb") { |contents| contents.read }
+  end
+end
+end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/formatter.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/formatter.rb
new file mode 100644
index 0000000..afcac6a
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/formatter.rb
@@ -0,0 +1,39 @@
+require 'yaml'
+
+module Facter
+  module Util
+    module Formatter
+
+      def self.format_json(hash)
+        if Facter.json?
+          JSON.pretty_generate(hash)
+        else
+          raise "Cannot format facts as JSON; 'json' library is not present"
+        end
+      end
+
+      def self.format_yaml(hash)
+        YAML.dump(hash)
+      end
+
+      def self.format_plaintext(hash)
+        output = ''
+
+        # Print the value of a single fact, otherwise print a list sorted by fact
+        # name and separated by "=>"
+        if hash.length == 1
+          if !(value = hash.values.first).nil?
+            output = value.is_a?(String) ? value : value.inspect
+          end
+        else
+          hash.sort_by { |(name, value)| name }.each do |name,value|
+            value = value.is_a?(String) ? value : value.inspect
+            output << "#{name} => #{value}\n"
+          end
+        end
+
+        output
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/ip.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/ip.rb
new file mode 100644
index 0000000..62df8a4
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/ip.rb
@@ -0,0 +1,340 @@
+# A base module for collecting IP-related
+# information from all kinds of platforms.
+module Facter::Util::IP
+  # A map of all the different regexes that work for
+  # a given platform or set of platforms.
+  REGEX_MAP = {
+    :linux => {
+      :ipaddress  => /inet (?:addr:)?([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/,
+      :ipaddress6 => /inet6 (?:addr: )?((?![fe80|::1])(?>[0-9,a-f,A-F]*\:{1,2})+[0-9,a-f,A-F]{0,4})/,
+      :macaddress => /(?:ether|HWaddr)\s+((\w{1,2}:){5,}\w{1,2})/,
+      :netmask  => /(?:Mask:|netmask )([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/,
+      :mtu  => /MTU:?\s*(\d+)/i
+    },
+    :bsd   => {
+      :aliases  => [:openbsd, :netbsd, :freebsd, :darwin, :"gnu/kfreebsd", :dragonfly],
+      :ipaddress  => /inet\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/,
+      :ipaddress6 => /inet6 ((?![fe80|::1])(?>[0-9,a-f,A-F]*\:{1,2})+[0-9,a-f,A-F]{0,4})/,
+      :macaddress => /(?:ether|lladdr)\s+(\w?\w:\w?\w:\w?\w:\w?\w:\w?\w:\w?\w)/,
+      :netmask  => /netmask\s+0x(\w{8})/,
+      :mtu => /mtu\s+(\d+)/
+    },
+    :sunos => {
+      :ipaddress  => /inet\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/,
+      :ipaddress6 => /inet6 ((?![fe80|::1])(?>[0-9,a-f,A-F]*\:{1,2})+[0-9,a-f,A-F]{0,4})/,
+      :macaddress => /(?:ether|lladdr)\s+(\w?\w:\w?\w:\w?\w:\w?\w:\w?\w:\w?\w)/,
+      :netmask  => /netmask\s+(\w{8})/,
+      :mtu => /mtu\s+(\d+)/
+    },
+    :"hp-ux" => {
+      :ipaddress  => /\s+inet (\S+)\s.*/,
+      :macaddress => /(\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2})/,
+      :netmask  => /.*\s+netmask (\S+)\s.*/
+    },
+    :aix   => {
+      :ipaddress  => /inet\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/,
+      :ipaddress6 => /inet6 ((?![fe80|::1])(?>[0-9,a-f,A-F]*\:{1,2})+[0-9,a-f,A-F]{0,4})/,
+      :netmask  => /netmask\s+0x(\w{8})/,
+      :mtu => /mtu\s+(\d+)/,
+      :macaddress => /^Hardware\sAddress:\s(\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2})/
+    },
+    :windows => {}
+  }
+
+  # Convert an interface name into purely alphanumeric characters.
+  def self.alphafy(interface)
+    interface.gsub(/[^a-z0-9_]/i, '_')
+  end
+
+  def self.convert_from_hex?(kernel)
+    kernels_to_convert = [:sunos, :openbsd, :netbsd, :freebsd, :darwin, :"hp-ux", :"gnu/kfreebsd", :dragonfly, :aix]
+    kernels_to_convert.include?(kernel)
+  end
+
+  def self.supported_platforms
+    REGEX_MAP.inject([]) do |result, tmp|
+      key, map = tmp
+      if map[:aliases]
+        result += map[:aliases]
+      else
+        result << key
+      end
+      result
+    end
+  end
+
+  def self.get_interfaces
+    if Facter.value(:kernel) == 'windows'
+      require 'facter/util/ip/windows'
+      return Facter::Util::IP::Windows.interfaces
+    end
+
+    return [] unless output = Facter::Util::IP.get_all_interface_output()
+
+    # Our regex appears to be stupid, in that it leaves colons sitting
+    # at the end of interfaces.  So, we have to trim those trailing
+    # characters.  I tried making the regex better but supporting all
+    # platforms with a single regex is probably a bit too much.
+    output.scan(/^\S+/).collect { |i| i.sub(/:$/, '') }.uniq
+  end
+
+  def self.get_all_interface_output
+    case Facter.value(:kernel)
+    when 'Linux', 'OpenBSD', 'NetBSD', 'FreeBSD', 'Darwin', 'GNU/kFreeBSD', 'DragonFly', 'AIX'
+      output = Facter::Util::IP.exec_ifconfig(["-a","2>/dev/null"])
+    when 'SunOS'
+      output = Facter::Util::IP.exec_ifconfig(["-a"])
+    when 'HP-UX'
+      # (#17487)[https://projects.puppetlabs.com/issues/17487]
+      # Handle NIC bonding where asterisks and virtual NICs are printed.
+      if output = hpux_netstat_in
+        output.gsub!(/\*/, "")                  # delete asterisks.
+        output.gsub!(/^[^\n]*none[^\n]*\n/, "") # delete lines with 'none' instead of IPs.
+        output.sub!(/^[^\n]*\n/, "")            # delete the header line.
+        output
+      end
+    end
+    output
+  end
+
+
+  ##
+  # exec_ifconfig uses the ifconfig command
+  #
+  # @return [String] the output of `ifconfig #{arguments} 2>/dev/null` or nil
+  def self.exec_ifconfig(additional_arguments=[])
+    Facter::Core::Execution.exec("#{self.get_ifconfig} #{additional_arguments.join(' ')}")
+  end
+  ##
+  # get_ifconfig looks up the ifconfig binary
+  #
+  # @return [String] path to the ifconfig binary
+  def self.get_ifconfig
+    common_paths=["/bin/ifconfig","/sbin/ifconfig","/usr/sbin/ifconfig"]
+    common_paths.select{|path| File.executable?(path)}.first
+  end
+
+  ##
+  # exec_netstat uses the netstat command
+  #
+  # @return [String] the output of `netstat #{arguments} 2>/dev/null` or nil
+  def self.exec_netstat(additional_arguments=[])
+    Facter::Core::Execution.exec("#{self.get_netstat} #{additional_arguments.join(' ')}")
+  end
+  ##
+  # get_netstat looks up the netstat binary
+  #
+  # @return [String] path to the netstat binary
+  def self.get_netstat
+    common_paths=["/bin/netstat","/sbin/netstat","/usr/sbin/netstat","/usr/bin/netstat"]
+    common_paths.select{|path| File.executable?(path)}.first
+  end
+  
+  ##
+  # hpux_netstat_in is a delegate method that allows us to stub netstat -in
+  # without stubbing exec.
+  def self.hpux_netstat_in
+    Facter::Core::Execution.exec("/bin/netstat -in")
+  end
+
+  def self.get_infiniband_macaddress(interface)
+    if File.exists?("/sys/class/net/#{interface}/address") then
+      ib_mac_address = `cat /sys/class/net/#{interface}/address`.chomp
+    elsif File.exists?("/sbin/ip") then
+      ip_output = %x{/sbin/ip link show '#{interface}'}
+      ib_mac_address = ip_output.scan(%r{infiniband\s+((\w{1,2}:){5,}\w{1,2})})
+    else
+      ib_mac_address = "FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF"
+      Facter.debug("ip.rb: nothing under /sys/class/net/#{interface}/address and /sbin/ip not available")
+    end
+    ib_mac_address
+  end
+
+  def self.ifconfig_interface(interface)
+    output = Facter::Util::IP.exec_ifconfig(["'#{interface}'","2>/dev/null"])
+  end
+
+  def self.get_single_interface_output(interface)
+    output = ""
+    case Facter.value(:kernel)
+    when 'OpenBSD', 'NetBSD', 'FreeBSD', 'Darwin', 'GNU/kFreeBSD', 'DragonFly'
+      output = Facter::Util::IP.ifconfig_interface(interface)
+    when 'Linux'
+      ifconfig_output = Facter::Util::IP.ifconfig_interface(interface)
+      if interface =~ /^ib/ then
+        real_mac_address = get_infiniband_macaddress(interface)
+        output = ifconfig_output.sub(%r{(?:ether|HWaddr)\s+((\w{1,2}:){5,}\w{1,2})}, "HWaddr #{real_mac_address}")
+      else
+        output = ifconfig_output
+      end
+    when 'SunOS'
+      output = Facter::Util::IP.exec_ifconfig([interface])
+    when 'HP-UX'
+       mac = ""
+       ifc = hpux_ifconfig_interface(interface)
+       hpux_lanscan.scan(/(\dx\S+).*UP\s+(\w+\d+)/).each {|i| mac = i[0] if i.include?(interface) }
+       mac = mac.sub(/0x(\S+)/,'\1').scan(/../).join(":")
+       output = ifc + "\n" + mac
+    when 'AIX'
+        output = Facter::Util::IP.ifconfig_interface(interface) + "\n" + aix_get_mtu(interface) + "\n" + aix_get_macadress(interface)
+        output
+    end
+    output
+  end
+
+  def self.hpux_ifconfig_interface(interface)
+    Facter::Util::IP.exec_ifconfig([interface])
+  end
+
+  def self.hpux_lanscan
+    Facter::Core::Execution.exec("/usr/sbin/lanscan")
+  end
+
+  def self.aix_lsattr_interface(interface)
+    Facter::Core::Execution.exec("/usr/sbin/lsattr -El #{interface}")
+  end
+
+  def self.aix_entstat_interface(interface)
+    if interface[0..1] != "lo"
+      Facter::Core::Execution.exec("/usr/bin/entstat #{interface}")
+    else
+      return ""
+    end
+  end
+
+  def self.aix_get_mtu(interface)
+    aix_lsattr_interface(interface).each_line do |s|
+      if s =~ /mtu\s+(\d+)/
+        return s
+      end
+    end
+  end
+
+  def self.aix_get_macadress(interface)
+    aix_entstat_interface(interface).each_line do |s|
+      if s =~ /^Hardware\sAddress:\s(\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2})/
+        return s
+      end
+    end
+  end
+
+  def self.get_output_for_interface_and_label(interface, label)
+    return get_single_interface_output(interface) unless Facter.value(:kernel) == 'windows'
+
+    require 'facter/util/ip/windows'
+    output = Facter::Util::IP::Windows.value_for_interface_and_label(interface, label)
+    output ? output : ""
+  end
+
+  def self.get_bonding_master(interface)
+    if Facter.value(:kernel) != 'Linux'
+      return nil
+    end
+    # We need ip instead of ifconfig because it will show us
+    # the bonding master device.
+    if not FileTest.executable?("/sbin/ip")
+      return nil
+    end
+    # A bonding interface can never be an alias interface. Alias
+    # interfaces do have a colon in their name and the ip link show
+    # command throws an error message when we pass it an alias
+    # interface.
+    if interface =~ /:/
+      return nil
+    end
+    regex = /SLAVE[,>].* (bond[0-9]+)/
+      ethbond = regex.match(%x{/sbin/ip link show '#{interface}'})
+    if ethbond
+      device = ethbond[1]
+    else
+      device = nil
+    end
+    device
+  end
+
+  ##
+  # get_interface_value obtains the value of a specific attribute of a specific
+  # interface.
+  #
+  # @param interface [String] the interface identifier, e.g. "eth0" or "bond0"
+  #
+  # @param label [String] the attribute of the interface to obtain a value for,
+  # e.g. "netmask" or "ipaddress"
+  #
+  # @api private
+  #
+  # @return [String] representing the requested value.  An empty array is
+  # returned if the kernel is not supported by the REGEX_MAP constant.
+  def self.get_interface_value(interface, label)
+    if Facter.value(:kernel) == 'windows'
+      require 'facter/util/ip/windows'
+      return Facter::Util::IP::Windows.value_for_interface_and_label(interface, label)
+    end
+
+    tmp1 = []
+
+    kernel = Facter.value(:kernel).downcase.to_sym
+
+    # If it's not directly in the map or aliased in the map, then we don't know how to deal with it.
+    unless map = REGEX_MAP[kernel] || REGEX_MAP.values.find { |tmp| tmp[:aliases] and tmp[:aliases].include?(kernel) }
+      return []
+    end
+
+    # Pull the correct regex out of the map.
+    regex = map[label.to_sym]
+
+    # Linux changes the MAC address reported via ifconfig when an ethernet interface
+    # becomes a slave of a bonding device to the master MAC address.
+    # We have to dig a bit to get the original/real MAC address of the interface.
+    bonddev = get_bonding_master(interface) if label == 'macaddress'
+    if bonddev
+      bondinfo = read_proc_net_bonding("/proc/net/bonding/#{bonddev}")
+      re = /^Slave Interface: #{interface}\b.*?\bPermanent HW addr: (([0-9A-F]{2}:?)*)$/im
+      if match = re.match(bondinfo)
+        value = match[1].upcase
+      end
+    else
+      output_int = get_output_for_interface_and_label(interface, label)
+
+      output_int.each_line do |s|
+        if s =~ regex
+          value = $1
+            if label == 'netmask' && convert_from_hex?(kernel)
+              value = value.scan(/../).collect do |byte| byte.to_i(16) end.join('.')
+            end
+          tmp1.push(value)
+        end
+      end
+
+      if tmp1
+        value = tmp1.shift
+      end
+    end
+  end
+
+  ##
+  # read_proc_net_bonding is a seam method for mocking purposes.
+  #
+  # @param path [String] representing the path to read, e.g. "/proc/net/bonding/bond0"
+  #
+  # @api private
+  #
+  # @return [String] modeling the raw file read
+  def self.read_proc_net_bonding(path)
+    File.read(path) if File.exists?(path)
+  end
+  private_class_method :read_proc_net_bonding
+
+  def self.get_network_value(interface)
+    require 'ipaddr'
+
+    ipaddress = get_interface_value(interface, "ipaddress")
+    netmask = get_interface_value(interface, "netmask")
+
+    if ipaddress && netmask
+      ip = IPAddr.new(ipaddress, Socket::AF_INET)
+      subnet = IPAddr.new(netmask, Socket::AF_INET)
+      network = ip.mask(subnet.to_s).to_s
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/ip/windows.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/ip/windows.rb
new file mode 100644
index 0000000..b8b6501
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/ip/windows.rb
@@ -0,0 +1,215 @@
+# encoding: UTF-8
+
+require 'facter/util/wmi'
+require 'facter/util/ip'
+
+class Facter::Util::IP::Windows
+  # The WMI query used to return ip information
+  #
+  # @return [String]
+  #
+  # @api private
+  WMI_IP_INFO_QUERY = 'SELECT Description, ServiceName, IPAddress, IPConnectionMetric, InterfaceIndex, Index, IPSubnet, MACAddress, MTU, SettingID FROM Win32_NetworkAdapterConfiguration WHERE IPConnectionMetric IS NOT NULL AND IPEnabled = TRUE'
+
+  # Mapping fact names to WMI properties of the Win32_NetworkAdapterConfiguration
+  #
+  # @api private
+  WINDOWS_LABEL_WMI_MAP = {
+      :ipaddress => 'IPAddress',
+      :ipaddress6 => 'IPAddress',
+      :macaddress => 'MACAddress',
+      :netmask => 'IPSubnet'
+  }
+
+  def self.to_s
+    'windows'
+  end
+
+  # Windows doesn't display netmask in hex.
+  #
+  # @return [Boolean] false by default
+  #
+  # @api private
+  def self.convert_netmask_from_hex?
+    false
+  end
+
+  # Retrieves a list of unique interfaces names.
+  #
+  # @return [Array<String>]
+  #
+  # @api private
+  def self.interfaces
+    interface_names = []
+
+    network_adapter_configurations.map do |nic|
+      Facter::Util::WMI.execquery("SELECT * FROM Win32_NetworkAdapter WHERE Index = #{nic.Index} AND NetEnabled = TRUE").each do |sub_nic|
+        interface_names << sub_nic.NetConnectionId unless sub_nic.NetConnectionId.nil? or sub_nic.NetConnectionId.empty?
+      end
+    end
+
+    interface_names.uniq
+  end
+
+  # Get the value of an interface and label. For example, you may want to find
+  # the MTU for eth0.
+  #
+  # @param [String] interface the name of the interface returned by the {#interfaces} method.
+  # @param [String] label the type of value to return, e.g. ipaddress
+  # @return [String] the value, or nil if not defined
+  #
+  # @api private
+  def self.value_for_interface_and_label(interface, label)
+    wmi_value = WINDOWS_LABEL_WMI_MAP[label.downcase.to_sym]
+    label_value = nil
+    Facter::Util::WMI.execquery("SELECT Index FROM Win32_NetworkAdapter WHERE NetConnectionID = '#{interface}'").each do |nic|
+      Facter::Util::WMI.execquery("SELECT #{wmi_value} FROM Win32_NetworkAdapterConfiguration WHERE Index = #{nic.Index}").each do |nic_config|
+        case label.downcase.to_sym
+        when :ipaddress
+          nic_config.IPAddress.any? do |addr|
+            label_value = addr if valid_ipv4_address?(addr)
+            label_value
+          end
+        when :ipaddress6
+          nic_config.IPAddress.any? do |addr|
+            label_value = addr if Facter::Util::IP::Windows.valid_ipv6_address?(addr)
+            label_value
+          end
+        when :netmask
+          nic_config.IPSubnet.any? do |addr|
+            label_value = addr if Facter::Util::IP::Windows.valid_ipv4_address?(addr)
+            label_value
+          end
+        when :macaddress
+          label_value = nic_config.MACAddress
+        end
+      end
+    end
+
+    label_value
+  end
+
+  # Returns an array of partial Win32_NetworkAdapterConfiguration objects.
+  #
+  # @return [Array<WIN32OLE>] objects
+  #
+  # @api private
+  def self.network_adapter_configurations
+    nics = []
+    # WIN32OLE doesn't implement Enumerable
+    Facter::Util::WMI.execquery(WMI_IP_INFO_QUERY).each do |nic|
+      nics << nic
+    end
+    nics
+  end
+
+  # Gets a list of active IPv4 network adapter configurations sorted by the
+  # lowest IP connection metric. If two configurations have the same metric,
+  # then the IPv4 specific binding order as specified in the registry will
+  # be used.
+  #
+  # @return [Array<WIN32OLE>]
+  #
+  # @api private
+  def self.get_preferred_ipv4_adapters
+    get_preferred_network_adapters(Bindings4.new)
+  end
+
+  # Gets a list of active IPv6 network adapter configurations sorted by the
+  # lowest IP connection metric. If two configurations have the same metric,
+  # then the IPv6 specific binding order as specified in the registry will
+  # be used.
+  #
+  # @return [Array<WIN32OLE>]
+  #
+  # @api private
+  def self.get_preferred_ipv6_adapters
+    get_preferred_network_adapters(Bindings6.new)
+  end
+
+  # Gets a list of active network adapter configurations sorted by the lowest
+  # IP connection metric. If two configurations have the same metric, then
+  # the adapter binding order as specified in the registry will be used.
+  # Note the order may different for IPv4 vs IPv6 addresses.
+  #
+  # @see http://support.microsoft.com/kb/894564
+  # @return [Array<WIN32OLE>]
+  #
+  # @api private
+  def self.get_preferred_network_adapters(bindings)
+    network_adapter_configurations.select do |nic|
+      bindings.bindings.include?(nic.SettingID)
+    end.sort do |nic_left,nic_right|
+      cmp = nic_left.IPConnectionMetric <=> nic_right.IPConnectionMetric
+      if cmp == 0
+        bindings.bindings[nic_left.SettingID] <=> bindings.bindings[nic_right.SettingID]
+      else
+        cmp
+      end
+    end
+  end
+
+  class Bindings4
+    def initialize
+      @key = 'SYSTEM\CurrentControlSet\Services\Tcpip\Linkage'
+    end
+
+    def bindings
+      require 'facter/util/registry'
+      bindings = {}
+
+      Facter::Util::Registry.hklm_read(@key, 'Bind').each_with_index do |entry, index|
+        match_data = entry.match(/\\Device\\(\{.*\})/)
+        unless match_data.nil?
+          bindings[match_data[1]] = index
+        end
+      end
+
+      bindings
+    rescue
+      {}
+    end
+  end
+
+  class Bindings6 < Bindings4
+    def initialize
+      @key = 'SYSTEM\CurrentControlSet\Services\Tcpip6\Linkage'
+    end
+  end
+
+  # Determines if the value passed in is a valid ipv4 address.
+  #
+  # @param [String] ip_address the IPv4 address to validate
+  # @return [Boolean]
+  #
+  # @api private
+  def self.valid_ipv4_address?(ip_address)
+    String(ip_address).scan(/(?:[0-9]{1,3}\.){3}[0-9]{1,3}/).each do |match|
+      # excluding 169.254.x.x in Windows - this is the DHCP APIPA
+      #  meaning that if the node cannot get an ip address from the dhcp server,
+      #  it auto-assigns a private ip address
+      unless match == "127.0.0.1" or match =~ /^169.254.*/
+        return !!match
+      end
+    end
+
+    false
+  end
+
+  # Determines if the value passed in is a valid ipv6 address.
+  #
+  # @param [String] ip_address the IPv6 address to validate
+  # @return [Boolean]
+  #
+  # @api private
+  def self.valid_ipv6_address?(ip_address)
+    String(ip_address).scan(/(?>[0-9,a-f,A-F]*\:{1,2})+[0-9,a-f,A-F]{0,4}/).each do |match|
+      unless match =~ /fe80.*/ or match == "::1"
+        return !!match
+      end
+    end
+
+    false
+  end
+
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/loader.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/loader.rb
new file mode 100644
index 0000000..37dd177
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/loader.rb
@@ -0,0 +1,155 @@
+require 'facter'
+require 'pathname'
+require 'facter/util/directory_loader'
+
+# Load facts on demand.
+class Facter::Util::Loader
+
+  def initialize(environment_vars = ENV)
+    @loaded = []
+    @environment_vars = environment_vars
+  end
+
+  # Load all resolutions for a single fact.
+  #
+  # @api public
+  # @param name [Symbol]
+  def load(fact)
+    # Now load from the search path
+    shortname = fact.to_s.downcase
+    load_env(shortname)
+
+    filename = shortname + ".rb"
+
+    paths = search_path
+    unless paths.nil?
+      paths.each do |dir|
+        # Load individual files
+        file = File.join(dir, filename)
+
+        load_file(file) if File.file?(file)
+      end
+    end
+  end
+
+  # Load all facts from all directories.
+  #
+  # @api public
+  def load_all
+    return if defined?(@loaded_all)
+
+    load_env
+
+    paths = search_path
+    unless paths.nil?
+      paths.each do |dir|
+        # dir is already an absolute path
+        Dir.glob(File.join(dir, '*.rb')).each do |path|
+          # exclude dirs that end with .rb
+          load_file(path) if File.file?(path)
+        end
+      end
+    end
+
+    @loaded_all = true
+  end
+
+  # List directories to search for fact files.
+  #
+  # Search paths are gathered from the following sources:
+  #
+  # 1. $LOAD_PATH entries are expanded to absolute paths
+  # 2. ENV['FACTERLIB'] is split and used verbatim
+  # 3. Entries from Facter.search_path are used verbatim
+  #
+  # A warning will be generated for paths in Facter.search_path that are not
+  # absolute directories.
+  #
+  # @api public
+  # @return [Array<String>]
+  def search_path
+    search_paths = []
+    search_paths += $LOAD_PATH.map { |path| File.expand_path('facter', path) }
+
+    if @environment_vars.include?("FACTERLIB")
+      search_paths += @environment_vars["FACTERLIB"].split(File::PATH_SEPARATOR)
+    end
+
+    search_paths.delete_if { |path| ! valid_search_path?(path) }
+
+    Facter.search_path.each do |path|
+      if valid_search_path?(path)
+        search_paths << path
+      else
+        Facter.warn "Excluding #{path} from search path. Fact file paths must be an absolute directory"
+      end
+    end
+
+    search_paths.delete_if { |path| ! File.directory?(path) }
+
+    search_paths.uniq
+  end
+
+  private
+
+  # Validate that the given path is valid, ie it is an absolute path.
+  #
+  # @api private
+  # @param path [String]
+  # @return [Boolean]
+  def valid_search_path?(path)
+    Pathname.new(path).absolute?
+  end
+
+  # Load a file and record is paths to prevent duplicate loads.
+  #
+  # @api private
+  # @params file [String] The *absolute path* to the file to load
+  def load_file(file)
+    return if @loaded.include? file
+
+    # We have to specify Kernel.load, because we have a load method.
+    begin
+      # Store the file path so we don't try to reload it
+      @loaded << file
+      kernel_load(file)
+    rescue ScriptError => detail
+      # Don't store the path if the file can't be loaded
+      # in case it's loadable later on.
+      @loaded.delete(file)
+      Facter.log_exception(detail, "Error loading fact #{file}: #{detail.message}")
+    end
+  end
+
+  # Load and execute the Ruby program specified in the file. This exists
+  # for testing purposes.
+  #
+  # @api private
+  # @return [Boolean]
+  def kernel_load(file)
+    Kernel.load(file)
+  end
+
+  # Load facts from the environment.  If no name is provided,
+  # all will be loaded.
+  def load_env(fact = nil)
+    # Load from the environment, if possible
+    @environment_vars.each do |name, value|
+      # Skip anything that doesn't match our regex.
+      next unless name =~ /^facter_?(\w+)$/i
+      env_name = $1
+
+      # If a fact name was specified, skip anything that doesn't
+      # match it.
+      next if fact and env_name != fact
+
+      Facter.add($1) do
+        has_weight 1_000_000
+        setcode { value }
+      end
+
+      # Short-cut, if we are only looking for one value.
+      break if fact
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/macaddress.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/macaddress.rb
new file mode 100644
index 0000000..2848672
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/macaddress.rb
@@ -0,0 +1,43 @@
+# A module to gather macaddress facts
+#
+module Facter::Util::Macaddress
+
+  def self.standardize(macaddress)
+    return nil unless macaddress
+    macaddress.split(":").map{|x| "0#{x}"[-2..-1]}.join(":")
+  end
+
+  module Darwin
+    def self.macaddress
+      iface = default_interface
+      Facter.warn "Could not find a default route. Using first non-loopback interface" if iface.empty?
+
+      macaddress = `#{ifconfig_command} #{iface} | /usr/bin/awk '/ether/{print $2;exit}'`.chomp
+      macaddress.empty? ? nil : macaddress
+    end
+
+    def self.default_interface
+      `#{netstat_command} | /usr/bin/awk  '/^default/{print $6;exit}'`.chomp
+    end
+
+    private
+
+    def self.netstat_command
+      '/usr/sbin/netstat -rn'
+    end
+
+    def self.ifconfig_command
+      '/sbin/ifconfig'
+    end
+  end
+
+  module Windows
+    def macaddress
+      require 'facter/util/ip/windows'
+
+      adapter = Facter::Util::IP::Windows.get_preferred_ipv4_adapters.first
+      adapter ? adapter.MACAddress : nil
+    end
+    module_function :macaddress
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/macosx.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/macosx.rb
new file mode 100644
index 0000000..42e0f72
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/macosx.rb
@@ -0,0 +1,73 @@
+## macosx.rb
+## Support methods for Apple OSX facts
+##
+## Copyright (C) 2007 Jeff McCune
+## Author: Jeff McCune <jeff.mccune@northstarlabs.net>
+##
+
+module Facter::Util::Macosx
+  require 'cfpropertylist'
+  require 'facter/util/resolution'
+
+  Plist_Xml_Doctype  = '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'
+
+  # JJM I'd really like to dynamically generate these methods
+  # by looking at the _name key of the _items dict for each _dataType
+
+  def self.profiler_xml(data_field)
+    Facter::Core::Execution.exec("/usr/sbin/system_profiler -xml #{data_field} 2>/dev/null")
+  end
+
+  def self.intern_xml(xml)
+    return nil unless xml
+    bad_xml_doctype = /^.*<!DOCTYPE plist PUBLIC -\/\/Apple Computer.*$/
+    if xml =~ bad_xml_doctype
+      xml.gsub!( bad_xml_doctype, Plist_Xml_Doctype )
+      Facter.debug("Had to fix plist with incorrect DOCTYPE declaration")
+    end
+    plist = CFPropertyList::List.new
+    begin
+      plist.load_str(xml)
+    rescue CFFormatError => e
+      raise RuntimeError, "A plist file could not be properly read by CFPropertyList: #{e.message}", e.backtrace
+    end
+    CFPropertyList.native_types(plist.value)
+  end
+
+  # Return an xml result, modified as we need it.
+  def self.profiler_data(data_field)
+    begin
+      return nil unless parsed_xml = intern_xml(profiler_xml(data_field))
+      return nil unless data = parsed_xml[0]['_items'][0]
+      data.delete '_name'
+      data
+    rescue
+      return nil
+    end
+  end
+
+  def self.hardware_overview
+    profiler_data("SPHardwareDataType")
+  end
+
+  def self.os_overview
+    profiler_data("SPSoftwareDataType")
+  end
+
+  def self.sw_vers
+    ver = Hash.new
+    [ "productName", "productVersion", "buildVersion" ].each do |option|
+      ver["macosx_#{option}"] = Facter::Core::Execution.exec("/usr/bin/sw_vers -#{option}").strip
+    end
+    productversion = ver["macosx_productVersion"]
+    if not productversion.nil?
+      versions = productversion.scan(/(\d+)\.(\d+)\.*(\d*)/)[0]
+      ver["macosx_productversion_major"] = "#{versions[0]}.#{versions[1]}"
+      if versions[2].empty?  # 10.x should be treated as 10.x.0
+        versions[2] = "0"
+      end
+      ver["macosx_productversion_minor"] = versions[2]
+    end
+    ver
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/manufacturer.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/manufacturer.rb
new file mode 100644
index 0000000..2d82306
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/manufacturer.rb
@@ -0,0 +1,99 @@
+# mamufacturer.rb
+# Support methods for manufacturer specific facts
+
+require 'facter/util/posix'
+
+module Facter::Manufacturer
+  def self.get_dmi_table()
+    case Facter.value(:kernel)
+    when 'Linux', 'GNU/kFreeBSD'
+      cmd = '/usr/sbin/dmidecode'
+    when 'FreeBSD'
+      cmd = '/usr/local/sbin/dmidecode'
+    when 'NetBSD', 'DragonFly'
+      cmd = '/usr/pkg/sbin/dmidecode'
+    when 'SunOS'
+      cmd = '/usr/sbin/smbios'
+    end
+
+    if cmd and (output = Facter::Core::Execution.exec("#{cmd} 2>/dev/null"))
+
+      if output.respond_to?(:force_encoding)
+        output.force_encoding(Encoding::ASCII_8BIT)
+      end
+
+      return output
+    end
+  end
+
+  def self.dmi_find_system_info(name)
+    splitstr=  Facter.value(:kernel) ==  'SunOS' ? "ID  SIZE TYPE" : /^Handle/
+    output = self.get_dmi_table()
+    return if output.nil?
+    name.each_pair do |key,v|
+      v.each do |v2|
+        v2.each_pair do |value,facterkey|
+          output.split(splitstr).each do |line|
+            if line =~ /#{key}/ and line =~ /\n\s+#{value} (.+)\n/
+              result = $1.strip
+              Facter.add(facterkey) do
+                confine :kernel => [ :linux, :freebsd, :netbsd, :sunos, :"gnu/kfreebsd", :dragonfly ]
+                setcode do
+                  result
+                end
+              end
+            end
+          end
+        end
+      end
+    end
+  end
+
+  def self.sysctl_find_system_info(name)
+    name.each do |sysctlkey,facterkey|
+      Facter.add(facterkey) do
+        confine :kernel => [:openbsd, :darwin]
+        setcode { Facter::Util::POSIX.sysctl(sysctlkey) }
+      end
+    end
+  end
+
+  def self.prtdiag_sparc_find_system_info()
+    # Parses prtdiag for a SPARC architecture string, won't work with Solaris x86
+    output = Facter::Core::Execution.exec('/usr/sbin/prtdiag 2>/dev/null | /usr/bin/head -n 10')
+
+    # System Configuration:  Sun Microsystems  sun4u Sun SPARC Enterprise M3000 Server
+    if output and output =~ /^System Configuration:\s+(.+?)\s+(sun\d+\S+)\s+(.+)/
+      Facter.add('manufacturer') do
+        setcode do
+          $1
+        end
+      end
+      Facter.add('productname') do
+        setcode do
+          $3
+        end
+      end
+    end
+
+    Facter.add('serialnumber') do
+      setcode "/usr/sbin/sneep"
+    end
+  end
+
+  def self.win32_find_system_info(name)
+    require 'facter/util/wmi'
+    value = ""
+    wmi = Facter::Util::WMI.connect()
+    name.each do |facterkey, win32key|
+      query = wmi.ExecQuery("select * from Win32_#{win32key.last}")
+      Facter.add(facterkey) do
+        confine :kernel => :windows
+        setcode do
+          query.each { |x| value = x.__send__( (win32key.first).to_sym) }
+          value
+        end
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/memory.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/memory.rb
new file mode 100644
index 0000000..8b2b2ad
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/memory.rb
@@ -0,0 +1,228 @@
+## memory.rb
+## Support module for memory related facts
+##
+
+require 'facter/util/posix'
+
+module Facter::Memory
+  def self.meminfo_number(tag)
+    memsize = ""
+    size = [0]
+    File.readlines("/proc/meminfo").each do |l|
+      size = $1.to_f if l =~ /^#{tag}:\s+(\d+)\s+\S+/
+      if tag == "MemFree" &&
+          l =~ /^(?:Buffers|Cached):\s+(\d+)\s+\S+/
+        size += $1.to_f
+      end
+    end
+    size / 1024.0
+  end
+
+  def self.scale_number(size, multiplier)
+    suffixes = ['', 'kB', 'MB', 'GB', 'TB']
+
+    s = suffixes.shift
+    while s != multiplier
+      s = suffixes.shift
+    end
+
+    while size > 1024.0
+      size /= 1024.0
+      s = suffixes.shift
+    end
+
+    "%.2f %s" % [size, s]
+  end
+
+  def self.vmstat_find_free_memory(args = [])
+    cmd = 'vmstat'
+    cmd += (' ' + args.join(' ')) unless args.empty?
+    row = Facter::Core::Execution.exec(cmd).split("\n")[-1]
+    if row =~ /^\s*\d+\s*\d+\s*\d+\s*\d+\s*(\d+)/
+      memfree = $1
+    end
+  end
+
+  # Darwin had to be different. It's generally opaque with how much RAM it is
+  # using, and this figure could be improved upon too I fear.
+  # Parses the output of "vm_stat", takes the pages free & pages speculative
+  # and multiples that by the page size (also given in output). Ties in with
+  # what activity monitor outputs for free memory.
+  def self.vmstat_darwin_find_free_memory()
+
+    memfree = 0
+    pagesize = 0
+    memspecfree = 0
+
+    vmstats = Facter::Core::Execution.exec('vm_stat')
+    vmstats.each_line do |vmline|
+      case
+      when vmline =~ /page\ssize\sof\s(\d+)\sbytes/
+        pagesize = $1.to_i
+      when vmline =~ /^Pages\sfree:\s+(\d+)\./
+        memfree = $1.to_i
+      when vmline =~ /^Pages\sspeculative:\s+(\d+)\./
+        memspecfree = $1.to_i
+      end
+    end
+
+    freemem = ( memfree + memspecfree ) * pagesize
+  end
+
+  # on AIX use svmon to get the free memory:
+  # it's the third value on the line starting with memory
+  # svmon can be run by non root users
+  def self.svmon_aix_find_free_memory()
+    Facter::Core::Execution.exec("/usr/bin/svmon -O unit=KB") =~ /^memory\s+\d+\s+\d+\s+(\d+)\s+/
+    $1
+  end
+
+  def self.mem_free(kernel = Facter.value(:kernel))
+    output = mem_free_info(kernel)
+    scale_mem_free_value output, kernel
+  end
+
+  def self.mem_free_info(kernel = Facter.value(:kernel))
+    case kernel
+    when /OpenBSD/i, /SunOS/i, /Dragonfly/i
+      vmstat_find_free_memory()
+    when /FreeBSD/i
+      vmstat_find_free_memory(["-H"])
+    when /Darwin/i
+      vmstat_darwin_find_free_memory()
+    when /AIX/i
+      svmon_aix_find_free_memory()
+    end
+  end
+
+  def self.scale_mem_free_value (value, kernel)
+    case kernel
+    when /OpenBSD/i, /FreeBSD/i, /SunOS/i, /Dragonfly/i, /AIX/i
+      value.to_f / 1024.0
+    when /Darwin/i
+      value.to_f / 1024.0 / 1024.0
+    else
+      value.to_f
+    end
+ end
+
+  def self.mem_size(kernel = Facter.value(:kernel))
+    output = mem_size_info(kernel)
+    scale_mem_size_value output, kernel
+  end
+
+  def self.mem_size_info(kernel = Facter.value(:kernel))
+    case kernel
+    when /Dragonfly/i, /FreeBSD/i, /OpenBSD/i
+      Facter::Util::POSIX.sysctl("hw.physmem")
+    when /Darwin/i
+      Facter::Util::POSIX.sysctl("hw.memsize")
+    when /AIX/i
+      if Facter::Core::Execution.exec("/usr/bin/svmon -O unit=KB") =~ /^memory\s+(\d+)\s+/
+        $1
+      end
+    end
+  end
+
+  def self.scale_mem_size_value(value, kernel)
+    case kernel
+    when /OpenBSD/i, /FreeBSD/i, /Darwin/i, /Dragonfly/i
+      value.to_f / 1024.0 / 1024.0
+    when /AIX/i
+      value.to_f / 1024.0
+    else
+      value.to_f
+    end
+  end
+
+  def self.swap_size(kernel = Facter.value(:kernel))
+    output = swap_info(kernel)
+    parse_swap output, kernel, :size if output
+  end
+
+  def self.swap_free(kernel = Facter.value(:kernel))
+    output = swap_info(kernel)
+    parse_swap output, kernel, :free if output
+  end
+
+  def self.swap_info(kernel = Facter.value(:kernel))
+    case kernel
+    when /AIX/i
+      (Facter.value(:id) == "root") ? Facter::Core::Execution.exec('swap -l 2>/dev/null') : nil
+    when /OpenBSD/i
+      Facter::Core::Execution.exec('swapctl -s')
+    when /FreeBSD/i
+      Facter::Core::Execution.exec('swapinfo -k')
+    when /Darwin/i
+      Facter::Util::POSIX.sysctl('vm.swapusage')
+    when /SunOS/i
+      Facter::Core::Execution.exec('/usr/sbin/swap -l 2>/dev/null')
+    end
+  end
+
+  def self.parse_swap (output, kernel = Facter.value(:kernel), size_or_free = :size)
+    value_in_mb = 0.0
+    value = 0
+    is_size = size_or_free == :size
+    unless output.nil?
+      output.each_line do |line|
+        value += parse_swap_line(line, kernel, is_size)
+      end
+    end      
+    value_in_mb = scale_swap_value(value, kernel)
+  end
+
+  # There is a lot of duplication here because of concern over being able to add
+  # new platforms in a reasonable manner. For all of these platforms the first
+  # regex corresponds to the swap size value and the second corresponds to the swap
+  # free value, but this may not always be the case. In Ruby 1.9.3 it is possible
+  # to give these names, but sadly 1.8.7 does not support this.
+ 
+  def self.parse_swap_line(line, kernel, is_size)
+    case kernel
+    when /AIX/i
+      if line =~ /^\/\S+\s.*\s+(\S+)MB\s+(\S+)MB/
+        (is_size) ? $1.to_i : $2.to_i
+      else
+        0
+      end
+    when /OpenBSD/i
+      if line =~ /^total: (\d+) (\d+)-blocks allocated, (\d+) used, (\d+) available$/
+        (is_size) ? ($1.to_i * $2.to_i) : ($4.to_i * $2.to_i)
+      else
+        0
+      end
+    when /FreeBSD/i
+      if line =~ /\S+\s+(\d+)\s+\d+\s+(\d+)\s+\d+%$/
+        (is_size) ? $1.to_i : $2.to_i
+      else
+        0
+      end
+    when /Darwin/i
+      if line =~ /total\s=\s(\S+)M\s+used\s=\s\S+M\s+free\s=\s(\S+)M\s/
+        (is_size) ? $1.to_i : $2.to_i
+      else
+        0
+      end
+    when /SunOS/i
+      if line =~ /^\S+\s.*\s+(\d+)\s+(\d+)$/
+        (is_size) ? $1.to_i : $2.to_i
+      else
+        0
+      end
+    end
+  end
+
+  def self.scale_swap_value(value, kernel)
+    case kernel
+    when /FreeBSD/i
+      value.to_f / 1024.0
+    when /OpenBSD/i
+      value.to_f / 1024.0 / 1024.0
+    when /SunOS/i
+      value.to_f / 2 / 1024.0
+    else
+      value.to_f
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/netmask.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/netmask.rb
new file mode 100644
index 0000000..4c4cf01
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/netmask.rb
@@ -0,0 +1,40 @@
+module Facter::NetMask
+  def self.get_netmask
+    netmask = nil;
+    ipregex = %r{(\d{1,3}\.){3}\d{1,3}}
+
+    ops = nil
+    case Facter.value(:kernel)
+    when 'Linux'
+      ops = {
+        :ifconfig_opts => ['2>/dev/null'],
+        :regex => %r{#{Facter.value(:ipaddress)}.*?(?:Mask:|netmask)\s*(#{ipregex})}x,
+        :munge => nil,
+      }
+    when 'SunOS'
+      ops = {
+        :ifconfig_opts => ['-a'],
+        :regex => %r{\s+ inet \s #{Facter.value(:ipaddress)} \s netmask \s (\w{8})}x,
+        :munge => Proc.new { |mask| mask.scan(/../).collect do |byte| byte.to_i(16) end.join('.') }
+      }
+    when 'FreeBSD','NetBSD','OpenBSD', 'Darwin', 'GNU/kFreeBSD', 'DragonFly', 'AIX'
+      ops = {
+        :ifconfig_opts => ['-a'],
+        :regex => %r{\s+ inet \s #{Facter.value(:ipaddress)} \s netmask \s 0x(\w{8})}x,
+        :munge => Proc.new { |mask| mask.scan(/../).collect do |byte| byte.to_i(16) end.join('.') }
+      }
+    end
+
+    String(Facter::Util::IP.exec_ifconfig(ops[:ifconfig_opts])).split(/\n/).collect do |line|
+      matches = line.match(ops[:regex])
+      if !matches.nil?
+        if ops[:munge].nil?
+          netmask = matches[1]
+        else
+          netmask = ops[:munge].call(matches[1])
+        end
+      end
+    end
+    netmask
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/normalization.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/normalization.rb
new file mode 100644
index 0000000..f3149f6
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/normalization.rb
@@ -0,0 +1,94 @@
+module Facter
+  module Util
+    module Normalization
+      class NormalizationError < StandardError; end
+
+      VALID_TYPES = [Integer, Float, TrueClass, FalseClass, NilClass, String, Array, Hash]
+
+      module_function
+
+      # Recursively normalize the given data structure
+      #
+      # @api public
+      # @raise [NormalizationError] If the data structure contained an invalid element.
+      # @return [void]
+      def normalize(value)
+        case value
+        when Integer, Float, TrueClass, FalseClass, NilClass
+          value
+        when String
+          normalize_string(value)
+        when Array
+          normalize_array(value)
+        when Hash
+          normalize_hash(value)
+        else
+          raise NormalizationError, "Expected #{value} to be one of #{VALID_TYPES.inspect}, but was #{value.class}"
+        end
+      end
+
+      # @!method normalize_string(value)
+      #
+      # Attempt to normalize and validate the given string.
+      #
+      # On Ruby 1.8 the string is checked by stripping out all non UTF-8
+      # characters and comparing the converted string to the original. If they
+      # do not match then the string is considered invalid.
+      #
+      # On Ruby 1.9+, the string is validate by checking that the string encoding
+      # is UTF-8 and that the string content matches the encoding. If the string
+      # is not an expected encoding then it is converted to UTF-8.
+      #
+      # @api public
+      # @raise [NormalizationError] If the string used an unsupported encoding or did not match its encoding
+      # @param value [String]
+      # @return [void]
+
+      if RUBY_VERSION =~ /^1\.8/
+        require 'iconv'
+
+        def normalize_string(value)
+          converted = Iconv.conv('UTF-8//IGNORE', 'UTF-8', value)
+          if converted != value
+            raise NormalizationError, "String #{value.inspect} is not valid UTF-8"
+          end
+          value
+        end
+      else
+        def normalize_string(value)
+          value = value.encode(Encoding::UTF_8)
+
+          unless value.valid_encoding?
+            raise NormalizationError, "String #{value.inspect} doesn't match the reported encoding #{value.encoding}"
+          end
+
+          value
+        rescue EncodingError
+          raise NormalizationError, "String encoding #{value.encoding} is not UTF-8 and could not be converted to UTF-8"
+        end
+      end
+
+      # Validate all elements of the array.
+      #
+      # @api public
+      # @raise [NormalizationError] If one of the elements failed validation
+      # @param value [Array]
+      # @return [void]
+      def normalize_array(value)
+        value.collect do |elem|
+          normalize(elem)
+        end
+      end
+
+      # Validate all keys and values of the hash.
+      #
+      # @api public
+      # @raise [NormalizationError] If one of the keys or values failed normalization
+      # @param value [Hash]
+      # @return [void]
+      def normalize_hash(value)
+        Hash[value.collect { |k, v| [ normalize(k), normalize(v) ] } ]
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/nothing_loader.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/nothing_loader.rb
new file mode 100644
index 0000000..e700aa1
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/nothing_loader.rb
@@ -0,0 +1,12 @@
+module Facter
+  module Util
+
+    # An external fact loader that doesn't load anything
+    # This makes it possible to disable loading
+    # of external facts
+    class NothingLoader
+      def load(collection)
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/operatingsystem.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/operatingsystem.rb
new file mode 100644
index 0000000..13f2ca6
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/operatingsystem.rb
@@ -0,0 +1,21 @@
+module Facter
+  module Util
+    module Operatingsystem
+
+      # @see http://www.freedesktop.org/software/systemd/man/os-release.html
+      def self.os_release(file = '/etc/os-release')
+        values = {}
+
+        if File.readable?(file)
+          File.readlines(file).each do |line|
+            if (match = line.match(/^(\w+)=["']?(.+?)["']?$/))
+              values[match[1]] = match[2]
+            end
+          end
+        end
+
+        values
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/parser.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/parser.rb
new file mode 100644
index 0000000..47f75f7
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/parser.rb
@@ -0,0 +1,168 @@
+# This class acts as the factory and parent class for parsed
+# facts such as scripts, text, json and yaml files.
+#
+# Parsers must subclass this class and provide their own #results method.
+require 'facter'
+require 'yaml'
+
+module Facter::Util::Parser
+  @parsers = []
+
+  # For support mutliple extensions you can pass an array of extensions as
+  # +ext+.
+  def self.extension_matches?(filename, ext)
+    extension = case ext
+    when String
+      ext.downcase
+    when Enumerable
+      ext.collect {|x| x.downcase }
+    end
+    [extension].flatten.to_a.include?(file_extension(filename).downcase)
+  end
+
+  def self.file_extension(filename)
+    File.extname(filename).sub(".", '')
+  end
+
+  def self.register(klass, &suitable)
+    @parsers << [klass, suitable]
+  end
+
+  def self.parser_for(filename)
+    registration = @parsers.detect { |k| k[1].call(filename) }
+
+    if registration.nil?
+      NothingParser.new
+    else
+      registration[0].new(filename)
+    end
+  end
+
+  class Base
+    attr_reader :filename
+
+    def initialize(filename, content = nil)
+      @filename = filename
+      @content  = content
+    end
+
+    def content
+      @content ||= File.read(filename)
+    end
+
+    # results on the base class is really meant to be just an exception handler
+    # wrapper.
+    def results
+      parse_results
+    rescue Exception => detail
+      Facter.log_exception(detail, "Failed to handle #{filename} as #{self.class} facts: #{detail.message}")
+      nil
+    end
+
+    def parse_results
+      raise ArgumentError, "Subclasses must respond to parse_results"
+    end
+  end
+
+  module KeyValuePairOutputFormat
+    def self.parse(output)
+      return {} if output.nil?
+
+      result = {}
+      re = /^(.+?)=(.+)$/
+      output.each_line do |line|
+        if match_data = re.match(line.chomp)
+          result[match_data[1]] = match_data[2]
+        end
+      end
+      result
+    end
+  end
+
+  class YamlParser < Base
+    def parse_results
+      YAML.load(content)
+    end
+  end
+
+  register(YamlParser) do |filename|
+    extension_matches?(filename, "yaml")
+  end
+
+  class TextParser < Base
+    def parse_results
+      KeyValuePairOutputFormat.parse content
+    end
+  end
+
+  register(TextParser) do |filename|
+    extension_matches?(filename, "txt")
+  end
+
+  class JsonParser < Base
+    def parse_results
+      if Facter.json?
+        JSON.load(content)
+      else
+        Facter.warnonce "Cannot parse JSON data file #{filename} without the json library."
+        Facter.warnonce "Suggested next step is `gem install json` to install the json library."
+        nil
+      end
+    end
+  end
+
+  register(JsonParser) do |filename|
+    extension_matches?(filename, "json")
+  end
+
+  class ScriptParser < Base
+    def parse_results
+      KeyValuePairOutputFormat.parse Facter::Core::Execution.exec(quote(filename))
+    end
+
+    private
+
+    def quote(filename)
+      filename.index(' ') ? "\"#{filename}\"" : filename
+    end
+  end
+
+  register(ScriptParser) do |filename|
+    if Facter::Util::Config.is_windows?
+      extension_matches?(filename, %w{bat cmd com exe}) && File.file?(filename)
+    else
+      File.executable?(filename) && File.file?(filename) && ! extension_matches?(filename, %w{bat cmd com exe})
+    end
+  end
+
+  # Executes and parses the key value output of Powershell scripts
+  class PowershellParser < Base
+    # Returns a hash of facts from powershell output
+    def parse_results
+      powershell =
+        if File.exists?("#{ENV['SYSTEMROOT']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe")
+          "#{ENV['SYSTEMROOT']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe"
+        elsif File.exists?("#{ENV['SYSTEMROOT']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe")
+          "#{ENV['SYSTEMROOT']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe"
+        else
+          'powershell.exe'
+        end
+
+      shell_command = "\"#{powershell}\" -NoProfile -NonInteractive -NoLogo -ExecutionPolicy Bypass -File \"#{filename}\""
+      output = Facter::Core::Execution.exec(shell_command)
+      KeyValuePairOutputFormat.parse(output)
+    end
+  end
+
+  register(PowershellParser) do |filename|
+    Facter::Util::Config.is_windows? && extension_matches?(filename, "ps1") && File.file?(filename)
+  end
+
+  # A parser that is used when there is no other parser that can handle the file
+  # The return from results indicates to the caller the file was not parsed correctly.
+  class NothingParser
+    def results
+      nil
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/partitions.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/partitions.rb
new file mode 100644
index 0000000..adf9465
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/partitions.rb
@@ -0,0 +1,47 @@
+require 'facter/util/partitions/linux'
+require 'facter/util/partitions/openbsd'
+
+module Facter::Util::Partitions
+  IMPLEMENTATIONS = {
+    'Linux'   => Linux,
+    'OpenBSD' => OpenBSD,
+  }
+
+  module NoImplementation
+    def self.list
+      []
+    end
+  end
+
+  def self.implementation
+    IMPLEMENTATIONS[Facter.fact(:kernel).value] || NoImplementation
+  end
+
+  def self.list
+    implementation.list
+  end
+
+  def self.uuid(partition)
+    implementation.uuid(partition)
+  end
+
+  def self.size(partition)
+    implementation.size(partition)
+  end
+
+  def self.mount(partition)
+    implementation.mount(partition)
+  end
+
+  def self.filesystem(partition)
+    implementation.filesystem(partition)
+  end
+
+  def self.label(partition)
+    implementation.label(partition)
+  end
+
+  def self.available?
+    !self.list.empty?
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/partitions/linux.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/partitions/linux.rb
new file mode 100644
index 0000000..02dff3e
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/partitions/linux.rb
@@ -0,0 +1,71 @@
+module Facter::Util::Partitions
+  module Linux
+    # Only Linux 2.6+ kernels support sysfs which is required to easily get device details
+    SYSFS_BLOCK_DIRECTORY     = '/sys/block/'
+    DEVDISK_BY_UUID_DIRECTORY = '/dev/disk/by-uuid/'
+
+    def self.list
+      if File.exist?(SYSFS_BLOCK_DIRECTORY)
+        devices = Dir.entries(SYSFS_BLOCK_DIRECTORY).select { |d| File.exist?( SYSFS_BLOCK_DIRECTORY + d + "/device" ) }
+  
+        if devices.empty?
+          []
+        else
+          devices.collect do |device|
+            Dir.glob( SYSFS_BLOCK_DIRECTORY + device + "/#{device}*" ).collect do |d|
+              File.basename(d)
+            end
+          end.flatten
+        end
+      else
+        []
+      end
+    end
+
+    def self.uuid(partition)
+      uuid = nil
+      if File.exist?(DEVDISK_BY_UUID_DIRECTORY)
+        Dir.entries(DEVDISK_BY_UUID_DIRECTORY).each do |file|
+          qualified_file = File.join(DEVDISK_BY_UUID_DIRECTORY, file)
+
+          #A uuid is 16 octets long (RFC4122) which is 32hex chars + 4 '-'s
+          next unless file.length == 36
+          next unless File.symlink?(qualified_file)
+          next unless File.readlink(qualified_file).match(%r[(?:\.\./\.\./|/dev/)#{partition}$])
+
+          uuid = file
+        end
+      end
+      uuid
+    end
+
+    def self.size(partition)
+      read_size(partition)
+    end
+
+    def self.mount(partition)
+      if Facter::Core::Execution.which('mount')
+        Facter::Core::Execution.exec('mount').scan(/\/dev\/#{partition}\son\s(\S+)/).flatten.first
+      end
+    end
+
+    def self.filesystem(partition)
+      if Facter::Core::Execution.which('blkid')
+        Facter::Core::Execution.exec("blkid #{File.join('/dev', partition)}").scan(/TYPE="([^"]*)"/).flatten.first
+      end
+    end
+    
+    def self.label(partition)
+      if Facter::Core::Execution.which('blkid')
+        Facter::Core::Execution.exec("blkid #{File.join('/dev', partition)}").scan(/LABEL="([^"]*)"/).flatten.first
+      end
+    end
+    
+    private
+    def self.read_size(partition)
+      if device = partition.match(/(\D+)/)[1] and File.readable?(File.join(SYSFS_BLOCK_DIRECTORY, device, partition, 'size'))
+        File.read(File.join(SYSFS_BLOCK_DIRECTORY, device, partition, 'size')).chomp
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/partitions/openbsd.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/partitions/openbsd.rb
new file mode 100644
index 0000000..90c6a78
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/partitions/openbsd.rb
@@ -0,0 +1,40 @@
+module Facter::Util::Partitions
+  module OpenBSD
+    def self.list
+      Facter::Core::Execution.exec('df').scan(/\/dev\/(\S+)/).flatten
+    end
+
+    # On OpenBSD partitions don't have a UUID; disks have DUID but that's not
+    # compatible.
+    def self.uuid(partition)
+      nil
+    end
+
+    def self.mount(partition)
+      scan_mount(/\/dev\/#{partition}\son\s(\S+)/)
+    end
+
+    # Reported size is in 1K blocks
+    def self.size(partition)
+      scan_df(/\/dev\/#{partition}\s+(\S+)/)
+    end
+
+    def self.filesystem(partition)
+      scan_mount(/\/dev\/#{partition}\son\s\S+\stype\s(\S+)/)
+    end
+   
+    # On OpenBSD there are no labels for partitions
+    def self.label(partition)
+      nil
+    end
+
+    private
+    def self.scan_mount(scan_regex)
+      Facter::Core::Execution.exec('mount').scan(scan_regex).flatten.first
+    end
+
+    def self.scan_df(scan_regex)
+      Facter::Core::Execution.exec('df -k').scan(scan_regex).flatten.first
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/plist.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/plist.rb
new file mode 100644
index 0000000..32e9e2b
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/plist.rb
@@ -0,0 +1,24 @@
+#--
+##############################################################
+# Copyright 2006, Ben Bleything <ben@bleything.net> and      #
+# Patrick May <patrick@hexane.org>                           #
+#                                                            #
+# Distributed under the MIT license.                         #
+##############################################################
+#++
+# = Plist
+#
+# This is the main file for plist.  Everything interesting happens in Plist and Plist::Emit.
+
+require 'base64'
+require 'cgi'
+require 'stringio'
+
+require 'facter/util/plist/generator'
+require 'facter/util/plist/parser'
+
+module Plist
+  VERSION = '3.0.0'
+end
+
+# $Id: plist.rb 1781 2006-10-16 01:01:35Z luke $
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/plist/generator.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/plist/generator.rb
new file mode 100644
index 0000000..6cbc4b3
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/plist/generator.rb
@@ -0,0 +1,228 @@
+#--###########################################################
+# Copyright 2006, Ben Bleything <ben@bleything.net> and    #
+# Patrick May <patrick@hexane.org>               #
+#                              #
+# Distributed under the MIT license.             #
+##############################################################
+#++
+# See Plist::Emit.
+module Plist
+  # === Create a plist
+  # You can dump an object to a plist in one of two ways:
+  #
+  # * <tt>Plist::Emit.dump(obj)</tt>
+  # * <tt>obj.to_plist</tt>
+  #   * This requires that you mixin the <tt>Plist::Emit</tt> module, which is already done for +Array+ and +Hash+.
+  #
+  # The following Ruby classes are converted into native plist types:
+  #   Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time, true, false
+  # * +Array+ and +Hash+ are both recursive; their elements will be converted into plist nodes inside the <array> and <dict> containers (respectively).
+  # * +IO+ (and its descendants) and +StringIO+ objects are read from and their contents placed in a <data> element.
+  # * User classes may implement +to_plist_node+ to dictate how they should be serialized; otherwise the object will be passed to <tt>Marshal.dump</tt> and the result placed in a <data> element.
+  #
+  # For detailed usage instructions, refer to USAGE[link:files/docs/USAGE.html] and the methods documented below.
+  module Emit
+    # Helper method for injecting into classes.  Calls <tt>Plist::Emit.dump</tt> with +self+.
+    def to_plist(envelope = true)
+      return Plist::Emit.dump(self, envelope)
+    end
+
+    # Helper method for injecting into classes.  Calls <tt>Plist::Emit.save_plist</tt> with +self+.
+    def save_plist(filename)
+      Plist::Emit.save_plist(self, filename)
+    end
+
+    # The following Ruby classes are converted into native plist types:
+    #   Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time
+    #
+    # Write us (via RubyForge) if you think another class can be coerced safely into one of the expected plist classes.
+    #
+    # +IO+ and +StringIO+ objects are encoded and placed in <data> elements; other objects are <tt>Marshal.dump</tt>'ed unless they implement +to_plist_node+.
+    #
+    # The +envelope+ parameters dictates whether or not the resultant plist fragment is wrapped in the normal XML/plist header and footer.  Set it to false if you only want the fragment.
+    def self.dump(obj, envelope = true)
+      output = plist_node(obj)
+
+      output = wrap(output) if envelope
+
+      return output
+    end
+
+    # Writes the serialized object's plist to the specified filename.
+    def self.save_plist(obj, filename)
+      File.open(filename, 'wb') do |f|
+        f.write(Plist::Emit.dump(obj))
+      end
+    end
+
+    private
+    def self.plist_node(element)
+      output = ''
+
+      if element.respond_to? :to_plist_node
+        output << element.to_plist_node
+      else
+        case element
+        when Array
+          if element.empty?
+            output << "<array/>\n"
+          else
+            output << tag('array') {
+              element.collect {|e| plist_node(e)}
+            }
+          end
+        when Hash
+          if element.empty?
+            output << "<dict/>\n"
+          else
+            inner_tags = []
+
+            element.keys.sort.each do |k|
+              v = element[k]
+              inner_tags << tag('key', CGI::escapeHTML(k.to_s))
+              inner_tags << plist_node(v)
+            end
+
+            output << tag('dict') {
+              inner_tags
+            }
+          end
+        when true, false
+          output << "<#{element}/>\n"
+        when Time
+          output << tag('date', element.utc.strftime('%Y-%m-%dT%H:%M:%SZ'))
+        when Date # also catches DateTime
+          output << tag('date', element.strftime('%Y-%m-%dT%H:%M:%SZ'))
+        when String, Symbol, Fixnum, Bignum, Integer, Float
+          output << tag(element_type(element), CGI::escapeHTML(element.to_s))
+        when IO, StringIO
+          element.rewind
+          contents = element.read
+          # note that apple plists are wrapped at a different length then
+          # what ruby's base64 wraps by default.
+          # I used #encode64 instead of #b64encode (which allows a length arg)
+          # because b64encode is b0rked and ignores the length arg.
+          data = "\n"
+          Base64::encode64(contents).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" }
+          output << tag('data', data)
+        else
+          output << comment( 'The <data> element below contains a Ruby object which has been serialized with Marshal.dump.' )
+          data = "\n"
+          Base64::encode64(Marshal.dump(element)).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" }
+          output << tag('data', data )
+        end
+      end
+
+      return output
+    end
+
+    def self.comment(content)
+      return "<!-- #{content} -->\n"
+    end
+
+    def self.tag(type, contents = '', &block)
+      out = nil
+
+      if block_given?
+        out = IndentedString.new
+        out << "<#{type}>"
+        out.raise_indent
+
+        out << block.call
+
+        out.lower_indent
+        out << "</#{type}>"
+      else
+        out = "<#{type}>#{contents.to_s}</#{type}>\n"
+      end
+
+      return out.to_s
+    end
+
+    def self.wrap(contents)
+      output = ''
+
+      output << '<?xml version="1.0" encoding="UTF-8"?>' + "\n"
+      output << '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' + "\n"
+      output << '<plist version="1.0">' + "\n"
+
+      output << contents
+
+      output << '</plist>' + "\n"
+
+      return output
+    end
+
+    def self.element_type(item)
+      return case item
+      when String, Symbol;      'string'
+      when Fixnum, Bignum, Integer; 'integer'
+      when Float;           'real'
+      else
+        raise "Don't know about this data type... something must be wrong!"
+      end
+    end
+
+    private
+
+    class IndentedString #:nodoc:
+      attr_accessor :indent_string
+
+      @@indent_level = 0
+
+      def initialize(str = "\t")
+        @indent_string = str
+        @contents = ''
+      end
+
+      def to_s
+        return @contents
+      end
+
+      def raise_indent
+        @@indent_level += 1
+      end
+
+      def lower_indent
+        @@indent_level -= 1 if @@indent_level > 0
+      end
+
+      def <<(val)
+        if val.is_a? Array
+          val.each do |f|
+            self << f
+          end
+        else
+          # if it's already indented, don't bother indenting further
+          unless val =~ /\A#{@indent_string}/
+            indent = @indent_string * @@indent_level
+
+            @contents << val.gsub(/^/, indent)
+          else
+            @contents << val
+          end
+
+          # it already has a newline, don't add another
+          @contents << "\n" unless val =~ /\n$/
+        end
+      end
+    end
+  end
+end
+
+# we need to add this so sorting hash keys works properly
+class Symbol #:nodoc:
+  def <=> (other)
+    self.to_s <=> other.to_s
+  end
+end
+
+class Array #:nodoc:
+  include Plist::Emit
+end
+
+class Hash #:nodoc:
+  include Plist::Emit
+end
+
+# $Id: generator.rb 1781 2006-10-16 01:01:35Z luke $
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/plist/parser.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/plist/parser.rb
new file mode 100644
index 0000000..ffbb7ba
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/plist/parser.rb
@@ -0,0 +1,226 @@
+#--###########################################################
+# Copyright 2006, Ben Bleything <ben@bleything.net> and    #
+# Patrick May <patrick@hexane.org>               #
+#                              #
+# Distributed under the MIT license.             #
+##############################################################
+#++
+# Plist parses Mac OS X xml property list files into ruby data structures.
+#
+# === Load a plist file
+# This is the main point of the library:
+#
+#   r = Plist::parse_xml( filename_or_xml )
+module Plist
+# Note that I don't use these two elements much:
+#
+#  + Date elements are returned as DateTime objects.
+#  + Data elements are implemented as Tempfiles
+#
+# Plist::parse_xml will blow up if it encounters a data element.
+# If you encounter such an error, or if you have a Date element which
+# can't be parsed into a Time object, please send your plist file to
+# plist@hexane.org so that I can implement the proper support.
+  def Plist::parse_xml( filename_or_xml )
+    listener = Listener.new
+    #parser = REXML::Parsers::StreamParser.new(File.new(filename), listener)
+    parser = StreamParser.new(filename_or_xml, listener)
+    parser.parse
+    listener.result
+  end
+
+  class Listener
+    #include REXML::StreamListener
+
+    attr_accessor :result, :open
+
+    def initialize
+      @result = nil
+      @open   = Array.new
+    end
+
+
+    def tag_start(name, attributes)
+      @open.push PTag::mappings[name].new
+    end
+
+    def text( contents )
+      @open.last.text = contents if @open.last
+    end
+
+    def tag_end(name)
+      last = @open.pop
+      if @open.empty?
+        @result = last.to_ruby
+      else
+        @open.last.children.push last
+      end
+    end
+  end
+
+  class StreamParser
+    def initialize( filename_or_xml, listener )
+      @filename_or_xml = filename_or_xml
+      @listener = listener
+    end
+
+    TEXT      = /([^<]+)/
+    XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>*/um
+    DOCTYPE_PATTERN = /\s*<!DOCTYPE\s+(.*?)(\[|>)/um
+    COMMENT_START   = /\A<!--/u
+    COMMENT_END   = /.*?-->/um
+
+    def parse
+      plist_tags = PTag::mappings.keys.join('|')
+      start_tag  = /<(#{plist_tags})([^>]*)>/i
+      end_tag  = /<\/(#{plist_tags})[^>]*>/i
+
+      require 'strscan'
+
+      contents = (
+        if (File.exists? @filename_or_xml)
+          File.open(@filename_or_xml) {|f| f.read}
+        else
+          @filename_or_xml
+        end
+      )
+
+      @scanner = StringScanner.new( contents )
+      until @scanner.eos?
+        if @scanner.scan(COMMENT_START)
+          @scanner.scan(COMMENT_END)
+        elsif @scanner.scan(XMLDECL_PATTERN)
+        elsif @scanner.scan(DOCTYPE_PATTERN)
+        elsif @scanner.scan(start_tag)
+          @listener.tag_start(@scanner[1], nil)
+          if (@scanner[2] =~ /\/$/)
+            @listener.tag_end(@scanner[1])
+          end
+        elsif @scanner.scan(TEXT)
+          @listener.text(@scanner[1])
+        elsif @scanner.scan(end_tag)
+          @listener.tag_end(@scanner[1])
+        else
+          raise "Unimplemented element"
+        end
+      end
+    end
+  end
+
+  class PTag
+    @@mappings = { }
+    def PTag::mappings
+      @@mappings
+    end
+
+    def PTag::inherited( sub_class )
+      key = sub_class.to_s.downcase
+      key.gsub!(/^plist::/, '' )
+      key.gsub!(/^p/, '')  unless key == "plist"
+
+      @@mappings[key] = sub_class
+    end
+
+    attr_accessor :text, :children
+    def initialize
+      @children = Array.new
+    end
+
+    def to_ruby
+      raise "Unimplemented: " + self.class.to_s + "#to_ruby on #{self.inspect}"
+    end
+  end
+
+  class PList < PTag
+    def to_ruby
+      children.first.to_ruby if children.first
+    end
+  end
+
+  class PDict < PTag
+    def to_ruby
+      dict = Hash.new
+      key = nil
+
+      children.each do |c|
+        if key.nil?
+          key = c.to_ruby
+        else
+          dict[key] = c.to_ruby
+          key = nil
+        end
+      end
+
+      dict
+    end
+  end
+
+  class PKey < PTag
+    def to_ruby
+      CGI::unescapeHTML(text || '')
+    end
+  end
+
+  class PString < PTag
+    def to_ruby
+      CGI::unescapeHTML(text || '')
+    end
+  end
+
+  class PArray < PTag
+    def to_ruby
+      children.collect do |c|
+        c.to_ruby
+      end
+    end
+  end
+
+  class PInteger < PTag
+    def to_ruby
+      text.to_i
+    end
+  end
+
+  class PTrue < PTag
+    def to_ruby
+      true
+    end
+  end
+
+  class PFalse < PTag
+    def to_ruby
+      false
+    end
+  end
+
+  class PReal < PTag
+    def to_ruby
+      text.to_f
+    end
+  end
+
+  require 'date'
+  class PDate < PTag
+    def to_ruby
+      DateTime.parse(text)
+    end
+  end
+
+  require 'base64'
+  class PData < PTag
+    def to_ruby
+      data = Base64.decode64(text.gsub(/\s+/, ''))
+
+      begin
+        return Marshal.load(data)
+      rescue Exception => e
+        io = StringIO.new
+        io.write data
+        io.rewind
+        return io
+      end
+    end
+  end
+end
+
+# $Id: parser.rb 1781 2006-10-16 01:01:35Z luke $
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/posix.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/posix.rb
new file mode 100644
index 0000000..62c71a3
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/posix.rb
@@ -0,0 +1,16 @@
+module Facter
+module Util
+module POSIX
+  # Provides a consistent way of invoking sysctl(8) across POSIX platforms
+  #
+  # @param mib [String] the sysctl(8) MIB name
+  #
+  # @api private
+  def sysctl(mib)
+    Facter::Util::Resolution.exec("sysctl -n #{mib} 2>/dev/null")
+  end
+
+  module_function :sysctl
+end
+end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/processor.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/processor.rb
new file mode 100644
index 0000000..435b7d6
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/processor.rb
@@ -0,0 +1,289 @@
+module Facter
+module Util
+module Processor
+  ##
+  # aix_processor_list is intended to generate a list of values for the
+  # processorX facts.  The behavior is as follows from
+  # [#11609](http://projects.puppetlabs.com/issues/11609)
+  #
+  # 1. Take a list of all the processor identifiers for the platform,
+  #    represented as system-native identifiers in strings.
+  # 2. Sort the list
+  # 3. Assign an incrementing from 0 integer index to each identifier.
+  # 4. Store the value of the system identifier in the processorX fact where X
+  #    is the incrementing index.
+  #
+  # Returns an Array, sorted, containing the values for the facts.
+  def self.aix_processor_list
+    return_value = []
+    aix_proc_id_list = []
+
+    if output = lsdev then
+      output.split("\n").each do |line|
+        if match = line.match(/proc\d+/)
+          aix_proc_id_list << match[0]
+        end
+      end
+    end
+
+    # Generalized alphanumeric sort to put "proc12" behind "proc4"
+    padding = 8
+    aix_proc_id_list = aix_proc_id_list.sort do |a,b|
+      a,b = [a,b].map do |s|
+        s.gsub(/\d+/) { |m| "0"*(padding - m.size) + m }
+      end
+      a<=>b
+    end
+
+    aix_proc_id_list.each do |proc_id|
+      if output = lsattr("lsattr -El #{proc_id} -a type")
+        if match = output.match(/type\s+([^\s]+)\s+Processor/i)
+          return_value << match[1]
+        end
+      end
+    end
+
+    return_value
+  end
+
+  ##
+  # lsdev is intended to directly delegate to Facter::Core::Execution.exec in an
+  # effort to make the processorX facts easier to test by stubbing only the
+  # behaviors we need to stub to get the output of the system command.
+  def self.lsdev(command="lsdev -Cc processor")
+    Facter::Core::Execution.exec(command)
+  end
+
+  ##
+  # lsattr is intended to directly delegate to Facter::Core::Execution.exec in
+  # an effort to make the processorX facts easier to test.  See also the
+  # {lsdev} method.
+  def self.lsattr(command="lsattr -El proc0 -a type")
+    Facter::Core::Execution.exec(command)
+  end
+
+  ##
+  # kernel_fact_value is intended to directly delegate to Facter.value(:kernel)
+  # to make it easier to stub the kernel fact without affecting the entire
+  # system.
+  def self.kernel_fact_value
+    Facter.value(:kernel)
+  end
+
+  ##
+  # hpux_processor_list is intended to generate a list of values for the
+  # processorX facts.
+  def self.hpux_processor_list
+    return_value = []
+    hpux_proc_id_list = []
+    cpu = ""
+
+    ##
+    # first, try parsing machinfo output.
+    if output = machinfo then
+      output.split("\n").each do |line|
+        if line.match(/processor model:\s+\d+\s+(.*)/) then
+          cpu = $1.to_s
+        elsif line.match(/\d+\s+((?:PA-RISC|Intel).*processors.*)/) then
+          cpu = $1.to_s
+          cpu.sub!(/processors/, "processor")
+        elsif line.match(/\s+(Intel.*Processor.*)/) then
+          cpu = $1.to_s
+        end
+      end
+    end
+
+    ##
+    # if that fails, try looking using model command and cross referencing against
+    # sched.models, which could be in three places. This file only catered for
+    # PA-RISC. Unfortunately, the file is not up to date sometimes.
+    if cpu.empty? then
+      m = model
+      m.sub!(/\s+$/, "")
+      m.sub!(/.*\//, "")
+      m.sub!(/.*\s+/, "")
+
+      if sched_models_lines = read_sched_models
+        sched_models_lines.each do |l|
+          if l.match(m) and l.match(/^\S+\s+\d+\.\d+\s+(\S+)/) then
+            cpu = "PA-RISC " + $1.to_s.sub!(/^PA/, "") + " processor"
+            break # we assume first match is the only match.
+          end
+        end
+      end
+    end
+
+    ##
+    # if that also fails, report the CPU version based on unistd.h and chip type based on getconf.
+    if cpu.empty? then
+      cpu_version = getconf_cpu_version
+      cpu_chip_type = getconf_cpu_chip_type
+      cpu_string = ""
+
+      if lines = read_unistd_h("/usr/include/sys/unistd.h") then
+        lines.each do |l|
+          if l.match(/define.*0x#{cpu_version.to_i.to_s(16)}.*\/\*\s+(.*)\s+\*\//) then
+            cpu_string = $1.to_s
+            break
+          end
+        end
+      end
+
+      if cpu_string.empty? then
+        cpu_string = "CPU v" + cpu_version
+      end
+
+      cpu = cpu_string + " CHIP TYPE #" + cpu_chip_type
+    end
+
+    ##
+    # now count (logical) CPUs using ioscan. We set processorX for X in 0..processorcount
+    # to cpu as worked out above. HP-UX does not support more than one installed CPU
+    # model.
+    if output = ioscan then
+      output.split("\n").each do |line|
+        if line.match(/processor/) then
+          hpux_proc_id_list << cpu
+        end
+      end
+    end
+
+    hpux_proc_id_list
+  end
+
+  ##
+  # read_sched_models is intended to be stubbed instead of File.readlines
+  # @return [Array] of strings containing the lines of the file or nil if the
+  # sched.models file could not be located.
+  def self.read_sched_models
+    path = if File.exists?("/usr/lib/sched.models")
+             "/usr/lib/sched.models"
+           elsif File.exists?("/usr/sam/lib/mo/sched.models")
+             "/usr/sam/lib/mo/sched.models"
+           elsif File.exists?("/opt/langtools/lib/sched.models")
+             "/opt/langtools/lib/sched.models"
+           end
+
+    if path
+      File.readlines(path)
+    end
+  end
+  private_class_method :read_sched_models
+
+  ##
+  # read_unistd_h is intended to be stubbed instead of File.readlines
+  # @return [Array] of Strings or nil if the file does not exist.
+  def self.read_unistd_h(path)
+    if File.exists?(path) then
+      File.readlines(path)
+    end
+  end
+  private_class_method :read_unistd_h
+
+  ##
+  # machinfo delegates directly to Facter::Core::Execution.exec, as with lsdev
+  # above.
+  def self.machinfo(command="/usr/contrib/bin/machinfo")
+    Facter::Core::Execution.exec(command)
+  end
+
+  ##
+  # model delegates directly to Facter::Core::Execution.exec.
+  def self.model(command="model")
+    Facter::Core::Execution.exec(command)
+  end
+
+  ##
+  # ioscan delegates directly to Facter::Core::Execution.exec.
+  def self.ioscan(command="ioscan -fknCprocessor")
+    Facter::Core::Execution.exec(command)
+  end
+
+  ##
+  # getconf_cpu_version delegates directly to Facter::Core::Execution.exec.
+  def self.getconf_cpu_version(command="getconf CPU_VERSION")
+    Facter::Core::Execution.exec(command)
+  end
+
+  ##
+  # getconf_cpu_chip_type delegates directly to Facter::Core::Execution.exec.
+  def self.getconf_cpu_chip_type(command="getconf CPU_CHIP_TYPE")
+    Facter::Core::Execution.exec(command)
+  end
+
+  def self.enum_cpuinfo
+    processor_num = -1
+    processor_list = []
+    cpuinfo = "/proc/cpuinfo"
+
+    if File.exists?(cpuinfo)
+      model = Facter.value(:architecture)
+      case model
+      when "x86_64", "amd64", "i386", "x86", /parisc/, "hppa", "ia64"
+        File.readlines(cpuinfo).each do |l|
+          if l =~ /processor\s+:\s+(\d+)/
+            processor_num = $1.to_i
+          elsif l =~ /model name\s+:\s+(.*)\s*$/
+            processor_list[processor_num] = $1 unless processor_num == -1
+            processor_num = -1
+          elsif l =~ /processor\s+(\d+):\s+(.*)/
+            processor_num = $1.to_i
+            processor_list[processor_num] = $2 unless processor_num == -1
+          end
+        end
+
+      when "ppc64", "ppc64le"
+        File.readlines(cpuinfo).each do |l|
+          if l =~ /processor\s+:\s+(\d+)/
+            processor_num = $1.to_i
+          elsif l =~ /cpu\s+:\s+(.*)\s*$/
+            processor_list[processor_num] = $1 unless processor_num == -1
+            processor_num = -1
+          end
+        end
+
+      when /arm/
+        File.readlines(cpuinfo).each do |l|
+          if l =~ /Processor\s+:\s+(.+)/
+            processor_num += 1
+            processor_list[processor_num] = $1.chomp
+          elsif l =~ /processor\s+:\s+(\d+)\s*$/
+            proc_num = $1.to_i
+            if proc_num != 0
+              processor_num += 1
+              processor_list[processor_num] = processor_list[processor_num-1]
+            end
+          end
+        end
+
+      when /sparc/
+        File.readlines(cpuinfo).each do |l|
+          if l =~ /cpu\s+:\s+(.*)\s*$/
+            processor_num += 1
+            processor_list[processor_num] = $1
+          end
+        end
+      end
+    end
+    processor_list
+  end
+
+  def self.enum_kstat
+    processor_num = -1
+    processor_list = []
+    kstat = Facter::Core::Execution.exec('/usr/bin/kstat cpu_info')
+    if kstat
+      kstat.each_line do |l|
+        if l =~ /cpu_info(\d+)/
+          processor_num = $1.to_i
+        elsif l =~ /brand\s+(.*)\s*$/
+          processor_list[processor_num] = $1 unless processor_num == -1
+          processor_num = -1
+        end
+      end
+    end
+    processor_list
+  end
+end
+end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/registry.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/registry.rb
new file mode 100644
index 0000000..e349724
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/registry.rb
@@ -0,0 +1,11 @@
+module Facter::Util::Registry
+  class << self
+    def hklm_read(key, value)
+      require 'win32/registry'
+      reg = Win32::Registry::HKEY_LOCAL_MACHINE.open(key)
+      rval = reg[value]
+      reg.close
+      rval
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/resolution.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/resolution.rb
new file mode 100644
index 0000000..793261d
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/resolution.rb
@@ -0,0 +1,160 @@
+require 'facter/util/confine'
+require 'facter/util/config'
+require 'facter/util/normalization'
+require 'facter/core/execution'
+require 'facter/core/resolvable'
+require 'facter/core/suitable'
+
+# This represents a fact resolution. A resolution is a concrete
+# implementation of a fact. A single fact can have many resolutions and
+# the correct resolution will be chosen at runtime. Each time
+# {Facter.add} is called, a new resolution is created and added to the
+# set of resolutions for the fact named in the call.  Each resolution
+# has a {#has_weight weight}, which defines its priority over other
+# resolutions, and a set of {#confine _confinements_}, which defines the
+# conditions under which it will be chosen. All confinements must be
+# satisfied for a fact to be considered _suitable_.
+#
+# @api public
+class Facter::Util::Resolution
+  # @api private
+  attr_accessor :code
+  attr_writer :value
+
+  extend Facter::Core::Execution
+
+  class << self
+    # Expose command execution methods that were extracted into
+    # Facter::Core::Execution from Facter::Util::Resolution in Facter 2.0.0 for
+    # compatibility.
+    #
+    # @deprecated
+    public :search_paths, :which, :absolute_path?, :expand_command, :with_env, :exec
+  end
+
+  include Facter::Core::Resolvable
+  include Facter::Core::Suitable
+
+  # @!attribute [rw] name
+  # The name of this resolution. The resolution name should be unique with
+  # respect to the given fact.
+  # @return [String]
+  # @api public
+  attr_accessor :name
+
+  # @!attribute [r] fact
+  # @return [Facter::Util::Fact]
+  # @api private
+  attr_reader :fact
+
+  # Create a new resolution mechanism.
+  #
+  # @param name [String] The name of the resolution.
+  # @return [void]
+  #
+  # @api private
+  def initialize(name, fact)
+    @name = name
+    @fact = fact
+    @confines = []
+    @value = nil
+    @timeout = 0
+    @weight = nil
+  end
+
+  def resolution_type
+    :simple
+  end
+
+  # Evaluate the given block in the context of this resolution. If a block has
+  # already been evaluated emit a warning to that effect.
+  #
+  # @return [void]
+  def evaluate(&block)
+    if @last_evaluated
+      msg = "Already evaluated #{@name}"
+      msg << " at #{@last_evaluated}" if msg.is_a? String
+      msg << ", reevaluating anyways"
+      Facter.warn msg
+    end
+
+    instance_eval(&block)
+
+    # Ruby 1.9+ provides the source location of procs which can provide useful
+    # debugging information if a resolution is being evaluated twice. Since 1.8
+    # doesn't support this we opportunistically provide this information.
+    if block.respond_to? :source_location
+      @last_evaluated = block.source_location.join(':')
+    else
+      @last_evaluated = true
+    end
+  end
+
+  def set_options(options)
+    if options[:name]
+      @name = options.delete(:name)
+    end
+
+    if options.has_key?(:value)
+      @value = options.delete(:value)
+    end
+
+    if options.has_key?(:timeout)
+      @timeout = options.delete(:timeout)
+    end
+
+    if options.has_key?(:weight)
+      @weight = options.delete(:weight)
+    end
+
+    if not options.keys.empty?
+      raise ArgumentError, "Invalid resolution options #{options.keys.inspect}"
+    end
+  end
+
+  # Sets the code block or external program that will be evaluated to
+  # get the value of the fact.
+  #
+  # @return [void]
+  #
+  # @overload setcode(string)
+  #   Sets an external program to call to get the value of the resolution
+  #   @param [String] string the external program to run to get the
+  #     value
+  #
+  # @overload setcode(&block)
+  #   Sets the resolution's value by evaluating a block at runtime
+  #   @param [Proc] block The block to determine the resolution's value.
+  #     This block is run when the fact is evaluated. Errors raised from
+  #     inside the block are rescued and printed to stderr.
+  #
+  # @api public
+  def setcode(string = nil, &block)
+    if string
+      @code = Proc.new do
+        output = Facter::Core::Execution.execute(string, :on_fail => nil)
+        if output.nil? or output.empty?
+          nil
+        else
+          output
+        end
+      end
+    elsif block_given?
+      @code = block
+    else
+      raise ArgumentError, "You must pass either code or a block"
+    end
+  end
+
+  private
+
+  def resolve_value
+    if @value
+      @value
+    elsif @code.nil?
+      nil
+    elsif @code
+      @code.call()
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/solaris_zones.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/solaris_zones.rb
new file mode 100644
index 0000000..df9d661
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/solaris_zones.rb
@@ -0,0 +1,158 @@
+require 'facter/util/resolution'
+
+module Facter
+module Util
+  ##
+  # Provide a set of utility methods to interact with Solaris zones.  This class
+  # is expected to be instantiated once per set of resolutions in order to
+  # cache the output of the zoneadm command, which can be quite expensive.
+  #
+  # @api private
+  class SolarisZones
+    attr_reader :zone_hash
+    attr_reader :zoneadm_cmd
+    attr_reader :zoneadm_output
+    attr_reader :zoneadm_keys
+
+    ##
+    # add_facts defines all of the facts for solaris zones, for example `zones`,
+    # `zone_global_id`, `zone_global_status`, etc...  This method defines the
+    # static fact named `zones`.  The value of this fact is the numver of zones
+    # reported by the zoneadm system command.  The `zones` fact also defines
+    # all of the dynamic facts describing the following seven attribute values
+    # for each zone.
+    #
+    # Zones may be added to the system while Facter is loaded.  In order to
+    # define new dynamic facts that reflect this new information, the `virtual`
+    # will define new facts as a side effect of refreshing it's own value.
+    #
+    # @api private
+    def self.add_facts
+      model = new
+      model.refresh
+      model.add_dynamic_facts
+      Facter.add("zones") do
+        setcode do
+          model.refresh if model.flushed?
+          model.add_dynamic_facts
+          model.count
+        end
+        on_flush do
+          model.flush!
+        end
+      end
+    end
+
+    ##
+    # @param [Hash] opts the options to create the instance with
+    # @option opts [String] :zoneadm_cmd ('/usr/sbin/zoneadm list -cp') the
+    #   system command to inspect zones
+    # @option opts [String] :zoneadm_output (nil) the cached output of the
+    #   zoneadm_cmd
+    def initialize(opts = {})
+      @zoneadm_keys = [:id, :name, :status, :path, :uuid, :brand, :iptype]
+      @zoneadm_cmd = opts[:zoneadm_cmd] || '/usr/sbin/zoneadm list -cp'
+      if opts[:zoneadm_output]
+        @zoneadm_output = opts[:zoneadm_output]
+      end
+    end
+
+    ##
+    # add_dynamic_facts defines all of the dynamic facts derived from parsing
+    # the output of the zoneadm command.  The zone facts are dynamic, so this
+    # method has the behavior of figuring out what dynamic zone facts need to
+    # be defined and how they should be resolved.
+    #
+    # @param model [SolarisZones] the model used to store data from the system
+    #
+    # @api private
+    def add_dynamic_facts
+      model = self
+      zone_hash.each_pair do |zone, attr_hsh|
+        attr_hsh.keys.each do |attr|
+          Facter.add("zone_#{zone}_#{attr}") do
+            setcode do
+              model.refresh if model.flushed?
+              # Don't resolve if the zone has since been deleted
+              if zone_hsh = model.zone_hash[zone]
+                zone_hsh[attr] # the value
+              end
+            end
+            on_flush do
+              model.flush!
+            end
+          end
+        end
+      end
+    end
+
+    ##
+    # refresh executes the zoneadm_cmd and stores the output data.
+    #
+    # @api private
+    #
+    # @return [Hash] the parsed output of the zoneadm command
+    def refresh
+      @zoneadm_output = Facter::Core::Execution.execute(zoneadm_cmd, {:on_fail => nil})
+      parse!
+    end
+
+    ##
+    # parse! parses the string stored in {@zoneadm_output} and stores the
+    # resulting Hash data structure in {@zone_hash}
+    #
+    # @api private
+    def parse!
+      if @zoneadm_output
+        rows = @zoneadm_output.split("\n").collect { |line| line.split(':') }
+      else
+        Facter.debug "Cannot parse zone facts, #{zoneadm_cmd} returned no output"
+        rows = []
+      end
+
+      @zone_hash = rows.inject({}) do |memo, fields|
+        zone = fields[1].intern
+        # Transform the row into a hash with keys named by the column names
+        memo[zone] = Hash[*@zoneadm_keys.zip(fields).flatten]
+        memo
+      end
+    end
+    private :parse!
+
+    ##
+    # count returns the number of running zones, including the global zone.
+    # This method is intended to be used from the setcode block of the `zones`
+    # fact.
+    #
+    # @api private
+    #
+    # @return [Fixnum, nil] the number of running zones or nil if the number
+    #   could not be determined.
+    def count
+      if @zone_hash
+        @zone_hash.size
+      end
+    end
+
+    ##
+    # flush! purges the saved data from the zoneadm_cmd output
+    #
+    # @api private
+    def flush!
+      @zoneadm_output = nil
+      @zone_hash = nil
+    end
+
+    ##
+    # flushed? returns true if the instance has no parsed data accessible via
+    # the {zone_hash} method.
+    #
+    # @api private
+    #
+    # @return [Boolean] true if there is no parsed data, false otherwise
+    def flushed?
+      !@zone_hash
+    end
+  end
+end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/unix_root.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/unix_root.rb
new file mode 100644
index 0000000..c7be2ff
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/unix_root.rb
@@ -0,0 +1,5 @@
+module Facter::Util::Root
+  def self.root?
+    Process.uid == 0
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/uptime.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/uptime.rb
new file mode 100644
index 0000000..ed0a565
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/uptime.rb
@@ -0,0 +1,83 @@
+require 'time'
+
+# A module to gather uptime facts
+#
+module Facter::Util::Uptime
+  def self.get_uptime_seconds_unix
+    uptime_proc_uptime or uptime_sysctl or uptime_executable
+  end
+
+  def self.get_uptime_seconds_win
+    require 'facter/util/wmi'
+
+    last_boot = ""
+    Facter::Util::WMI.execquery("select * from Win32_OperatingSystem").each do |x|
+      last_boot = x.LastBootupTime
+    end
+    self.compute_uptime(Time.parse(last_boot.split('.').first))
+  end
+
+  private
+
+  def self.uptime_proc_uptime
+    output = Facter::Core::Execution.execute("/bin/cat #{uptime_file} 2>/dev/null")
+
+    if not output.empty?
+      output.chomp.split(" ").first.to_i
+    end
+  end
+
+  def self.uptime_sysctl
+    require 'facter/util/posix'
+    output = Facter::Util::POSIX.sysctl(uptime_sysctl_variable)
+    if output
+      compute_uptime(Time.at(output.match(/\d+/)[0].to_i))
+    end
+  end
+
+  def self.uptime_executable
+    output = Facter::Core::Execution.execute("#{uptime_executable_cmd} 2>/dev/null", :on_fail => nil)
+
+    if output
+      up=0
+      if output =~ /(\d+) day(?:s|\(s\))?,?\s+(\d+):-?(\d+)/
+        # Regexp handles Solaris, AIX, HP-UX, and Tru64.
+        # 'day(?:s|\(s\))?' says maybe 'day', 'days',
+        #   or 'day(s)', and don't set $2.
+        up=86400*$1.to_i + 3600*$2.to_i + 60*$3.to_i
+      elsif output =~ /(\d+) day(?:s|\(s\))?,\s+(\d+) hr(?:s|\(s\))?,/
+        up=86400*$1.to_i + 3600*$2.to_i
+      elsif output =~ /(\d+) day(?:s|\(s\))?,\s+(\d+) min(?:s|\(s\))?,/
+        up=86400*$1.to_i + 60*$2.to_i
+      elsif output =~ /(\d+) day(?:s|\(s\))?,/
+        up=86400*$1.to_i
+      elsif output =~ /up\s+(\d+):-?(\d+),/
+        # must anchor to 'up' to avoid matching time of day
+        # at beginning of line. Certain versions of uptime on
+        # Solaris may insert a '-' into the minutes field.
+        up=3600*$1.to_i + 60*$2.to_i
+      elsif output =~ /(\d+) hr(?:s|\(s\))?,/
+        up=3600*$1.to_i
+      elsif output =~ /(\d+) min(?:s|\(s\))?,/
+        up=60*$1.to_i
+      end
+      up
+    end
+  end
+
+  def self.compute_uptime(time)
+    (Time.now - time).to_i
+  end
+
+  def self.uptime_file
+    "/proc/uptime"
+  end
+
+  def self.uptime_sysctl_variable
+    'kern.boottime'
+  end
+
+  def self.uptime_executable_cmd
+    "uptime"
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/values.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/values.rb
new file mode 100644
index 0000000..1fbb1b6
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/values.rb
@@ -0,0 +1,109 @@
+
+module Facter
+  module Util
+    # A util module for facter containing helper methods
+    module Values
+      module_function
+
+      class DeepFreezeError < StandardError; end
+
+      # Duplicate and deeply freeze a given data structure
+      #
+      # @param value [Object] The structure to freeze
+      # @return [void]
+      def deep_freeze(value)
+        case value
+        when Numeric, Symbol, TrueClass, FalseClass, NilClass
+          # These are immutable values, we can safely ignore them
+          value
+        when String
+          value.dup.freeze
+        when Array
+          value.map do |entry|
+            deep_freeze(entry)
+          end.freeze
+        when Hash
+          value.inject({}) do |hash, (key, value)|
+            hash[deep_freeze(key)] = deep_freeze(value)
+            hash
+          end.freeze
+        else
+          raise DeepFreezeError, "Cannot deep freeze #{value}:#{value.class}"
+        end
+      end
+
+      class DeepMergeError < StandardError; end
+
+      # Perform a deep merge of two nested data structures.
+      #
+      # @param left [Object]
+      # @param right [Object]
+      # @param path [Array<String>] The traversal path followed when merging nested hashes
+      #
+      # @return [Object] The merged data structure.
+      def deep_merge(left, right, path = [], &block)
+        ret = nil
+
+        if left.is_a? Hash and right.is_a? Hash
+          ret = left.merge(right) do |key, left_val, right_val|
+            path.push(key)
+            merged = deep_merge(left_val, right_val, path)
+            path.pop
+            merged
+          end
+        elsif left.is_a? Array and right.is_a? Array
+          ret = left.dup.concat(right)
+        elsif right.nil?
+          ret = left
+        elsif left.nil?
+          ret = right
+        elsif left.nil? and right.nil?
+          ret = nil
+        else
+          msg = "Cannot merge #{left.inspect}:#{left.class} and #{right.inspect}:#{right.class}"
+          if not path.empty?
+            msg << " at root"
+            msg << path.map { |part| "[#{part.inspect}]" }.join
+          end
+          raise DeepMergeError, msg
+        end
+
+        ret
+      end
+
+      def convert(value)
+        value = value.to_s if value.is_a?(Symbol)
+        value = value.downcase if value.is_a?(String)
+        value
+      end
+
+      # Flatten the given data structure to something that's suitable to return
+      # as flat facts.
+      #
+      # @param path [String] The fact path to be prefixed to the given value.
+      # @param structure [Object] The data structure to flatten. Nested hashes
+      #   will be recursively flattened, everything else will be returned as-is.
+      #
+      # @return [Hash] The given data structure prefixed with the given path
+      def flatten_structure(path, structure)
+        results = {}
+
+        if structure.is_a? Hash
+          structure.each_pair do |name, value|
+            new_path = "#{path}_#{name}".gsub(/\-|\//, '_')
+            results.merge! flatten_structure(new_path, value)
+          end
+        elsif structure.is_a? Array
+          structure.each_with_index do |value, index|
+            new_path = "#{path}_#{index}"
+            results.merge! flatten_structure(new_path, value)
+          end
+        else
+          results[path] = structure
+        end
+
+        results
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/virtual.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/virtual.rb
new file mode 100644
index 0000000..089b25f
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/virtual.rb
@@ -0,0 +1,212 @@
+require 'facter/util/posix'
+require 'facter/util/file_read'
+require 'pathname'
+
+module Facter::Util::Virtual
+  ##
+  # virt_what is a delegating helper method intended to make it easier to stub
+  # the system call without affecting other calls to
+  # Facter::Core::Execution.exec
+  #
+  # Per https://bugzilla.redhat.com/show_bug.cgi?id=719611 when run as a
+  # non-root user the virt-what command may emit an error message on stdout,
+  # and later versions of virt-what may emit this message on stderr. This
+  # method ensures stderr is redirected and that error messages are stripped
+  # from stdout.
+  def self.virt_what(cmd = "virt-what")
+    if bindir = Facter::Util::Config.override_binary_dir
+      command = Facter::Core::Execution.which(File.join(bindir, cmd))
+    else
+      command = nil
+    end
+
+    if !command
+      command = Facter::Core::Execution.which(cmd)
+      return unless command
+    end
+
+    if Facter.value(:kernel) == 'windows'
+      redirected_cmd = "#{command} 2>NUL"
+    else
+      redirected_cmd = "#{command} 2>/dev/null"
+    end
+    output = Facter::Core::Execution.exec redirected_cmd
+    output.gsub(/^virt-what: .*$/, '') if output
+  end
+
+  ##
+  # lspci is a delegating helper method intended to make it easier to stub the
+  # system call without affecting other calls to Facter::Core::Execution.exec
+  def self.lspci(command = nil)
+    if command.nil?
+      if ["FreeBSD", "OpenBSD"].include? Facter.value(:kernel)
+        command = "pciconf -lv 2>/dev/null"
+      else
+        command = "lspci 2>/dev/null"
+      end
+    end
+
+    Facter::Core::Execution.exec command
+  end
+
+  def self.openvz?
+    FileTest.directory?("/proc/vz") and not self.openvz_cloudlinux?
+  end
+
+  # So one can either have #6728 work on OpenVZ or Cloudlinux. Whoo.
+  def self.openvz_type
+    return false unless self.openvz?
+    return false unless FileTest.exists?( '/proc/self/status' )
+
+    envid = Facter::Core::Execution.exec( 'grep "envID" /proc/self/status' )
+    if envid =~ /^envID:\s+0$/i
+    return 'openvzhn'
+    elsif envid =~ /^envID:\s+(\d+)$/i
+    return 'openvzve'
+    end
+  end
+
+  # Cloudlinux uses OpenVZ to a degree, but always has an empty /proc/vz/ and
+  # has /proc/lve/list present
+  def self.openvz_cloudlinux?
+    FileTest.file?("/proc/lve/list") or Dir.glob('/proc/vz/*').empty?
+  end
+
+  def self.zone?
+    return true if FileTest.directory?("/.SUNWnative")
+    z = Facter::Core::Execution.exec("/sbin/zonename")
+    return false unless z
+    return z.chomp != 'global'
+  end
+
+  def self.vserver?
+    return false unless FileTest.exists?("/proc/self/status")
+    txt = File.open("/proc/self/status", "rb").read
+    if txt.respond_to?(:encode!)
+      txt.encode!('UTF-16', 'UTF-8', :invalid => :replace)
+      txt.encode!('UTF-8', 'UTF-16')
+    end
+    return true if txt =~ /^(s_context|VxID):[[:blank:]]*[0-9]/
+    return false
+  end
+
+  def self.vserver_type
+    if self.vserver?
+      if FileTest.exists?("/proc/virtual")
+        "vserver_host"
+      else
+        "vserver"
+      end
+    end
+  end
+
+  def self.xen?
+    ["/proc/sys/xen", "/sys/bus/xen", "/proc/xen" ].detect do |f|
+      FileTest.exists?(f)
+    end
+  end
+
+  def self.kvm?
+     txt = if FileTest.exists?("/proc/cpuinfo")
+       File.read("/proc/cpuinfo")
+     elsif ["FreeBSD", "OpenBSD"].include? Facter.value(:kernel)
+       Facter::Util::POSIX.sysctl("hw.model")
+     elsif Facter.value(:kernel) == "SunOS" and FileTest.exists?("/usr/sbin/prtconf")
+       Facter::Core::Execution.exec("/usr/sbin/prtconf -v")
+     end
+     (txt =~ /QEMU Virtual (CPU|Machine)/i) ? true : false
+  end
+
+  def self.virtualbox?
+    File.read("/sys/devices/virtual/dmi/id/product_name") =~ /VirtualBox/ rescue false
+  end
+
+  def self.kvm_type
+    # TODO Tell the difference between kvm and qemu
+    # Can't work out a way to do this at the moment that doesn't
+    # require a special binary
+    if self.kvm?
+      "kvm"
+    end
+  end
+
+  def self.rhev?
+    File.read("/sys/devices/virtual/dmi/id/product_name") =~ /RHEV Hypervisor/ rescue false
+  end
+
+  def self.ovirt?
+    File.read("/sys/devices/virtual/dmi/id/product_name") =~ /oVirt Node/ rescue false
+  end
+
+  def self.gce?
+    File.read("/sys/devices/virtual/dmi/id/product_name") =~ /Google/ rescue false
+  end
+
+  def self.jail?
+    path = case Facter.value(:kernel)
+      when "FreeBSD" then "/sbin"
+      when "GNU/kFreeBSD" then "/bin"
+    end
+    Facter::Core::Execution.exec("#{path}/sysctl -n security.jail.jailed") == "1"
+  end
+
+  def self.hpvm?
+    Facter::Core::Execution.exec("/usr/bin/getconf MACHINE_MODEL").chomp =~ /Virtual Machine/
+  end
+
+  ##
+  # lxc? returns true if the process is running inside of a linux container.
+  # Implementation derived from
+  # http://stackoverflow.com/questions/20010199/determining-if-a-process-runs-inside-lxc-docker
+  def self.lxc?
+    path = Pathname.new('/proc/1/cgroup')
+    return false unless path.readable?
+    begin
+      in_lxc = path.readlines.any? {|l| l.split(":")[2].to_s.include? '/lxc' }
+    rescue Errno::EPERM => exc
+      # If we get "operation not permitted" here, it probably means we are
+      # running OpenVZ. We are not running LXC anyway, so...
+      return false
+    end
+    return true if in_lxc
+    return false
+  end
+
+  ##
+  # docker? returns true if the process is running inside of a docker container.
+  # Implementation derived from observation of a boot2docker system
+  def self.docker?
+    path = Pathname.new('/proc/1/cgroup')
+    return false unless path.readable?
+    begin
+      in_docker = path.readlines.any? {|l| l.split(":")[2].to_s.include? '/docker' }
+    rescue Errno::EPERM => exc
+      # This can fail under OpenVZ, just like in .lxc?
+      return false
+    end
+    return true if in_docker
+    return false
+  end
+
+  def self.zlinux?
+    "zlinux"
+  end
+
+  ##
+  # read_sysfs Reads the raw data as per the documentation at [Detecting if You
+  # Are Running in Google Compute
+  # Engine](https://developers.google.com/compute/docs/instances#dmi)  This
+  # method is intended to provide an easy seam to mock.
+  #
+  # @api public
+  #
+  # @return [String] or nil if the path does not exist or is unreadable
+  def self.read_sysfs_dmi_entries(path="/sys/firmware/dmi/entries/1-0/raw")
+    if File.readable?(path)
+      begin
+        Facter::Util::FileRead.read_binary(path)
+      rescue Errno::EINVAL
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/vlans.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/vlans.rb
new file mode 100644
index 0000000..5082380
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/vlans.rb
@@ -0,0 +1,21 @@
+# A module to gather vlan facts
+#
+module Facter::Util::Vlans
+  def self.get_vlan_config
+    if File.exist?('/proc/net/vlan/config') and File.readable?('/proc/net/vlan/config')
+      File.read('/proc/net/vlan/config')
+    end
+  end
+
+  def self.get_vlans
+    if (config = self.get_vlan_config)
+      vlans = []
+      config.each_line do |line|
+        if (match = line.match(/^([0-9A-Za-z]+)\.([0-9]+) /))
+          vlans << match[2] if match[2]
+        end
+      end
+      vlans.join(',') unless vlans.empty?
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/windows_root.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/windows_root.rb
new file mode 100644
index 0000000..7f14993
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/windows_root.rb
@@ -0,0 +1,7 @@
+require 'win32/security'
+
+module Facter::Util::Root
+  def self.root?
+    Win32::Security.elevated_security?
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/wmi.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/wmi.rb
new file mode 100644
index 0000000..f69f563
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/wmi.rb
@@ -0,0 +1,16 @@
+module Facter::Util::WMI
+  class << self
+    def connect(uri = wmi_resource_uri)
+      require 'win32ole'
+      WIN32OLE.connect(uri)
+    end
+
+    def wmi_resource_uri( host = '.' )
+      "winmgmts:{impersonationLevel=impersonate}!//#{host}/root/cimv2"
+    end
+
+    def execquery(query)
+      connect().execquery(query)
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/xendomains.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/xendomains.rb
new file mode 100644
index 0000000..8f78e9c
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/util/xendomains.rb
@@ -0,0 +1,28 @@
+# A module to gather running Xen Domains
+#
+module Facter::Util::Xendomains
+  XEN_COMMANDS = ['/usr/sbin/xl', '/usr/sbin/xm']
+
+  def self.xen_command
+    if File.file?('/usr/lib/xen-common/bin/xen-toolstack')
+      xen_toolstack_cmd = Facter::Util::Resolution.exec('/usr/lib/xen-common/bin/xen-toolstack')
+      if xen_toolstack_cmd
+        xen_toolstack_cmd.chomp
+      else
+        nil
+      end
+    else
+      XEN_COMMANDS.find { |cmd| Facter::Util::Resolution.which(cmd) }
+    end
+  end
+
+  def self.get_domains
+    command = self.xen_command
+    if command
+      if domains_list = Facter::Util::Resolution.exec("#{command} list 2>/dev/null")
+        domains = domains_list.split("\n").reject { |line| line =~ /^(Name|Domain-0)/ }
+        domains.map { |line| line.split(/\s/)[0] }.join(',')
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/version.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/version.rb
new file mode 100644
index 0000000..4e71bd5
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/version.rb
@@ -0,0 +1,86 @@
+module Facter
+  if not defined? FACTERVERSION then
+    FACTERVERSION = '2.4.6'
+  end
+
+  # Returns the running version of Facter.
+  #
+  # @comment The intent is that software external to Facter be able to
+  #   determine the Facter version with no side-effects.  The expected
+  #   use is:
+  #
+  #     require 'facter/version'
+  #     version = Facter.version
+  #
+  #   This function has the following ordering precedence.  This precedence list
+  #   is designed to facilitate automated packaging tasks by simply writing to
+  #   the VERSION file in the same directory as this source file.
+  #
+  #    1. If a version has been explicitly assigned using the Facter.version=
+  #       method, return that version.
+  #    2. If there is a VERSION file, read the contents, trim any
+  #       trailing whitespace, and return that version string.
+  #    3. Return the value of the Facter::FACTERVERSION constant hard-coded into
+  #       the source code.
+  #
+  #   If there is no VERSION file, the method must return the version string of
+  #   the nearest parent version that is an officially released version.  That is
+  #   to say, if a branch named 3.1.x contains 25 patches on top of the most
+  #   recent official release of 3.1.1, then the version method must return the
+  #   string "3.1.1" if no "VERSION" file is present.
+  #
+  #   By design the version identifier is _not_ intended to vary during the life of
+  #   a process.  There is no guarantee provided that writing to the VERSION file
+  #   while a Puppet process is running will cause the version string to be
+  #   updated.  On the contrary, the contents of the VERSION are cached to reduce
+  #   filesystem accesses.
+  #
+  #   The VERSION file is intended to be used by package maintainers who may be
+  #   applying patches or otherwise changing the software version in a manner
+  #   that warrants a different software version identifier.  The VERSION file is
+  #   intended to be managed and owned by the release process and packaging
+  #   related tasks, and as such should not reside in version control.  The
+  #   FACTERVERSION constant is intended to be version controlled in history.
+  #
+  #   Ideally, this behavior will allow package maintainers to precisely specify
+  #   the version of the software they're packaging as in the following example:
+  #
+  #       $ git describe > lib/facter/VERSION
+  #       $ ruby -r facter -e 'puts Facter.version'
+  #       1.6.14-6-g66f2c99
+  #
+  # @api public
+  #
+  # @return [String] containing the facter version, e.g. "1.6.14"
+  def self.version
+    version_file = File.join(File.dirname(__FILE__), 'VERSION')
+    return @facter_version if @facter_version
+    if version = read_version_file(version_file)
+      @facter_version = version
+    end
+    @facter_version ||= FACTERVERSION
+  end
+
+  # Sets the Facter version
+  #
+  # @return [void]
+  #
+  # @api private
+  def self.version=(version)
+    @facter_version = version
+  end
+
+  # This reads the content of the "VERSION" file that lives in the
+  # same directory as this source code file.
+  #
+  # @api private
+  #
+  # @return [String] the version -- for example: "1.6.14-6-gea42046" or nil if the VERSION
+  #   file does not exist.
+  def self.read_version_file(path)
+    if File.exists?(path)
+      File.read(path).chomp
+    end
+  end
+  private_class_method :read_version_file
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/virtual.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/virtual.rb
new file mode 100644
index 0000000..78da014
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/virtual.rb
@@ -0,0 +1,326 @@
+# Fact: virtual
+#
+# Purpose: Determine if the system's hardware is real or virtualized.
+#
+# Resolution:
+#   Assumes physical unless proven otherwise.
+#
+#   On Darwin, use the macosx util module to acquire the SPHardwareDataType
+#   and SPEthernetDataType, from which it is possible to determine if the host is
+#   a VMware, Parallels, or VirtualBox. This previously used SPDisplaysDataType,
+#   which was not reliable if running headless, and also caused lagging issues
+#   on actual Macs.
+#
+#   On Linux, BSD, Solaris and HPUX: Much of the logic here is obscured behind
+#   `util/virtual.rb`, which you can consult directly for more detailed resolution
+#   information.
+#   The Xen tests in here rely on `/sys` and `/proc,` and check for the presence and
+#   contents of files in there.
+#   If after all the other tests it's still seen as physical, then it tries to
+#   parse the output of the `lspci`, `dmidecode`, and `prtdiag` and parses them
+#   for obvious signs of being under VMware, Parallels or VirtualBox.
+#   Finally, it checks for the existence of `vmware-vmx`, which would hint that
+#   it's VMware.
+#
+# Caveats:
+#   Many checks rely purely on existence of files.
+#
+
+# Fact: is_virtual
+#
+# Purpose: Return `true` or `false` depending on whether a machine is virtualized or not.
+#
+# Resolution: Hypervisors and the like may be detected as a virtual type, but
+#   are not actual virtual machines, or should not be treated as such. This
+#   determines if the host is actually virtualized.
+#
+# Caveats:
+#
+
+require 'facter/util/virtual'
+
+Facter.add("virtual") do
+  confine :kernel => "Darwin"
+
+  setcode do
+    require 'facter/util/macosx'
+    result = "physical"
+    # use SPHardwareDataType for VMware and VirtualBox, since it is the most
+    # reliable source.
+    output = Facter::Util::Macosx.profiler_data("SPHardwareDataType")
+    if output.is_a?(Hash)
+      result = "vmware" if output["machine_model"] =~ /VMware/
+      result = "virtualbox" if output["boot_rom_version"] =~ /VirtualBox/
+    end
+    # Parallels passes through almost all of the host's hardware info to the
+    # virtual machine, so use a different field.
+    output = Facter::Util::Macosx.profiler_data("SPEthernetDataType")
+    if output.is_a?(Hash)
+      result = "parallels" if output["spethernet_subsystem-vendor-id"] =~ /0x1ab8/
+    end
+    result
+  end
+end
+
+Facter.add("virtual") do
+  confine :kernel => ["FreeBSD", "GNU/kFreeBSD"]
+  has_weight 10
+  setcode do
+    "jail" if Facter::Util::Virtual.jail?
+  end
+end
+
+Facter.add("virtual") do
+  confine :kernel => 'SunOS'
+  has_weight 10
+  self.timeout = 20
+
+  setcode do
+    next "zone" if Facter::Util::Virtual.zone?
+
+    output = Facter::Core::Execution.exec('prtdiag 2>/dev/null')
+    if output
+      lines = output.split("\n")
+      next "parallels"  if lines.any? {|l| l =~ /Parallels/ }
+      next "vmware"     if lines.any? {|l| l =~ /VM[wW]are/ }
+      next "virtualbox" if lines.any? {|l| l =~ /VirtualBox/ }
+      next "xenhvm"     if lines.any? {|l| l =~ /HVM domU/ }
+    end
+  end
+end
+
+Facter.add("virtual") do
+  confine :kernel => 'SunOS'
+  confine :hardwareisa => 'sparc'
+  confine :ldom_domainrole_control => 'false'
+  has_weight 20 # Weight this before the default solaris implementation
+  setcode do
+    Facter.value(:ldom_domainrole_impl)
+  end
+end
+
+
+Facter.add("virtual") do
+  confine :kernel => 'HP-UX'
+  has_weight 10
+  setcode do
+    "hpvm" if Facter::Util::Virtual.hpvm?
+  end
+end
+
+Facter.add("virtual") do
+  confine :architecture => 's390x'
+  has_weight 10
+  setcode do
+    "zlinux" if Facter::Util::Virtual.zlinux?
+  end
+end
+
+Facter.add("virtual") do
+  confine :kernel => 'OpenBSD'
+  has_weight 10
+  setcode do
+    output = Facter::Util::POSIX.sysctl("hw.product")
+    if output
+      lines = output.split("\n")
+      next "parallels"  if lines.any? {|l| l =~ /Parallels/ }
+      next "vmware"     if lines.any? {|l| l =~ /VMware/ }
+      next "virtualbox" if lines.any? {|l| l =~ /VirtualBox/ }
+      next "xenhvm"     if lines.any? {|l| l =~ /HVM domU/ }
+      next "ovirt"      if lines.any? {|l| l =~ /oVirt Node/ }
+      next "kvm"        if lines.any? {|l| l =~ /KVM/ }
+    end
+  end
+end
+
+Facter.add("virtual") do
+  confine :kernel => %w{Linux FreeBSD OpenBSD SunOS HP-UX GNU/kFreeBSD}
+
+  setcode do
+    next Facter::Util::Virtual.openvz_type if Facter::Util::Virtual.openvz?
+    next Facter::Util::Virtual.vserver_type if Facter::Util::Virtual.vserver?
+
+    if Facter::Util::Virtual.xen?
+      next "xen0" if FileTest.exists?("/dev/xen/evtchn")
+      next "xenu" if FileTest.exists?("/proc/xen") || FileTest.exists?("/dev/xvda1")
+    end
+
+    next "virtualbox" if Facter::Util::Virtual.virtualbox?
+    next Facter::Util::Virtual.kvm_type if Facter::Util::Virtual.kvm?
+    next "rhev" if Facter::Util::Virtual.rhev?
+    next "ovirt" if Facter::Util::Virtual.ovirt?
+
+    # Parse lspci
+    output = Facter::Util::Virtual.lspci
+    if output
+      lines = output.split("\n")
+      next "vmware"     if lines.any? {|l| l =~ /VM[wW]are/ }
+      next "virtualbox" if lines.any? {|l| l =~ /VirtualBox/ }
+      next "parallels"  if lines.any? {|l| l =~ /1ab8:|[Pp]arallels/ }
+      next "xenhvm"     if lines.any? {|l| l =~ /XenSource/ }
+      next "hyperv"     if lines.any? {|l| l =~ /Microsoft Corporation Hyper-V/ }
+      next "gce"        if lines.any? {|l| l =~ /Class 8007: Google, Inc/ }
+      next "kvm"        if lines.any? {|l| l =~ /virtio/i }
+    end
+
+    # Parse dmidecode
+    output = Facter::Core::Execution.exec('dmidecode 2> /dev/null')
+    if output
+      lines = output.split("\n")
+      next "parallels"  if lines.any? {|l| l =~ /Parallels/ }
+      next "vmware"     if lines.any? {|l| l =~ /VMware/ }
+      next "virtualbox" if lines.any? {|l| l =~ /VirtualBox/ }
+      next "xenhvm"     if lines.any? {|l| l =~ /HVM domU/ }
+      next "hyperv"     if lines.any? {|l| l =~ /Product Name: Virtual Machine/ }
+      next "rhev"       if lines.any? {|l| l =~ /Product Name: RHEV Hypervisor/ }
+      next "ovirt"      if lines.any? {|l| l =~ /Product Name: oVirt Node/ }
+      next "bochs"      if lines.any? {|l| l =~ /Bochs/ }
+      next "kvm"        if lines.any? {|l| l =~ /Manufacturer: QEMU/ }
+    end
+
+    # Default to 'physical'
+    next 'physical'
+  end
+end
+
+Facter.add("virtual") do
+  confine do
+    Facter::Core::Execution.which('vmware')
+  end
+
+  setcode do
+    # Sample output of vmware -v `VMware Server 1.0.5 build-80187`
+    output = Facter::Core::Execution.exec("vmware -v")
+    if output
+      mdata = output.match /(\S+)\s+(\S+)/
+      next "#{mdata[1]}_#{mdata[2]}".downcase if mdata
+    end
+  end
+end
+
+Facter.add("virtual") do
+  confine :kernel => "windows"
+  setcode do
+      require 'facter/util/wmi'
+      result = nil
+      Facter::Util::WMI.execquery("SELECT manufacturer, model FROM Win32_ComputerSystem").each do |computersystem|
+        case computersystem.model
+        when /VirtualBox/
+          result = "virtualbox"
+        when /Virtual Machine/
+          result = "hyperv" if computersystem.manufacturer =~ /Microsoft/
+        when /VMware/
+          result = "vmware"
+        when /KVM/
+          result = "kvm"
+        when /Bochs/
+          result = "bochs"
+        end
+
+        if result.nil? and computersystem.manufacturer =~ /Xen/
+          result = "xen"
+        end
+
+        break
+      end
+      result ||= "physical"
+
+      result
+  end
+end
+
+##
+# virtual fact based on virt-what command.
+#
+# The output is mapped onto existing known values for the virtual fact in an
+# effort to preserve consistency.  This fact has a high weight becuase the
+# virt-what tool is expected to be maintained upstream.
+#
+# If the virt-what command is not available, this fact will not resolve to a
+# value and lower-weight virtual facts will be attempted.
+#
+# Only the last line of the virt-what command is returned
+Facter.add("virtual") do
+  has_weight 500
+
+  setcode do
+    if output = Facter::Util::Virtual.virt_what
+      case output
+      when 'linux_vserver'
+        Facter::Util::Virtual.vserver_type
+      when /xen-hvm/i
+        'xenhvm'
+      when /xen-dom0/i
+        'xen0'
+      when /xen-domU/i
+        'xenu'
+      when /ibm_systemz/i
+        'zlinux'
+      else
+        output.to_s.split("\n").last
+      end
+    end
+  end
+end
+
+##
+# virtual fact specific to Google Compute Engine's Linux sysfs entry.
+Facter.add("virtual") do
+  has_weight 600
+  confine :kernel => "Linux"
+
+  setcode do
+    if dmi_data = Facter::Util::Virtual.read_sysfs_dmi_entries
+      case dmi_data
+      when /Google/
+        "gce"
+      end
+    end
+  end
+end
+
+##
+# virtual fact specific to linux containers.  This also works for Docker
+# containers running in lxc.
+Facter.add("virtual") do
+  has_weight 700
+  confine :kernel => "Linux"
+
+  setcode do
+    "lxc" if Facter::Util::Virtual.lxc?
+  end
+end
+
+##
+# virtual fact specific to docker containers.
+Facter.add("virtual") do
+  has_weight 750
+  confine :kernel => "Linux"
+
+  setcode do
+    "docker" if Facter::Util::Virtual.docker?
+  end
+end
+
+Facter.add("virtual") do
+  has_weight 600
+  confine :kernel => "Linux"
+
+  setcode do
+    "gce" if Facter::Util::Virtual.gce?
+  end
+end
+
+Facter.add("is_virtual") do
+  confine :kernel => %w{Linux FreeBSD OpenBSD SunOS HP-UX Darwin GNU/kFreeBSD windows}
+
+  setcode do
+    physical_types = %w{physical xen0 vmware_server vmware_workstation openvzhn vserver_host}
+
+    if physical_types.include? Facter.value(:virtual)
+      false
+    else
+      true
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/vlans.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/vlans.rb
new file mode 100644
index 0000000..165e5f6
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/vlans.rb
@@ -0,0 +1,17 @@
+# Fact: vlans
+#
+# Purpose: On Linux, return a list of all the VLANs on the system.
+#
+# Resolution: On Linux only, checks for and reads `/proc/net/vlan/config` and
+# parses it.
+#
+# Caveats:
+#
+require 'facter/util/vlans'
+
+Facter.add("vlans") do
+  confine :kernel => :linux
+  setcode do
+    Facter::Util::Vlans.get_vlans
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/xendomains.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/xendomains.rb
new file mode 100644
index 0000000..e1c8212
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/xendomains.rb
@@ -0,0 +1,20 @@
+# Fact: xendomains
+#
+# Purpose: Return the list of Xen domains on the Dom0.
+#
+# Resolution:
+#   On a Xen Dom0 host, return a list of Xen domains using the `util/xendomains`
+#   library.
+#
+# Caveats:
+#
+require 'facter/util/xendomains'
+
+Facter.add("xendomains") do
+  confine :kernel => %w{Linux FreeBSD OpenBSD SunOS}
+  confine :virtual => 'xen0'
+
+  setcode do
+    Facter::Util::Xendomains.get_domains
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/zfs_version.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/zfs_version.rb
new file mode 100644
index 0000000..0b39445
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/zfs_version.rb
@@ -0,0 +1,14 @@
+require 'facter'
+
+Facter.add('zfs_version') do
+  setcode do
+    if Facter::Core::Execution.which('zfs')
+      zfs_help = Facter::Core::Execution.exec('zfs -? 2> /dev/null')
+      zfs_has_upgrade = zfs_help.match(/\A.*upgrade.*\z/m) unless zfs_help.nil?
+      if zfs_has_upgrade
+        zfs_v = Facter::Core::Execution.exec('zfs upgrade -v')
+        zfs_version = zfs_v.scan(/^\s+(\d+)\s+/m).flatten.last unless zfs_v.nil?
+      end
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/zonename.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/zonename.rb
new file mode 100644
index 0000000..42f577d
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/zonename.rb
@@ -0,0 +1,6 @@
+require 'facter'
+
+Facter.add('zonename') do
+  confine :kernel => :sunos
+  setcode('zonename')
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/zones.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/zones.rb
new file mode 100644
index 0000000..8b15499
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/zones.rb
@@ -0,0 +1,18 @@
+# Fact: zones_<ZONE>
+#
+# Purpose:
+#   Return the list of zones on the system and add one zones_ fact
+#   for each zone with its state e.g. `running`, `incomplete`, or `installed`.
+#
+# Resolution:
+#   Uses `usr/sbin/zoneadm list -cp` to get the list of zones in separate parsable
+#   lines with delimeter being `:` which is used to split the line string and get
+#   the zone details.
+#
+# Caveats:
+#   Only supported on Solaris 10 and up.
+#
+require 'facter/util/solaris_zones'
+if Facter.value(:kernel) == 'SunOS'
+  Facter::Util::SolarisZones.add_facts
+end
diff --git a/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/zpool_version.rb b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/zpool_version.rb
new file mode 100644
index 0000000..c59fc5a
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/lib/ruby/vendor_ruby/facter/zpool_version.rb
@@ -0,0 +1,10 @@
+require 'facter'
+
+Facter.add('zpool_version') do
+  setcode do
+    if Facter::Core::Execution.which('zpool')
+      zpool_v = Facter::Core::Execution.exec('zpool upgrade -v')
+      zpool_version = zpool_v.scan(/^\s+(\d+)\s+/m).flatten.last unless zpool_v.nil?
+    end
+  end
+end
diff --git a/debian/stretch/facter-linex/usr/share/doc/facter/NEWS.Debian.gz b/debian/stretch/facter-linex/usr/share/doc/facter/NEWS.Debian.gz
new file mode 100644
index 0000000..5af1d13
Binary files /dev/null and b/debian/stretch/facter-linex/usr/share/doc/facter/NEWS.Debian.gz differ
diff --git a/debian/stretch/facter-linex/usr/share/doc/facter/README.md b/debian/stretch/facter-linex/usr/share/doc/facter/README.md
new file mode 100644
index 0000000..f7333c0
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/share/doc/facter/README.md
@@ -0,0 +1,65 @@
+Facter
+======
+
+This package is largely meant to be a library for collecting facts about your
+system.  These facts are mostly strings (i.e., not numbers), and are things
+like the output of `uname`, public ssh keys, the number of processors, etc.
+
+See `bin/facter` for an example of the interface.
+
+Installation
+------------
+
+Generally, you need the following things installed:
+
+* A supported Ruby version. Ruby 1.8.7, 1.9.3, and 2.0.0 (at least p195) are fully supported.
+
+Running Facter
+--------------
+
+Run the `facter` binary on the command for a full list of facts supported on
+your host.
+
+Adding your own facts
+---------------------
+
+See the [Adding Facts](http://docs.puppetlabs.com/guides/custom_facts.html)
+page for details of how to add your own custom facts to Facter.
+
+Running Specs
+-------------
+
+* bundle install --path .bundle/gems
+* bundle exec rake spec
+
+Note: external facts in the system facts.d directory can cause spec failures.
+
+Further Information
+-------------------
+
+See http://www.puppetlabs.com/puppet/related-projects/facter for more details.
+
+Support
+-------
+Please log tickets and issues at our [JIRA tracker](http://tickets.puppetlabs.com).  A [mailing
+list](https://groups.google.com/forum/?fromgroups#!forum/puppet-users) is
+available for asking questions and getting help from others. In addition there
+is an active #puppet channel on Freenode.
+
+We use semantic version numbers for our releases, and recommend that users stay
+as up-to-date as possible by upgrading to patch releases and minor releases as
+they become available.
+
+Bugfixes and ongoing development will occur in minor releases for the current
+major version. Security fixes will be backported to a previous major version on
+a best-effort basis, until the previous major version is no longer maintained.
+
+
+For example: If a security vulnerability is discovered in Facter 2.1.0, we
+would fix it in the 2 series, most likely as 2.1.1. Maintainers would then make
+a best effort to backport that fix onto the latest Facter 1.7 release.
+
+Long-term support, including security patches and bug fixes, is available for
+commercial customers. Please see the following page for more details:
+
+[Puppet Enterprise Support Lifecycle](http://puppetlabs.com/misc/puppet-enterprise-lifecycle)
diff --git a/debian/stretch/facter-linex/usr/share/doc/facter/changelog.Debian.gz b/debian/stretch/facter-linex/usr/share/doc/facter/changelog.Debian.gz
new file mode 100644
index 0000000..269e554
Binary files /dev/null and b/debian/stretch/facter-linex/usr/share/doc/facter/changelog.Debian.gz differ
diff --git a/debian/stretch/facter-linex/usr/share/doc/facter/copyright b/debian/stretch/facter-linex/usr/share/doc/facter/copyright
new file mode 100644
index 0000000..08c5cff
--- /dev/null
+++ b/debian/stretch/facter-linex/usr/share/doc/facter/copyright
@@ -0,0 +1,98 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+
+Files: *
+Copyright: 2011-2012 Puppet Labs Inc
+           2007 Mark 'phips' Phillips
+           2007 Jeff McCune
+           2007 David Schmitt <david@schmitt.edv-bus.at>
+           2006 Mooter Media Ltd
+License: Apache-2.0
+ See /usr/share/common-licenses/Apache-2.0
+
+Files: lib/facter/util/cfpropertylist/*
+Copyright: 2010 Christian Kruse, <cjk@wwwtech.de>
+License: Expat
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+ .
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+ .
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+Files: install.rb
+Copyright: 2004 Austin Ziegler <ruby-install@halostatue.ca>
+License: GPL-2+ or Ruby
+
+License: GPL-2+
+  See /usr/share/common-licenses/GPL-2
+
+License: Ruby
+  1. You may make and give away verbatim copies of the source form of the
+     software without restriction, provided that you duplicate all of the
+     original copyright notices and associated disclaimers.
+ .
+  2. You may modify your copy of the software in any way, provided that
+     you do at least ONE of the following:
+ .
+       a) place your modifications in the Public Domain or otherwise
+          make them Freely Available, such as by posting said
+          modifications to Usenet or an equivalent medium, or by
+          allowing the author to include your modifications in the
+          software.
+ .
+       b) use the modified software only within your corporation or
+          organization.
+ .
+       c) rename any non-standard executables so the names do not
+          conflict with standard executables, which must also be
+          provided.
+ .
+       d) make other distribution arrangements with the author.
+ .
+  3. You may distribute the software in object code or executable
+     form, provided that you do at least ONE of the following:
+ .
+       a) distribute the executables and library files of the
+          software, together with instructions (in the manual page or
+          equivalent) on where to get the original distribution.
+ .
+       b) accompany the distribution with the machine-readable source
+          of the software.
+ .
+       c) give non-standard executables non-standard names, with
+          instructions on where to get the original software
+          distribution.
+ .
+       d) make other distribution arrangements with the author.
+ .
+  4. You may modify and include the part of the software into any
+     other software (possibly commercial). But some files in the
+     distribution are not written by the author, so that they are not
+     under this terms.
+ .
+     They are gc.c(partly), utils.c(partly), regex.[ch], st.[ch] and
+     some files under the ./missing directory. See each file for the
+     copying condition.
+ .
+  5. The scripts and library files supplied as input to or produced as
+     output from the software do not automatically fall under the
+     copyright of the software, but belong to whomever generated them,
+     and may be sold commercially, and may be aggregated with this
+     software.
+ .
+  6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+     IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+     PURPOSE.
+
diff --git a/debian/stretch/facter-linex/usr/share/man/man8/facter.8.gz b/debian/stretch/facter-linex/usr/share/man/man8/facter.8.gz
new file mode 100644
index 0000000..0f5d853
Binary files /dev/null and b/debian/stretch/facter-linex/usr/share/man/man8/facter.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/debian/conffiles b/debian/stretch/puppet-linex-common/debian/conffiles
new file mode 100644
index 0000000..7e42f81
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/debian/conffiles
@@ -0,0 +1,5 @@
+/etc/ldap/schema/puppet.schema
+/etc/logcheck/ignore.d.server/puppet-common
+/etc/puppet/etckeeper-commit-post
+/etc/puppet/etckeeper-commit-pre
+/etc/puppet/puppet.conf
diff --git a/debian/stretch/puppet-linex-common/debian/control b/debian/stretch/puppet-linex-common/debian/control
new file mode 100644
index 0000000..ded91e3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/debian/control
@@ -0,0 +1,31 @@
+Source: puppet-linex-common
+Section: admin
+Priority: optional
+Maintainer: Rafael Jesús García Perdigón <rafael.garciap@juntaex.es>
+Build-Depends: debhelper (>= 8.0.0)
+Standards-Version: 3.9.4
+
+Package: puppet-linex-common
+Architecture: all
+Depends: adduser, facter-linex, ruby-augeas, hiera, lsb-base, ruby | ruby-interpreter, ruby-rgen, ruby-safe-yaml, ruby-shadow, sysv-rc | file-rc
+Recommends: debconf-utils, lsb-release, ruby-selinux
+Conflicts: puppet-common
+Suggests: ruby-rrd
+Breaks: puppet (<< 2.7.5-3), puppetmaster (<< 0.25.4-1), ruby-hiera-puppet
+Replaces: puppet (<< 2.7.5-3), puppetmaster (<< 0.25.4-1), ruby-hiera-puppet
+Description: configuration management system
+ Puppet is a server automation tool. It is composed of a declarative
+ language for expressing system configuration, a client and server for
+ distributing it, and a library for realizing the configuration.
+ .
+ The primary design goal of Puppet is to have an expressive enough
+ language backed by a powerful enough library that you can write your
+ own server automation applications in just a few lines of code.
+ Puppet’s deep extensibility and open source license lets you add
+ functionality as needed and share your innovations with others.
+ .
+ This package contains the puppet software and documentation. To
+ automatically start a puppet agent, install the "puppet" package. To
+ install and configure a puppet master, install one of the
+ "puppetmaster" or "puppetmaster-passenger" packages.
+
diff --git a/debian/stretch/puppet-linex-common/debian/postinst b/debian/stretch/puppet-linex-common/debian/postinst
new file mode 100755
index 0000000..4b41f91
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/debian/postinst
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+set -e
+
+if [ "$1" = "configure" ]; then
+
+	# Create the "puppet" user
+	if ! getent passwd puppet > /dev/null; then
+		adduser --quiet --system --group --home /var/lib/puppet  \
+			--no-create-home                                 \
+			--gecos "Puppet configuration management daemon" \
+			puppet
+	fi
+
+        # Create the "puppet" group, if it is missing, and set the
+        # primary group of the "puppet" user to this group.
+        if ! getent group puppet > /dev/null; then
+            addgroup --quiet --system puppet
+            usermod -g puppet puppet
+        fi
+
+	# Set correct permissions and ownership for puppet directories
+	if ! dpkg-statoverride --list /var/log/puppet >/dev/null 2>&1; then
+		dpkg-statoverride --update --add puppet puppet 0750 /var/log/puppet
+	fi
+
+	if ! dpkg-statoverride --list /var/lib/puppet >/dev/null 2>&1; then
+		dpkg-statoverride --update --add puppet puppet 0750 /var/lib/puppet
+	fi
+
+	# Create folders common to "puppet" and "puppetmaster", which need
+	# to be owned by the "puppet" user
+	install --owner puppet --group puppet --directory \
+		/var/lib/puppet/state
+	
+	# Handle 
+	if [ -d /etc/puppet/ssl ] && [ ! -e /var/lib/puppet/ssl ] && grep -q 'ssldir=/var/lib/puppet/ssl' /etc/puppet/puppet.conf; then
+		mv /etc/puppet/ssl /var/lib/puppet/ssl
+	fi
+fi
+
+# Automatically added by dh_installinit
+if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ]; then
+	# In case this system is running systemd, we need to ensure that all
+	# necessary tmpfiles (if any) are created before starting.
+	if [ -d /run/systemd/system ] ; then
+		systemd-tmpfiles --create /usr/lib/tmpfiles.d/puppet-common.conf >/dev/null || true
+	fi
+fi
+# End automatically added section
+
diff --git a/debian/stretch/puppet-linex-common/debian/postrm b/debian/stretch/puppet-linex-common/debian/postrm
new file mode 100755
index 0000000..7986d3c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/debian/postrm
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+set -e
+
+case "$1" in
+    purge)
+	rm -rf /var/lib/puppet
+	;;
+    remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
+        ;;
+    *)
+        echo "postrm called with unknown argument \`$1'" >&2
+        exit 1
+
+esac
+
+
+
+exit 0
diff --git a/debian/stretch/puppet-linex-common/debian/preinst b/debian/stretch/puppet-linex-common/debian/preinst
new file mode 100755
index 0000000..0316303
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/debian/preinst
@@ -0,0 +1,75 @@
+#!/bin/sh
+# preinst script for puppet-common
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <new-preinst> `install'
+#        * <new-preinst> `install' <old-version>
+#        * <new-preinst> `upgrade' <old-version>
+#        * <old-preinst> `abort-upgrade' <new-version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+disable_puppet_agent() {
+    mkdir -p /var/lib/puppet/state
+    tmp_lockfile=$(mktemp /var/lib/puppet/state/agent_disabled.lock.XXXXXXXX)
+    lockfile=/var/lib/puppet/state/agent_disabled.lock
+
+    printf '{"disabled_message":"Disabled by default on new or unconfigured old installations"}' \
+        > $tmp_lockfile
+
+    mv $tmp_lockfile $lockfile
+}
+
+case "$1" in
+    install)
+        # disable the puppet agent on the first install
+        if [ -z "$2" ]; then
+            disable_puppet_agent
+        elif dpkg --compare-versions "$2" lt "3.2.4-1~" && \
+            [ -e "/etc/default/puppet" ]; then
+            # Also disable puppet if we use conffiles from a version where the
+            # START flag mattered.
+            . /etc/default/puppet
+
+            if [ "x$START" != "xtrue" -a "x$START" != "xyes" -a "x$START" != "x0" ]; then
+                # Note that "0" is not a typo, it reflects the checks done
+                # in wheezy's initscript.
+                disable_puppet_agent
+            fi
+        fi
+        ;;
+
+    upgrade)
+        # Disable puppet if we are upgrading from a version where the START
+        # flag mattered.
+        if dpkg --compare-versions "$2" lt "3.2.4-1~" && \
+            [ -e "/etc/default/puppet" ]; then
+            . /etc/default/puppet
+
+            if [ "x$START" != "xtrue" -a "x$START" != "xyes" -a "x$START" != "x0" ]; then
+                # Note that "0" is not a typo, it reflects the checks done
+                # in wheezy's initscript.
+                disable_puppet_agent
+            fi
+        fi
+        ;;
+
+    abort-upgrade)
+        ;;
+
+    *)
+        echo "preinst called with unknown argument \`$1'" >&2
+        exit 1
+        ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+
+
+exit 0
diff --git a/debian/stretch/puppet-linex-common/etc/ldap/schema/puppet.schema b/debian/stretch/puppet-linex-common/etc/ldap/schema/puppet.schema
new file mode 100644
index 0000000..e5561f2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/etc/ldap/schema/puppet.schema
@@ -0,0 +1,24 @@
+attributetype (  1.3.6.1.4.1.34380.1.1.3.10 NAME 'puppetClass'
+	DESC 'Puppet Node Class'
+	EQUALITY caseIgnoreIA5Match
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.34380.1.1.3.9 NAME 'parentNode'
+	DESC 'Puppet Parent Node'
+	EQUALITY caseIgnoreIA5Match
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+        SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.34380.1.1.3.11 NAME 'environment'
+	DESC 'Puppet Node Environment'
+	EQUALITY caseIgnoreIA5Match
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.34380.1.1.3.12 NAME 'puppetVar'
+	DESC 'A variable setting for puppet'
+	EQUALITY caseIgnoreIA5Match
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+objectclass ( 1.3.6.1.4.1.34380.1.1.1.2 NAME 'puppetClient' SUP top AUXILIARY
+	DESC 'Puppet Client objectclass'
+	MAY ( puppetclass $ parentnode $ environment $ puppetvar ))
diff --git a/debian/stretch/puppet-linex-common/etc/logcheck/ignore.d.server/puppet-common b/debian/stretch/puppet-linex-common/etc/logcheck/ignore.d.server/puppet-common
new file mode 100644
index 0000000..4e5134f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/etc/logcheck/ignore.d.server/puppet-common
@@ -0,0 +1,23 @@
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-master\[[0-9]+\]: (Handled resources in|Resource comparison took|Searched for (host|resources|resource params and tags) in) [0-9.]+ seconds
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-master\[[0-9]+\]: Starting Puppet server version [.0-9]+$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-master\[[0-9]+\]: Compiled catalog for [._[:alnum:]-]+ in environment [._[:alnum:]-]+ in [.[:digit:]]+ seconds$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-master\[[0-9]+\]: Caught TERM; shutting down$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-master\[[0-9]+\]: Shutting down$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Starting Puppet client version [.0-9]+$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: getting config$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Caching configuration at [\/._[:alnum:]-]+$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Loaded state in [.0-9]+ seconds$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Calling puppetmaster.getconfig$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Retrieved configuration in [.0-9]+ seconds$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Starting configuration run$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Finished configuration run in [.0-9]+ seconds$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Caught (TERM|INT); shutting down$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Shutting down$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Restarting with .*$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Starting catalog run$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Finished catalog run in [.0-9]+ seconds$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Loading fact .*$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Ignoring cache$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Ignoring --listen on onetime run$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Retrieving plugins$
+^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-master\[[0-9]+\]: Reopening log files$
diff --git a/debian/stretch/puppet-linex-common/etc/puppet/etckeeper-commit-post b/debian/stretch/puppet-linex-common/etc/puppet/etckeeper-commit-post
new file mode 100755
index 0000000..489b2bd
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/etc/puppet/etckeeper-commit-post
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
+
+which etckeeper > /dev/null 2>&1 || exit 0
+
+etckeeper commit "committing changes in /etc after puppet catalog run"
+
+# Failure of etckeeper should not be fatal.
+exit 0
diff --git a/debian/stretch/puppet-linex-common/etc/puppet/etckeeper-commit-pre b/debian/stretch/puppet-linex-common/etc/puppet/etckeeper-commit-pre
new file mode 100755
index 0000000..a66fb62
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/etc/puppet/etckeeper-commit-pre
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
+
+which etckeeper > /dev/null 2>&1 || exit 0
+
+etckeeper commit "saving uncommitted changes in /etc prior to puppet catalog run"
+
+# Failure of etckeeper should not be fatal.
+exit 0
diff --git a/debian/stretch/puppet-linex-common/etc/puppet/puppet.conf b/debian/stretch/puppet-linex-common/etc/puppet/puppet.conf
new file mode 100644
index 0000000..856a854
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/etc/puppet/puppet.conf
@@ -0,0 +1,14 @@
+[main]
+logdir=/var/log/puppet
+vardir=/var/lib/puppet
+ssldir=/var/lib/puppet/ssl
+rundir=/run/puppet
+factpath=$vardir/lib/facter
+prerun_command=/etc/puppet/etckeeper-commit-pre
+postrun_command=/etc/puppet/etckeeper-commit-post
+
+[master]
+# These are needed when the puppetmaster is run by passenger
+# and can safely be removed if webrick is used.
+ssl_client_header = SSL_CLIENT_S_DN 
+ssl_client_verify_header = SSL_CLIENT_VERIFY
diff --git a/debian/stretch/puppet-linex-common/usr/bin/extlookup2hiera b/debian/stretch/puppet-linex-common/usr/bin/extlookup2hiera
new file mode 100755
index 0000000..063f985
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/bin/extlookup2hiera
@@ -0,0 +1,56 @@
+#!/usr/bin/ruby
+
+require 'optparse'
+require 'csv'
+
+options = {:in => nil, :out => nil, :format => :yaml}
+
+OptionParser.new do |opts|
+  opts.banner = "Converter for extlookup CSV files into Hiera JSON and YAML files"
+
+  opts.on("--in FILE", "-i", "Input CSV file") do |v|
+    options[:in] = v
+  end
+
+  opts.on("--out FILE", "-o", "Output Hiera file") do |v|
+    options[:out] = v
+  end
+
+  opts.on("--json", "-j", "Create JSON format file") do |v|
+    options[:format] = :json
+  end
+end.parse!
+
+if options[:in].nil? || options[:out].nil?
+  STDERR.puts "Please specify an input and output file with --in and --out"
+  exit 1
+end
+
+unless File.exist?(options[:in])
+  STDERR.puts "Cannot find input file #{options[:in]}"
+  exit 1
+end
+
+csvdata = CSV.read(options[:in])
+hieradata = {}
+
+csvdata.each do |d|
+  d = d.map{|item| item.to_s}
+
+  if d.size > 2
+    hieradata[d[0]] = d[1, d.size].flatten
+  else
+    hieradata[d[0]] = d[1]
+  end
+end
+
+case options[:format]
+when :yaml
+  require 'yaml'
+  File.open(options[:out], "w") {|f| f.write hieradata.to_yaml}
+when :json
+  require 'rubygems'
+  require 'json'
+  File.open(options[:out], "w") {|f| f.write JSON.pretty_generate hieradata}
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/bin/puppet b/debian/stretch/puppet-linex-common/usr/bin/puppet
new file mode 100755
index 0000000..320c039
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/bin/puppet
@@ -0,0 +1,8 @@
+#!/usr/bin/ruby
+
+# For security reasons, ensure that '.' is not on the load path
+# This is primarily for 1.8.7 since 1.9.2+ doesn't put '.' on the load path
+$LOAD_PATH.delete '.'
+
+require 'puppet/util/command_line'
+Puppet::Util::CommandLine.new.execute
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/hiera/backend/puppet_backend.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/hiera/backend/puppet_backend.rb
new file mode 100644
index 0000000..a227ce2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/hiera/backend/puppet_backend.rb
@@ -0,0 +1,103 @@
+require 'hiera/backend'
+
+class Hiera
+  module Backend
+    class Puppet_backend
+      def initialize
+        Hiera.debug("Hiera Puppet backend starting")
+      end
+
+      def hierarchy(scope, override)
+        begin
+          data_class = Config[:puppet][:datasource] || "data"
+        rescue
+          data_class = "data"
+        end
+
+        calling_class = scope.resource.name.to_s.downcase
+        calling_module = calling_class.split("::").first
+
+        hierarchy = Config[:hierarchy] || [calling_class, calling_module]
+
+        hierarchy = [hierarchy].flatten.map do |klass|
+          klass = Backend.parse_string(klass, scope,
+            {
+              "calling_class"  => calling_class,
+              "calling_module" => calling_module
+            }
+          )
+
+          next if klass == ""
+
+          [data_class, klass].join("::")
+        end.compact
+
+        hierarchy << [calling_class, data_class].join("::")
+
+        unless calling_module == calling_class
+          hierarchy << [calling_module, data_class].join("::")
+        end
+
+        hierarchy.insert(0, [data_class, override].join("::")) if override
+
+        hierarchy
+      end
+
+      def lookup(key, scope, order_override, resolution_type)
+        answer = nil
+
+        Hiera.debug("Looking up #{key} in Puppet backend")
+
+        Puppet::Parser::Functions.function(:include)
+        loaded_classes = scope.catalog.classes
+
+        hierarchy(scope, order_override).each do |klass|
+          Hiera.debug("Looking for data in #{klass}")
+
+          varname = [klass, key].join("::")
+          temp_answer = nil
+
+          unless loaded_classes.include?(klass)
+            begin
+              if scope.respond_to?(:function_include)
+                scope.function_include([klass])
+              else
+                scope.real.function_include([klass])
+              end
+
+              temp_answer = scope[varname]
+              Hiera.debug("Found data in class #{klass}")
+            rescue
+            end
+          else
+            temp_answer = scope[varname]
+          end
+
+          # Note that temp_answer might be define but false.
+          if temp_answer.nil?
+            next
+          else
+            # For array resolution we just append to the array whatever we
+            # find, we then go onto the next file and keep adding to the array.
+            #
+            # For priority searches we break after the first found data item.
+            case resolution_type
+            when :array
+              answer ||= []
+              answer << Backend.parse_answer(temp_answer, scope)
+            when :hash
+              answer ||= {}
+              answer = Backend.parse_answer(temp_answer, scope).merge answer
+            else
+              answer = Backend.parse_answer(temp_answer, scope)
+              break
+            end
+          end
+        end
+
+        answer
+      end
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/hiera/puppet_function.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/hiera/puppet_function.rb
new file mode 100644
index 0000000..fe5f441
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/hiera/puppet_function.rb
@@ -0,0 +1,82 @@
+require 'hiera_puppet'
+
+# Provides the base class for the puppet functions hiera, hiera_array, hiera_hash, and hiera_include.
+# The actual function definitions will call init_dispatch and override the merge_type and post_lookup methods.
+#
+# @see hiera_array.rb, hiera_include.rb under lib/puppet/functions for sample usage
+#
+class Hiera::PuppetFunction < Puppet::Functions::InternalFunction
+  def self.init_dispatch
+    dispatch :hiera_splat do
+      scope_param
+      param 'Tuple[String, Any, Any, 1, 3]', :args
+    end
+
+    dispatch :hiera_no_default do
+      scope_param
+      param 'String',:key
+    end
+
+    dispatch :hiera_with_default do
+      scope_param
+      param 'String',:key
+      param 'Any',   :default
+      optional_param 'Any',   :override
+    end
+
+    dispatch :hiera_block1 do
+      scope_param
+      param 'String',              :key
+      block_param 'Callable[1,1]', :default_block
+    end
+
+    dispatch :hiera_block2 do
+      scope_param
+      param 'String',              :key
+      param 'Any',                 :override
+      block_param 'Callable[1,1]', :default_block
+    end
+  end
+
+  def hiera_splat(scope, args)
+    hiera(scope, *args)
+  end
+
+  def hiera_no_default(scope, key)
+    post_lookup(scope, key, lookup(scope, key, nil, nil))
+  end
+
+  def hiera_with_default(scope, key, default, override = nil)
+    undefined = (@@undefined_value ||= Object.new)
+    result = lookup(scope, key, undefined, override)
+    post_lookup(scope, key, result.equal?(undefined) ? default : result)
+  end
+
+  def hiera_block1(scope, key, &default_block)
+    common(scope, key, nil, default_block)
+  end
+
+  def hiera_block2(scope, key, override, &default_block)
+    common(scope, key, override, default_block)
+  end
+
+  def common(scope, key, override, default_block)
+    undefined = (@@undefined_value ||= Object.new)
+    result = lookup(scope, key, undefined, override)
+    post_lookup(scope, key, result.equal?(undefined) ? default_block.call(key) : result)
+  end
+
+  private :common
+
+  def lookup(scope, key, default, override)
+    HieraPuppet.lookup(key, default, scope, override, merge_type)
+  end
+
+  def merge_type
+    :priority
+  end
+
+  def post_lookup(scope, key, result)
+    result
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/hiera/scope.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/hiera/scope.rb
new file mode 100644
index 0000000..781c1eb
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/hiera/scope.rb
@@ -0,0 +1,60 @@
+class Hiera
+  class Scope
+    CALLING_CLASS = "calling_class"
+    CALLING_MODULE = "calling_module"
+    MODULE_NAME = "module_name"
+
+    attr_reader :real
+
+    def initialize(real)
+      @real = real
+    end
+
+    def [](key)
+      if key == CALLING_CLASS
+        ans = find_hostclass(@real)
+      elsif key == CALLING_MODULE
+        ans = @real.lookupvar(MODULE_NAME)
+      else
+        ans = @real.lookupvar(key)
+      end
+
+      if ans.nil? or ans == ""
+        nil
+      else
+        ans
+      end
+    end
+
+    def include?(key)
+      if key == CALLING_CLASS or key == CALLING_MODULE
+        true
+      else
+        @real.lookupvar(key) != ""
+      end
+    end
+
+    def catalog
+      @real.catalog
+    end
+
+    def resource
+      @real.resource
+    end
+
+    def compiler
+      @real.compiler
+    end
+
+    def find_hostclass(scope)
+      if scope.source and scope.source.type == :hostclass
+        return scope.source.name.downcase
+      elsif scope.parent
+        return find_hostclass(scope.parent)
+      else
+        return nil
+      end
+    end
+    private :find_hostclass
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/hiera_puppet.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/hiera_puppet.rb
new file mode 100644
index 0000000..fe4fecd
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/hiera_puppet.rb
@@ -0,0 +1,87 @@
+require 'hiera'
+require 'hiera/scope'
+require 'puppet'
+
+module HieraPuppet
+  module_function
+
+  def lookup(key, default, scope, override, resolution_type)
+    scope = Hiera::Scope.new(scope)
+
+    answer = hiera.lookup(key, default, scope, override, resolution_type)
+
+    if answer.nil?
+      raise(Puppet::ParseError, "Could not find data item #{key} in any Hiera data file and no default supplied")
+    end
+
+    answer
+  end
+
+  def parse_args(args)
+    # Functions called from Puppet manifests like this:
+    #
+    #   hiera("foo", "bar")
+    #
+    # Are invoked internally after combining the positional arguments into a
+    # single array:
+    #
+    #   func = function_hiera
+    #   func(["foo", "bar"])
+    #
+    # Functions called from templates preserve the positional arguments:
+    #
+    #   scope.function_hiera("foo", "bar")
+    #
+    # Deal with Puppet's special calling mechanism here.
+    if args[0].is_a?(Array)
+      args = args[0]
+    end
+
+    if args.empty?
+      raise(Puppet::ParseError, "Please supply a parameter to perform a Hiera lookup")
+    end
+
+    key      = args[0]
+    default  = args[1]
+    override = args[2]
+
+    return [key, default, override]
+  end
+
+  private
+  module_function
+
+  def hiera
+    @hiera ||= Hiera.new(:config => hiera_config)
+  end
+
+  def hiera_config
+    config = {}
+
+    if config_file = hiera_config_file
+      config = Hiera::Config.load(config_file)
+    end
+
+    config[:logger] = 'puppet'
+    config
+  end
+
+  def hiera_config_file
+    config_file = nil
+
+    if Puppet.settings[:hiera_config].is_a?(String)
+      expanded_config_file = File.expand_path(Puppet.settings[:hiera_config])
+      if Puppet::FileSystem.exist?(expanded_config_file)
+        config_file = expanded_config_file
+      end
+    elsif Puppet.settings[:confdir].is_a?(String)
+      expanded_config_file = File.expand_path(File.join(Puppet.settings[:confdir], '/hiera.yaml'))
+      if Puppet::FileSystem.exist?(expanded_config_file)
+        config_file = expanded_config_file
+      end
+    end
+
+    config_file
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet.rb
new file mode 100644
index 0000000..7b89f4c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet.rb
@@ -0,0 +1,289 @@
+require 'puppet/version'
+
+# see the bottom of the file for further inclusions
+# Also see the new Vendor support - towards the end
+#
+require 'facter'
+require 'puppet/error'
+require 'puppet/util'
+require 'puppet/util/autoload'
+require 'puppet/settings'
+require 'puppet/util/feature'
+require 'puppet/util/suidmanager'
+require 'puppet/util/run_mode'
+require 'puppet/external/pson/common'
+require 'puppet/external/pson/version'
+require 'puppet/external/pson/pure'
+
+#------------------------------------------------------------
+# the top-level module
+#
+# all this really does is dictate how the whole system behaves, through
+# preferences for things like debugging
+#
+# it's also a place to find top-level commands like 'debug'
+
+# The main Puppet class. Everything is contained here.
+#
+# @api public
+module Puppet
+  require 'puppet/file_system'
+  require 'puppet/context'
+  require 'puppet/environments'
+
+  class << self
+    include Puppet::Util
+    attr_reader :features
+    attr_writer :name
+  end
+
+  # the hash that determines how our system behaves
+  @@settings = Puppet::Settings.new
+
+  # Note: It's important that these accessors (`self.settings`, `self.[]`) are
+  # defined before we try to load any "features" (which happens a few lines below),
+  # because the implementation of the features loading may examine the values of
+  # settings.
+  def self.settings
+    @@settings
+  end
+
+  # Get the value for a setting
+  #
+  # @param [Symbol] param the setting to retrieve
+  #
+  # @api public
+  def self.[](param)
+    if param == :debug
+      return Puppet::Util::Log.level == :debug
+    else
+      return @@settings[param]
+    end
+  end
+
+  # The services running in this process.
+  @services ||= []
+
+  require 'puppet/util/logging'
+
+  extend Puppet::Util::Logging
+
+  # The feature collection
+  @features = Puppet::Util::Feature.new('puppet/feature')
+
+  # Load the base features.
+  require 'puppet/feature/base'
+
+  # Store a new default value.
+  def self.define_settings(section, hash)
+    @@settings.define_settings(section, hash)
+  end
+
+  # setting access and stuff
+  def self.[]=(param,value)
+    @@settings[param] = value
+    # Ensure that all environment caches are cleared if we're changing the parser
+    lookup(:environments).clear_all if param == :parser
+  end
+
+  def self.clear
+    @@settings.clear
+  end
+
+  def self.debug=(value)
+    if value
+      Puppet::Util::Log.level=(:debug)
+    else
+      Puppet::Util::Log.level=(:notice)
+    end
+  end
+
+  def self.run_mode
+    # This sucks (the existence of this method); there are a lot of places in our code that branch based the value of
+    # "run mode", but there used to be some really confusing code paths that made it almost impossible to determine
+    # when during the lifecycle of a puppet application run the value would be set properly.  A lot of the lifecycle
+    # stuff has been cleaned up now, but it still seems frightening that we rely so heavily on this value.
+    #
+    # I'd like to see about getting rid of the concept of "run_mode" entirely, but there are just too many places in
+    # the code that call this method at the moment... so I've settled for isolating it inside of the Settings class
+    # (rather than using a global variable, as we did previously...).  Would be good to revisit this at some point.
+    #
+    # --cprice 2012-03-16
+    Puppet::Util::RunMode[@@settings.preferred_run_mode]
+  end
+
+  # Load all of the settings.
+  require 'puppet/defaults'
+
+  def self.genmanifest
+    if Puppet[:genmanifest]
+      puts Puppet.settings.to_manifest
+      exit(0)
+    end
+  end
+
+  # Parse the config file for this process.
+  # @deprecated Use {initialize_settings}
+  def self.parse_config()
+    Puppet.deprecation_warning("Puppet.parse_config is deprecated; please use Faces API (which will handle settings and state management for you), or (less desirable) call Puppet.initialize_settings")
+    Puppet.initialize_settings
+  end
+
+  # Initialize puppet's settings. This is intended only for use by external tools that are not
+  #  built off of the Faces API or the Puppet::Util::Application class. It may also be used
+  #  to initialize state so that a Face may be used programatically, rather than as a stand-alone
+  #  command-line tool.
+  #
+  # @api public
+  # @param args [Array<String>] the command line arguments to use for initialization
+  # @return [void]
+  def self.initialize_settings(args = [])
+    do_initialize_settings_for_run_mode(:user, args)
+  end
+
+  # Initialize puppet's settings for a specified run_mode.
+  #
+  # @deprecated Use {initialize_settings}
+  def self.initialize_settings_for_run_mode(run_mode)
+    Puppet.deprecation_warning("initialize_settings_for_run_mode may be removed in a future release, as may run_mode itself")
+    do_initialize_settings_for_run_mode(run_mode, [])
+  end
+
+  # private helper method to provide the implementation details of initializing for a run mode,
+  #  but allowing us to control where the deprecation warning is issued
+  def self.do_initialize_settings_for_run_mode(run_mode, args)
+    Puppet.settings.initialize_global_settings(args)
+    run_mode = Puppet::Util::RunMode[run_mode]
+    Puppet.settings.initialize_app_defaults(Puppet::Settings.app_defaults_for_run_mode(run_mode))
+    Puppet.push_context(Puppet.base_context(Puppet.settings), "Initial context after settings initialization")
+    Puppet::Parser::Functions.reset
+    Puppet::Util::Log.level = Puppet[:log_level]
+  end
+  private_class_method :do_initialize_settings_for_run_mode
+
+  # Create a new type.  Just proxy to the Type class.  The mirroring query
+  # code was deprecated in 2008, but this is still in heavy use.  I suppose
+  # this can count as a soft deprecation for the next dev. --daniel 2011-04-12
+  def self.newtype(name, options = {}, &block)
+    Puppet::Type.newtype(name, options, &block)
+  end
+
+  # Load vendored (setup paths, and load what is needed upfront).
+  # See the Vendor class for how to add additional vendored gems/code
+  require "puppet/vendor"
+  Puppet::Vendor.load_vendored
+
+  # Set default for YAML.load to unsafe so we don't affect programs
+  # requiring puppet -- in puppet we will call safe explicitly
+  SafeYAML::OPTIONS[:default_mode] = :unsafe
+
+  # The bindings used for initialization of puppet
+  # @api private
+  def self.base_context(settings)
+    environments = settings[:environmentpath]
+    modulepath = Puppet::Node::Environment.split_path(settings[:basemodulepath])
+
+    if environments.empty?
+      loaders = [Puppet::Environments::Legacy.new]
+    else
+      loaders = Puppet::Environments::Directories.from_path(environments, modulepath)
+      # in case the configured environment (used for the default sometimes)
+      # doesn't exist
+      default_environment = Puppet[:environment].to_sym
+      if default_environment == :production
+        loaders << Puppet::Environments::StaticPrivate.new(
+          Puppet::Node::Environment.create(Puppet[:environment].to_sym,
+                                           [],
+                                           Puppet::Node::Environment::NO_MANIFEST))
+      end
+    end
+
+    {
+      :environments => Puppet::Environments::Cached.new(Puppet::Environments::Combined.new(*loaders)),
+      :http_pool => proc {
+        require 'puppet/network/http'
+        Puppet::Network::HTTP::NoCachePool.new
+      }
+    }
+  end
+
+  # A simple set of bindings that is just enough to limp along to
+  # initialization where the {base_context} bindings are put in place
+  # @api private
+  def self.bootstrap_context
+    root_environment = Puppet::Node::Environment.create(:'*root*', [], Puppet::Node::Environment::NO_MANIFEST)
+    {
+      :current_environment => root_environment,
+      :root_environment => root_environment
+    }
+  end
+
+  # @param overrides [Hash] A hash of bindings to be merged with the parent context.
+  # @param description [String] A description of the context.
+  # @api private
+  def self.push_context(overrides, description = "")
+    @context.push(overrides, description)
+  end
+
+  # Return to the previous context.
+  # @raise [StackUnderflow] if the current context is the root
+  # @api private
+  def self.pop_context
+    @context.pop
+  end
+
+  # Lookup a binding by name or return a default value provided by a passed block (if given).
+  # @api private
+  def self.lookup(name, &block)
+    @context.lookup(name, &block)
+  end
+
+  # @param bindings [Hash] A hash of bindings to be merged with the parent context.
+  # @param description [String] A description of the context.
+  # @yield [] A block executed in the context of the temporarily pushed bindings.
+  # @api private
+  def self.override(bindings, description = "", &block)
+    @context.override(bindings, description, &block)
+  ensure
+    lookup(:root_environment).instance_variable_set(:@future_parser, nil)
+  end
+
+  # @api private
+  def self.mark_context(name)
+    @context.mark(name)
+  end
+
+  # @api private
+  def self.rollback_context(name)
+    @context.rollback(name)
+  end
+
+  require 'puppet/node'
+
+  # The single instance used for normal operation
+  @context = Puppet::Context.new(bootstrap_context)
+
+  # Is the future parser in effect for the given environment, or in :current_environment if no
+  # environment is given.
+  #
+  def self.future_parser?(in_environment = nil)
+    env = in_environment || Puppet.lookup(:current_environment) { return Puppet[:parser] == 'future' }
+    env.future_parser?
+  end
+end
+
+# This feels weird to me; I would really like for us to get to a state where there is never a "require" statement
+#  anywhere besides the very top of a file.  That would not be possible at the moment without a great deal of
+#  effort, but I think we should strive for it and revisit this at some point.  --cprice 2012-03-16
+
+require 'puppet/indirector'
+require 'puppet/type'
+require 'puppet/resource'
+require 'puppet/parser'
+require 'puppet/network'
+require 'puppet/ssl'
+require 'puppet/module'
+require 'puppet/data_binding'
+require 'puppet/util/storage'
+require 'puppet/status'
+require 'puppet/file_bucket/file'
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/agent.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/agent.rb
new file mode 100644
index 0000000..f6172d2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/agent.rb
@@ -0,0 +1,121 @@
+require 'puppet/application'
+
+# A general class for triggering a run of another
+# class.
+class Puppet::Agent
+  require 'puppet/agent/locker'
+  include Puppet::Agent::Locker
+
+  require 'puppet/agent/disabler'
+  include Puppet::Agent::Disabler
+
+  attr_reader :client_class, :client, :splayed, :should_fork
+
+  def initialize(client_class, should_fork=true)
+    @splayed = false
+
+    @should_fork = can_fork? && should_fork
+    @client_class = client_class
+  end
+
+  def can_fork?
+    Puppet.features.posix? && RUBY_PLATFORM != 'java'
+  end
+
+  def needing_restart?
+    Puppet::Application.restart_requested?
+  end
+
+  # Perform a run with our client.
+  def run(client_options = {})
+    if running?
+      Puppet.notice "Run of #{client_class} already in progress; skipping  (#{lockfile_path} exists)"
+      return
+    end
+    if disabled?
+      Puppet.notice "Skipping run of #{client_class}; administratively disabled (Reason: '#{disable_message}');\nUse 'puppet agent --enable' to re-enable."
+      return
+    end
+
+    result = nil
+    block_run = Puppet::Application.controlled_run do
+      splay client_options.fetch :splay, Puppet[:splay]
+      result = run_in_fork(should_fork) do
+        with_client do |client|
+          begin
+            client_args = client_options.merge(:pluginsync => Puppet[:pluginsync])
+            lock { client.run(client_args) }
+          rescue SystemExit,NoMemoryError
+            raise
+          rescue Exception => detail
+            Puppet.log_exception(detail, "Could not run #{client_class}: #{detail}")
+          end
+        end
+      end
+      true
+    end
+    Puppet.notice "Shutdown/restart in progress (#{Puppet::Application.run_status.inspect}); skipping run" unless block_run
+    result
+  end
+
+  def stopping?
+    Puppet::Application.stop_requested?
+  end
+
+  # Have we splayed already?
+  def splayed?
+    splayed
+  end
+
+  # Sleep when splay is enabled; else just return.
+  def splay(do_splay = Puppet[:splay])
+    return unless do_splay
+    return if splayed?
+
+    time = rand(Puppet[:splaylimit] + 1)
+    Puppet.info "Sleeping for #{time} seconds (splay is enabled)"
+    sleep(time)
+    @splayed = true
+  end
+
+  def run_in_fork(forking = true)
+    return yield unless forking or Puppet.features.windows?
+
+    child_pid = Kernel.fork do
+      $0 = "puppet agent: applying configuration"
+      begin
+        exit(yield)
+      rescue SystemExit
+        exit(-1)
+      rescue NoMemoryError
+        exit(-2)
+      end
+    end
+    exit_code = Process.waitpid2(child_pid)
+    case exit_code[1].exitstatus
+    when -1
+      raise SystemExit
+    when -2
+      raise NoMemoryError
+    end
+    exit_code[1].exitstatus
+  end
+
+  private
+
+  # Create and yield a client instance, keeping a reference
+  # to it during the yield.
+  def with_client
+    begin
+      @client = client_class.new
+    rescue SystemExit,NoMemoryError
+      raise
+    rescue Exception => detail
+      Puppet.log_exception(detail, "Could not create instance of #{client_class}: #{detail}")
+      return
+    end
+    yield @client
+  ensure
+    @client = nil
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/agent/disabler.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/agent/disabler.rb
new file mode 100644
index 0000000..b71dd03
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/agent/disabler.rb
@@ -0,0 +1,53 @@
+require 'puppet/util/json_lockfile'
+
+# This module is responsible for encapsulating the logic for
+#  "disabling" the puppet agent during a run; in other words,
+#  keeping track of enough state to answer the question
+#  "has the puppet agent been administratively disabled?"
+#
+# The implementation involves writing a lockfile with JSON
+#  contents, and is considered part of the public Puppet API
+#  because it used by external tools such as mcollective.
+#
+# For more information, please see docs on the website.
+#  http://links.puppetlabs.com/agent_lockfiles
+module Puppet::Agent::Disabler
+  DISABLED_MESSAGE_JSON_KEY = "disabled_message"
+
+  # Let the daemon run again, freely in the filesystem.
+  def enable
+    Puppet.notice "Enabling Puppet."
+    disable_lockfile.unlock
+  end
+
+  # Stop the daemon from making any catalog runs.
+  def disable(msg=nil)
+    data = {}
+    Puppet.notice "Disabling Puppet."
+    if (! msg.nil?)
+      data[DISABLED_MESSAGE_JSON_KEY] = msg
+    end
+    disable_lockfile.lock(data)
+  end
+
+  def disabled?
+    disable_lockfile.locked?
+  end
+
+  def disable_message
+    data = disable_lockfile.lock_data
+    return nil if data.nil?
+    if data.has_key?(DISABLED_MESSAGE_JSON_KEY)
+      return data[DISABLED_MESSAGE_JSON_KEY]
+    end
+    nil
+  end
+
+
+  def disable_lockfile
+    @disable_lockfile ||= Puppet::Util::JsonLockfile.new(Puppet[:agent_disabled_lockfile])
+
+    @disable_lockfile
+  end
+  private :disable_lockfile
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/agent/locker.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/agent/locker.rb
new file mode 100644
index 0000000..b262813
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/agent/locker.rb
@@ -0,0 +1,43 @@
+require 'puppet/util/pidlock'
+
+# This module is responsible for encapsulating the logic for "locking" the
+# puppet agent during a catalog run; in other words, keeping track of enough
+# state to answer the question "is there a puppet agent currently applying a
+# catalog?"
+#
+# The implementation involves writing a lockfile whose contents are simply the
+# PID of the running agent process.  This is considered part of the public
+# Puppet API because it used by external tools such as mcollective.
+#
+# For more information, please see docs on the website.
+#  http://links.puppetlabs.com/agent_lockfiles
+module Puppet::Agent::Locker
+  # Yield if we get a lock, else do nothing.  Return
+  # true/false depending on whether we get the lock.
+  def lock
+    if lockfile.lock
+      begin
+        yield
+      ensure
+        lockfile.unlock
+      end
+    end
+  end
+
+  def running?
+    lockfile.locked?
+  end
+
+  def lockfile_path
+    @lockfile_path ||= Puppet[:agent_catalog_run_lockfile]
+  end
+
+  def lockfile
+    @lockfile ||= Puppet::Util::Pidlock.new(lockfile_path)
+
+    @lockfile
+  end
+  private :lockfile
+
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application.rb
new file mode 100644
index 0000000..369f001
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application.rb
@@ -0,0 +1,513 @@
+require 'optparse'
+require 'puppet/util/command_line'
+require 'puppet/util/plugins'
+require 'puppet/util/constant_inflector'
+require 'puppet/error'
+
+module Puppet
+
+# This class handles all the aspects of a Puppet application/executable
+# * setting up options
+# * setting up logs
+# * choosing what to run
+# * representing execution status
+#
+# === Usage
+# An application is a subclass of Puppet::Application.
+#
+# For legacy compatibility,
+#      Puppet::Application[:example].run
+# is equivalent to
+#      Puppet::Application::Example.new.run
+#
+#
+# class Puppet::Application::Example < Puppet::Application
+#
+#     def preinit
+#         # perform some pre initialization
+#         @all = false
+#     end
+#
+#     # run_command is called to actually run the specified command
+#     def run_command
+#         send Puppet::Util::CommandLine.new.args.shift
+#     end
+#
+#     # option uses metaprogramming to create a method
+#     # and also tells the option parser how to invoke that method
+#     option("--arg ARGUMENT") do |v|
+#         @args << v
+#     end
+#
+#     option("--debug", "-d") do |v|
+#         @debug = v
+#     end
+#
+#     option("--all", "-a:) do |v|
+#         @all = v
+#     end
+#
+#     def handle_unknown(opt,arg)
+#         # last chance to manage an option
+#         ...
+#         # let's say to the framework we finally handle this option
+#         true
+#     end
+#
+#     def read
+#         # read action
+#     end
+#
+#     def write
+#         # writeaction
+#     end
+#
+# end
+#
+# === Preinit
+# The preinit block is the first code to be called in your application, before option parsing,
+# setup or command execution.
+#
+# === Options
+# Puppet::Application uses +OptionParser+ to manage the application options.
+# Options are defined with the +option+ method to which are passed various
+# arguments, including the long option, the short option, a description...
+# Refer to +OptionParser+ documentation for the exact format.
+# * If the option method is given a block, this one will be called whenever
+# the option is encountered in the command-line argument.
+# * If the option method has no block, a default functionnality will be used, that
+# stores the argument (or true/false if the option doesn't require an argument) in
+# the global (to the application) options array.
+# * If a given option was not defined by a the +option+ method, but it exists as a Puppet settings:
+#  * if +unknown+ was used with a block, it will be called with the option name and argument
+#  * if +unknown+ wasn't used, then the option/argument is handed to Puppet.settings.handlearg for
+#    a default behavior
+#
+# --help is managed directly by the Puppet::Application class, but can be overriden.
+#
+# === Setup
+# Applications can use the setup block to perform any initialization.
+# The default +setup+ behaviour is to: read Puppet configuration and manage log level and destination
+#
+# === What and how to run
+# If the +dispatch+ block is defined it is called. This block should return the name of the registered command
+# to be run.
+# If it doesn't exist, it defaults to execute the +main+ command if defined.
+#
+# === Execution state
+# The class attributes/methods of Puppet::Application serve as a global place to set and query the execution
+# status of the application: stopping, restarting, etc.  The setting of the application status does not directly
+# affect its running status; it's assumed that the various components within the application will consult these
+# settings appropriately and affect their own processing accordingly.  Control operations (signal handlers and
+# the like) should set the status appropriately to indicate to the overall system that it's the process of
+# stopping or restarting (or just running as usual).
+#
+# So, if something in your application needs to stop the process, for some reason, you might consider:
+#
+#  def stop_me!
+#      # indicate that we're stopping
+#      Puppet::Application.stop!
+#      # ...do stuff...
+#  end
+#
+# And, if you have some component that involves a long-running process, you might want to consider:
+#
+#  def my_long_process(giant_list_to_munge)
+#      giant_list_to_munge.collect do |member|
+#          # bail if we're stopping
+#          return if Puppet::Application.stop_requested?
+#          process_member(member)
+#      end
+#  end
+class Application
+  require 'puppet/util'
+  include Puppet::Util
+
+  DOCPATTERN = ::File.expand_path(::File.dirname(__FILE__) + "/util/command_line/*" )
+  CommandLineArgs = Struct.new(:subcommand_name, :args)
+
+  @loader = Puppet::Util::Autoload.new(self, 'puppet/application')
+
+  class << self
+    include Puppet::Util
+
+    attr_accessor :run_status
+
+    def clear!
+      self.run_status = nil
+    end
+
+    def stop!
+      self.run_status = :stop_requested
+    end
+
+    def restart!
+      self.run_status = :restart_requested
+    end
+
+    # Indicates that Puppet::Application.restart! has been invoked and components should
+    # do what is necessary to facilitate a restart.
+    def restart_requested?
+      :restart_requested == run_status
+    end
+
+    # Indicates that Puppet::Application.stop! has been invoked and components should do what is necessary
+    # for a clean stop.
+    def stop_requested?
+      :stop_requested == run_status
+    end
+
+    # Indicates that one of stop! or start! was invoked on Puppet::Application, and some kind of process
+    # shutdown/short-circuit may be necessary.
+    def interrupted?
+      [:restart_requested, :stop_requested].include? run_status
+    end
+
+    # Indicates that Puppet::Application believes that it's in usual running run_mode (no stop/restart request
+    # currently active).
+    def clear?
+      run_status.nil?
+    end
+
+    # Only executes the given block if the run status of Puppet::Application is clear (no restarts, stops,
+    # etc. requested).
+    # Upon block execution, checks the run status again; if a restart has been requested during the block's
+    # execution, then controlled_run will send a new HUP signal to the current process.
+    # Thus, long-running background processes can potentially finish their work before a restart.
+    def controlled_run(&block)
+      return unless clear?
+      result = block.call
+      Process.kill(:HUP, $PID) if restart_requested?
+      result
+    end
+
+    SHOULD_PARSE_CONFIG_DEPRECATION_MSG = "is no longer supported; config file parsing " +
+        "is now controlled by the puppet engine, rather than by individual applications.  This " +
+        "method will be removed in a future version of puppet."
+
+    def should_parse_config
+      Puppet.deprecation_warning("should_parse_config " + SHOULD_PARSE_CONFIG_DEPRECATION_MSG)
+    end
+
+    def should_not_parse_config
+      Puppet.deprecation_warning("should_not_parse_config " + SHOULD_PARSE_CONFIG_DEPRECATION_MSG)
+    end
+
+    def should_parse_config?
+      Puppet.deprecation_warning("should_parse_config? " + SHOULD_PARSE_CONFIG_DEPRECATION_MSG)
+      true
+    end
+
+    # used to declare code that handle an option
+    def option(*options, &block)
+      long = options.find { |opt| opt =~ /^--/ }.gsub(/^--(?:\[no-\])?([^ =]+).*$/, '\1' ).gsub('-','_')
+      fname = "handle_#{long}".intern
+      if (block_given?)
+        define_method(fname, &block)
+      else
+        define_method(fname) do |value|
+          self.options["#{long}".to_sym] = value
+        end
+      end
+      self.option_parser_commands << [options, fname]
+    end
+
+    def banner(banner = nil)
+      @banner ||= banner
+    end
+
+    def option_parser_commands
+      @option_parser_commands ||= (
+        superclass.respond_to?(:option_parser_commands) ? superclass.option_parser_commands.dup : []
+      )
+      @option_parser_commands
+    end
+
+    # @return [Array<String>] the names of available applications
+    # @api public
+    def available_application_names
+      @loader.files_to_load.map do |fn|
+        ::File.basename(fn, '.rb')
+      end.uniq
+    end
+
+    # Finds the class for a given application and loads the class. This does
+    # not create an instance of the application, it only gets a handle to the
+    # class. The code for the application is expected to live in a ruby file
+    # `puppet/application/#{name}.rb` that is available on the `$LOAD_PATH`.
+    #
+    # @param application_name [String] the name of the application to find (eg. "apply").
+    # @return [Class] the Class instance of the application that was found.
+    # @raise [Puppet::Error] if the application class was not found.
+    # @raise [LoadError] if there was a problem loading the application file.
+    # @api public
+    def find(application_name)
+      begin
+        require @loader.expand(application_name.to_s.downcase)
+      rescue LoadError => e
+        Puppet.log_and_raise(e, "Unable to find application '#{application_name}'. #{e}")
+      end
+
+      class_name = Puppet::Util::ConstantInflector.file2constant(application_name.to_s)
+
+      clazz = try_load_class(class_name)
+
+      ################################################################
+      #### Begin 2.7.x backward compatibility hack;
+      ####  eventually we need to issue a deprecation warning here,
+      ####  and then get rid of this stanza in a subsequent release.
+      ################################################################
+      if (clazz.nil?)
+        class_name = application_name.capitalize
+        clazz = try_load_class(class_name)
+      end
+      ################################################################
+      #### End 2.7.x backward compatibility hack
+      ################################################################
+
+      if clazz.nil?
+        raise Puppet::Error.new("Unable to load application class '#{class_name}' from file 'puppet/application/#{application_name}.rb'")
+      end
+
+      return clazz
+    end
+
+    # Given the fully qualified name of a class, attempt to get the class instance.
+    # @param [String] class_name the fully qualified name of the class to try to load
+    # @return [Class] the Class instance, or nil? if it could not be loaded.
+    def try_load_class(class_name)
+        return self.const_defined?(class_name) ? const_get(class_name) : nil
+    end
+    private :try_load_class
+
+    def [](name)
+      find(name).new
+    end
+
+    # Sets or gets the run_mode name. Sets the run_mode name if a mode_name is
+    # passed. Otherwise, gets the run_mode or a default run_mode
+    #
+    def run_mode( mode_name = nil)
+      if mode_name
+        Puppet.settings.preferred_run_mode = mode_name
+      end
+
+      return @run_mode if @run_mode and not mode_name
+
+      require 'puppet/util/run_mode'
+      @run_mode = Puppet::Util::RunMode[ mode_name || Puppet.settings.preferred_run_mode ]
+    end
+
+    # This is for testing only
+    def clear_everything_for_tests
+      @run_mode = @banner = @run_status = @option_parser_commands = nil
+    end
+  end
+
+  attr_reader :options, :command_line
+
+  # Every app responds to --version
+  # See also `lib/puppet/util/command_line.rb` for some special case early
+  # handling of this.
+  option("--version", "-V") do |arg|
+    puts "#{Puppet.version}"
+    exit
+  end
+
+  # Every app responds to --help
+  option("--help", "-h") do |v|
+    puts help
+    exit
+  end
+
+  def app_defaults()
+    Puppet::Settings.app_defaults_for_run_mode(self.class.run_mode).merge(
+        :name => name
+    )
+  end
+
+  def initialize_app_defaults()
+    Puppet.settings.initialize_app_defaults(app_defaults)
+  end
+
+  # override to execute code before running anything else
+  def preinit
+  end
+
+  def initialize(command_line = Puppet::Util::CommandLine.new)
+    @command_line = CommandLineArgs.new(command_line.subcommand_name, command_line.args.dup)
+    @options = {}
+  end
+
+  # Execute the application.
+  # @api public
+  # @return [void]
+  def run
+
+    # I don't really like the names of these lifecycle phases.  It would be nice to change them to some more meaningful
+    # names, and make deprecated aliases.  Also, Daniel suggests that we can probably get rid of this "plugin_hook"
+    # pattern, but we need to check with PE and the community first.  --cprice 2012-03-16
+    #
+
+    exit_on_fail("get application-specific default settings") do
+      plugin_hook('initialize_app_defaults') { initialize_app_defaults }
+    end
+
+    Puppet.push_context(Puppet.base_context(Puppet.settings), "Update for application settings (#{self.class.run_mode})")
+    # This use of configured environment is correct, this is used to establish
+    # the defaults for an application that does not override, or where an override
+    # has not been made from the command line.
+    #
+    configured_environment_name = Puppet[:environment]
+    if self.class.run_mode.name == :agent
+      configured_environment = Puppet::Node::Environment.remote(configured_environment_name)
+    else
+      configured_environment = Puppet.lookup(:environments).get!(configured_environment_name)
+    end
+    configured_environment = configured_environment.override_from_commandline(Puppet.settings)
+
+    # Setup a new context using the app's configuration
+    Puppet.push_context({ :current_environment => configured_environment },
+                    "Update current environment from application's configuration")
+
+    require 'puppet/util/instrumentation'
+    Puppet::Util::Instrumentation.init
+
+    exit_on_fail("initialize")                                   { plugin_hook('preinit')       { preinit } }
+    exit_on_fail("parse application options")                    { plugin_hook('parse_options') { parse_options } }
+    exit_on_fail("prepare for execution")                        { plugin_hook('setup')         { setup } }
+    exit_on_fail("configure routes from #{Puppet[:route_file]}") { configure_indirector_routes }
+    exit_on_fail("log runtime debug info")                       { log_runtime_environment }
+    exit_on_fail("run")                                          { plugin_hook('run_command')   { run_command } }
+  end
+
+  def main
+    raise NotImplementedError, "No valid command or main"
+  end
+
+  def run_command
+    main
+  end
+
+  def setup
+    setup_logs
+  end
+
+  def setup_logs
+    if options[:debug] || options[:verbose]
+      Puppet::Util::Log.newdestination(:console)
+    end
+
+    set_log_level
+
+    Puppet::Util::Log.setup_default unless options[:setdest]
+  end
+
+  def set_log_level
+    if options[:debug]
+      Puppet::Util::Log.level = :debug
+    elsif options[:verbose]
+      Puppet::Util::Log.level = :info
+    end
+  end
+
+  def handle_logdest_arg(arg)
+    begin
+      Puppet::Util::Log.newdestination(arg)
+      options[:setdest] = true
+    rescue => detail
+      Puppet.log_exception(detail)
+    end
+  end
+
+  def configure_indirector_routes
+    route_file = Puppet[:route_file]
+    if Puppet::FileSystem.exist?(route_file)
+      routes = YAML.load_file(route_file)
+      application_routes = routes[name.to_s]
+      Puppet::Indirector.configure_routes(application_routes) if application_routes
+    end
+  end
+
+  # Output basic information about the runtime environment for debugging
+  # purposes.
+  #
+  # @api public
+  #
+  # @param extra_info [Hash{String => #to_s}] a flat hash of extra information
+  #   to log. Intended to be passed to super by subclasses.
+  # @return [void]
+  def log_runtime_environment(extra_info=nil)
+    runtime_info = {
+      'puppet_version' => Puppet.version,
+      'ruby_version'   => RUBY_VERSION,
+      'run_mode'       => self.class.run_mode.name,
+    }
+    runtime_info['default_encoding'] = Encoding.default_external if RUBY_VERSION >= '1.9.3'
+    runtime_info.merge!(extra_info) unless extra_info.nil?
+
+    Puppet.debug 'Runtime environment: ' + runtime_info.map{|k,v| k + '=' + v.to_s}.join(', ')
+  end
+
+  def parse_options
+    # Create an option parser
+    option_parser = OptionParser.new(self.class.banner)
+
+    # Here we're building up all of the options that the application may need to handle.  The main
+    # puppet settings defined in "defaults.rb" have already been parsed once (in command_line.rb) by
+    # the time we get here; however, our app may wish to handle some of them specially, so we need to
+    # make the parser aware of them again.  We might be able to make this a bit more efficient by
+    # re-using the parser object that gets built up in command_line.rb.  --cprice 2012-03-16
+
+    # Add all global options to it.
+    Puppet.settings.optparse_addargs([]).each do |option|
+      option_parser.on(*option) do |arg|
+        handlearg(option[0], arg)
+      end
+    end
+
+    # Add options that are local to this application, which were
+    # created using the "option()" metaprogramming method.  If there
+    # are any conflicts, this application's options will be favored.
+    self.class.option_parser_commands.each do |options, fname|
+      option_parser.on(*options) do |value|
+        # Call the method that "option()" created.
+        self.send(fname, value)
+      end
+    end
+
+    # Scan command line.  We just hand any exceptions to our upper levels,
+    # rather than printing help and exiting, so that we can meaningfully
+    # respond with context-sensitive help if we want to. --daniel 2011-04-12
+    option_parser.parse!(self.command_line.args)
+  end
+
+  def handlearg(opt, val)
+    opt, val = Puppet::Settings.clean_opt(opt, val)
+    send(:handle_unknown, opt, val) if respond_to?(:handle_unknown)
+  end
+
+  # this is used for testing
+  def self.exit(code)
+    exit(code)
+  end
+
+  def name
+    self.class.to_s.sub(/.*::/,"").downcase.to_sym
+  end
+
+  def help
+    "No help available for puppet #{name}"
+  end
+
+
+
+  def plugin_hook(step,&block)
+    Puppet::Plugins.send("before_application_#{step}",:application_object => self)
+    x = yield
+    Puppet::Plugins.send("after_application_#{step}",:application_object => self, :return_value => x)
+    x
+  end
+  private :plugin_hook
+end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/agent.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/agent.rb
new file mode 100644
index 0000000..fd6fdbd
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/agent.rb
@@ -0,0 +1,485 @@
+require 'puppet/application'
+require 'puppet/run'
+require 'puppet/daemon'
+require 'puppet/util/pidlock'
+
+class Puppet::Application::Agent < Puppet::Application
+
+  run_mode :agent
+
+  def app_defaults
+    super.merge({
+      :catalog_terminus => :rest,
+      :catalog_cache_terminus => :json,
+      :node_terminus => :rest,
+      :facts_terminus => :facter,
+    })
+  end
+
+  def preinit
+    # Do an initial trap, so that cancels don't get a stack trace.
+    Signal.trap(:INT) do
+      $stderr.puts "Cancelling startup"
+      exit(0)
+    end
+
+    {
+      :waitforcert => nil,
+      :detailed_exitcodes => false,
+      :verbose => false,
+      :debug => false,
+      :setdest => false,
+      :enable => false,
+      :disable => false,
+      :client => true,
+      :fqdn => nil,
+      :serve => [],
+      :digest => 'SHA256',
+      :graph => true,
+      :fingerprint => false,
+    }.each do |opt,val|
+      options[opt] = val
+    end
+
+    @argv = ARGV.dup
+  end
+
+  option("--disable [MESSAGE]") do |message|
+    options[:disable] = true
+    options[:disable_message] = message
+  end
+
+  option("--enable")
+  option("--debug","-d")
+  option("--fqdn FQDN","-f")
+  option("--test","-t")
+  option("--verbose","-v")
+
+  option("--fingerprint")
+  option("--digest DIGEST")
+
+  option("--no-client") do |arg|
+    options[:client] = false
+  end
+
+  option("--detailed-exitcodes") do |arg|
+    options[:detailed_exitcodes] = true
+  end
+
+  option("--logdest DEST", "-l DEST") do |arg|
+    handle_logdest_arg(arg)
+  end
+
+  option("--waitforcert WAITFORCERT", "-w") do |arg|
+    options[:waitforcert] = arg.to_i
+  end
+
+  def help
+    <<-'HELP'
+
+puppet-agent(8) -- The puppet agent daemon
+========
+
+SYNOPSIS
+--------
+Retrieves the client configuration from the puppet master and applies it to
+the local host.
+
+This service may be run as a daemon, run periodically using cron (or something
+similar), or run interactively for testing purposes.
+
+
+USAGE
+-----
+puppet agent [--certname <NAME>] [-D|--daemonize|--no-daemonize]
+  [-d|--debug] [--detailed-exitcodes] [--digest <DIGEST>] [--disable [MESSAGE]] [--enable]
+  [--fingerprint] [-h|--help] [-l|--logdest syslog|eventlog|<FILE>|console]
+  [--masterport <PORT>] [--no-client] [--noop] [-o|--onetime] [-t|--test]
+  [-v|--verbose] [-V|--version] [-w|--waitforcert <SECONDS>]
+
+
+DESCRIPTION
+-----------
+This is the main puppet client. Its job is to retrieve the local
+machine's configuration from a remote server and apply it. In order to
+successfully communicate with the remote server, the client must have a
+certificate signed by a certificate authority that the server trusts;
+the recommended method for this, at the moment, is to run a certificate
+authority as part of the puppet server (which is the default). The
+client will connect and request a signed certificate, and will continue
+connecting until it receives one.
+
+Once the client has a signed certificate, it will retrieve its
+configuration and apply it.
+
+
+USAGE NOTES
+-----------
+'puppet agent' does its best to find a compromise between interactive
+use and daemon use. Run with no arguments and no configuration, it will
+go into the background, attempt to get a signed certificate, and retrieve
+and apply its configuration every 30 minutes.
+
+Some flags are meant specifically for interactive use -- in particular,
+'test', 'tags' or 'fingerprint' are useful. 'test' enables verbose
+logging, causes the daemon to stay in the foreground, exits if the
+server's configuration is invalid (this happens if, for instance, you've
+left a syntax error on the server), and exits after running the
+configuration once (rather than hanging around as a long-running
+process).
+
+'tags' allows you to specify what portions of a configuration you want
+to apply. Puppet elements are tagged with all of the class or definition
+names that contain them, and you can use the 'tags' flag to specify one
+of these names, causing only configuration elements contained within
+that class or definition to be applied. This is very useful when you are
+testing new configurations -- for instance, if you are just starting to
+manage 'ntpd', you would put all of the new elements into an 'ntpd'
+class, and call puppet with '--tags ntpd', which would only apply that
+small portion of the configuration during your testing, rather than
+applying the whole thing.
+
+'fingerprint' is a one-time flag. In this mode 'puppet agent' will run
+once and display on the console (and in the log) the current certificate
+(or certificate request) fingerprint. Providing the '--digest' option
+allows to use a different digest algorithm to generate the fingerprint.
+The main use is to verify that before signing a certificate request on
+the master, the certificate request the master received is the same as
+the one the client sent (to prevent against man-in-the-middle attacks
+when signing certificates).
+
+
+OPTIONS
+-------
+
+Note that any Puppet setting that's valid in the configuration file is also a
+valid long argument. For example, 'server' is a valid setting, so you can
+specify '--server <servername>' as an argument. Boolean settings translate into
+'--setting' and '--no-setting' pairs.
+
+See the configuration file documentation at
+http://docs.puppetlabs.com/references/stable/configuration.html for the
+full list of acceptable settings. A commented list of all settings can also be
+generated by running puppet agent with '--genconfig'.
+
+* --certname:
+  Set the certname (unique ID) of the client. The master reads this
+  unique identifying string, which is usually set to the node's
+  fully-qualified domain name, to determine which configurations the
+  node will receive. Use this option to debug setup problems or
+  implement unusual node identification schemes.
+  (This is a Puppet setting, and can go in puppet.conf.)
+
+* --daemonize:
+  Send the process into the background. This is the default.
+  (This is a Puppet setting, and can go in puppet.conf. Note the special 'no-'
+  prefix for boolean settings on the command line.)
+
+* --no-daemonize:
+  Do not send the process into the background.
+  (This is a Puppet setting, and can go in puppet.conf. Note the special 'no-'
+  prefix for boolean settings on the command line.)
+
+* --debug:
+  Enable full debugging.
+
+* --detailed-exitcodes:
+  Provide transaction information via exit codes. If this is enabled, an exit
+  code of '2' means there were changes, an exit code of '4' means there were
+  failures during the transaction, and an exit code of '6' means there were both
+  changes and failures.
+
+* --digest:
+  Change the certificate fingerprinting digest algorithm. The default is
+  SHA256. Valid values depends on the version of OpenSSL installed, but
+  will likely contain MD5, MD2, SHA1 and SHA256.
+
+* --disable:
+  Disable working on the local system. This puts a lock file in place,
+  causing 'puppet agent' not to work on the system until the lock file
+  is removed. This is useful if you are testing a configuration and do
+  not want the central configuration to override the local state until
+  everything is tested and committed.
+
+  Disable can also take an optional message that will be reported by the
+  'puppet agent' at the next disabled run.
+
+  'puppet agent' uses the same lock file while it is running, so no more
+  than one 'puppet agent' process is working at a time.
+
+  'puppet agent' exits after executing this.
+
+* --enable:
+  Enable working on the local system. This removes any lock file,
+  causing 'puppet agent' to start managing the local system again
+  (although it will continue to use its normal scheduling, so it might
+  not start for another half hour).
+
+  'puppet agent' exits after executing this.
+
+* --fingerprint:
+  Display the current certificate or certificate signing request
+  fingerprint and then exit. Use the '--digest' option to change the
+  digest algorithm used.
+
+* --help:
+  Print this help message
+
+* --logdest:
+  Where to send log messages. Choose between 'syslog' (the POSIX syslog
+  service), 'eventlog' (the Windows Event Log), 'console', or the path to a log
+  file. If debugging or verbosity is enabled, this defaults to 'console'.
+  Otherwise, it defaults to 'syslog' on POSIX systems and 'eventlog' on Windows.
+
+  A path ending with '.json' will receive structured output in JSON format. The
+  log file will not have an ending ']' automatically written to it due to the
+  appending nature of logging. It must be appended manually to make the content
+  valid JSON.
+
+* --masterport:
+  The port on which to contact the puppet master.
+  (This is a Puppet setting, and can go in puppet.conf.)
+
+* --no-client:
+  Do not create a config client. This will cause the daemon to start
+  but not check configuration unless it is triggered with `puppet
+  kick`. This only makes sense when puppet agent is being run with
+  listen = true in puppet.conf or was started with the `--listen` option.
+
+* --noop:
+  Use 'noop' mode where the daemon runs in a no-op or dry-run mode. This
+  is useful for seeing what changes Puppet will make without actually
+  executing the changes.
+  (This is a Puppet setting, and can go in puppet.conf. Note the special 'no-'
+  prefix for boolean settings on the command line.)
+
+* --onetime:
+  Run the configuration once. Runs a single (normally daemonized) Puppet
+  run. Useful for interactively running puppet agent when used in
+  conjunction with the --no-daemonize option.
+  (This is a Puppet setting, and can go in puppet.conf. Note the special 'no-'
+  prefix for boolean settings on the command line.)
+
+* --test:
+  Enable the most common options used for testing. These are 'onetime',
+  'verbose', 'ignorecache', 'no-daemonize', 'no-usecacheonfailure',
+  'detailed-exitcodes', 'no-splay', and 'show_diff'.
+
+* --verbose:
+  Turn on verbose reporting.
+
+* --version:
+  Print the puppet version number and exit.
+
+* --waitforcert:
+  This option only matters for daemons that do not yet have certificates
+  and it is enabled by default, with a value of 120 (seconds). This
+  causes 'puppet agent' to connect to the server every 2 minutes and ask
+  it to sign a certificate request. This is useful for the initial setup
+  of a puppet client. You can turn off waiting for certificates by
+  specifying a time of 0.
+  (This is a Puppet setting, and can go in puppet.conf. Note the special 'no-'
+  prefix for boolean settings on the command line.)
+
+
+EXAMPLE
+-------
+    $ puppet agent --server puppet.domain.com
+
+
+DIAGNOSTICS
+-----------
+
+Puppet agent accepts the following signals:
+
+* SIGHUP:
+  Restart the puppet agent daemon.
+* SIGINT and SIGTERM:
+  Shut down the puppet agent daemon.
+* SIGUSR1:
+  Immediately retrieve and apply configurations from the puppet master.
+* SIGUSR2:
+  Close file descriptors for log files and reopen them. Used with logrotate.
+
+AUTHOR
+------
+Luke Kanies
+
+
+COPYRIGHT
+---------
+Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License
+
+    HELP
+  end
+
+  def run_command
+    if options[:fingerprint]
+      fingerprint
+    else
+      # It'd be nice to daemonize later, but we have to daemonize before
+      # waiting for certificates so that we don't block
+      daemon = daemonize_process_when(Puppet[:daemonize])
+
+      wait_for_certificates
+
+      if Puppet[:onetime]
+        onetime(daemon)
+      else
+        main(daemon)
+      end
+    end
+  end
+
+  def fingerprint
+    host = Puppet::SSL::Host.new
+    unless cert = host.certificate || host.certificate_request
+      $stderr.puts "Fingerprint asked but no certificate nor certificate request have yet been issued"
+      exit(1)
+      return
+    end
+    unless digest = cert.digest(options[:digest].to_s)
+      raise ArgumentError, "Could not get fingerprint for digest '#{options[:digest]}'"
+    end
+    puts digest.to_s
+  end
+
+  def onetime(daemon)
+    if Puppet[:listen]
+      Puppet.notice "Ignoring --listen on onetime run"
+    end
+
+    unless options[:client]
+      Puppet.err "onetime is specified but there is no client"
+      exit(43)
+      return
+    end
+
+    daemon.set_signal_traps
+
+    begin
+      exitstatus = daemon.agent.run
+    rescue => detail
+      Puppet.log_exception(detail)
+    end
+
+    daemon.stop(:exit => false)
+
+    if not exitstatus
+      exit(1)
+    elsif options[:detailed_exitcodes] then
+      exit(exitstatus)
+    else
+      exit(0)
+    end
+  end
+
+  def main(daemon)
+    if Puppet[:listen]
+      setup_listen(daemon)
+    end
+    Puppet.notice "Starting Puppet client version #{Puppet.version}"
+
+    daemon.start
+  end
+
+  # Enable all of the most common test options.
+  def setup_test
+    Puppet.settings.handlearg("--ignorecache")
+    Puppet.settings.handlearg("--no-usecacheonfailure")
+    Puppet.settings.handlearg("--no-splay")
+    Puppet.settings.handlearg("--show_diff")
+    Puppet.settings.handlearg("--no-daemonize")
+    options[:verbose] = true
+    Puppet[:onetime] = true
+    options[:detailed_exitcodes] = true
+  end
+
+  def setup
+    setup_test if options[:test]
+
+    setup_logs
+
+    exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
+
+    if options[:fqdn]
+      Puppet[:certname] = options[:fqdn]
+    end
+
+    Puppet.settings.use :main, :agent, :ssl
+
+    # Always ignoreimport for agent. It really shouldn't even try to import,
+    # but this is just a temporary band-aid.
+    Puppet[:ignoreimport] = true
+
+    Puppet::Transaction::Report.indirection.terminus_class = :rest
+    # we want the last report to be persisted locally
+    Puppet::Transaction::Report.indirection.cache_class = :yaml
+
+    if Puppet[:catalog_cache_terminus]
+      Puppet::Resource::Catalog.indirection.cache_class = Puppet[:catalog_cache_terminus]
+    end
+
+    if options[:fingerprint]
+      # in fingerprint mode we just need
+      # access to the local files and we don't need a ca
+      Puppet::SSL::Host.ca_location = :none
+    else
+      Puppet::SSL::Host.ca_location = :remote
+      setup_agent
+    end
+  end
+
+  private
+
+  def enable_disable_client(agent)
+    if options[:enable]
+      agent.enable
+    elsif options[:disable]
+      agent.disable(options[:disable_message] || 'reason not specified')
+    end
+    exit(0)
+  end
+
+  def setup_listen(daemon)
+    Puppet.warning "Puppet --listen / kick is deprecated. See http://links.puppetlabs.com/puppet-kick-deprecation"
+    unless Puppet::FileSystem.exist?(Puppet[:rest_authconfig])
+      Puppet.err "Will not start without authorization file #{Puppet[:rest_authconfig]}"
+      exit(14)
+    end
+
+    require 'puppet/network/server'
+    # No REST handlers yet.
+    server = Puppet::Network::Server.new(Puppet[:bindaddress], Puppet[:puppetport])
+
+    daemon.server = server
+  end
+
+  def setup_agent
+    # We need to make the client either way, we just don't start it
+    # if --no-client is set.
+    require 'puppet/agent'
+    require 'puppet/configurer'
+    agent = Puppet::Agent.new(Puppet::Configurer, (not(Puppet[:onetime])))
+
+    enable_disable_client(agent) if options[:enable] or options[:disable]
+
+    @agent = agent if options[:client]
+  end
+
+  def daemonize_process_when(should_daemonize)
+    daemon = Puppet::Daemon.new(Puppet::Util::Pidlock.new(Puppet[:pidfile]))
+    daemon.argv = @argv
+    daemon.agent = @agent
+
+    daemon.daemonize if should_daemonize
+
+    daemon
+  end
+
+  def wait_for_certificates
+    host = Puppet::SSL::Host.new
+    waitforcert = options[:waitforcert] || (Puppet[:onetime] ? 0 : Puppet[:waitforcert])
+    host.wait_for_cert(waitforcert)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/apply.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/apply.rb
new file mode 100644
index 0000000..304381d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/apply.rb
@@ -0,0 +1,304 @@
+require 'puppet/application'
+require 'puppet/configurer'
+require 'puppet/util/profiler/aggregate'
+
+class Puppet::Application::Apply < Puppet::Application
+
+  option("--debug","-d")
+  option("--execute EXECUTE","-e") do |arg|
+    options[:code] = arg
+  end
+  option("--loadclasses","-L")
+  option("--test","-t")
+  option("--verbose","-v")
+  option("--use-nodes")
+  option("--detailed-exitcodes")
+
+  option("--write-catalog-summary")
+
+  option("--catalog catalog",  "-c catalog") do |arg|
+    options[:catalog] = arg
+  end
+
+  option("--logdest LOGDEST", "-l") do |arg|
+    handle_logdest_arg(arg)
+  end
+
+  option("--parseonly") do |args|
+    puts "--parseonly has been removed. Please use 'puppet parser validate <manifest>'"
+    exit 1
+  end
+
+  def help
+    <<-'HELP'
+
+puppet-apply(8) -- Apply Puppet manifests locally
+========
+
+SYNOPSIS
+--------
+Applies a standalone Puppet manifest to the local system.
+
+
+USAGE
+-----
+puppet apply [-h|--help] [-V|--version] [-d|--debug] [-v|--verbose]
+  [-e|--execute] [--detailed-exitcodes] [-L|--loadclasses]
+  [-l|--logdest syslog|eventlog|<FILE>|console] [--noop]
+  [--catalog <catalog>] [--write-catalog-summary] <file>
+
+
+DESCRIPTION
+-----------
+This is the standalone puppet execution tool; use it to apply
+individual manifests.
+
+When provided with a modulepath, via command line or config file, puppet
+apply can effectively mimic the catalog that would be served by puppet
+master with access to the same modules, although there are some subtle
+differences. When combined with scheduling and an automated system for
+pushing manifests, this can be used to implement a serverless Puppet
+site.
+
+Most users should use 'puppet agent' and 'puppet master' for site-wide
+manifests.
+
+
+OPTIONS
+-------
+Note that any setting that's valid in the configuration
+file is also a valid long argument. For example, 'tags' is a
+valid setting, so you can specify '--tags <class>,<tag>'
+as an argument.
+
+See the configuration file documentation at
+http://docs.puppetlabs.com/references/stable/configuration.html for the
+full list of acceptable parameters. A commented list of all
+configuration options can also be generated by running puppet with
+'--genconfig'.
+
+* --debug:
+  Enable full debugging.
+
+* --detailed-exitcodes:
+  Provide transaction information via exit codes. If this is enabled, an exit
+  code of '2' means there were changes, an exit code of '4' means there were
+  failures during the transaction, and an exit code of '6' means there were both
+  changes and failures.
+
+* --help:
+  Print this help message
+
+* --loadclasses:
+  Load any stored classes. 'puppet agent' caches configured classes
+  (usually at /etc/puppet/classes.txt), and setting this option causes
+  all of those classes to be set in your puppet manifest.
+
+* --logdest:
+  Where to send log messages. Choose between 'syslog' (the POSIX syslog
+  service), 'eventlog' (the Windows Event Log), 'console', or the path to a log
+  file. Defaults to 'console'.
+
+  A path ending with '.json' will receive structured output in JSON format. The
+  log file will not have an ending ']' automatically written to it due to the
+  appending nature of logging. It must be appended manually to make the content
+  valid JSON.
+
+* --noop:
+  Use 'noop' mode where Puppet runs in a no-op or dry-run mode. This
+  is useful for seeing what changes Puppet will make without actually
+  executing the changes.
+
+* --execute:
+  Execute a specific piece of Puppet code
+
+* --test:
+  Enable the most common options used for testing. These are 'verbose',
+  'detailed-exitcodes' and 'show_diff'.
+
+* --verbose:
+  Print extra information.
+
+* --catalog:
+  Apply a JSON catalog (such as one generated with 'puppet master --compile'). You can
+  either specify a JSON file or pipe in JSON from standard input.
+
+* --write-catalog-summary
+  After compiling the catalog saves the resource list and classes list to the node
+  in the state directory named classes.txt and resources.txt
+
+EXAMPLE
+-------
+    $ puppet apply -l /tmp/manifest.log manifest.pp
+    $ puppet apply --modulepath=/root/dev/modules -e "include ntpd::server"
+    $ puppet apply --catalog catalog.json
+
+
+AUTHOR
+------
+Luke Kanies
+
+
+COPYRIGHT
+---------
+Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License
+
+    HELP
+  end
+
+  def app_defaults
+    super.merge({
+      :default_file_terminus => :file_server,
+    })
+  end
+
+  def run_command
+    if options[:catalog]
+      apply
+    else
+      main
+    end
+  end
+
+  def apply
+    if options[:catalog] == "-"
+      text = $stdin.read
+    else
+      text = ::File.read(options[:catalog])
+    end
+    catalog = read_catalog(text)
+    apply_catalog(catalog)
+  end
+
+  def main
+    # Set our code or file to use.
+    if options[:code] or command_line.args.length == 0
+      Puppet[:code] = options[:code] || STDIN.read
+    else
+      manifest = command_line.args.shift
+      raise "Could not find file #{manifest}" unless Puppet::FileSystem.exist?(manifest)
+      Puppet.warning("Only one file can be applied per run.  Skipping #{command_line.args.join(', ')}") if command_line.args.size > 0
+    end
+
+    unless Puppet[:node_name_fact].empty?
+      # Collect our facts.
+      unless facts = Puppet::Node::Facts.indirection.find(Puppet[:node_name_value])
+        raise "Could not find facts for #{Puppet[:node_name_value]}"
+      end
+
+      Puppet[:node_name_value] = facts.values[Puppet[:node_name_fact]]
+      facts.name = Puppet[:node_name_value]
+    end
+
+    configured_environment = Puppet.lookup(:current_environment)
+    apply_environment = manifest ?
+      configured_environment.override_with(:manifest => manifest) :
+      configured_environment
+
+    Puppet.override({:current_environment => apply_environment}, "For puppet apply") do
+      # Find our Node
+      unless node = Puppet::Node.indirection.find(Puppet[:node_name_value])
+        raise "Could not find node #{Puppet[:node_name_value]}"
+      end
+
+      # Merge in the facts.
+      node.merge(facts.values) if facts
+
+      # Allow users to load the classes that puppet agent creates.
+      if options[:loadclasses]
+        file = Puppet[:classfile]
+        if Puppet::FileSystem.exist?(file)
+          unless FileTest.readable?(file)
+            $stderr.puts "#{file} is not readable"
+            exit(63)
+          end
+          node.classes = ::File.read(file).split(/[\s\n]+/)
+        end
+      end
+
+      begin
+        # Compile our catalog
+        starttime = Time.now
+        catalog = Puppet::Resource::Catalog.indirection.find(node.name, :use_node => node)
+
+        # Translate it to a RAL catalog
+        catalog = catalog.to_ral
+
+        catalog.finalize
+
+        catalog.retrieval_duration = Time.now - starttime
+
+        if options[:write_catalog_summary]
+          catalog.write_class_file
+          catalog.write_resource_file
+        end
+
+        exit_status = apply_catalog(catalog)
+
+        if not exit_status
+          exit(1)
+        elsif options[:detailed_exitcodes] then
+          exit(exit_status)
+        else
+          exit(0)
+        end
+      rescue => detail
+        Puppet.log_exception(detail)
+        exit(1)
+      end
+    end
+
+  ensure
+    if @profiler
+      Puppet::Util::Profiler.remove_profiler(@profiler)
+      @profiler.shutdown
+    end
+  end
+
+  # Enable all of the most common test options.
+  def setup_test
+    Puppet.settings.handlearg("--show_diff")
+    options[:verbose] = true
+    options[:detailed_exitcodes] = true
+  end
+
+  def setup
+    setup_test if options[:test]
+
+    exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
+
+    Puppet::Util::Log.newdestination(:console) unless options[:setdest]
+
+    Signal.trap(:INT) do
+      $stderr.puts "Exiting"
+      exit(1)
+    end
+
+    # we want the last report to be persisted locally
+    Puppet::Transaction::Report.indirection.cache_class = :yaml
+
+    set_log_level
+
+    if Puppet[:profile]
+      @profiler = Puppet::Util::Profiler.add_profiler(Puppet::Util::Profiler::Aggregate.new(Puppet.method(:debug), "apply"))
+    end
+  end
+
+  private
+
+  def read_catalog(text)
+    begin
+      catalog = Puppet::Resource::Catalog.convert_from(Puppet::Resource::Catalog.default_format,text)
+      catalog = Puppet::Resource::Catalog.pson_create(catalog) unless catalog.is_a?(Puppet::Resource::Catalog)
+    rescue => detail
+      raise Puppet::Error, "Could not deserialize catalog from pson: #{detail}", detail.backtrace
+    end
+
+    catalog.to_ral
+  end
+
+  def apply_catalog(catalog)
+    configurer = Puppet::Configurer.new
+    configurer.run(:catalog => catalog, :pluginsync => false)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/ca.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/ca.rb
new file mode 100644
index 0000000..d1ec250
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/ca.rb
@@ -0,0 +1,5 @@
+require 'puppet/application/face_base'
+
+class Puppet::Application::Ca < Puppet::Application::FaceBase
+  run_mode :master
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/catalog.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/catalog.rb
new file mode 100644
index 0000000..10ce05b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/catalog.rb
@@ -0,0 +1,4 @@
+require 'puppet/application/indirection_base'
+
+class Puppet::Application::Catalog < Puppet::Application::IndirectionBase
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/cert.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/cert.rb
new file mode 100644
index 0000000..6f3fa4b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/cert.rb
@@ -0,0 +1,277 @@
+require 'puppet/application'
+require 'puppet/ssl/certificate_authority/interface'
+
+class Puppet::Application::Cert < Puppet::Application
+
+  run_mode :master
+
+  attr_accessor :all, :ca, :digest, :signed
+
+  def subcommand
+    @subcommand
+  end
+
+  def subcommand=(name)
+    # Handle the nasty, legacy mapping of "clean" to "destroy".
+    sub = name.to_sym
+    @subcommand = (sub == :clean ? :destroy : sub)
+  end
+
+  option("--clean", "-c") do |arg|
+    self.subcommand = "destroy"
+  end
+
+  option("--all", "-a") do |arg|
+    @all = true
+  end
+
+  option("--digest DIGEST") do |arg|
+    @digest = arg
+  end
+
+  option("--signed", "-s") do |arg|
+    @signed = true
+  end
+
+  option("--debug", "-d") do |arg|
+    Puppet::Util::Log.level = :debug
+  end
+
+  option("--list", "-l") do |arg|
+    self.subcommand = :list
+  end
+
+  option("--revoke", "-r") do |arg|
+    self.subcommand = :revoke
+  end
+
+  option("--generate", "-g") do |arg|
+    self.subcommand = :generate
+  end
+
+  option("--sign", "-s") do |arg|
+    self.subcommand = :sign
+  end
+
+  option("--print", "-p") do |arg|
+    self.subcommand = :print
+  end
+
+  option("--verify", "-v") do |arg|
+    self.subcommand = :verify
+  end
+
+  option("--fingerprint", "-f") do |arg|
+    self.subcommand = :fingerprint
+  end
+
+  option("--reinventory") do |arg|
+    self.subcommand = :reinventory
+  end
+
+  option("--[no-]allow-dns-alt-names") do |value|
+    options[:allow_dns_alt_names] = value
+  end
+
+  option("--verbose", "-v") do |arg|
+    Puppet::Util::Log.level = :info
+  end
+
+  def help
+    <<-'HELP'
+
+puppet-cert(8) -- Manage certificates and requests
+========
+
+SYNOPSIS
+--------
+Standalone certificate authority. Capable of generating certificates,
+but mostly used for signing certificate requests from puppet clients.
+
+
+USAGE
+-----
+puppet cert <action> [-h|--help] [-V|--version] [-d|--debug] [-v|--verbose]
+  [--digest <digest>] [<host>]
+
+
+DESCRIPTION
+-----------
+Because the puppet master service defaults to not signing client
+certificate requests, this script is available for signing outstanding
+requests. It can be used to list outstanding requests and then either
+sign them individually or sign all of them.
+
+ACTIONS
+-------
+
+Every action except 'list' and 'generate' requires a hostname to act on,
+unless the '--all' option is set.
+
+* clean:
+  Revoke a host's certificate (if applicable) and remove all files
+  related to that host from puppet cert's storage. This is useful when
+  rebuilding hosts, since new certificate signing requests will only be
+  honored if puppet cert does not have a copy of a signed certificate
+  for that host. If '--all' is specified then all host certificates,
+  both signed and unsigned, will be removed.
+
+* fingerprint:
+  Print the DIGEST (defaults to the signing algorithm) fingerprint of a
+  host's certificate.
+
+* generate:
+  Generate a certificate for a named client. A certificate/keypair will
+  be generated for each client named on the command line.
+
+* list:
+  List outstanding certificate requests. If '--all' is specified, signed
+  certificates are also listed, prefixed by '+', and revoked or invalid
+  certificates are prefixed by '-' (the verification outcome is printed
+  in parenthesis).
+
+* print:
+  Print the full-text version of a host's certificate.
+
+* revoke:
+  Revoke the certificate of a client. The certificate can be specified either
+  by its serial number (given as a hexadecimal number prefixed by '0x') or by its
+  hostname. The certificate is revoked by adding it to the Certificate Revocation
+  List given by the 'cacrl' configuration option. Note that the puppet master
+  needs to be restarted after revoking certificates.
+
+* sign:
+  Sign an outstanding certificate request.
+
+* verify:
+  Verify the named certificate against the local CA certificate.
+
+* reinventory:
+  Build an inventory of the issued certificates. This will destroy the current
+  inventory file specified by 'cert_inventory' and recreate it from the
+  certificates found in the 'certdir'. Ensure the puppet master is stopped
+  before running this action.
+
+OPTIONS
+-------
+Note that any setting that's valid in the configuration
+file is also a valid long argument. For example, 'ssldir' is a valid
+setting, so you can specify '--ssldir <directory>' as an
+argument.
+
+See the configuration file documentation at
+http://docs.puppetlabs.com/references/stable/configuration.html for the
+full list of acceptable parameters. A commented list of all
+configuration options can also be generated by running puppet cert with
+'--genconfig'.
+
+* --all:
+  Operate on all items. Currently only makes sense with the 'sign',
+  'clean', 'list', and 'fingerprint' actions.
+
+* --digest:
+  Set the digest for fingerprinting (defaults to the digest used when
+  signing the cert). Valid values depends on your openssl and openssl ruby
+  extension version.
+
+* --debug:
+  Enable full debugging.
+
+* --help:
+  Print this help message
+
+* --verbose:
+  Enable verbosity.
+
+* --version:
+  Print the puppet version number and exit.
+
+
+EXAMPLE
+-------
+    $ puppet cert list
+    culain.madstop.com
+    $ puppet cert sign culain.madstop.com
+
+
+AUTHOR
+------
+Luke Kanies
+
+
+COPYRIGHT
+---------
+Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License
+
+    HELP
+  end
+
+  def main
+    if @all
+      hosts = :all
+    elsif @signed
+      hosts = :signed
+    else
+      hosts = command_line.args.collect { |h| h.downcase }
+    end
+    begin
+      apply(@ca, :revoke, options.merge(:to => hosts)) if subcommand == :destroy
+      apply(@ca, subcommand, options.merge(:to => hosts, :digest => @digest))
+    rescue => detail
+      Puppet.log_exception(detail)
+      exit(24)
+    end
+  end
+
+  def setup
+    require 'puppet/ssl/certificate_authority'
+    exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
+
+    Puppet::Util::Log.newdestination :console
+
+    if [:generate, :destroy].include? subcommand
+      Puppet::SSL::Host.ca_location = :local
+    else
+      Puppet::SSL::Host.ca_location = :only
+    end
+
+    # If we are generating, and the option came from the CLI, it gets added to
+    # the data.  This will do the right thing for non-local certificates, in
+    # that the command line but *NOT* the config file option will apply.
+    if subcommand == :generate
+      if Puppet.settings.set_by_cli?(:dns_alt_names)
+        options[:dns_alt_names] = Puppet[:dns_alt_names]
+      end
+    end
+
+    begin
+      @ca = Puppet::SSL::CertificateAuthority.new
+    rescue => detail
+      Puppet.log_exception(detail)
+      exit(23)
+    end
+  end
+
+  def parse_options
+    # handle the bareword subcommand pattern.
+    result = super
+    unless self.subcommand then
+      if sub = self.command_line.args.shift then
+        self.subcommand = sub
+      else
+        puts help
+        exit
+      end
+    end
+    result
+  end
+
+  # Create and run an applicator.  I wanted to build an interface where you could do
+  # something like 'ca.apply(:generate).to(:all) but I don't think it's really possible.
+  def apply(ca, method, options)
+    raise ArgumentError, "You must specify the hosts to apply to; valid values are an array or the symbol :all" unless options[:to]
+    applier = Puppet::SSL::CertificateAuthority::Interface.new(method, options)
+    applier.apply(ca)
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/certificate.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/certificate.rb
new file mode 100644
index 0000000..77dfb82
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/certificate.rb
@@ -0,0 +1,15 @@
+require 'puppet/application/indirection_base'
+
+class Puppet::Application::Certificate < Puppet::Application::IndirectionBase
+  def setup
+    location = Puppet::SSL::Host.ca_location
+    if location == :local && !Puppet::SSL::CertificateAuthority.ca?
+      # I'd prefer if this could be dealt with differently; ideally, run_mode should be set as
+      #  part of a class definition, and should not be modifiable beyond that.  This is one of
+      #  the cases where that isn't currently possible.
+      Puppet.settings.preferred_run_mode = "master"
+    end
+
+    super
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/certificate_request.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/certificate_request.rb
new file mode 100644
index 0000000..ba8c891
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/certificate_request.rb
@@ -0,0 +1,7 @@
+require 'puppet/application/indirection_base'
+
+# NOTE: this is using an "old" naming convention (underscores instead of camel-case), for backwards
+#  compatibility with 2.7.x.  When the old naming convention is officially and publicly deprecated,
+#  this should be changed to camel-case.
+class Puppet::Application::Certificate_request < Puppet::Application::IndirectionBase
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/certificate_revocation_list.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/certificate_revocation_list.rb
new file mode 100644
index 0000000..218d2e6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/certificate_revocation_list.rb
@@ -0,0 +1,7 @@
+require 'puppet/application/indirection_base'
+
+# NOTE: this is using an "old" naming convention (underscores instead of camel-case), for backwards
+#  compatibility with 2.7.x.  When the old naming convention is officially and publicly deprecated,
+#  this should be changed to camel-case.
+class Puppet::Application::Certificate_revocation_list < Puppet::Application::IndirectionBase
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/config.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/config.rb
new file mode 100644
index 0000000..a94441e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/config.rb
@@ -0,0 +1,4 @@
+require 'puppet/application/face_base'
+
+class Puppet::Application::Config < Puppet::Application::FaceBase
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/describe.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/describe.rb
new file mode 100644
index 0000000..9d8cf35
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/describe.rb
@@ -0,0 +1,254 @@
+require 'puppet/application'
+
+class Formatter
+
+  def initialize(width)
+    @width = width
+  end
+
+  def wrap(txt, opts)
+    return "" unless txt && !txt.empty?
+    work = (opts[:scrub] ? scrub(txt) : txt)
+    indent = (opts[:indent] ? opts[:indent] : 0)
+    textLen = @width - indent
+    patt = Regexp.new("^(.{0,#{textLen}})[ \n]")
+    prefix = " " * indent
+
+    res = []
+
+    while work.length > textLen
+      if work =~ patt
+        res << $1
+        work.slice!(0, $MATCH.length)
+      else
+        res << work.slice!(0, textLen)
+      end
+    end
+    res << work if work.length.nonzero?
+    prefix + res.join("\n#{prefix}")
+  end
+
+  def header(txt, sep = "-")
+    "\n#{txt}\n" + sep * txt.size
+  end
+
+  private
+
+  def scrub(text)
+    # For text with no carriage returns, there's nothing to do.
+    return text if text !~ /\n/
+    indent = nil
+
+    # If we can match an indentation, then just remove that same level of
+    # indent from every line.
+    if text =~ /^(\s+)/
+      indent = $1
+      return text.gsub(/^#{indent}/,'')
+    else
+      return text
+    end
+  end
+
+end
+
+class TypeDoc
+
+  def initialize
+    @format = Formatter.new(76)
+    @types = {}
+    Puppet::Type.loadall
+    Puppet::Type.eachtype { |type|
+      next if type.name == :component
+      @types[type.name] = type
+    }
+  end
+
+  def list_types
+    puts "These are the types known to puppet:\n"
+    @types.keys.sort { |a, b|
+      a.to_s <=> b.to_s
+    }.each do |name|
+      type = @types[name]
+      s = type.doc.gsub(/\s+/, " ")
+      n = s.index(". ")
+      if n.nil?
+        s = ".. no documentation .."
+      elsif n > 45
+        s = s[0, 45] + " ..."
+      else
+        s = s[0, n]
+      end
+      printf "%-15s - %s\n", name, s
+    end
+  end
+
+  def format_type(name, opts)
+    name = name.to_sym
+    unless @types.has_key?(name)
+      puts "Unknown type #{name}"
+      return
+    end
+    type = @types[name]
+    puts @format.header(name.to_s, "=")
+    puts @format.wrap(type.doc, :indent => 0, :scrub => true) + "\n\n"
+
+    puts @format.header("Parameters")
+    if opts[:parameters]
+      format_attrs(type, [:property, :param])
+    else
+      list_attrs(type, [:property, :param])
+    end
+
+    if opts[:meta]
+      puts @format.header("Meta Parameters")
+      if opts[:parameters]
+        format_attrs(type, [:meta])
+      else
+        list_attrs(type, [:meta])
+      end
+    end
+
+    if type.providers.size > 0
+      puts @format.header("Providers")
+      if opts[:providers]
+        format_providers(type)
+      else
+        list_providers(type)
+      end
+    end
+  end
+
+  # List details about attributes
+  def format_attrs(type, attrs)
+    docs = {}
+    type.allattrs.each do |name|
+      kind = type.attrtype(name)
+      docs[name] = type.attrclass(name).doc if attrs.include?(kind) && name != :provider
+    end
+
+    docs.sort { |a,b|
+      a[0].to_s <=> b[0].to_s
+    }.each { |name, doc|
+      print "\n- **#{name}**"
+      if type.key_attributes.include?(name) and name != :name
+        puts " (*namevar*)"
+      else
+        puts ""
+      end
+      puts @format.wrap(doc, :indent => 4, :scrub => true)
+    }
+  end
+
+  # List the names of attributes
+  def list_attrs(type, attrs)
+    params = []
+    type.allattrs.each do |name|
+      kind = type.attrtype(name)
+      params << name.to_s if attrs.include?(kind) && name != :provider
+    end
+    puts @format.wrap(params.sort.join(", "), :indent => 4)
+  end
+
+  def format_providers(type)
+    type.providers.sort { |a,b|
+      a.to_s <=> b.to_s
+    }.each { |prov|
+      puts "\n- **#{prov}**"
+      puts @format.wrap(type.provider(prov).doc, :indent => 4, :scrub => true)
+    }
+  end
+
+  def list_providers(type)
+    list = type.providers.sort { |a,b|
+      a.to_s <=> b.to_s
+    }.join(", ")
+    puts @format.wrap(list, :indent => 4)
+  end
+
+end
+
+class Puppet::Application::Describe < Puppet::Application
+  banner "puppet describe [options] [type]"
+
+  option("--short", "-s", "Only list parameters without detail") do |arg|
+    options[:parameters] = false
+  end
+
+  option("--providers","-p")
+  option("--list", "-l")
+  option("--meta","-m")
+
+  def help
+    <<-'HELP'
+
+puppet-describe(8) -- Display help about resource types
+========
+
+SYNOPSIS
+--------
+Prints help about Puppet resource types, providers, and metaparameters.
+
+
+USAGE
+-----
+puppet describe [-h|--help] [-s|--short] [-p|--providers] [-l|--list] [-m|--meta]
+
+
+OPTIONS
+-------
+* --help:
+  Print this help text
+
+* --providers:
+  Describe providers in detail for each type
+
+* --list:
+  List all types
+
+* --meta:
+  List all metaparameters
+
+* --short:
+  List only parameters without detail
+
+
+EXAMPLE
+-------
+    $ puppet describe --list
+    $ puppet describe file --providers
+    $ puppet describe user -s -m
+
+
+AUTHOR
+------
+David Lutterkort
+
+
+COPYRIGHT
+---------
+Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License
+
+    HELP
+  end
+
+  def preinit
+    options[:parameters] = true
+  end
+
+  def main
+    doc = TypeDoc.new
+
+    if options[:list]
+      doc.list_types
+    else
+      options[:types].each { |name| doc.format_type(name, options) }
+    end
+  end
+
+  def setup
+    options[:types] = command_line.args.dup
+    handle_help(nil) unless options[:list] || options[:types].size > 0
+    $stderr.puts "Warning: ignoring types when listing all types" if options[:list] && options[:types].size > 0
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/device.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/device.rb
new file mode 100644
index 0000000..f56c4ad
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/device.rb
@@ -0,0 +1,260 @@
+require 'puppet/application'
+require 'puppet/util/network_device'
+
+class Puppet::Application::Device < Puppet::Application
+
+  run_mode :agent
+
+  attr_accessor :args, :agent, :host
+
+  def app_defaults
+    super.merge({
+      :catalog_terminus => :rest,
+      :catalog_cache_terminus => :json,
+      :node_terminus => :rest,
+      :facts_terminus => :network_device,
+    })
+  end
+
+  def preinit
+    # Do an initial trap, so that cancels don't get a stack trace.
+    Signal.trap(:INT) do
+      $stderr.puts "Cancelling startup"
+      exit(0)
+    end
+
+    {
+      :waitforcert => nil,
+      :detailed_exitcodes => false,
+      :verbose => false,
+      :debug => false,
+      :centrallogs => false,
+      :setdest => false,
+    }.each do |opt,val|
+      options[opt] = val
+    end
+
+    @args = {}
+  end
+
+  option("--centrallogging")
+  option("--debug","-d")
+  option("--verbose","-v")
+
+  option("--detailed-exitcodes") do |arg|
+    options[:detailed_exitcodes] = true
+  end
+
+  option("--logdest DEST", "-l DEST") do |arg|
+    handle_logdest_arg(arg)
+  end
+
+  option("--waitforcert WAITFORCERT", "-w") do |arg|
+    options[:waitforcert] = arg.to_i
+  end
+
+  option("--port PORT","-p") do |arg|
+    @args[:Port] = arg
+  end
+
+    def help
+      <<-'HELP'
+
+puppet-device(8) -- Manage remote network devices
+========
+
+SYNOPSIS
+--------
+Retrieves all configurations from the puppet master and apply
+them to the remote devices configured in /etc/puppet/device.conf.
+
+Currently must be run out periodically, using cron or something similar.
+
+USAGE
+-----
+  puppet device [-d|--debug] [--detailed-exitcodes] [-V|--version]
+                [-h|--help] [-l|--logdest syslog|<file>|console]
+                [-v|--verbose] [-w|--waitforcert <seconds>]
+
+
+DESCRIPTION
+-----------
+Once the client has a signed certificate for a given remote device, it will
+retrieve its configuration and apply it.
+
+USAGE NOTES
+-----------
+One need a /etc/puppet/device.conf file with the following content:
+
+[remote.device.fqdn]
+type <type>
+url <url>
+
+where:
+ * type: the current device type (the only value at this time is cisco)
+ * url: an url allowing to connect to the device
+
+Supported url must conforms to:
+ scheme://user:password@hostname/?query
+
+ with:
+  * scheme: either ssh or telnet
+  * user: username, can be omitted depending on the switch/router configuration
+  * password: the connection password
+  * query: this is device specific. Cisco devices supports an enable parameter whose
+  value would be the enable password.
+
+OPTIONS
+-------
+Note that any setting that's valid in the configuration file
+is also a valid long argument.  For example, 'server' is a valid configuration
+parameter, so you can specify '--server <servername>' as an argument.
+
+* --debug:
+  Enable full debugging.
+
+* --detailed-exitcodes:
+  Provide transaction information via exit codes. If this is enabled, an exit
+  code of '1' means at least one device had a compile failure, an exit code of
+  '2' means at least one device had resource changes, and an exit code of '4'
+  means at least one device had resource failures. Exit codes of '3', '5', '6',
+  or '7' means that a bitwise combination of the preceeding exit codes happened.
+
+* --help:
+  Print this help message
+
+* --logdest:
+  Where to send log messages. Choose between 'syslog' (the POSIX syslog
+  service), 'console', or the path to a log file. If debugging or verbosity is
+  enabled, this defaults to 'console'. Otherwise, it defaults to 'syslog'.
+
+  A path ending with '.json' will receive structured output in JSON format. The
+  log file will not have an ending ']' automatically written to it due to the
+  appending nature of logging. It must be appended manually to make the content
+  valid JSON.
+
+* --verbose:
+  Turn on verbose reporting.
+
+* --waitforcert:
+  This option only matters for daemons that do not yet have certificates
+  and it is enabled by default, with a value of 120 (seconds).  This causes
+  +puppet agent+ to connect to the server every 2 minutes and ask it to sign a
+  certificate request.  This is useful for the initial setup of a puppet
+  client.  You can turn off waiting for certificates by specifying a time
+  of 0.
+
+EXAMPLE
+-------
+      $ puppet device --server puppet.domain.com
+
+AUTHOR
+------
+Brice Figureau
+
+
+COPYRIGHT
+---------
+Copyright (c) 2011 Puppet Labs, LLC
+Licensed under the Apache 2.0 License
+      HELP
+    end
+
+
+  def main
+    vardir = Puppet[:vardir]
+    confdir = Puppet[:confdir]
+    certname = Puppet[:certname]
+
+    # find device list
+    require 'puppet/util/network_device/config'
+    devices = Puppet::Util::NetworkDevice::Config.devices
+    if devices.empty?
+      Puppet.err "No device found in #{Puppet[:deviceconfig]}"
+      exit(1)
+    end
+    returns = devices.collect do |devicename,device|
+      begin
+        device_url = URI.parse(device.url)
+        # Handle nil scheme & port
+        scheme = "#{device_url.scheme}://" if device_url.scheme
+        port = ":#{device_url.port}" if device_url.port
+        Puppet.info "starting applying configuration to #{device.name} at #{scheme}#{device_url.host}#{port}#{device_url.path}"
+
+        # override local $vardir and $certname
+        Puppet[:confdir] = ::File.join(Puppet[:devicedir], device.name)
+        Puppet[:vardir] = ::File.join(Puppet[:devicedir], device.name)
+        Puppet[:certname] = device.name
+
+        # this will reload and recompute default settings and create the devices sub vardir, or we hope so :-)
+        Puppet.settings.use :main, :agent, :ssl
+
+        # this init the device singleton, so that the facts terminus
+        # and the various network_device provider can use it
+        Puppet::Util::NetworkDevice.init(device)
+
+        # ask for a ssl cert if needed, but at least
+        # setup the ssl system for this device.
+        setup_host
+
+        require 'puppet/configurer'
+        configurer = Puppet::Configurer.new
+        configurer.run(:network_device => true, :pluginsync => Puppet[:pluginsync])
+      rescue => detail
+        Puppet.log_exception(detail)
+        # If we rescued an error, then we return 1 as the exit code
+        1
+      ensure
+        Puppet[:vardir] = vardir
+        Puppet[:confdir] = confdir
+        Puppet[:certname] = certname
+        Puppet::SSL::Host.reset
+      end
+    end
+    if ! returns or returns.compact.empty?
+      exit(1)
+    elsif options[:detailed_exitcodes]
+      # Bitwise OR the return codes together, puppet style
+      exit(returns.compact.reduce(:|))
+    elsif returns.include? 1
+      exit(1)
+    else
+      exit(0)
+    end
+  end
+
+  def setup_host
+    @host = Puppet::SSL::Host.new
+    waitforcert = options[:waitforcert] || (Puppet[:onetime] ? 0 : Puppet[:waitforcert])
+    @host.wait_for_cert(waitforcert)
+  end
+
+  def setup
+    setup_logs
+
+    args[:Server] = Puppet[:server]
+    if options[:centrallogs]
+      logdest = args[:Server]
+
+      logdest += ":" + args[:Port] if args.include?(:Port)
+      Puppet::Util::Log.newdestination(logdest)
+    end
+
+    Puppet.settings.use :main, :agent, :device, :ssl
+
+    # Always ignoreimport for agent. It really shouldn't even try to import,
+    # but this is just a temporary band-aid.
+    Puppet[:ignoreimport] = true
+
+    # We need to specify a ca location for all of the SSL-related
+    # indirected classes to work; in fingerprint mode we just need
+    # access to the local files and we don't need a ca.
+    Puppet::SSL::Host.ca_location = :remote
+
+    Puppet::Transaction::Report.indirection.terminus_class = :rest
+
+    if Puppet[:catalog_cache_terminus]
+      Puppet::Resource::Catalog.indirection.cache_class = Puppet[:catalog_cache_terminus].intern
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/doc.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/doc.rb
new file mode 100644
index 0000000..e45d4d0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/doc.rb
@@ -0,0 +1,273 @@
+require 'puppet/application'
+
+class Puppet::Application::Doc < Puppet::Application
+  run_mode :master
+
+  attr_accessor :unknown_args, :manifest
+
+  def preinit
+    {:references => [], :mode => :text, :format => :to_markdown }.each do |name,value|
+      options[name] = value
+    end
+    @unknown_args = []
+    @manifest = false
+  end
+
+  option("--all","-a")
+  option("--outputdir OUTPUTDIR","-o")
+  option("--verbose","-v")
+  option("--debug","-d")
+  option("--charset CHARSET")
+
+  option("--format FORMAT", "-f") do |arg|
+    method = "to_#{arg}"
+    require 'puppet/util/reference'
+    if Puppet::Util::Reference.method_defined?(method)
+      options[:format] = method
+    else
+      raise "Invalid output format #{arg}"
+    end
+  end
+
+  option("--mode MODE", "-m") do |arg|
+    require 'puppet/util/reference'
+    if Puppet::Util::Reference.modes.include?(arg) or arg.intern==:rdoc
+      options[:mode] = arg.intern
+    else
+      raise "Invalid output mode #{arg}"
+    end
+  end
+
+  option("--list", "-l") do |arg|
+    require 'puppet/util/reference'
+    puts Puppet::Util::Reference.references.collect { |r| Puppet::Util::Reference.reference(r).doc }.join("\n")
+    exit(0)
+  end
+
+  option("--reference REFERENCE", "-r") do |arg|
+    options[:references] << arg.intern
+  end
+
+  def help
+    <<-'HELP'
+
+puppet-doc(8) -- Generate Puppet documentation and references
+========
+
+SYNOPSIS
+--------
+Generates a reference for all Puppet types. Largely meant for internal
+Puppet Labs use.
+
+
+USAGE
+-----
+puppet doc [-a|--all] [-h|--help] [-l|--list] [-o|--outputdir <rdoc-outputdir>]
+  [-m|--mode text|pdf|rdoc] [-r|--reference <reference-name>]
+  [--charset <charset>] [<manifest-file>]
+
+
+DESCRIPTION
+-----------
+If mode is not 'rdoc', then this command generates a Markdown document
+describing all installed Puppet types or all allowable arguments to
+puppet executables. It is largely meant for internal use and is used to
+generate the reference document available on the Puppet Labs web site.
+
+In 'rdoc' mode, this command generates an html RDoc hierarchy describing
+the manifests that are in 'manifestdir' and 'modulepath' configuration
+directives. The generated documentation directory is doc by default but
+can be changed with the 'outputdir' option.
+
+If the command is run with the name of a manifest file as an argument,
+puppet doc will output a single manifest's documentation on stdout.
+
+
+OPTIONS
+-------
+* --all:
+  Output the docs for all of the reference types. In 'rdoc' mode, this also
+  outputs documentation for all resources.
+
+* --help:
+  Print this help message
+
+* --outputdir:
+  Used only in 'rdoc' mode. The directory to which the rdoc output should
+  be written.
+
+* --mode:
+  Determine the output mode. Valid modes are 'text', 'pdf' and 'rdoc'. The 'pdf'
+  mode creates PDF formatted files in the /tmp directory. The default mode is
+  'text'.
+
+* --reference:
+  Build a particular reference. Get a list of references by running
+  'puppet doc --list'.
+
+* --charset:
+  Used only in 'rdoc' mode. It sets the charset used in the html files produced.
+
+* --manifestdir:
+  Used only in 'rdoc' mode. The directory to scan for stand-alone manifests.
+  If not supplied, puppet doc will use the manifestdir from puppet.conf.
+
+* --modulepath:
+  Used only in 'rdoc' mode. The directory or directories to scan for modules.
+  If not supplied, puppet doc will use the modulepath from puppet.conf.
+
+* --environment:
+  Used only in 'rdoc' mode. The configuration environment from which
+  to read the modulepath and manifestdir settings, when reading said settings
+  from puppet.conf.
+
+
+EXAMPLE
+-------
+    $ puppet doc -r type > /tmp/type_reference.markdown
+
+or
+
+    $ puppet doc --outputdir /tmp/rdoc --mode rdoc /path/to/manifests
+
+or
+
+    $ puppet doc /etc/puppet/manifests/site.pp
+
+or
+
+    $ puppet doc -m pdf -r configuration
+
+
+AUTHOR
+------
+Luke Kanies
+
+
+COPYRIGHT
+---------
+Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License
+
+HELP
+  end
+
+  def handle_unknown( opt, arg )
+    @unknown_args << {:opt => opt, :arg => arg }
+    true
+  end
+
+  def run_command
+    return [:rdoc].include?(options[:mode]) ? send(options[:mode]) : other
+  end
+
+  def rdoc
+    exit_code = 0
+    files = []
+    unless @manifest
+      env = Puppet.lookup(:current_environment)
+      files += env.modulepath
+      files << ::File.dirname(env.manifest) if env.manifest != Puppet::Node::Environment::NO_MANIFEST
+    end
+    files += command_line.args
+    Puppet.info "scanning: #{files.inspect}"
+
+    Puppet.settings[:document_all] = options[:all] || false
+    begin
+      require 'puppet/util/rdoc'
+      if @manifest
+        Puppet::Util::RDoc.manifestdoc(files)
+      else
+        options[:outputdir] = "doc" unless options[:outputdir]
+        Puppet::Util::RDoc.rdoc(options[:outputdir], files, options[:charset])
+      end
+    rescue => detail
+      Puppet.log_exception(detail, "Could not generate documentation: #{detail}")
+      exit_code = 1
+    end
+    exit exit_code
+  end
+
+  def other
+    text = ""
+    with_contents = options[:references].length <= 1
+    exit_code = 0
+    require 'puppet/util/reference'
+    options[:references].sort { |a,b| a.to_s <=> b.to_s }.each do |name|
+      raise "Could not find reference #{name}" unless section = Puppet::Util::Reference.reference(name)
+
+      begin
+        # Add the per-section text, but with no ToC
+        text += section.send(options[:format], with_contents)
+      rescue => detail
+        Puppet.log_exception(detail, "Could not generate reference #{name}: #{detail}")
+        exit_code = 1
+        next
+      end
+    end
+
+    text += Puppet::Util::Reference.footer unless with_contents # We've only got one reference
+
+    if options[:mode] == :pdf
+      Puppet::Util::Reference.pdf(text)
+    else
+      puts text
+    end
+
+    exit exit_code
+  end
+
+  def setup
+    # sole manifest documentation
+    if command_line.args.size > 0
+      options[:mode] = :rdoc
+      @manifest = true
+    end
+
+    if options[:mode] == :rdoc
+      setup_rdoc
+    else
+      setup_reference
+    end
+
+    setup_logging
+  end
+
+  def setup_reference
+    if options[:all]
+      # Don't add dynamic references to the "all" list.
+      require 'puppet/util/reference'
+      options[:references] = Puppet::Util::Reference.references.reject do |ref|
+        Puppet::Util::Reference.reference(ref).dynamic?
+      end
+    end
+
+    options[:references] << :type if options[:references].empty?
+  end
+
+  def setup_rdoc(dummy_argument=:work_arround_for_ruby_GC_bug)
+    # consume the unknown options
+    # and feed them as settings
+    if @unknown_args.size > 0
+      @unknown_args.each do |option|
+        # force absolute path for modulepath when passed on commandline
+        if option[:opt]=="--modulepath" or option[:opt] == "--manifestdir"
+          option[:arg] = option[:arg].split(::File::PATH_SEPARATOR).collect { |p| ::File.expand_path(p) }.join(::File::PATH_SEPARATOR)
+        end
+        Puppet.settings.handlearg(option[:opt], option[:arg])
+      end
+    end
+  end
+
+  def setup_logging
+  # Handle the logging settings.
+    if options[:debug]
+      Puppet::Util::Log.level = :debug
+    elsif options[:verbose]
+      Puppet::Util::Log.level = :info
+    else
+      Puppet::Util::Log.level = :warning
+    end
+
+    Puppet::Util::Log.newdestination(:console)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/face_base.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/face_base.rb
new file mode 100644
index 0000000..3154d6d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/face_base.rb
@@ -0,0 +1,250 @@
+require 'puppet/application'
+require 'puppet/face'
+require 'optparse'
+require 'pp'
+
+class Puppet::Application::FaceBase < Puppet::Application
+  option("--debug", "-d") do |arg|
+    Puppet::Util::Log.level = :debug
+  end
+
+  option("--verbose", "-v") do |_|
+    Puppet::Util::Log.level = :info
+  end
+
+  option("--render-as FORMAT") do |format|
+    self.render_as = format.to_sym
+  end
+
+  attr_accessor :face, :action, :type, :arguments, :render_as
+
+  def render_as=(format)
+    if format == :json then
+      @render_as = Puppet::Network::FormatHandler.format(:pson)
+    else
+      @render_as = Puppet::Network::FormatHandler.format(format)
+    end
+    @render_as or raise ArgumentError, "I don't know how to render '#{format}'"
+  end
+
+  def render(result, args_and_options)
+    hook = action.when_rendering(render_as.name)
+
+    if hook
+      # when defining when_rendering on your action you can optionally
+      # include arguments and options
+      if hook.arity > 1
+        result = hook.call(result, *args_and_options)
+      else
+        result = hook.call(result)
+      end
+    end
+
+    render_as.render(result)
+  end
+
+  def preinit
+    super
+    Signal.trap(:INT) do
+      $stderr.puts "Cancelling Face"
+      exit(0)
+    end
+  end
+
+  def parse_options
+    # We need to parse enough of the command line out early, to identify what
+    # the action is, so that we can obtain the full set of options to parse.
+
+    # REVISIT: These should be configurable versions, through a global
+    # '--version' option, but we don't implement that yet... --daniel 2011-03-29
+    @type = Puppet::Util::ConstantInflector.constant2file(self.class.name.to_s.sub(/.+:/, '')).to_sym
+    @face = Puppet::Face[@type, :current]
+
+    # Now, walk the command line and identify the action.  We skip over
+    # arguments based on introspecting the action and all, and find the first
+    # non-option word to use as the action.
+    action_name = nil
+    index       = -1
+    until action_name or (index += 1) >= command_line.args.length do
+      item = command_line.args[index]
+      if item =~ /^-/ then
+        option = @face.options.find do |name|
+          item =~ /^-+#{name.to_s.gsub(/[-_]/, '[-_]')}(?:[ =].*)?$/
+        end
+        if option then
+          option = @face.get_option(option)
+          # If we have an inline argument, just carry on.  We don't need to
+          # care about optional vs mandatory in that case because we do a real
+          # parse later, and that will totally take care of raising the error
+          # when we get there. --daniel 2011-04-04
+          if option.takes_argument? and !item.index('=') then
+            index += 1 unless
+              (option.optional_argument? and command_line.args[index + 1] =~ /^-/)
+          end
+        elsif option = find_global_settings_argument(item) then
+          unless Puppet.settings.boolean? option.name then
+            # As far as I can tell, we treat non-bool options as always having
+            # a mandatory argument. --daniel 2011-04-05
+            # ... But, the mandatory argument will not be the next item if an = is
+            # employed in the long form of the option. --jeffmccune 2012-09-18
+            index += 1 unless item =~ /^--#{option.name}=/
+          end
+        elsif option = find_application_argument(item) then
+          index += 1 if (option[:argument] and not option[:optional])
+        else
+          raise OptionParser::InvalidOption.new(item.sub(/=.*$/, ''))
+        end
+      else
+        # Stash away the requested action name for later, and try to fetch the
+        # action object it represents; if this is an invalid action name that
+        # will be nil, and handled later.
+        action_name = item.to_sym
+        @action = Puppet::Face.find_action(@face.name, action_name)
+        @face   = @action.face if @action
+      end
+    end
+
+    if @action.nil?
+      if @action = @face.get_default_action() then
+        @is_default_action = true
+      else
+        face   = @face.name
+        action = action_name.nil? ? 'default' : "'#{action_name}'"
+        msg = "'#{face}' has no #{action} action.  See `puppet help #{face}`."
+
+        Puppet.err(msg)
+        Puppet::Util::Log.force_flushqueue()
+
+        exit false
+      end
+    end
+
+    # Now we can interact with the default option code to build behaviour
+    # around the full set of options we now know we support.
+    @action.options.each do |option|
+      option = @action.get_option(option) # make it the object.
+      self.class.option(*option.optparse) # ...and make the CLI parse it.
+    end
+
+    # ...and invoke our parent to parse all the command line options.
+    super
+  end
+
+  def find_global_settings_argument(item)
+    Puppet.settings.each do |name, object|
+      object.optparse_args.each do |arg|
+        next unless arg =~ /^-/
+        # sadly, we have to emulate some of optparse here...
+        pattern = /^#{arg.sub('[no-]', '').sub(/[ =].*$/, '')}(?:[ =].*)?$/
+        pattern.match item and return object
+      end
+    end
+    return nil                  # nothing found.
+  end
+
+  def find_application_argument(item)
+    self.class.option_parser_commands.each do |options, function|
+      options.each do |option|
+        next unless option =~ /^-/
+        pattern = /^#{option.sub('[no-]', '').sub(/[ =].*$/, '')}(?:[ =].*)?$/
+        next unless pattern.match(item)
+        return {
+          :argument => option =~ /[ =]/,
+          :optional => option =~ /[ =]\[/
+        }
+      end
+    end
+    return nil                  # not found
+  end
+
+  def setup
+    Puppet::Util::Log.newdestination :console
+
+    @arguments = command_line.args
+
+    # Note: because of our definition of where the action is set, we end up
+    # with it *always* being the first word of the remaining set of command
+    # line arguments.  So, strip that off when we construct the arguments to
+    # pass down to the face action. --daniel 2011-04-04
+    # Of course, now that we have default actions, we should leave the
+    # "action" name on if we didn't actually consume it when we found our
+    # action.
+    @arguments.delete_at(0) unless @is_default_action
+
+    # We copy all of the app options to the end of the call; This allows each
+    # action to read in the options.  This replaces the older model where we
+    # would invoke the action with options set as global state in the
+    # interface object.  --daniel 2011-03-28
+    @arguments << options
+
+    # If we don't have a rendering format, set one early.
+    self.render_as ||= (@action.render_as || :console)
+  end
+
+
+  def main
+    status = false
+
+    # Call the method associated with the provided action (e.g., 'find').
+    unless @action
+      puts Puppet::Face[:help, :current].help(@face.name)
+      raise "#{face} does not respond to action #{arguments.first}"
+    end
+
+    # We need to do arity checking here because this is generic code
+    # calling generic methods – that have argument defaulting.  We need to
+    # make sure we don't accidentally pass the options as the first
+    # argument to a method that takes one argument.  eg:
+    #
+    #   puppet facts find
+    #   => options => {}
+    #      @arguments => [{}]
+    #   => @face.send :bar, {}
+    #
+    #   def face.bar(argument, options = {})
+    #   => bar({}, {})  # oops!  we thought the options were the
+    #                   # positional argument!!
+    #
+    # We could also fix this by making it mandatory to pass the options on
+    # every call, but that would make the Ruby API much more annoying to
+    # work with; having the defaulting is a much nicer convention to have.
+    #
+    # We could also pass the arguments implicitly, by having a magic
+    # 'options' method that was visible in the scope of the action, which
+    # returned the right stuff.
+    #
+    # That sounds attractive, but adds complications to all sorts of
+    # things, especially when you think about how to pass options when you
+    # are writing Ruby code that calls multiple faces.  Especially if
+    # faces are involved in that. ;)
+    #
+    # --daniel 2011-04-27
+    if (arity = @action.positional_arg_count) > 0
+      unless (count = arguments.length) == arity then
+        s = arity == 2 ? '' : 's'
+        raise ArgumentError, "puppet #{@face.name} #{@action.name} takes #{arity-1} argument#{s}, but you gave #{count-1}"
+      end
+    end
+
+    result = @face.send(@action.name, *arguments)
+    puts render(result, arguments) unless result.nil?
+    status = true
+
+  # We need an easy way for the action to set a specific exit code, so we
+  # rescue SystemExit here; This allows each action to set the desired exit
+  # code by simply calling Kernel::exit.  eg:
+  #
+  #   exit(2)
+  #
+  # --kelsey 2012-02-14
+  rescue SystemExit => detail
+    status = detail.status
+
+  rescue => detail
+    Puppet.log_exception(detail)
+    Puppet.err "Try 'puppet help #{@face.name} #{@action.name}' for usage"
+
+  ensure
+    exit status
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/facts.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/facts.rb
new file mode 100644
index 0000000..d18b21e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/facts.rb
@@ -0,0 +1,4 @@
+require 'puppet/application/indirection_base'
+
+class Puppet::Application::Facts < Puppet::Application::IndirectionBase
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/file.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/file.rb
new file mode 100644
index 0000000..32a81c7
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/file.rb
@@ -0,0 +1,4 @@
+require 'puppet/application/indirection_base'
+
+class Puppet::Application::File < Puppet::Application::IndirectionBase
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/filebucket.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/filebucket.rb
new file mode 100644
index 0000000..3f59f72
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/filebucket.rb
@@ -0,0 +1,184 @@
+require 'puppet/application'
+
+class Puppet::Application::Filebucket < Puppet::Application
+
+  option("--bucket BUCKET","-b")
+  option("--debug","-d")
+  option("--local","-l")
+  option("--remote","-r")
+  option("--verbose","-v")
+
+  attr :args
+
+  def help
+    <<-'HELP'
+
+puppet-filebucket(8) -- Store and retrieve files in a filebucket
+========
+
+SYNOPSIS
+--------
+A stand-alone Puppet filebucket client.
+
+
+USAGE
+-----
+puppet filebucket <mode> [-h|--help] [-V|--version] [-d|--debug]
+  [-v|--verbose] [-l|--local] [-r|--remote] [-s|--server <server>]
+  [-b|--bucket <directory>] <file> <file> ...
+
+Puppet filebucket can operate in three modes, with only one mode per call:
+
+backup:
+  Send one or more files to the specified file bucket. Each sent file is
+  printed with its resulting md5 sum.
+
+get:
+  Return the text associated with an md5 sum. The text is printed to
+  stdout, and only one file can be retrieved at a time.
+
+restore:
+  Given a file path and an md5 sum, store the content associated with
+  the sum into the specified file path. You can specify an entirely new
+  path to this argument; you are not restricted to restoring the content
+  to its original location.
+
+
+DESCRIPTION
+-----------
+This is a stand-alone filebucket client for sending files to a local or
+central filebucket.
+
+Note that 'filebucket' defaults to using a network-based filebucket
+available on the server named 'puppet'. To use this, you'll have to be
+running as a user with valid Puppet certificates. Alternatively, you can
+use your local file bucket by specifying '--local'.
+
+
+OPTIONS
+-------
+Note that any setting that's valid in the configuration
+file is also a valid long argument. For example, 'ssldir' is a valid
+setting, so you can specify '--ssldir <directory>' as an
+argument.
+
+See the configuration file documentation at
+http://docs.puppetlabs.com/references/stable/configuration.html for the
+full list of acceptable parameters. A commented list of all
+configuration options can also be generated by running puppet with
+'--genconfig'.
+
+* --debug:
+  Enable full debugging.
+
+* --help:
+  Print this help message
+
+* --local:
+  Use the local filebucket. This will use the default configuration
+  information.
+
+* --remote:
+  Use a remote filebucket. This will use the default configuration
+  information.
+
+* --server:
+  The server to send the file to, instead of locally.
+
+* --verbose:
+  Print extra information.
+
+* --version:
+  Print version information.
+
+
+EXAMPLE
+-------
+    $ puppet filebucket backup /etc/passwd
+    /etc/passwd: 429b225650b912a2ee067b0a4cf1e949
+    $ puppet filebucket restore /tmp/passwd 429b225650b912a2ee067b0a4cf1e949
+
+
+AUTHOR
+------
+Luke Kanies
+
+
+COPYRIGHT
+---------
+Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License
+
+    HELP
+  end
+
+
+  def run_command
+    @args = command_line.args
+    command = args.shift
+    return send(command) if %w{get backup restore}.include? command
+    help
+  end
+
+  def get
+    md5 = args.shift
+    out = @client.getfile(md5)
+    print out
+  end
+
+  def backup
+    raise "You must specify a file to back up" unless args.length > 0
+
+    args.each do |file|
+      unless Puppet::FileSystem.exist?(file)
+        $stderr.puts "#{file}: no such file"
+        next
+      end
+      unless FileTest.readable?(file)
+        $stderr.puts "#{file}: cannot read file"
+        next
+      end
+      md5 = @client.backup(file)
+      puts "#{file}: #{md5}"
+    end
+  end
+
+  def restore
+    file = args.shift
+    md5 = args.shift
+    @client.restore(file, md5)
+  end
+
+  def setup
+    Puppet::Log.newdestination(:console)
+
+    @client = nil
+    @server = nil
+
+    Signal.trap(:INT) do
+      $stderr.puts "Cancelling"
+      exit(1)
+    end
+
+    if options[:debug]
+      Puppet::Log.level = :debug
+    elsif options[:verbose]
+      Puppet::Log.level = :info
+    end
+
+      exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
+
+    require 'puppet/file_bucket/dipper'
+    begin
+      if options[:local] or options[:bucket]
+        path = options[:bucket] || Puppet[:bucketdir]
+        @client = Puppet::FileBucket::Dipper.new(:Path => path)
+      else
+        @client = Puppet::FileBucket::Dipper.new(:Server => Puppet[:server])
+      end
+    rescue => detail
+      Puppet.log_exception(detail)
+      exit(1)
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/help.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/help.rb
new file mode 100644
index 0000000..66baa46
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/help.rb
@@ -0,0 +1,4 @@
+require 'puppet/application/face_base'
+
+class Puppet::Application::Help < Puppet::Application::FaceBase
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/indirection_base.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/indirection_base.rb
new file mode 100644
index 0000000..580a099
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/indirection_base.rb
@@ -0,0 +1,4 @@
+require 'puppet/application/face_base'
+
+class Puppet::Application::IndirectionBase < Puppet::Application::FaceBase
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/inspect.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/inspect.rb
new file mode 100644
index 0000000..3aec9fa
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/inspect.rb
@@ -0,0 +1,179 @@
+require 'puppet/application'
+
+class Puppet::Application::Inspect < Puppet::Application
+
+  run_mode :agent
+
+  option("--debug","-d")
+  option("--verbose","-v")
+
+  option("--logdest LOGDEST", "-l") do |arg|
+    handle_logdest_arg(arg)
+  end
+
+  def help
+    <<-'HELP'
+
+puppet-inspect(8) -- Send an inspection report
+========
+
+SYNOPSIS
+--------
+
+Prepares and submits an inspection report to the puppet master.
+
+
+USAGE
+-----
+puppet inspect [--archive_files] [--archive_file_server]
+
+
+DESCRIPTION
+-----------
+
+This command uses the cached catalog from the previous run of 'puppet
+agent' to determine which attributes of which resources have been
+marked as auditable with the 'audit' metaparameter. It then examines
+the current state of the system, writes the state of the specified
+resource attributes to a report, and submits the report to the puppet
+master.
+
+Puppet inspect does not run as a daemon, and must be run manually or
+from cron.
+
+
+OPTIONS
+-------
+
+Any configuration setting which is valid in the configuration file is
+also a valid long argument, e.g. '--server=master.domain.com'. See the
+configuration file documentation at
+http://docs.puppetlabs.com/references/latest/configuration.html for
+the full list of acceptable settings.
+
+* --archive_files:
+  During an inspect run, whether to archive files whose contents are audited to
+  a file bucket.
+
+* --archive_file_server:
+  During an inspect run, the file bucket server to archive files to if
+  archive_files is set.  The default value is '$server'.
+
+
+AUTHOR
+------
+
+Puppet Labs
+
+
+COPYRIGHT
+---------
+Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License
+
+    HELP
+  end
+
+  def setup
+    exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
+
+    raise "Inspect requires reporting to be enabled. Set report=true in puppet.conf to enable reporting." unless Puppet[:report]
+
+    @report = Puppet::Transaction::Report.new("inspect")
+
+    Puppet::Util::Log.newdestination(@report)
+    Puppet::Util::Log.newdestination(:console) unless options[:setdest]
+
+    Signal.trap(:INT) do
+      $stderr.puts "Exiting"
+      exit(1)
+    end
+
+    set_log_level
+
+    Puppet::Transaction::Report.indirection.terminus_class = :rest
+    Puppet::Resource::Catalog.indirection.terminus_class = :yaml
+  end
+
+  def preinit
+    require 'puppet'
+    require 'puppet/file_bucket/dipper'
+  end
+
+  def run_command
+    benchmark(:notice, "Finished inspection") do
+      retrieval_starttime = Time.now
+
+      unless catalog = Puppet::Resource::Catalog.indirection.find(Puppet[:certname])
+        raise "Could not find catalog for #{Puppet[:certname]}"
+      end
+
+      @report.configuration_version = catalog.version
+      @report.environment = Puppet[:environment]
+
+      inspect_starttime = Time.now
+      @report.add_times("config_retrieval", inspect_starttime - retrieval_starttime)
+
+      if Puppet[:archive_files]
+        dipper = Puppet::FileBucket::Dipper.new(:Server => Puppet[:archive_file_server])
+      end
+
+      catalog.to_ral.resources.each do |ral_resource|
+        audited_attributes = ral_resource[:audit]
+        next unless audited_attributes
+
+        status = Puppet::Resource::Status.new(ral_resource)
+
+        begin
+          audited_resource = ral_resource.to_resource
+        rescue StandardError => detail
+          ral_resource.log_exception(detail, "Could not inspect #{ral_resource}; skipping: #{detail}")
+          audited_attributes.each do |name|
+            event = ral_resource.event(
+                                       :property => name,
+                                       :status   => "failure",
+                                       :audited  => true,
+                                       :message  => "failed to inspect #{name}"
+                                       )
+            status.add_event(event)
+          end
+        else
+          audited_attributes.each do |name|
+            next if audited_resource[name].nil?
+            # Skip :absent properties of :absent resources. Really, it would be nicer if the RAL returned nil for those, but it doesn't. ~JW
+            if name == :ensure or audited_resource[:ensure] != :absent or audited_resource[name] != :absent
+              event = ral_resource.event(
+                                         :previous_value => audited_resource[name],
+                                         :property       => name,
+                                         :status         => "audit",
+                                         :audited        => true,
+                                         :message        => "inspected value is #{audited_resource[name].inspect}"
+                                         )
+              status.add_event(event)
+            end
+          end
+        end
+        if Puppet[:archive_files] and ral_resource.type == :file and audited_attributes.include?(:content)
+          path = ral_resource[:path]
+          if ::File.readable?(path)
+            begin
+              dipper.backup(path)
+            rescue StandardError => detail
+              Puppet.warning detail
+            end
+          end
+        end
+        @report.add_resource_status(status)
+      end
+
+      finishtime = Time.now
+      @report.add_times("inspect", finishtime - inspect_starttime)
+      @report.finalize_report
+
+      begin
+        Puppet::Transaction::Report.indirection.save(@report)
+      rescue => detail
+        Puppet.log_exception(detail, "Could not send report: #{detail}")
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/instrumentation_data.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/instrumentation_data.rb
new file mode 100644
index 0000000..ab431c3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/instrumentation_data.rb
@@ -0,0 +1,7 @@
+require 'puppet/application/indirection_base'
+
+# NOTE: this is using an "old" naming convention (underscores instead of camel-case), for backwards
+#  compatibility with 2.7.x.  When the old naming convention is officially and publicly deprecated,
+#  this should be changed to camel-case.
+class Puppet::Application::Instrumentation_data < Puppet::Application::IndirectionBase
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/instrumentation_listener.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/instrumentation_listener.rb
new file mode 100644
index 0000000..10e2893
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/instrumentation_listener.rb
@@ -0,0 +1,7 @@
+require 'puppet/application/indirection_base'
+
+# NOTE: this is using an "old" naming convention (underscores instead of camel-case), for backwards
+#  compatibility with 2.7.x.  When the old naming convention is officially and publicly deprecated,
+#  this should be changed to camel-case.
+class Puppet::Application::Instrumentation_listener < Puppet::Application::IndirectionBase
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/instrumentation_probe.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/instrumentation_probe.rb
new file mode 100644
index 0000000..d6d3644
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/instrumentation_probe.rb
@@ -0,0 +1,7 @@
+require 'puppet/application/indirection_base'
+
+# NOTE: this is using an "old" naming convention (underscores instead of camel-case), for backwards
+#  compatibility with 2.7.x.  When the old naming convention is officially and publicly deprecated,
+#  this should be changed to camel-case.
+class Puppet::Application::Instrumentation_probe < Puppet::Application::IndirectionBase
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/key.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/key.rb
new file mode 100644
index 0000000..57835b6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/key.rb
@@ -0,0 +1,4 @@
+require 'puppet/application/indirection_base'
+
+class Puppet::Application::Key < Puppet::Application::IndirectionBase
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/kick.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/kick.rb
new file mode 100644
index 0000000..f5e36dd
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/kick.rb
@@ -0,0 +1,351 @@
+require 'puppet/application'
+
+class Puppet::Application::Kick < Puppet::Application
+
+  attr_accessor :hosts, :tags, :classes
+
+  option("--all","-a")
+  option("--foreground","-f")
+  option("--debug","-d")
+  option("--ping","-P")
+  option("--test")
+  option("--ignoreschedules")
+
+  option("--host HOST") do |arg|
+    @hosts << arg
+  end
+
+  option("--tag TAG", "-t") do |arg|
+    @tags << arg
+  end
+
+  option("--class CLASS", "-c") do |arg|
+    @classes << arg
+  end
+
+  option("--no-fqdn", "-n") do |arg|
+    options[:fqdn] = false
+  end
+
+  option("--parallel PARALLEL", "-p") do |arg|
+    begin
+      options[:parallel] = Integer(arg)
+    rescue
+      $stderr.puts "Could not convert #{arg.inspect} to an integer"
+      exit(23)
+    end
+  end
+
+  def help
+    <<-'HELP'
+
+puppet-kick(8) -- Remotely control puppet agent
+========
+
+SYNOPSIS
+--------
+Trigger a puppet agent run on a set of hosts.
+
+
+USAGE
+-----
+puppet kick [-a|--all] [-c|--class <class>] [-d|--debug] [-f|--foreground]
+  [-h|--help] [--host <host>] [--no-fqdn] [--ignoreschedules]
+  [-t|--tag <tag>] [--test] [-p|--ping] <host> [<host> [...]]
+
+
+DESCRIPTION
+-----------
+This script can be used to connect to a set of machines running 'puppet
+agent' and trigger them to run their configurations. The most common
+usage would be to specify a class of hosts and a set of tags, and
+'puppet kick' would look up in LDAP all of the hosts matching that
+class, then connect to each host and trigger a run of all of the objects
+with the specified tags.
+
+If you are not storing your host configurations in LDAP, you can specify
+hosts manually.
+
+You will most likely have to run 'puppet kick' as root to get access to
+the SSL certificates.
+
+'puppet kick' reads 'puppet master''s configuration file, so that it can
+copy things like LDAP settings.
+
+
+USAGE NOTES
+-----------
+Puppet kick needs the puppet agent on the target machine to be running as a
+daemon, be configured to listen for incoming network connections, and have an
+appropriate security configuration.
+
+The specific changes required are:
+
+* Set `listen = true` in the agent's `puppet.conf` file (or `--listen` on the
+  command line)
+* Configure the node's firewall to allow incoming connections on port 8139
+* Insert the following stanza at the top of the node's `auth.conf` file:
+
+        # Allow puppet kick access
+        path    /run
+        method  save
+        auth    any
+        allow   workstation.example.com
+
+This example would allow the machine `workstation.example.com` to trigger a
+Puppet run; adjust the "allow" directive to suit your site. You may also use
+`allow *` to allow anyone to trigger a Puppet run, but that makes it possible
+to interfere with your site by triggering excessive Puppet runs.
+
+See `http://docs.puppetlabs.com/guides/rest_auth_conf.html` for more details
+about security settings.
+
+OPTIONS
+-------
+Note that any setting that's valid in the configuration
+file is also a valid long argument. For example, 'ssldir' is a valid
+setting, so you can specify '--ssldir <directory>' as an
+argument.
+
+See the configuration file documentation at
+http://docs.puppetlabs.com/references/latest/configuration.html for
+the full list of acceptable parameters. A commented list of all
+configuration options can also be generated by running puppet master
+with '--genconfig'.
+
+* --all:
+  Connect to all available hosts. Requires LDAP support at this point.
+
+* --class:
+  Specify a class of machines to which to connect. This only works if
+  you have LDAP configured, at the moment.
+
+* --debug:
+  Enable full debugging.
+
+* --foreground:
+  Run each configuration in the foreground; that is, when connecting to
+  a host, do not return until the host has finished its run. The default
+  is false.
+
+* --help:
+  Print this help message
+
+* --host:
+  A specific host to which to connect. This flag can be specified more
+  than once.
+
+* --ignoreschedules:
+  Whether the client should ignore schedules when running its
+  configuration. This can be used to force the client to perform work it
+  would not normally perform so soon. The default is false.
+
+* --parallel:
+  How parallel to make the connections. Parallelization is provided by
+  forking for each client to which to connect. The default is 1, meaning
+  serial execution.
+
+* --puppetport:
+  Use the specified TCP port to connect to agents. Defaults to 8139.
+
+* --tag:
+  Specify a tag for selecting the objects to apply. Does not work with
+  the --test option.
+
+* --test:
+  Print the hosts you would connect to but do not actually connect. This
+  option requires LDAP support at this point.
+
+* --ping:
+  Do an ICMP echo against the target host. Skip hosts that don't respond
+  to ping.
+
+
+EXAMPLE
+-------
+    $ sudo puppet kick -p 10 -t remotefile -t webserver host1 host2
+
+
+AUTHOR
+------
+Luke Kanies
+
+
+COPYRIGHT
+---------
+Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License
+
+    HELP
+  end
+
+  def run_command
+    @hosts += command_line.args
+    options[:test] ? test : main
+  end
+
+  def test
+    puts "Skipping execution in test mode"
+    exit(0)
+  end
+
+  def main
+    Puppet.warning "Failed to load ruby LDAP library. LDAP functionality will not be available" unless Puppet.features.ldap?
+    require 'puppet/util/ldap/connection'
+
+    todo = @hosts.dup
+
+    failures = []
+
+    # Now do the actual work
+    go = true
+    while go
+      # If we don't have enough children in process and we still have hosts left to
+      # do, then do the next host.
+      if @children.length < options[:parallel] and ! todo.empty?
+        host = todo.shift
+        pid = safe_posix_fork do
+          run_for_host(host)
+        end
+        @children[pid] = host
+      else
+        # Else, see if we can reap a process.
+        begin
+          pid = Process.wait
+
+          if host = @children[pid]
+            # Remove our host from the list of children, so the parallelization
+            # continues working.
+            @children.delete(pid)
+            failures << host if $CHILD_STATUS.exitstatus != 0
+            print "#{host} finished with exit code #{$CHILD_STATUS.exitstatus}\n"
+          else
+            $stderr.puts "Could not find host for PID #{pid} with status #{$CHILD_STATUS.exitstatus}"
+          end
+        rescue Errno::ECHILD
+          # There are no children left, so just exit unless there are still
+          # children left to do.
+          next unless todo.empty?
+
+          if failures.empty?
+            puts "Finished"
+            exit(0)
+          else
+            puts "Failed: #{failures.join(", ")}"
+            exit(3)
+          end
+        end
+      end
+    end
+  end
+
+  def run_for_host(host)
+    if options[:ping]
+      %x{ping -c 1 #{host}}
+      unless $CHILD_STATUS == 0
+        $stderr.print "Could not contact #{host}\n"
+        exit($CHILD_STATUS)
+      end
+    end
+
+    require 'puppet/run'
+    Puppet::Run.indirection.terminus_class = :rest
+    port = Puppet[:puppetport]
+    url = ["https://#{host}:#{port}", "production", "run", host].join('/')
+
+    print "Triggering #{host}\n"
+    begin
+      run_options = {
+        :tags => @tags,
+        :background => ! options[:foreground],
+        :ignoreschedules => options[:ignoreschedules]
+      }
+      run = Puppet::Run.indirection.save(Puppet::Run.new( run_options ), url)
+      puts "Getting status"
+      result = run.status
+      puts "status is #{result}"
+    rescue => detail
+      Puppet.log_exception(detail, "Host #{host} failed: #{detail}\n")
+      exit(2)
+    end
+
+    case result
+    when "success";
+      exit(0)
+    when "running"
+      $stderr.puts "Host #{host} is already running"
+      exit(3)
+    else
+      $stderr.puts "Host #{host} returned unknown answer '#{result}'"
+      exit(12)
+    end
+  end
+
+  def initialize(*args)
+    super
+    @hosts = []
+    @classes = []
+    @tags = []
+  end
+
+  def preinit
+    [:INT, :TERM].each do |signal|
+      Signal.trap(signal) do
+        $stderr.puts "Cancelling"
+        exit(1)
+      end
+    end
+    options[:parallel] = 1
+    options[:verbose] = true
+    options[:fqdn] = true
+    options[:ignoreschedules] = false
+    options[:foreground] = false
+  end
+
+  def setup
+    super()
+    raise Puppet::Error.new("Puppet kick is not supported on Microsoft Windows") if Puppet.features.microsoft_windows?
+    Puppet.warning "Puppet kick is deprecated. See http://links.puppetlabs.com/puppet-kick-deprecation"
+
+    if options[:debug]
+      Puppet::Util::Log.level = :debug
+    else
+      Puppet::Util::Log.level = :info
+    end
+
+    if Puppet[:node_terminus] == :ldap and (options[:all] or @classes)
+      if options[:all]
+        @hosts = Puppet::Node.indirection.search("whatever", :fqdn => options[:fqdn]).collect { |node| node.name }
+        puts "all: #{@hosts.join(", ")}"
+      else
+        @hosts = []
+        @classes.each do |klass|
+          list = Puppet::Node.indirection.search("whatever", :fqdn => options[:fqdn], :class => klass).collect { |node| node.name }
+          puts "#{klass}: #{list.join(", ")}"
+
+          @hosts += list
+        end
+      end
+    elsif ! @classes.empty?
+      $stderr.puts "You must be using LDAP to specify host classes"
+      exit(24)
+    end
+
+    @children = {}
+
+    # If we get a signal, then kill all of our children and get out.
+    [:INT, :TERM].each do |signal|
+      Signal.trap(signal) do
+        Puppet.notice "Caught #{signal}; shutting down"
+        @children.each do |pid, host|
+          Process.kill("INT", pid)
+        end
+
+        waitall
+
+        exit(1)
+      end
+    end
+
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/man.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/man.rb
new file mode 100644
index 0000000..1ecc4d6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/man.rb
@@ -0,0 +1,4 @@
+require 'puppet/application/face_base'
+
+class Puppet::Application::Man < Puppet::Application::FaceBase
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/master.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/master.rb
new file mode 100644
index 0000000..c8abe7e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/master.rb
@@ -0,0 +1,309 @@
+require 'puppet/application'
+require 'puppet/daemon'
+require 'puppet/util/pidlock'
+
+class Puppet::Application::Master < Puppet::Application
+
+  run_mode :master
+
+  option("--debug", "-d")
+  option("--verbose", "-v")
+
+  # internal option, only to be used by ext/rack/config.ru
+  option("--rack")
+
+  option("--compile host",  "-c host") do |arg|
+    options[:node] = arg
+  end
+
+  option("--logdest DEST",  "-l DEST") do |arg|
+    handle_logdest_arg(arg)
+  end
+
+  option("--parseonly") do |args|
+    puts "--parseonly has been removed. Please use 'puppet parser validate <manifest>'"
+    exit 1
+  end
+
+  def help
+    <<-'HELP'
+
+puppet-master(8) -- The puppet master daemon
+========
+
+SYNOPSIS
+--------
+The central puppet server. Functions as a certificate authority by
+default.
+
+
+USAGE
+-----
+puppet master [-D|--daemonize|--no-daemonize] [-d|--debug] [-h|--help]
+  [-l|--logdest syslog|<FILE>|console] [-v|--verbose] [-V|--version]
+  [--compile <NODE-NAME>]
+
+
+DESCRIPTION
+-----------
+This command starts an instance of puppet master, running as a daemon
+and using Ruby's built-in Webrick webserver. Puppet master can also be
+managed by other application servers; when this is the case, this
+executable is not used.
+
+
+OPTIONS
+-------
+
+Note that any Puppet setting that's valid in the configuration file is also a
+valid long argument. For example, 'server' is a valid setting, so you can
+specify '--server <servername>' as an argument. Boolean settings translate into
+'--setting' and '--no-setting' pairs.
+
+See the configuration file documentation at
+http://docs.puppetlabs.com/references/stable/configuration.html for the
+full list of acceptable settings. A commented list of all settings can also be
+generated by running puppet master with '--genconfig'.
+
+* --daemonize:
+  Send the process into the background. This is the default.
+  (This is a Puppet setting, and can go in puppet.conf. Note the special 'no-'
+  prefix for boolean settings on the command line.)
+
+* --no-daemonize:
+  Do not send the process into the background.
+  (This is a Puppet setting, and can go in puppet.conf. Note the special 'no-'
+  prefix for boolean settings on the command line.)
+
+* --debug:
+  Enable full debugging.
+
+* --help:
+  Print this help message.
+
+* --logdest:
+  Where to send log messages. Choose between 'syslog' (the POSIX syslog
+  service), 'console', or the path to a log file. If debugging or verbosity is
+  enabled, this defaults to 'console'. Otherwise, it defaults to 'syslog'.
+
+  A path ending with '.json' will receive structured output in JSON format. The
+  log file will not have an ending ']' automatically written to it due to the
+  appending nature of logging. It must be appended manually to make the content
+  valid JSON.
+
+* --masterport:
+  The port on which to listen for traffic.
+  (This is a Puppet setting, and can go in puppet.conf.)
+
+* --verbose:
+  Enable verbosity.
+
+* --version:
+  Print the puppet version number and exit.
+
+* --compile:
+  Compile a catalogue and output it in JSON from the puppet master. Uses
+  facts contained in the $vardir/yaml/ directory to compile the catalog.
+
+
+EXAMPLE
+-------
+  puppet master
+
+DIAGNOSTICS
+-----------
+
+When running as a standalone daemon, puppet master accepts the
+following signals:
+
+* SIGHUP:
+  Restart the puppet master server.
+* SIGINT and SIGTERM:
+  Shut down the puppet master server.
+* SIGUSR2:
+  Close file descriptors for log files and reopen them. Used with logrotate.
+
+AUTHOR
+------
+Luke Kanies
+
+
+COPYRIGHT
+---------
+Copyright (c) 2012 Puppet Labs, LLC Licensed under the Apache 2.0 License
+
+    HELP
+  end
+
+  # Sets up the 'node_cache_terminus' default to use the Write Only Yaml terminus :write_only_yaml.
+  # If this is not wanted, the setting ´node_cache_terminus´ should be set to nil.
+  # @see Puppet::Node::WriteOnlyYaml
+  # @see #setup_node_cache
+  # @see puppet issue 16753
+  #
+  def app_defaults
+    super.merge({
+      :node_cache_terminus => :write_only_yaml,
+      :facts_terminus => 'yaml'
+    })
+  end
+
+  def preinit
+    Signal.trap(:INT) do
+      $stderr.puts "Canceling startup"
+      exit(0)
+    end
+
+    # save ARGV to protect us from it being smashed later by something
+    @argv = ARGV.dup
+  end
+
+  def run_command
+    if options[:node]
+      compile
+    else
+      main
+    end
+  end
+
+  def compile
+    begin
+      unless catalog = Puppet::Resource::Catalog.indirection.find(options[:node])
+        raise "Could not compile catalog for #{options[:node]}"
+      end
+
+      puts PSON::pretty_generate(catalog.to_resource, :allow_nan => true, :max_nesting => false)
+    rescue => detail
+      Puppet.log_exception(detail, "Failed to compile catalog for node #{options[:node]}: #{detail}")
+      exit(30)
+    end
+    exit(0)
+  end
+
+  def main
+    require 'etc'
+    # Make sure we've got a localhost ssl cert
+    Puppet::SSL::Host.localhost
+
+    # And now configure our server to *only* hit the CA for data, because that's
+    # all it will have write access to.
+    Puppet::SSL::Host.ca_location = :only if Puppet::SSL::CertificateAuthority.ca?
+
+    if Puppet.features.root?
+      begin
+        Puppet::Util.chuser
+      rescue => detail
+        Puppet.log_exception(detail, "Could not change user to #{Puppet[:user]}: #{detail}")
+        exit(39)
+      end
+    end
+
+    if options[:rack]
+      start_rack_master
+    else
+      start_webrick_master
+    end
+  end
+
+  def setup_logs
+    set_log_level
+
+    if !options[:setdest]
+      if options[:node]
+        # We are compiling a catalog for a single node with '--compile' and logging
+        # has not already been configured via '--logdest' so log to the console.
+        Puppet::Util::Log.newdestination(:console)
+      elsif !(Puppet[:daemonize] or options[:rack])
+        # We are running a webrick master which has been explicitly foregrounded
+        # and '--logdest' has not been passed, assume users want to see logging
+        # and log to the console.
+        Puppet::Util::Log.newdestination(:console)
+      else
+        # No explicit log destination has been given with '--logdest' and we're
+        # either a daemonized webrick master or running under rack, log to syslog.
+        Puppet::Util::Log.newdestination(:syslog)
+      end
+    end
+  end
+
+  def setup_terminuses
+    require 'puppet/file_serving/content'
+    require 'puppet/file_serving/metadata'
+
+    Puppet::FileServing::Content.indirection.terminus_class = :file_server
+    Puppet::FileServing::Metadata.indirection.terminus_class = :file_server
+
+    Puppet::FileBucket::File.indirection.terminus_class = :file
+  end
+
+  def setup_ssl
+    # Configure all of the SSL stuff.
+    if Puppet::SSL::CertificateAuthority.ca?
+      Puppet::SSL::Host.ca_location = :local
+      Puppet.settings.use :ca
+      Puppet::SSL::CertificateAuthority.instance
+    else
+      Puppet::SSL::Host.ca_location = :none
+    end
+  end
+
+  # Sets up a special node cache "write only yaml" that collects and stores node data in yaml
+  # but never finds or reads anything (this since a real cache causes stale data to be served
+  # in circumstances when the cache can not be cleared).
+  # @see puppet issue 16753
+  # @see Puppet::Node::WriteOnlyYaml
+  # @return [void]
+  def setup_node_cache
+    Puppet::Node.indirection.cache_class = Puppet[:node_cache_terminus]
+  end
+
+  def setup
+    raise Puppet::Error.new("Puppet master is not supported on Microsoft Windows") if Puppet.features.microsoft_windows?
+
+    setup_logs
+
+    exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
+
+    Puppet.settings.use :main, :master, :ssl, :metrics
+
+    setup_terminuses
+
+    setup_node_cache
+
+    setup_ssl
+  end
+
+  private
+
+  # Start a master that will be using WeBrick.
+  #
+  # This method will block until the master exits.
+  def start_webrick_master
+    require 'puppet/network/server'
+    daemon = Puppet::Daemon.new(Puppet::Util::Pidlock.new(Puppet[:pidfile]))
+
+    daemon.argv = @argv
+    daemon.server = Puppet::Network::Server.new(Puppet[:bindaddress], Puppet[:masterport])
+    daemon.daemonize if Puppet[:daemonize]
+
+    announce_start_of_master
+
+    daemon.start
+  end
+
+  # Start a master that will be used for a Rack container.
+  #
+  # This method immediately returns the Rack handler that must be returned to
+  # the calling Rack container
+  def start_rack_master
+    require 'puppet/network/http/rack'
+
+    announce_start_of_master
+
+    return Puppet::Network::HTTP::Rack.new()
+  end
+
+  def announce_start_of_master
+    Puppet.notice "Starting Puppet master version #{Puppet.version}"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/module.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/module.rb
new file mode 100644
index 0000000..8526974
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/module.rb
@@ -0,0 +1,4 @@
+require 'puppet/application/face_base'
+
+class Puppet::Application::Module < Puppet::Application::FaceBase
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/node.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/node.rb
new file mode 100644
index 0000000..38c1f86
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/node.rb
@@ -0,0 +1,4 @@
+require 'puppet/application/indirection_base'
+
+class Puppet::Application::Node < Puppet::Application::IndirectionBase
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/parser.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/parser.rb
new file mode 100644
index 0000000..b6ec3c1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/parser.rb
@@ -0,0 +1,5 @@
+require 'puppet/application/face_base'
+require 'puppet/face'
+
+class Puppet::Application::Parser < Puppet::Application::FaceBase
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/plugin.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/plugin.rb
new file mode 100644
index 0000000..2d0402e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/plugin.rb
@@ -0,0 +1,3 @@
+require 'puppet/application/face_base'
+class Puppet::Application::Plugin < Puppet::Application::FaceBase
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/queue.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/queue.rb
new file mode 100644
index 0000000..33155fc
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/queue.rb
@@ -0,0 +1,161 @@
+require 'puppet/application'
+require 'puppet/util'
+require 'puppet/daemon'
+require 'puppet/util/pidlock'
+
+class Puppet::Application::Queue < Puppet::Application
+
+  attr_accessor :daemon
+
+  def app_defaults()
+    super.merge( :pidfile => "$rundir/queue.pid" )
+  end
+
+  def preinit
+    @argv = ARGV.dup
+
+    # Do an initial trap, so that cancels don't get a stack trace.
+
+    # This exits with exit code 1
+    Signal.trap(:INT) do
+      $stderr.puts "Caught SIGINT; shutting down"
+      exit(1)
+    end
+
+    # This is a normal shutdown, so code 0
+    Signal.trap(:TERM) do
+      $stderr.puts "Caught SIGTERM; shutting down"
+      exit(0)
+    end
+
+    {
+      :verbose => false,
+      :debug => false
+    }.each do |opt,val|
+      options[opt] = val
+    end
+  end
+
+  option("--debug","-d")
+  option("--verbose","-v")
+
+  def help
+    <<-HELP
+
+puppet-queue(8) -- Deprecated queuing daemon for asynchronous storeconfigs
+========
+
+SYNOPSIS
+--------
+Retrieves serialized storeconfigs records from a queue and processes
+them in order. THIS FEATURE IS DEPRECATED; use PuppetDB instead.
+
+
+USAGE
+-----
+puppet queue [-d|--debug] [--help] [-v|--verbose] [--version]
+
+
+DESCRIPTION
+-----------
+This application runs as a daemon and processes storeconfigs data,
+retrieving the data from a stomp server message queue and writing it to
+a database. It was once necessary as a workaround for the poor performance
+of ActiveRecord-based storeconfigs, but has been supplanted by the PuppetDB
+service, which gives better performance with less complexity.
+
+For more information, see the PuppetDB documentation at
+http://docs.puppetlabs.com/puppetdb/latest
+
+
+OPTIONS
+-------
+Note that any setting that's valid in the configuration
+file is also a valid long argument. For example, 'server' is a valid
+setting, so you can specify '--server <servername>' as
+an argument.
+
+See the configuration file documentation at
+http://docs.puppetlabs.com/references/stable/configuration.html for the
+full list of acceptable parameters. A commented list of all
+configuration options can also be generated by running puppet queue with
+'--genconfig'.
+
+* --debug:
+  Enable full debugging.
+
+* --help:
+  Print this help message
+
+* --verbose:
+  Turn on verbose reporting.
+
+* --version:
+  Print the puppet version number and exit.
+
+
+EXAMPLE
+-------
+    $ puppet queue
+
+
+AUTHOR
+------
+Luke Kanies
+
+
+COPYRIGHT
+---------
+Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License
+
+    HELP
+  end
+
+  option("--logdest DEST", "-l DEST") do |arg|
+    handle_logdest_arg(arg)
+  end
+
+  def main
+    require 'puppet/indirector/catalog/queue' # provides Puppet::Indirector::Queue.subscribe
+    Puppet.notice "Starting puppet queue #{Puppet.version}"
+    Puppet::Resource::Catalog::Queue.subscribe do |catalog|
+      # Once you have a Puppet::Resource::Catalog instance, passing it to save should suffice
+      # to put it through to the database via its active_record indirector (which is determined
+      # by the terminus_class = :active_record setting above)
+      Puppet::Util.benchmark(:notice, "Processing queued catalog for #{catalog.name}") do
+        begin
+          Puppet::Resource::Catalog.indirection.save(catalog)
+        rescue => detail
+          Puppet.log_exception(detail, "Could not save queued catalog for #{catalog.name}: #{detail}")
+        end
+      end
+    end
+
+    Thread.list.each { |thread| thread.join }
+  end
+
+  def setup
+    Puppet.warning "Puppet queue is deprecated. See http://links.puppetlabs.com/puppet-queue-deprecation"
+
+    unless Puppet.features.stomp?
+      raise ArgumentError, "Could not load the 'stomp' library, which must be present for queueing to work.  You must install the required library."
+    end
+
+    setup_logs
+
+    exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
+
+    require 'puppet/resource/catalog'
+    Puppet::Resource::Catalog.indirection.terminus_class = :store_configs
+
+    daemon = Puppet::Daemon.new(Puppet::Util::Pidlock.new(Puppet[:pidfile]))
+    daemon.argv = @argv
+    daemon.daemonize if Puppet[:daemonize]
+
+    # We want to make sure that we don't have a cache
+    # class set up, because if storeconfigs is enabled,
+    # we'll get a loop of continually caching the catalog
+    # for storage again.
+    Puppet::Resource::Catalog.indirection.cache_class = nil
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/report.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/report.rb
new file mode 100644
index 0000000..f7f961e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/report.rb
@@ -0,0 +1,4 @@
+require 'puppet/application/indirection_base'
+
+class Puppet::Application::Report < Puppet::Application::IndirectionBase
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/resource.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/resource.rb
new file mode 100644
index 0000000..4a3a449
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/resource.rb
@@ -0,0 +1,228 @@
+require 'puppet/application'
+
+class Puppet::Application::Resource < Puppet::Application
+
+  attr_accessor :host, :extra_params
+
+  def preinit
+    @extra_params = []
+  end
+
+  option("--debug","-d")
+  option("--verbose","-v")
+  option("--edit","-e")
+
+  option("--host HOST","-H") do |arg|
+    Puppet.warning("Accessing resources on the network is deprecated. See http://links.puppetlabs.com/deprecate-networked-resource")
+    @host = arg
+  end
+
+  option("--types", "-t") do |arg|
+    types = []
+    Puppet::Type.loadall
+    Puppet::Type.eachtype do |t|
+      next if t.name == :component
+      types << t.name.to_s
+    end
+    puts types.sort
+    exit
+  end
+
+  option("--param PARAM", "-p") do |arg|
+    @extra_params << arg.to_sym
+  end
+
+  def help
+    <<-'HELP'
+
+puppet-resource(8) -- The resource abstraction layer shell
+========
+
+SYNOPSIS
+--------
+Uses the Puppet RAL to directly interact with the system.
+
+
+USAGE
+-----
+puppet resource [-h|--help] [-d|--debug] [-v|--verbose] [-e|--edit]
+  [-H|--host <host>] [-p|--param <parameter>] [-t|--types] <type>
+  [<name>] [<attribute>=<value> ...]
+
+
+DESCRIPTION
+-----------
+This command provides simple facilities for converting current system
+state into Puppet code, along with some ability to modify the current
+state using Puppet's RAL.
+
+By default, you must at least provide a type to list, in which case
+puppet resource will tell you everything it knows about all resources of
+that type. You can optionally specify an instance name, and puppet
+resource will only describe that single instance.
+
+If given a type, a name, and a series of <attribute>=<value> pairs,
+puppet resource will modify the state of the specified resource.
+Alternately, if given a type, a name, and the '--edit' flag, puppet
+resource will write its output to a file, open that file in an editor,
+and then apply the saved file as a Puppet transaction.
+
+
+OPTIONS
+-------
+Note that any setting that's valid in the configuration
+file is also a valid long argument. For example, 'ssldir' is a valid
+setting, so you can specify '--ssldir <directory>' as an
+argument.
+
+See the configuration file documentation at
+http://docs.puppetlabs.com/references/stable/configuration.html for the
+full list of acceptable parameters. A commented list of all
+configuration options can also be generated by running puppet with
+'--genconfig'.
+
+* --debug:
+  Enable full debugging.
+
+* --edit:
+  Write the results of the query to a file, open the file in an editor,
+  and read the file back in as an executable Puppet manifest.
+
+* --host:
+  When specified, connect to the resource server on the named host
+  and retrieve the list of resouces of the type specified.
+
+* --help:
+  Print this help message.
+
+* --param:
+  Add more parameters to be outputted from queries.
+
+* --types:
+  List all available types.
+
+* --verbose:
+  Print extra information.
+
+
+EXAMPLE
+-------
+This example uses `puppet resource` to return a Puppet configuration for
+the user `luke`:
+
+    $ puppet resource user luke
+    user { 'luke':
+     home => '/home/luke',
+     uid => '100',
+     ensure => 'present',
+     comment => 'Luke Kanies,,,',
+     gid => '1000',
+     shell => '/bin/bash',
+     groups => ['sysadmin','audio','video','puppet']
+    }
+
+
+AUTHOR
+------
+Luke Kanies
+
+
+COPYRIGHT
+---------
+Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License
+
+    HELP
+  end
+
+  def main
+    type, name, params = parse_args(command_line.args)
+
+    raise "You cannot edit a remote host" if options[:edit] and @host
+
+    resources = find_or_save_resources(type, name, params)
+    text = resources.
+      map { |resource| resource.prune_parameters(:parameters_to_include => @extra_params).to_manifest }.
+      join("\n")
+
+    options[:edit] ?
+      handle_editing(text) :
+      (puts text)
+  end
+
+  def setup
+    Puppet::Util::Log.newdestination(:console)
+    set_log_level
+  end
+
+  private
+
+  def remote_key(type, name)
+    Puppet::Resource.indirection.terminus_class = :rest
+    port = Puppet[:puppetport]
+    ["https://#{@host}:#{port}", "production", "resources", type, name].join('/')
+  end
+
+  def local_key(type, name)
+    [type, name].join('/')
+  end
+
+  def handle_editing(text)
+    require 'tempfile'
+    # Prefer the current directory, which is more likely to be secure
+    # and, in the case of interactive use, accessible to the user.
+    tmpfile = Tempfile.new('x2puppet', Dir.pwd)
+    begin
+      # sync write, so nothing buffers before we invoke the editor.
+      tmpfile.sync = true
+      tmpfile.puts text
+
+      # edit the content
+      system(ENV["EDITOR"] || 'vi', tmpfile.path)
+
+      # ...and, now, pass that file to puppet to apply.  Because
+      # many editors rename or replace the original file we need to
+      # feed the pathname, not the file content itself, to puppet.
+      system('puppet apply -v ' + tmpfile.path)
+    ensure
+      # The temporary file will be safely removed.
+      tmpfile.close(true)
+    end
+  end
+
+  def parse_args(args)
+    type = args.shift or raise "You must specify the type to display"
+    Puppet::Type.type(type) or raise "Could not find type #{type}"
+    name = args.shift
+    params = {}
+    args.each do |setting|
+      if setting =~ /^(\w+)=(.+)$/
+        params[$1] = $2
+      else
+        raise "Invalid parameter setting #{setting}"
+      end
+    end
+
+    [type, name, params]
+  end
+
+  def find_or_save_resources(type, name, params)
+    key = @host ? remote_key(type, name) : local_key(type, name)
+
+    if name
+      if params.empty?
+        [ Puppet::Resource.indirection.find( key ) ]
+      else
+        resource = Puppet::Resource.new( type, name, :parameters => params )
+
+        # save returns [resource that was saved, transaction log from applying the resource]
+        save_result = Puppet::Resource.indirection.save(resource, key)
+        [ save_result.first ]
+      end
+    else
+      if type == "file"
+        raise "Listing all file instances is not supported.  Please specify a file or directory, e.g. puppet resource file /etc"
+      end
+      Puppet::Resource.indirection.search( key, {} )
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/resource_type.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/resource_type.rb
new file mode 100644
index 0000000..ac001f0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/resource_type.rb
@@ -0,0 +1,7 @@
+require 'puppet/application/indirection_base'
+
+# NOTE: this is using an "old" naming convention (underscores instead of camel-case), for backwards
+#  compatibility with 2.7.x.  When the old naming convention is officially and publicly deprecated,
+#  this should be changed to camel-case.
+class Puppet::Application::Resource_type < Puppet::Application::IndirectionBase
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/secret_agent.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/secret_agent.rb
new file mode 100644
index 0000000..6bee284
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/secret_agent.rb
@@ -0,0 +1,9 @@
+require 'puppet/application/face_base'
+require 'puppet/face'
+
+# NOTE: this is using an "old" naming convention (underscores instead of camel-case), for backwards
+#  compatibility with 2.7.x.  When the old naming convention is officially and publicly deprecated,
+#  this should be changed to camel-case.
+class Puppet::Application::Secret_agent < Puppet::Application::FaceBase
+  run_mode :agent
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/status.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/status.rb
new file mode 100644
index 0000000..1c3ca05
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/application/status.rb
@@ -0,0 +1,4 @@
+require 'puppet/application/indirection_base'
+
+class Puppet::Application::Status < Puppet::Application::IndirectionBase
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/bindings.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/bindings.rb
new file mode 100644
index 0000000..a30cfe2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/bindings.rb
@@ -0,0 +1,147 @@
+# This class allows registration of named bindings that are later contributed to a layer via
+# a binding scheme.
+#
+# The intended use is for a .rb file to be placed in confdir's or module's `lib/bindings` directory structure, with a
+# name corresponding to the symbolic bindings name.
+#
+# Here are two equivalent examples, the first using chained methods (which is compact for simple cases), and the
+# second which uses a block.
+#
+# @example MyModule's lib/bindings/mymodule/default.rb
+#   Puppet::Bindings.newbindings('mymodule::default') do
+#     bind.integer.named('meaning of life').to(42)
+#   end
+#
+# @example Using blocks
+#   Puppet::Bindings.newbindings('mymodule::default') do
+#     bind do
+#       integer
+#       name 'meaning of life'
+#       to 42
+#     end
+#   end
+#
+# If access is needed to the scope, this can be declared as a block parameter.
+# @example MyModule's lib/bindings/mymodule/default.rb with scope
+#   Puppet::Bindings.newbindings('mymodule::default') do |scope|
+#     bind.integer.named('meaning of life').to("#{scope['::fqdn']} also think it is 42")
+#   end
+#
+# If late evaluation is wanted, this can be achieved by binding a puppet expression.
+# @example binding a puppet expression
+#   Puppet::Bindings.newbindings('mymodule::default') do |scope|
+#     bind.integer.named('meaning of life').to(puppet_string("${::fqdn} also think it is 42")
+#   end
+#
+# It is allowed to define methods in the block given to `newbindings`, these can be used when
+# producing bindings. (Care should naturally be taken to not override any of the already defined methods).
+# @example defining method to be used while creating bindings
+#   Puppet::Bindings.newbindings('mymodule::default') do
+#     def square(x)
+#       x * x
+#     end
+#     bind.integer.named('meaning of life squared').to(square(42))
+#   end
+#
+# For all details see {Puppet::Pops::Binder::BindingsFactory}, which is used behind the scenes.
+# @api public
+#
+class Puppet::Bindings
+  extend Enumerable
+
+  Environment = Puppet::Node::Environment
+
+  # Constructs and registers a {Puppet::Pops::Binder::Bindings::NamedBindings NamedBindings} that later can be contributed
+  # to a bindings layer in a bindings configuration via a URI. The name is symbolic, fully qualified with module name, and at least one
+  # more qualifying name (where the name `default` is used in the default bindings configuration.
+  #
+  # The given block is called with a `self` bound to an instance of {Puppet::Pops::Binder::BindingsFactory::BindingsContainerBuilder}
+  # which most notably has a `#bind` method which it turn calls a block bound to an instance of
+  # {Puppet::Pops::Binder::BindingsFactory::BindingsBuilder}.
+  # Depending on the use-case a direct chaining method calls or nested blocks may be used.
+  #
+  # @example simple bindings
+  #   Puppet::Bindings.newbindings('mymodule::default') do
+  #     bind.name('meaning of life').to(42)
+  #     bind.integer.named('port').to(8080)
+  #     bind.integer.named('apache::port').to(8080)
+  #   end
+  #
+  # The block form is more suitable for longer, more complex forms of bindings.
+  #
+  def self.newbindings(name, &block)
+    register_proc(name, block)
+  end
+
+  def self.register_proc(name, block)
+    adapter = NamedBindingsAdapter.adapt(Puppet.lookup(:current_environment))
+    adapter[name] = block
+  end
+
+  # Registers a named_binding under its name
+  # @param named_bindings [Puppet::Pops::Binder::Bindings::NamedBindings] The named bindings to register.
+  # @api public
+  #
+  def self.register(named_bindings)
+    adapter = NamedBindingsAdapter.adapt(Puppet.lookup(:current_environment))
+    adapter[named_bindings.name] = named_bindings
+  end
+
+  def self.resolve(scope, name)
+    entry = get(name)
+    return entry unless entry.is_a?(Proc)
+    named_bindings = Puppet::Pops::Binder::BindingsFactory.safe_named_bindings(name, scope, &entry).model
+    adapter = NamedBindingsAdapter.adapt(Puppet.lookup(:current_environment))
+    adapter[named_bindings.name] = named_bindings
+    named_bindings
+  end
+
+  # Returns the named bindings with the given name, or nil if no such bindings have been registered.
+  # @param name [String] The fully qualified name of a binding to get
+  # @return [Proc, Puppet::Pops::Binder::Bindings::NamedBindings] a Proc producing named bindings, or a named bindings directly
+  # @api public
+  #
+  def self.get(name)
+    adapter = NamedBindingsAdapter.adapt(Puppet.lookup(:current_environment))
+    adapter[name]
+  end
+
+  def self.[](name)
+    get(name)
+  end
+
+  # Supports Enumerable iteration (k,v) over the named bindings hash.
+  def self.each
+    adapter = NamedBindingsAdapter.adapt(Puppet.lookup(:current_environment))
+    adapter.each_pair {|k,v| yield k,v }
+  end
+
+  # A NamedBindingsAdapter holds a map of name to Puppet::Pops::Binder::Bindings::NamedBindings.
+  # It is intended to be used as an association between an Environment and named bindings.
+  #
+  class NamedBindingsAdapter < Puppet::Pops::Adaptable::Adapter
+    def initialize()
+      @named_bindings = {}
+    end
+
+    def [](name)
+      @named_bindings[name]
+    end
+
+    def has_name?(name)
+      @named_bindings.has_key?
+    end
+
+    def []=(name, value)
+      unless value.is_a?(Puppet::Pops::Binder::Bindings::NamedBindings) || value.is_a?(Proc)
+        raise ArgumentError, "Given value must be a NamedBindings, or a Proc producing one, got: #{value.class}."
+      end
+      @named_bindings[name] = value
+    end
+
+    def each_pair(&block)
+      @named_bindings.each_pair(&block)
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/coercion.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/coercion.rb
new file mode 100644
index 0000000..5de06a3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/coercion.rb
@@ -0,0 +1,40 @@
+# Various methods used to coerce values into a canonical form.
+#
+# @api private
+module Puppet::Coercion
+  # Try to coerce various input values into boolean true/false
+  #
+  # Only a very limited subset of values are allowed. This method does not try
+  # to provide a generic "truthiness" system.
+  #
+  # @param value [Boolean, Symbol, String]
+  # @return [Boolean]
+  # @raise
+  # @api private
+  def self.boolean(value)
+    # downcase strings
+    if value.respond_to? :downcase
+      value = value.downcase
+    end
+
+    case value
+    when true, :true, 'true', :yes, 'yes'
+      true
+    when false, :false, 'false', :no, 'no'
+      false
+    else
+      fail('expected a boolean value')
+    end
+  end
+
+  # Return the list of acceptable boolean values.
+  #
+  # This is limited to lower-case, even though boolean() is case-insensitive.
+  #
+  # @return [Array]
+  # @raise
+  # @api private
+  def self.boolean_values
+    ['true', 'false', 'yes', 'no']
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/configurer.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/configurer.rb
new file mode 100644
index 0000000..6159305
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/configurer.rb
@@ -0,0 +1,308 @@
+# The client for interacting with the puppetmaster config server.
+require 'sync'
+require 'timeout'
+require 'puppet/network/http_pool'
+require 'puppet/util'
+require 'securerandom'
+
+class Puppet::Configurer
+  require 'puppet/configurer/fact_handler'
+  require 'puppet/configurer/plugin_handler'
+  require 'puppet/configurer/downloader_factory'
+
+  include Puppet::Configurer::FactHandler
+
+  # For benchmarking
+  include Puppet::Util
+
+  attr_reader :compile_time, :environment
+
+  # Provide more helpful strings to the logging that the Agent does
+  def self.to_s
+    "Puppet configuration client"
+  end
+
+  def execute_postrun_command
+    execute_from_setting(:postrun_command)
+  end
+
+  def execute_prerun_command
+    execute_from_setting(:prerun_command)
+  end
+
+  # Initialize and load storage
+  def init_storage
+      Puppet::Util::Storage.load
+      @compile_time ||= Puppet::Util::Storage.cache(:configuration)[:compile_time]
+  rescue => detail
+    Puppet.log_exception(detail, "Removing corrupt state file #{Puppet[:statefile]}: #{detail}")
+    begin
+      Puppet::FileSystem.unlink(Puppet[:statefile])
+      retry
+    rescue => detail
+      raise Puppet::Error.new("Cannot remove #{Puppet[:statefile]}: #{detail}", detail)
+    end
+  end
+
+  def initialize(factory = Puppet::Configurer::DownloaderFactory.new)
+    Puppet.settings.use(:main, :ssl, :agent)
+
+    @running = false
+    @splayed = false
+    @environment = Puppet[:environment]
+    @transaction_uuid = SecureRandom.uuid
+    @handler = Puppet::Configurer::PluginHandler.new(factory)
+  end
+
+  # Get the remote catalog, yo.  Returns nil if no catalog can be found.
+  def retrieve_catalog(query_options)
+    query_options ||= {}
+    # First try it with no cache, then with the cache.
+    unless (Puppet[:use_cached_catalog] and result = retrieve_catalog_from_cache(query_options)) or result = retrieve_new_catalog(query_options)
+      if ! Puppet[:usecacheonfailure]
+        Puppet.warning "Not using cache on failed catalog"
+        return nil
+      end
+      result = retrieve_catalog_from_cache(query_options)
+    end
+
+    return nil unless result
+
+    convert_catalog(result, @duration)
+  end
+
+  # Convert a plain resource catalog into our full host catalog.
+  def convert_catalog(result, duration)
+    catalog = result.to_ral
+    catalog.finalize
+    catalog.retrieval_duration = duration
+    catalog.write_class_file
+    catalog.write_resource_file
+    catalog
+  end
+
+  def get_facts(options)
+    if options[:pluginsync]
+      remote_environment_for_plugins = Puppet::Node::Environment.remote(@environment)
+      download_plugins(remote_environment_for_plugins)
+    end
+
+    facts_hash = {}
+    if Puppet::Resource::Catalog.indirection.terminus_class == :rest
+      # This is a bit complicated.  We need the serialized and escaped facts,
+      # and we need to know which format they're encoded in.  Thus, we
+      # get a hash with both of these pieces of information.
+      #
+      # facts_for_uploading may set Puppet[:node_name_value] as a side effect
+      facts_hash = facts_for_uploading
+    end
+    facts_hash
+  end
+
+  def prepare_and_retrieve_catalog(options, query_options)
+    # set report host name now that we have the fact
+    options[:report].host = Puppet[:node_name_value]
+
+    unless catalog = (options.delete(:catalog) || retrieve_catalog(query_options))
+      Puppet.err "Could not retrieve catalog; skipping run"
+      return
+    end
+    catalog
+  end
+
+  # Retrieve (optionally) and apply a catalog. If a catalog is passed in
+  # the options, then apply that one, otherwise retrieve it.
+  def apply_catalog(catalog, options)
+    report = options[:report]
+    report.configuration_version = catalog.version
+
+    benchmark(:notice, "Finished catalog run") do
+      catalog.apply(options)
+    end
+
+    report.finalize_report
+    report
+  end
+
+  # The code that actually runs the catalog.
+  # This just passes any options on to the catalog,
+  # which accepts :tags and :ignoreschedules.
+  def run(options = {})
+    pool = Puppet::Network::HTTP::Pool.new(Puppet[:http_keepalive_timeout])
+    begin
+      Puppet.override(:http_pool => pool) do
+        run_internal(options)
+      end
+    ensure
+      pool.close
+    end
+  end
+
+  def run_internal(options)
+    # We create the report pre-populated with default settings for
+    # environment and transaction_uuid very early, this is to ensure
+    # they are sent regardless of any catalog compilation failures or
+    # exceptions.
+    options[:report] ||= Puppet::Transaction::Report.new("apply", nil, @environment, @transaction_uuid)
+    report = options[:report]
+    init_storage
+
+    Puppet::Util::Log.newdestination(report)
+
+    begin
+      unless Puppet[:node_name_fact].empty?
+        query_options = get_facts(options)
+      end
+
+      # We only need to find out the environment to run in if we don't already have a catalog
+      unless options[:catalog]
+        begin
+          if node = Puppet::Node.indirection.find(Puppet[:node_name_value],
+              :environment => Puppet::Node::Environment.remote(@environment),
+              :ignore_cache => true,
+              :transaction_uuid => @transaction_uuid,
+              :fail_on_404 => true)
+
+            # If we have deserialized a node from a rest call, we want to set
+            # an environment instance as a simple 'remote' environment reference.
+            if !node.has_environment_instance? && node.environment_name
+              node.environment = Puppet::Node::Environment.remote(node.environment_name)
+            end
+
+            if node.environment.to_s != @environment
+              Puppet.warning "Local environment: \"#{@environment}\" doesn't match server specified node environment \"#{node.environment}\", switching agent to \"#{node.environment}\"."
+              @environment = node.environment.to_s
+              report.environment = @environment
+              query_options = nil
+            end
+          end
+        rescue SystemExit,NoMemoryError
+          raise
+        rescue Exception => detail
+          Puppet.warning("Unable to fetch my node definition, but the agent run will continue:")
+          Puppet.warning(detail)
+        end
+      end
+
+      current_environment = Puppet.lookup(:current_environment)
+      local_node_environment =
+      if current_environment.name == @environment.intern
+        current_environment
+      else
+        Puppet::Node::Environment.create(@environment,
+                                         current_environment.modulepath,
+                                         current_environment.manifest,
+                                         current_environment.config_version)
+      end
+      Puppet.push_context({:current_environment => local_node_environment}, "Local node environment for configurer transaction")
+
+      query_options = get_facts(options) unless query_options
+      query_options[:transaction_uuid] = @transaction_uuid
+
+      unless catalog = prepare_and_retrieve_catalog(options, query_options)
+        return nil
+      end
+
+      # Here we set the local environment based on what we get from the
+      # catalog. Since a change in environment means a change in facts, and
+      # facts may be used to determine which catalog we get, we need to
+      # rerun the process if the environment is changed.
+      tries = 0
+      while catalog.environment and not catalog.environment.empty? and catalog.environment != @environment
+        if tries > 3
+          raise Puppet::Error, "Catalog environment didn't stabilize after #{tries} fetches, aborting run"
+        end
+        Puppet.warning "Local environment: \"#{@environment}\" doesn't match server specified environment \"#{catalog.environment}\", restarting agent run with environment \"#{catalog.environment}\""
+        @environment = catalog.environment
+        report.environment = @environment
+
+        query_options = get_facts(options)
+        query_options[:transaction_uuid] = @transaction_uuid
+
+        return nil unless catalog = prepare_and_retrieve_catalog(options, query_options)
+        tries += 1
+      end
+
+      execute_prerun_command or return nil
+      apply_catalog(catalog, options)
+      report.exit_status
+    rescue => detail
+      Puppet.log_exception(detail, "Failed to apply catalog: #{detail}")
+      return nil
+    ensure
+      execute_postrun_command or return nil
+    end
+  ensure
+    # Between Puppet runs we need to forget the cached values.  This lets us
+    # pick up on new functions installed by gems or new modules being added
+    # without the daemon being restarted.
+    $env_module_directories = nil
+
+    Puppet::Util::Log.close(report)
+    send_report(report)
+    Puppet.pop_context
+  end
+  private :run_internal
+
+  def send_report(report)
+    puts report.summary if Puppet[:summarize]
+    save_last_run_summary(report)
+    Puppet::Transaction::Report.indirection.save(report, nil, :environment => Puppet::Node::Environment.remote(@environment)) if Puppet[:report]
+  rescue => detail
+    Puppet.log_exception(detail, "Could not send report: #{detail}")
+  end
+
+  def save_last_run_summary(report)
+    mode = Puppet.settings.setting(:lastrunfile).mode
+    Puppet::Util.replace_file(Puppet[:lastrunfile], mode) do |fh|
+      fh.print YAML.dump(report.raw_summary)
+    end
+  rescue => detail
+    Puppet.log_exception(detail, "Could not save last run local report: #{detail}")
+  end
+
+  private
+
+  def execute_from_setting(setting)
+    return true if (command = Puppet[setting]) == ""
+
+    begin
+      Puppet::Util::Execution.execute([command])
+      true
+    rescue => detail
+      Puppet.log_exception(detail, "Could not run command from #{setting}: #{detail}")
+      false
+    end
+  end
+
+  def retrieve_catalog_from_cache(query_options)
+    result = nil
+    @duration = thinmark do
+      result = Puppet::Resource::Catalog.indirection.find(Puppet[:node_name_value],
+        query_options.merge(:ignore_terminus => true, :environment => Puppet::Node::Environment.remote(@environment)))
+    end
+    Puppet.notice "Using cached catalog"
+    result
+  rescue => detail
+    Puppet.log_exception(detail, "Could not retrieve catalog from cache: #{detail}")
+    return nil
+  end
+
+  def retrieve_new_catalog(query_options)
+    result = nil
+    @duration = thinmark do
+      result = Puppet::Resource::Catalog.indirection.find(Puppet[:node_name_value],
+        query_options.merge(:ignore_cache => true, :environment => Puppet::Node::Environment.remote(@environment), :fail_on_404 => true))
+    end
+    result
+  rescue SystemExit,NoMemoryError
+    raise
+  rescue Exception => detail
+    Puppet.log_exception(detail, "Could not retrieve catalog from remote server: #{detail}")
+    return nil
+  end
+
+  def download_plugins(remote_environment_for_plugins)
+    @handler.download_plugins(remote_environment_for_plugins)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/configurer/downloader.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/configurer/downloader.rb
new file mode 100644
index 0000000..319546b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/configurer/downloader.rb
@@ -0,0 +1,66 @@
+require 'puppet/configurer'
+require 'puppet/resource/catalog'
+
+class Puppet::Configurer::Downloader
+  attr_reader :name, :path, :source, :ignore
+
+  # Evaluate our download, returning the list of changed values.
+  def evaluate
+    Puppet.info "Retrieving #{name}"
+
+    files = []
+    begin
+      catalog.apply do |trans|
+        trans.changed?.each do |resource|
+          yield resource if block_given?
+          files << resource[:path]
+        end
+      end
+    rescue Puppet::Error => detail
+      Puppet.log_exception(detail, "Could not retrieve #{name}: #{detail}")
+    end
+    files
+  end
+
+  def initialize(name, path, source, ignore = nil, environment = nil, source_permissions = :ignore)
+    @name, @path, @source, @ignore, @environment, @source_permissions = name, path, source, ignore, environment, source_permissions
+  end
+
+  def catalog
+    catalog = Puppet::Resource::Catalog.new("PluginSync", @environment)
+    catalog.host_config = false
+    catalog.add_resource(file)
+    catalog
+  end
+
+  def file
+    args = default_arguments.merge(:path => path, :source => source)
+    args[:ignore] = ignore.split if ignore
+    Puppet::Type.type(:file).new(args)
+  end
+
+  private
+
+  def default_arguments
+    defargs = {
+      :path => path,
+      :recurse => true,
+      :source => source,
+      :source_permissions => @source_permissions,
+      :tag => name,
+      :purge => true,
+      :force => true,
+      :backup => false,
+      :noop => false
+    }
+    if !Puppet.features.microsoft_windows?
+      defargs.merge!(
+        {
+          :owner => Process.uid,
+          :group => Process.gid
+        }
+      )
+    end
+    return defargs
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/configurer/downloader_factory.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/configurer/downloader_factory.rb
new file mode 100644
index 0000000..65aac8b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/configurer/downloader_factory.rb
@@ -0,0 +1,34 @@
+require 'puppet/configurer'
+
+# Factory for <tt>Puppet::Configurer::Downloader</tt> objects.
+#
+# Puppet's pluginsync facilities can be used to download modules
+# and external facts, each with a different destination directory
+# and related settings.
+#
+# @api private
+#
+class Puppet::Configurer::DownloaderFactory
+  def create_plugin_downloader(environment)
+    plugin_downloader = Puppet::Configurer::Downloader.new(
+      "plugin",
+      Puppet[:plugindest],
+      Puppet[:pluginsource],
+      Puppet[:pluginsignore],
+      environment
+    )
+  end
+
+  def create_plugin_facts_downloader(environment)
+    source_permissions = Puppet.features.microsoft_windows? ? :ignore : :use
+
+    plugin_fact_downloader = Puppet::Configurer::Downloader.new(
+      "pluginfacts",
+      Puppet[:pluginfactdest],
+      Puppet[:pluginfactsource],
+      Puppet[:pluginsignore],
+      environment,
+      source_permissions
+    )
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/configurer/fact_handler.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/configurer/fact_handler.rb
new file mode 100644
index 0000000..5d20a5b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/configurer/fact_handler.rb
@@ -0,0 +1,37 @@
+require 'puppet/indirector/facts/facter'
+
+require 'puppet/configurer'
+require 'puppet/configurer/downloader'
+
+# Break out the code related to facts.  This module is
+# just included into the agent, but having it here makes it
+# easier to test.
+module Puppet::Configurer::FactHandler
+  def find_facts
+    # This works because puppet agent configures Facts to use 'facter' for
+    # finding facts and the 'rest' terminus for caching them.  Thus, we'll
+    # compile them and then "cache" them on the server.
+    begin
+      facts = Puppet::Node::Facts.indirection.find(Puppet[:node_name_value], :environment => @environment)
+      unless Puppet[:node_name_fact].empty?
+        Puppet[:node_name_value] = facts.values[Puppet[:node_name_fact]]
+        facts.name = Puppet[:node_name_value]
+      end
+      facts
+    rescue SystemExit,NoMemoryError
+      raise
+    rescue Exception => detail
+      message = "Could not retrieve local facts: #{detail}"
+      Puppet.log_exception(detail, message)
+      raise Puppet::Error, message, detail.backtrace
+    end
+  end
+
+  def facts_for_uploading
+    facts = find_facts
+
+    text = facts.render(:pson)
+
+    {:facts_format => :pson, :facts => CGI.escape(text)}
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/configurer/plugin_handler.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/configurer/plugin_handler.rb
new file mode 100644
index 0000000..908e49d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/configurer/plugin_handler.rb
@@ -0,0 +1,23 @@
+# Break out the code related to plugins.  This module is
+# just included into the agent, but having it here makes it
+# easier to test.
+require 'puppet/configurer'
+
+class Puppet::Configurer::PluginHandler
+  def initialize(factory)
+    @factory = factory
+  end
+
+  # Retrieve facts from the central server.
+  def download_plugins(environment)
+    plugin_downloader = @factory.create_plugin_downloader(environment)
+
+    if Puppet.features.external_facts?
+      plugin_fact_downloader = @factory.create_plugin_facts_downloader(environment)
+      plugin_fact_downloader.evaluate
+    end
+
+    plugin_downloader.evaluate
+    Puppet::Util::Autoload.reload_changed
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine.rb
new file mode 100644
index 0000000..41b5aa0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine.rb
@@ -0,0 +1,80 @@
+# The class that handles testing whether our providers
+# actually work or not.
+require 'puppet/util'
+
+class Puppet::Confine
+  include Puppet::Util
+
+  @tests = {}
+
+  class << self
+    attr_accessor :name
+  end
+
+  def self.inherited(klass)
+    name = klass.to_s.split("::").pop.downcase.to_sym
+    raise "Test #{name} is already defined" if @tests.include?(name)
+
+    klass.name = name
+
+    @tests[name] = klass
+  end
+
+  def self.test(name)
+    unless @tests[name]
+      begin
+        require "puppet/confine/#{name}"
+      rescue LoadError => detail
+        unless detail.to_s =~ /No such file|cannot load such file/i
+          warn "Could not load confine test '#{name}': #{detail}"
+        end
+        # Could not find file
+      end
+    end
+    @tests[name]
+  end
+
+  attr_reader :values
+
+  # Mark that this confine is used for testing binary existence.
+  attr_accessor :for_binary
+  def for_binary?
+    for_binary
+  end
+
+  # Used for logging.
+  attr_accessor :label
+
+  def initialize(values)
+    values = [values] unless values.is_a?(Array)
+    @values = values
+  end
+
+  # Provide a hook for the message when there's a failure.
+  def message(value)
+    ""
+  end
+
+  # Collect the results of all of them.
+  def result
+    values.collect { |value| pass?(value) }
+  end
+
+  # Test whether our confine matches.
+  def valid?
+    values.each do |value|
+      unless pass?(value)
+        Puppet.debug(label + ": " + message(value))
+        return false
+      end
+    end
+
+    return true
+  ensure
+    reset
+  end
+
+  # Provide a hook for subclasses.
+  def reset
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine/any.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine/any.rb
new file mode 100644
index 0000000..3921812
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine/any.rb
@@ -0,0 +1,26 @@
+class Puppet::Confine::Any < Puppet::Confine
+  def self.summarize(confines)
+    confines.inject(0) { |count, confine| count + confine.summary }
+  end
+
+  def pass?(value)
+    !! value
+  end
+
+  def message(value)
+    "0 confines (of #{value.length}) were true"
+  end
+
+  def summary
+    result.find_all { |v| v == true }.length
+  end
+
+  def valid?
+    if @values.any? { |value| pass?(value) }
+      true
+    else
+      Puppet.debug("#{label}: #{message(@values)}")
+      false
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine/exists.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine/exists.rb
new file mode 100644
index 0000000..6e29022
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine/exists.rb
@@ -0,0 +1,19 @@
+require 'puppet/confine'
+
+class Puppet::Confine::Exists < Puppet::Confine
+  def self.summarize(confines)
+    confines.inject([]) { |total, confine| total + confine.summary }
+  end
+
+  def pass?(value)
+    value && (for_binary? ? which(value) : Puppet::FileSystem.exist?(value))
+  end
+
+  def message(value)
+    "file #{value} does not exist"
+  end
+
+  def summary
+    result.zip(values).inject([]) { |array, args| val, f = args; array << f unless val; array }
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine/false.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine/false.rb
new file mode 100644
index 0000000..3b664df
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine/false.rb
@@ -0,0 +1,19 @@
+require 'puppet/confine'
+
+class Puppet::Confine::False < Puppet::Confine
+  def self.summarize(confines)
+    confines.inject(0) { |count, confine| count + confine.summary }
+  end
+
+  def pass?(value)
+    ! value
+  end
+
+  def message(value)
+    "true value when expecting false"
+  end
+
+  def summary
+    result.find_all { |v| v == false }.length
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine/feature.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine/feature.rb
new file mode 100644
index 0000000..5aff48a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine/feature.rb
@@ -0,0 +1,17 @@
+require 'puppet/confine'
+
+class Puppet::Confine::Feature < Puppet::Confine
+  def self.summarize(confines)
+    confines.collect { |c| c.values }.flatten.uniq.find_all { |value| ! confines[0].pass?(value) }
+  end
+
+  # Is the named feature available?
+  def pass?(value)
+    Puppet.features.send(value.to_s + "?")
+  end
+
+  def message(value)
+    "feature #{value} is missing"
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine/true.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine/true.rb
new file mode 100644
index 0000000..b7e3470
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine/true.rb
@@ -0,0 +1,20 @@
+require 'puppet/confine'
+
+class Puppet::Confine::True < Puppet::Confine
+  def self.summarize(confines)
+    confines.inject(0) { |count, confine| count + confine.summary }
+  end
+
+  def pass?(value)
+    # Double negate, so we only get true or false.
+    ! ! value
+  end
+
+  def message(value)
+    "false value when expecting true"
+  end
+
+  def summary
+    result.find_all { |v| v == true }.length
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine/variable.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine/variable.rb
new file mode 100644
index 0000000..9102d45
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine/variable.rb
@@ -0,0 +1,59 @@
+require 'puppet/confine'
+
+# Require a specific value for a variable, either a Puppet setting
+# or a Facter value.  This class is a bit weird because the name
+# is set explicitly by the ConfineCollection class -- from this class,
+# it's not obvious how the name would ever get set.
+class Puppet::Confine::Variable < Puppet::Confine
+  # Provide a hash summary of failing confines -- the key of the hash
+  # is the name of the confine, and the value is the missing yet required values.
+  # Only returns failed values, not all required values.
+  def self.summarize(confines)
+    result = Hash.new { |hash, key| hash[key] = [] }
+    confines.inject(result) { |total, confine| total[confine.name] += confine.values unless confine.valid?; total }
+  end
+
+  # This is set by ConfineCollection.
+  attr_accessor :name
+
+  # Retrieve the value from facter
+  def facter_value
+    @facter_value ||= ::Facter.value(name).to_s.downcase
+  end
+
+  def initialize(values)
+    super
+    @values = @values.collect { |v| v.to_s.downcase }
+  end
+
+  def message(value)
+    "facter value '#{test_value}' for '#{self.name}' not in required list '#{values.join(",")}'"
+  end
+
+  # Compare the passed-in value to the retrieved value.
+  def pass?(value)
+    test_value.downcase.to_s == value.to_s.downcase
+  end
+
+  def reset
+    # Reset the cache.  We want to cache it during a given
+    # run, but not across runs.
+    @facter_value = nil
+  end
+
+  def valid?
+    @values.include?(test_value.to_s.downcase)
+  ensure
+    reset
+  end
+
+  private
+
+  def setting?
+    Puppet.settings.valid?(name)
+  end
+
+  def test_value
+    setting? ? Puppet.settings[name] : facter_value
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine_collection.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine_collection.rb
new file mode 100644
index 0000000..7a2eba8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confine_collection.rb
@@ -0,0 +1,50 @@
+# Manage a collection of confines, returning a boolean or
+# helpful information.
+require 'puppet/confine'
+
+class Puppet::ConfineCollection
+  def confine(hash)
+    if hash.include?(:for_binary)
+      for_binary = true
+      hash.delete(:for_binary)
+    else
+      for_binary = false
+    end
+    hash.each do |test, values|
+      if klass = Puppet::Confine.test(test)
+        @confines << klass.new(values)
+        @confines[-1].for_binary = true if for_binary
+      else
+        confine = Puppet::Confine.test(:variable).new(values)
+        confine.name = test
+        @confines << confine
+      end
+      @confines[-1].label = self.label
+    end
+  end
+
+  attr_reader :label
+  def initialize(label)
+    @label = label
+    @confines = []
+  end
+
+  # Return a hash of the whole confine set, used for the Provider
+  # reference.
+  def summary
+    confines = Hash.new { |hash, key| hash[key] = [] }
+    @confines.each { |confine| confines[confine.class] << confine }
+    result = {}
+    confines.each do |klass, list|
+      value = klass.summarize(list)
+      next if (value.respond_to?(:length) and value.length == 0) or (value == 0)
+      result[klass.name] = value
+
+    end
+    result
+  end
+
+  def valid?
+    ! @confines.detect { |c| ! c.valid? }
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confiner.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confiner.rb
new file mode 100644
index 0000000..50282fd
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/confiner.rb
@@ -0,0 +1,46 @@
+require 'puppet/confine_collection'
+
+# The Confiner module contains methods for managing a Provider's confinement (suitability under given
+# conditions). The intent is to include this module in an object where confinement management is wanted.
+# It lazily adds an instance variable `@confine_collection` to the object where it is included.
+#
+module Puppet::Confiner
+  # Confines a provider to be suitable only under the given conditions.
+  # The hash describes a confine using mapping from symbols to values or predicate code.
+  #
+  # * _fact_name_ => value of fact (or array of facts)
+  # * `:exists` => the path to an existing file
+  # * `:true` => a predicate code block returning true
+  # * `:false` => a predicate code block returning false
+  # * `:feature` => name of system feature that must be present
+  # * `:any` => an array of expressions that will be ORed together
+  #
+  # @example
+  #   confine :operatingsystem => [:redhat, :fedora]
+  #   confine :true { ... }
+  #
+  # @param hash [Hash<{Symbol => Object}>] hash of confines
+  # @return [void]
+  # @api public
+  #
+  def confine(hash)
+    confine_collection.confine(hash)
+  end
+
+  # @return [Puppet::ConfineCollection] the collection of confines
+  # @api private
+  #
+  def confine_collection
+    @confine_collection ||= Puppet::ConfineCollection.new(self.to_s)
+  end
+
+  # Checks whether this implementation is suitable for the current platform (or returns a summary
+  # of all confines if short == false).
+  # @return [Boolean. Hash] Returns whether the confines are all valid (if short == true), or a hash of all confines
+  #   if short == false.
+  # @api public
+  #
+  def suitable?(short = true)
+    return(short ? confine_collection.valid? : confine_collection.summary)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/context.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/context.rb
new file mode 100644
index 0000000..d6f064c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/context.rb
@@ -0,0 +1,101 @@
+# Puppet::Context is a system for tracking services and contextual information
+# that puppet needs to be able to run. Values are "bound" in a context when it is created
+# and cannot be changed; however a child context can be created, using
+# {#override}, that provides a different value.
+#
+# When binding a {Proc}, the proc is called when the value is looked up, and the result
+# is memoized for subsequent lookups. This provides a lazy mechanism that can be used to
+# delay expensive production of values until they are needed.
+#
+# @api private
+class Puppet::Context
+  require 'puppet/context/trusted_information'
+
+  class UndefinedBindingError < Puppet::Error; end
+  class StackUnderflow < Puppet::Error; end
+
+  class UnknownRollbackMarkError < Puppet::Error; end
+  class DuplicateRollbackMarkError < Puppet::Error; end
+
+  # @api private
+  def initialize(initial_bindings)
+    @table = initial_bindings
+    @description = "root"
+    @id = 0
+    @rollbacks = {}
+    @stack = [[0, nil, nil]]
+  end
+
+  # @api private
+  def push(overrides, description = "")
+    @id += 1
+    @stack.push([@id, @table, @description])
+    @table = @table.merge(overrides || {})
+    @description = description
+  end
+
+  # @api private
+  def pop
+    if @stack[-1][0] == 0
+      raise(StackUnderflow, "Attempted to pop, but already at root of the context stack.")
+    else
+      (_, @table, @description) = @stack.pop
+    end
+  end
+
+  # @api private
+  def lookup(name, &block)
+    if @table.include?(name)
+      value = @table[name]
+      value.is_a?(Proc) ? (@table[name] = value.call) : value
+    elsif block
+      block.call
+    else
+      raise UndefinedBindingError, "no '#{name}' in #{@table.inspect} at top of #{@stack.inspect}"
+    end
+  end
+
+  # @api private
+  def override(bindings, description = "", &block)
+    mark_point = "override over #{@stack[-1][0]}"
+    mark(mark_point)
+    push(bindings, description)
+
+    yield
+  ensure
+    rollback(mark_point)
+  end
+
+  # Mark a place on the context stack to later return to with {rollback}.
+  #
+  # @param name [Object] The identifier for the mark
+  #
+  # @api private
+  def mark(name)
+    if @rollbacks[name].nil?
+      @rollbacks[name] = @stack[-1][0]
+    else
+      raise DuplicateRollbackMarkError, "Mark for '#{name}' already exists"
+    end
+  end
+
+  # Roll back to a mark set by {mark}.
+  #
+  # Rollbacks can only reach a mark accessible via {pop}. If the mark is not on
+  # the current context stack the behavior of rollback is undefined.
+  #
+  # @param name [Object] The identifier for the mark
+  #
+  # @api private
+  def rollback(name)
+    if @rollbacks[name].nil?
+      raise UnknownRollbackMarkError, "Unknown mark '#{name}'"
+    end
+
+    while @stack[-1][0] != @rollbacks[name]
+      pop
+    end
+
+    @rollbacks.delete(name)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/context/trusted_information.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/context/trusted_information.rb
new file mode 100644
index 0000000..35d3a77
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/context/trusted_information.rb
@@ -0,0 +1,56 @@
+# @api private
+class Puppet::Context::TrustedInformation
+  # one of 'remote', 'local', or false, where 'remote' is authenticated via cert,
+  # 'local' is trusted by virtue of running on the same machine (not a remote
+  # request), and false is an unauthenticated remote request.
+  #
+  # @return [String, Boolean]
+  attr_reader :authenticated
+
+  # The validated certificate name used for the request
+  #
+  # @return [String]
+  attr_reader :certname
+
+  # Extra information that comes from the trusted certificate's extensions.
+  #
+  # @return [Hash{Object => Object}]
+  attr_reader :extensions
+
+  def initialize(authenticated, certname, extensions)
+    @authenticated = authenticated.freeze
+    @certname = certname.freeze
+    @extensions = extensions.freeze
+  end
+
+  def self.remote(authenticated, node_name, certificate)
+    if authenticated
+      extensions = {}
+      if certificate.nil?
+        Puppet.info('TrustedInformation expected a certificate, but none was given.')
+      else
+        extensions = Hash[certificate.custom_extensions.collect do |ext|
+          [ext['oid'].freeze, ext['value'].freeze]
+        end]
+      end
+      new('remote', node_name, extensions)
+    else
+      new(false, nil, {})
+    end
+  end
+
+  def self.local(node)
+    # Always trust local data by picking up the available parameters.
+    client_cert = node ? node.parameters['clientcert'] : nil
+
+    new('local', client_cert, {})
+  end
+
+  def to_h
+    {
+      'authenticated'.freeze => authenticated,
+      'certname'.freeze => certname,
+      'extensions'.freeze => extensions
+    }.freeze
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/daemon.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/daemon.rb
new file mode 100644
index 0000000..6540c35
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/daemon.rb
@@ -0,0 +1,200 @@
+require 'puppet/application'
+require 'puppet/scheduler'
+
+# Run periodic actions and a network server in a daemonized process.
+#
+# A Daemon has 3 parts:
+#   * config reparse
+#   * (optional) an agent that responds to #run
+#   * (optional) a server that response to #stop, #start, and #wait_for_shutdown
+#
+# The config reparse will occur periodically based on Settings. The server will
+# be started and is expected to manage its own run loop (and so not block the
+# start call). The server will, however, still be waited for by using the
+# #wait_for_shutdown method. The agent is run periodically and a time interval
+# based on Settings. The config reparse will update this time interval when
+# needed.
+#
+# The Daemon is also responsible for signal handling, starting, stopping,
+# running the agent on demand, and reloading the entire process. It ensures
+# that only one Daemon is running by using a lockfile.
+#
+# @api private
+class Puppet::Daemon
+  SIGNAL_CHECK_INTERVAL = 5
+
+  attr_accessor :agent, :server, :argv
+  attr_reader :signals
+
+  def initialize(pidfile, scheduler = Puppet::Scheduler::Scheduler.new())
+    @scheduler = scheduler
+    @pidfile = pidfile
+    @signals = []
+  end
+
+  def daemonname
+    Puppet.run_mode.name
+  end
+
+  # Put the daemon into the background.
+  def daemonize
+    if pid = fork
+      Process.detach(pid)
+      exit(0)
+    end
+
+    create_pidfile
+
+    # Get rid of console logging
+    Puppet::Util::Log.close(:console)
+
+    Process.setsid
+    Dir.chdir("/")
+
+    close_streams
+  end
+
+  # Close stdin/stdout/stderr so that we can finish our transition into 'daemon' mode.
+  # @return nil
+  def self.close_streams()
+    Puppet.debug("Closing streams for daemon mode")
+    begin
+      $stdin.reopen "/dev/null"
+      $stdout.reopen "/dev/null", "a"
+      $stderr.reopen $stdout
+      Puppet::Util::Log.reopen
+      Puppet.debug("Finished closing streams for daemon mode")
+    rescue => detail
+      Puppet.err "Could not start #{Puppet.run_mode.name}: #{detail}"
+      Puppet::Util::replace_file("/tmp/daemonout", 0644) do |f|
+        f.puts "Could not start #{Puppet.run_mode.name}: #{detail}"
+      end
+      exit(12)
+    end
+  end
+
+  # Convenience signature for calling Puppet::Daemon.close_streams
+  def close_streams()
+    Puppet::Daemon.close_streams
+  end
+
+  def reexec
+    raise Puppet::DevError, "Cannot reexec unless ARGV arguments are set" unless argv
+    command = $0 + " " + argv.join(" ")
+    Puppet.notice "Restarting with '#{command}'"
+    stop(:exit => false)
+    exec(command)
+  end
+
+  def reload
+    return unless agent
+    if agent.running?
+      Puppet.notice "Not triggering already-running agent"
+      return
+    end
+
+    agent.run({:splay => false})
+  end
+
+  def restart
+    Puppet::Application.restart!
+    reexec unless agent and agent.running?
+  end
+
+  def reopen_logs
+    Puppet::Util::Log.reopen
+  end
+
+  # Trap a couple of the main signals.  This should probably be handled
+  # in a way that anyone else can register callbacks for traps, but, eh.
+  def set_signal_traps
+    [:INT, :TERM].each do |signal|
+      Signal.trap(signal) do
+        Puppet.notice "Caught #{signal}; exiting"
+        stop
+      end
+    end
+
+    # extended signals not supported under windows
+    if !Puppet.features.microsoft_windows?
+      signals = {:HUP => :restart, :USR1 => :reload, :USR2 => :reopen_logs }
+      signals.each do |signal, method|
+        Signal.trap(signal) do
+          Puppet.notice "Caught #{signal}; storing #{method}"
+          @signals << method
+        end
+      end
+    end
+  end
+
+  # Stop everything
+  def stop(args = {:exit => true})
+    Puppet::Application.stop!
+
+    server.stop if server
+
+    remove_pidfile
+
+    Puppet::Util::Log.close_all
+
+    exit if args[:exit]
+  end
+
+  def start
+    set_signal_traps
+
+    create_pidfile
+
+    raise Puppet::DevError, "Daemons must have an agent, server, or both" unless agent or server
+
+    # Start the listening server, if required.
+    server.start if server
+
+    # Finally, loop forever running events - or, at least, until we exit.
+    run_event_loop
+
+    server.wait_for_shutdown if server
+  end
+
+  private
+
+  # Create a pidfile for our daemon, so we can be stopped and others
+  # don't try to start.
+  def create_pidfile
+    raise "Could not create PID file: #{@pidfile.file_path}" unless @pidfile.lock
+  end
+
+  # Remove the pid file for our daemon.
+  def remove_pidfile
+    @pidfile.unlock
+  end
+
+  def run_event_loop
+    agent_run = Puppet::Scheduler.create_job(Puppet[:runinterval], Puppet[:splay], Puppet[:splaylimit]) do
+      # Splay for the daemon is handled in the scheduler
+      agent.run(:splay => false)
+    end
+
+    reparse_run = Puppet::Scheduler.create_job(Puppet[:filetimeout]) do
+      Puppet.settings.reparse_config_files
+      agent_run.run_interval = Puppet[:runinterval]
+      if Puppet[:filetimeout] == 0
+        reparse_run.disable
+      else
+        reparse_run.run_interval = Puppet[:filetimeout]
+      end
+    end
+
+    signal_loop = Puppet::Scheduler.create_job(SIGNAL_CHECK_INTERVAL) do
+      while method = @signals.shift
+        Puppet.notice "Processing #{method}"
+        send(method)
+      end
+    end
+
+    reparse_run.disable if Puppet[:filetimeout] == 0
+    agent_run.disable unless agent
+
+    @scheduler.run_loop([reparse_run, agent_run, signal_loop])
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/data_binding.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/data_binding.rb
new file mode 100644
index 0000000..76cc7a6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/data_binding.rb
@@ -0,0 +1,12 @@
+require 'puppet/indirector'
+
+# A class for managing data lookups
+class Puppet::DataBinding
+  class LookupError < Puppet::Error; end
+
+  # Set up indirection, so that data can be looked for in the compiler
+  extend Puppet::Indirector
+
+  indirects(:data_binding, :terminus_setting => :data_binding_terminus,
+    :doc => "Where to find external data bindings.")
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/defaults.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/defaults.rb
new file mode 100644
index 0000000..a68ce45
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/defaults.rb
@@ -0,0 +1,2115 @@
+module Puppet
+
+  def self.default_diffargs
+    if (Facter.value(:kernel) == "AIX" && Facter.value(:kernelmajversion) == "5300")
+      ""
+    else
+      "-u"
+    end
+  end
+
+  ############################################################################################
+  # NOTE: For information about the available values for the ":type" property of settings,
+  #   see the docs for Settings.define_settings
+  ############################################################################################
+
+  AS_DURATION = %q{This setting can be a time interval in seconds (30 or 30s), minutes (30m), hours (6h), days (2d), or years (5y).}
+  STORECONFIGS_ONLY = %q{This setting is only used by the ActiveRecord storeconfigs and inventory backends, which are deprecated.}
+
+  # This is defined first so that the facter implementation is replaced before other setting defaults are evaluated.
+  define_settings(:main,
+    :cfacter => {
+        :default => false,
+        :type    => :boolean,
+        :desc    => 'Whether or not to use the native facter (cfacter) implementation instead of the Ruby one (facter). Defaults to false.',
+        :hook    => proc do |value|
+          return unless value
+          raise ArgumentError, 'facter has already evaluated facts.' if Facter.instance_variable_get(:@collection)
+          raise ArgumentError, 'cfacter version 0.2.0 or later is not installed.' unless Puppet.features.cfacter?
+          CFacter.initialize
+        end
+    }
+  )
+
+  define_settings(:main,
+    :confdir  => {
+        :default  => nil,
+        :type     => :directory,
+        :desc     => "The main Puppet configuration directory.  The default for this setting
+          is calculated based on the user.  If the process is running as root or
+          the user that Puppet is supposed to run as, it defaults to a system
+          directory, but if it's running as any other user, it defaults to being
+          in the user's home directory.",
+    },
+    :vardir   => {
+        :default  => nil,
+        :type     => :directory,
+        :owner    => "service",
+        :group    => "service",
+        :desc     => "Where Puppet stores dynamic and growing data.  The default for this
+          setting is calculated specially, like `confdir`_.",
+    },
+
+    ### NOTE: this setting is usually being set to a symbol value.  We don't officially have a
+    ###     setting type for that yet, but we might want to consider creating one.
+    :name     => {
+        :default  => nil,
+        :desc     => "The name of the application, if we are running as one.  The
+          default is essentially $0 without the path or `.rb`.",
+    }
+  )
+
+  define_settings(:main,
+    :logdir => {
+        :default  => nil,
+        :type     => :directory,
+        :mode     => "0750",
+        :owner    => "service",
+        :group    => "service",
+        :desc     => "The directory in which to store log files",
+    },
+    :log_level => {
+      :default    => 'notice',
+      :type       => :enum,
+      :values     => ["debug","info","notice","warning","err","alert","emerg","crit"],
+      :desc       => "Default logging level for messages from Puppet. Allowed values are:
+
+        * debug
+        * info
+        * notice
+        * warning
+        * err
+        * alert
+        * emerg
+        * crit
+        ",
+    },
+    :disable_warnings => {
+      :default => [],
+      :type    => :array,
+      :desc    => "A comma-separated list of warning types to suppress. If large numbers
+        of warnings are making Puppet's logs too large or difficult to use, you
+        can temporarily silence them with this setting.
+
+        If you are preparing to upgrade Puppet to a new major version, you
+        should re-enable all warnings for a while.
+
+        Valid values for this setting are:
+
+        * `deprecations` --- disables deprecation warnings.",
+      :hook      => proc do |value|
+        values = munge(value)
+        valid   = %w[deprecations]
+        invalid = values - (values & valid)
+        if not invalid.empty?
+          raise ArgumentError, "Cannot disable unrecognized warning types #{invalid.inspect}. Valid values are #{valid.inspect}."
+        end
+      end
+    }
+  )
+
+  define_settings(:main,
+    :priority => {
+      :default => nil,
+      :type    => :priority,
+      :desc    => "The scheduling priority of the process.  Valid values are 'high',
+        'normal', 'low', or 'idle', which are mapped to platform-specific
+        values.  The priority can also be specified as an integer value and
+        will be passed as is, e.g. -5.  Puppet must be running as a privileged
+        user in order to increase scheduling priority.",
+    },
+    :trace => {
+        :default  => false,
+        :type     => :boolean,
+        :desc     => "Whether to print stack traces on some errors",
+    },
+    :profile => {
+        :default  => false,
+        :type     => :boolean,
+        :desc     => "Whether to enable experimental performance profiling",
+    },
+    :autoflush => {
+      :default => true,
+      :type       => :boolean,
+      :desc       => "Whether log files should always flush to disk.",
+      :hook       => proc { |value| Log.autoflush = value }
+    },
+    :syslogfacility => {
+        :default  => "daemon",
+        :desc     => "What syslog facility to use when logging to syslog.
+          Syslog has a fixed list of valid facilities, and you must
+          choose one of those; you cannot just make one up."
+    },
+    :statedir => {
+        :default  => "$vardir/state",
+        :type     => :directory,
+        :mode     => "01755",
+        :desc     => "The directory where Puppet state is stored.  Generally,
+          this directory can be removed without causing harm (although it
+          might result in spurious service restarts)."
+    },
+    :rundir => {
+      :default  => nil,
+      :type     => :directory,
+      :mode     => "0755",
+      :owner    => "service",
+      :group    => "service",
+      :desc     => "Where Puppet PID files are kept."
+    },
+    :genconfig => {
+        :default  => false,
+        :type     => :boolean,
+        :desc     => "When true, causes Puppet applications to print an example config file
+          to stdout and exit. The example will include descriptions of each
+          setting, and the current (or default) value of each setting,
+          incorporating any settings overridden on the CLI (with the exception
+          of `genconfig` itself). This setting only makes sense when specified
+          on the command line as `--genconfig`.",
+    },
+    :genmanifest => {
+        :default  => false,
+        :type     => :boolean,
+        :desc     => "Whether to just print a manifest to stdout and exit.  Only makes
+          sense when specified on the command line as `--genmanifest`.  Takes into account arguments specified
+          on the CLI.",
+    },
+    :configprint => {
+        :default  => "",
+        :desc     => "Print the value of a specific configuration setting.  If the name of a
+          setting is provided for this, then the value is printed and puppet
+          exits.  Comma-separate multiple values.  For a list of all values,
+          specify 'all'.",
+    },
+    :color => {
+      :default => "ansi",
+      :type    => :string,
+      :desc    => "Whether to use colors when logging to the console.  Valid values are
+        `ansi` (equivalent to `true`), `html`, and `false`, which produces no color.
+        Defaults to false on Windows, as its console does not support ansi colors.",
+    },
+    :mkusers => {
+        :default  => false,
+        :type     => :boolean,
+        :desc     => "Whether to create the necessary user and group that puppet agent will run as.",
+    },
+    :manage_internal_file_permissions => {
+        :default  => true,
+        :type     => :boolean,
+        :desc     => "Whether Puppet should manage the owner, group, and mode of files it uses internally",
+    },
+    :onetime => {
+        :default  => false,
+        :type     => :boolean,
+        :desc     => "Perform one configuration run and exit, rather than spawning a long-running
+          daemon. This is useful for interactively running puppet agent, or
+          running puppet agent from cron.",
+        :short    => 'o',
+    },
+    :path => {
+        :default          => "none",
+        :desc             => "The shell search path.  Defaults to whatever is inherited
+          from the parent process.",
+        :call_hook => :on_define_and_write,
+        :hook             => proc do |value|
+          ENV["PATH"] = "" if ENV["PATH"].nil?
+          ENV["PATH"] = value unless value == "none"
+          paths = ENV["PATH"].split(File::PATH_SEPARATOR)
+          Puppet::Util::Platform.default_paths.each do |path|
+            ENV["PATH"] += File::PATH_SEPARATOR + path unless paths.include?(path)
+          end
+          value
+        end
+    },
+    :libdir => {
+        :type           => :directory,
+        :default        => "$vardir/lib",
+        :desc           => "An extra search path for Puppet.  This is only useful
+          for those files that Puppet will load on demand, and is only
+          guaranteed to work for those cases.  In fact, the autoload
+          mechanism is responsible for making sure this directory
+          is in Ruby's search path\n",
+      :call_hook => :on_initialize_and_write,
+      :hook             => proc do |value|
+        $LOAD_PATH.delete(@oldlibdir) if defined?(@oldlibdir) and $LOAD_PATH.include?(@oldlibdir)
+        @oldlibdir = value
+        $LOAD_PATH << value
+      end
+    },
+    :ignoreimport => {
+        :default  => false,
+        :type     => :boolean,
+        :desc     => "If true, allows the parser to continue without requiring
+          all files referenced with `import` statements to exist. This setting was primarily
+          designed for use with commit hooks for parse-checking.",
+    },
+    :environment => {
+        :default  => "production",
+        :desc     => "The environment Puppet is running in.  For clients
+          (e.g., `puppet agent`) this determines the environment itself, which
+          is used to find modules and much more.  For servers (i.e., `puppet master`)
+          this provides the default environment for nodes we know nothing about."
+    },
+    :environmentpath => {
+      :default => "",
+      :desc    => "A search path for directory environments, as a list of directories
+        separated by the system path separator character. (The POSIX path separator
+        is ':', and the Windows path separator is ';'.)
+
+        This setting must have a value set to enable **directory environments.** The
+        recommended value is `$confdir/environments`. For more details, see
+        http://docs.puppetlabs.com/puppet/latest/reference/environments.html",
+      :type    => :path,
+    },
+    :always_cache_features => {
+      :type     => :boolean,
+      :default  => false,
+      :desc     => <<-'EOT'
+        Affects how we cache attempts to load Puppet 'features'.  If false, then
+        calls to `Puppet.features.<feature>?` will always attempt to load the
+        feature (which can be an expensive operation) unless it has already been
+        loaded successfully.  This makes it possible for a single agent run to,
+        e.g., install a package that provides the underlying capabilities for
+        a feature, and then later load that feature during the same run (even if
+        the feature had been tested earlier and had not been available).
+
+        If this setting is set to true, then features will only be checked once,
+        and if they are not available, the negative result is cached and returned
+        for all subsequent attempts to load the feature.  This behavior is almost
+        always appropriate for the server, and can result in a significant performance
+        improvement for features that are checked frequently.
+      EOT
+    },
+    :diff_args => {
+        :default  => lambda { default_diffargs },
+        :desc     => "Which arguments to pass to the diff command when printing differences between
+          files. The command to use can be chosen with the `diff` setting.",
+    },
+    :diff => {
+      :default => (Puppet.features.microsoft_windows? ? "" : "diff"),
+      :desc    => "Which diff command to use when printing differences between files. This setting
+          has no default value on Windows, as standard `diff` is not available, but Puppet can use many
+          third-party diff tools.",
+    },
+    :show_diff => {
+        :type     => :boolean,
+        :default  => false,
+        :desc     => "Whether to log and report a contextual diff when files are being replaced.
+          This causes partial file contents to pass through Puppet's normal
+          logging and reporting system, so this setting should be used with
+          caution if you are sending Puppet's reports to an insecure
+          destination. This feature currently requires the `diff/lcs` Ruby
+          library.",
+    },
+    :daemonize => {
+        :type     => :boolean,
+        :default  => (Puppet.features.microsoft_windows? ? false : true),
+        :desc     => "Whether to send the process into the background.  This defaults
+          to true on POSIX systems, and to false on Windows (where Puppet
+          currently cannot daemonize).",
+        :short    => "D",
+        :hook     => proc do |value|
+          if value and Puppet.features.microsoft_windows?
+            raise "Cannot daemonize on Windows"
+          end
+      end
+    },
+    :maximum_uid => {
+        :default  => 4294967290,
+        :desc     => "The maximum allowed UID.  Some platforms use negative UIDs
+          but then ship with tools that do not know how to handle signed ints,
+          so the UIDs show up as huge numbers that can then not be fed back into
+          the system.  This is a hackish way to fail in a slightly more useful
+          way when that happens.",
+    },
+    :route_file => {
+      :default    => "$confdir/routes.yaml",
+      :desc       => "The YAML file containing indirector route configuration.",
+    },
+    :node_terminus => {
+      :type       => :terminus,
+      :default    => "plain",
+      :desc       => "Where to find information about nodes.",
+    },
+    :node_cache_terminus => {
+      :type       => :terminus,
+      :default    => nil,
+      :desc       => "How to store cached nodes.
+      Valid values are (none), 'json', 'msgpack', 'yaml' or write only yaml ('write_only_yaml').
+      The master application defaults to 'write_only_yaml', all others to none.",
+    },
+    :data_binding_terminus => {
+      :type    => :terminus,
+      :default => "hiera",
+      :desc    => "Where to retrive information about data.",
+    },
+    :hiera_config => {
+      :default => "$confdir/hiera.yaml",
+      :desc    => "The hiera configuration file. Puppet only reads this file on startup, so you must restart the puppet master every time you edit it.",
+      :type    => :file,
+    },
+    :binder => {
+      :default => false,
+      :desc    => "Turns the binding system on or off. This includes bindings in modules.
+        The binding system aggregates data from modules and other locations and makes them available for lookup.
+        The binding system is experimental and any or all of it may change.",
+      :type    => :boolean,
+    },
+    :binder_config => {
+      :default => nil,
+      :desc    => "The binder configuration file. Puppet reads this file on each request to configure the bindings system.
+      If set to nil (the default), a $confdir/binder_config.yaml is optionally loaded. If it does not exists, a default configuration
+      is used. If the setting :binding_config is specified, it must reference a valid and existing yaml file.",
+      :type    => :file,
+    },
+    :catalog_terminus => {
+      :type       => :terminus,
+      :default    => "compiler",
+      :desc       => "Where to get node catalogs.  This is useful to change if, for instance,
+      you'd like to pre-compile catalogs and store them in memcached or some other easily-accessed store.",
+    },
+    :catalog_cache_terminus => {
+      :type       => :terminus,
+      :default    => nil,
+      :desc       => "How to store cached catalogs. Valid values are 'json', 'msgpack' and 'yaml'. The agent application defaults to 'json'."
+    },
+    :facts_terminus => {
+      :default => 'facter',
+      :desc => "The node facts terminus.",
+      :call_hook => :on_initialize_and_write,
+      :hook => proc do |value|
+        require 'puppet/node/facts'
+        # Cache to YAML if we're uploading facts away
+        if %w[rest inventory_service].include? value.to_s
+          Puppet.info "configuring the YAML fact cache because a remote terminus is active"
+          Puppet::Node::Facts.indirection.cache_class = :yaml
+        end
+      end
+    },
+    :inventory_terminus => {
+      :type       => :terminus,
+      :default    => "$facts_terminus",
+      :desc       => "Should usually be the same as the facts terminus",
+    },
+    :default_file_terminus => {
+      :type       => :terminus,
+      :default    => "rest",
+      :desc       => "The default source for files if no server is given in a
+      uri, e.g. puppet:///file. The default of `rest` causes the file to be
+      retrieved using the `server` setting. When running `apply` the default
+      is `file_server`, causing requests to be filled locally."
+    },
+    :httplog => {
+        :default  => "$logdir/http.log",
+        :type     => :file,
+        :owner    => "root",
+        :mode     => "0640",
+        :desc     => "Where the puppet agent web server logs.",
+    },
+    :http_proxy_host => {
+      :default    => "none",
+      :desc       => "The HTTP proxy host to use for outgoing connections.  Note: You
+      may need to use a FQDN for the server hostname when using a proxy. Environment variable
+      http_proxy or HTTP_PROXY will override this value",
+    },
+    :http_proxy_port => {
+      :default    => 3128,
+      :desc       => "The HTTP proxy port to use for outgoing connections",
+    },
+    :http_proxy_user => {
+      :default    => "none",
+      :desc       => "The user name for an authenticated HTTP proxy. Requires the `http_proxy_host` setting.",
+    },
+    :http_proxy_password =>{
+      :default    => "none",
+      :hook       => proc do |value|
+        if Puppet.settings[:http_proxy_password] =~ /[@!# \/]/
+          raise "Passwords set in the http_proxy_password setting must be valid as part of a URL, and any reserved characters must be URL-encoded. We received: #{value}"
+        end
+      end,
+      :desc       => "The password for the user of an authenticated HTTP proxy.
+        Requires the `http_proxy_user` setting.
+
+        Note that passwords must be valid when used as part of a URL. If a password
+        contains any characters with special meanings in URLs (as specified by RFC 3986
+        section 2.2), they must be URL-encoded. (For example, `#` would become `%23`.)",
+    },
+    :http_keepalive_timeout => {
+      :default    => "4s",
+      :type       => :duration,
+      :desc       => "The maximum amount of time a persistent HTTP connection can remain idle in the connection pool, before it is closed.  This timeout should be shorter than the keepalive timeout used on the HTTP server, e.g. Apache KeepAliveTimeout directive.
+      #{AS_DURATION}"
+    },
+    :http_debug => {
+      :default    => false,
+      :type       => :boolean,
+      :desc       => "Whether to write HTTP request and responses to stderr. This should never be used in a production environment."
+    },
+    :filetimeout => {
+      :default    => "15s",
+      :type       => :duration,
+      :desc       => "The minimum time to wait between checking for updates in
+      configuration files.  This timeout determines how quickly Puppet checks whether
+      a file (such as manifests or templates) has changed on disk. #{AS_DURATION}",
+    },
+    :environment_timeout => {
+      :default    => "0",
+      :type       => :ttl,
+      :desc       => "How long the Puppet master should cache data it loads from an
+      environment.
+      #{AS_DURATION}
+      A value of `0` will disable caching. This setting can also be set to
+      `unlimited`, which will cache environments until the master is restarted
+      or told to refresh the cache.
+
+      You should change this setting once your Puppet deployment is doing
+      non-trivial work. We chose the default value of `0` because it lets new
+      users update their code without any extra steps, but it lowers the
+      performance of your Puppet master.
+
+      We recommend setting this to `unlimited` and explicitly refreshing your
+      Puppet master as part of your code deployment process.
+
+      * With Puppet Server, you should refresh environments by calling the
+        `environment-cache` API endpoint. See the docs for the Puppet Server
+        administrative API.
+      * With a Rack Puppet master, you should restart the web server or the
+        application server. Passenger lets you touch a `restart.txt` file to
+        refresh an application without restarting Apache; see the Passenger docs
+        for details.
+
+      We don't recommend using any value other than `0` or `unlimited`, since
+      most Puppet masters use a pool of Ruby interpreters which all have their
+      own cache timers. When these timers drift out of sync, agents can be served
+      inconsistent catalogs."
+    },
+    :queue_type => {
+      :default    => "stomp",
+      :desc       => "Which type of queue to use for asynchronous processing.",
+    },
+    :queue_source => {
+      :default    => "stomp://localhost:61613/",
+      :desc       => "Which type of queue to use for asynchronous processing.  If your stomp server requires
+      authentication, you can include it in the URI as long as your stomp client library is at least 1.1.1",
+    },
+    :async_storeconfigs => {
+        :default  => false,
+        :type     => :boolean,
+        :desc     => "Whether to use a queueing system to provide asynchronous database integration.
+      Requires that `puppet queue` be running.",
+        :hook     => proc do |value|
+          if value
+            # This reconfigures the termini for Node, Facts, and Catalog
+            Puppet.settings.override_default(:storeconfigs, true)
+
+            # But then we modify the configuration
+            Puppet::Resource::Catalog.indirection.cache_class = :queue
+            Puppet.settings.override_default(:catalog_cache_terminus, :queue)
+          else
+            raise "Cannot disable asynchronous storeconfigs in a running process"
+          end
+        end
+    },
+    :thin_storeconfigs => {
+      :default  => false,
+      :type     => :boolean,
+      :desc     =>
+    "Boolean; whether Puppet should store only facts and exported resources in the storeconfigs
+    database. This will improve the performance of exported resources with the older
+    `active_record` backend, but will disable external tools that search the storeconfigs database.
+    Thinning catalogs is generally unnecessary when using PuppetDB to store catalogs.",
+      :hook     => proc do |value|
+        Puppet.settings.override_default(:storeconfigs, true) if value
+        end
+      },
+    :config_version => {
+      :default    => "",
+      :desc       => "How to determine the configuration version.  By default, it will be the
+      time that the configuration is parsed, but you can provide a shell script to override how the
+      version is determined.  The output of this script will be added to every log message in the
+      reports, allowing you to correlate changes on your hosts to the source version on the server.
+
+      Setting a global value for config_version in puppet.conf is deprecated. Please set a
+      per-environment value in environment.conf instead. For more info, see
+      http://docs.puppetlabs.com/puppet/latest/reference/environments.html",
+      :deprecated => :allowed_on_commandline,
+    },
+    :zlib => {
+        :default  => true,
+        :type     => :boolean,
+        :desc     => "Boolean; whether to use the zlib library",
+    },
+    :prerun_command => {
+      :default    => "",
+      :desc       => "A command to run before every agent run.  If this command returns a non-zero
+      return code, the entire Puppet run will fail.",
+    },
+    :postrun_command => {
+      :default    => "",
+      :desc       => "A command to run after every agent run.  If this command returns a non-zero
+      return code, the entire Puppet run will be considered to have failed, even though it might have
+      performed work during the normal run.",
+    },
+    :freeze_main => {
+        :default  => false,
+        :type     => :boolean,
+        :desc     => "Freezes the 'main' class, disallowing any code to be added to it.  This
+          essentially means that you can't have any code outside of a node,
+          class, or definition other than in the site manifest.",
+    },
+    :stringify_facts => {
+      :default => true,
+      :type    => :boolean,
+      :desc    => "Flatten fact values to strings using #to_s. Means you can't have arrays or
+        hashes as fact values. (DEPRECATED) This option will be removed in Puppet 4.0.",
+    },
+    :trusted_node_data => {
+      :default => false,
+      :type    => :boolean,
+      :desc    => "Stores trusted node data in a hash called $trusted.
+        When true also prevents $trusted from being overridden in any scope.",
+    },
+    :immutable_node_data => {
+      :default => '$trusted_node_data',
+      :type    => :boolean,
+      :desc    => "When true, also prevents $trusted and $facts from being overridden in any scope",
+    },
+    :preview_outputdir => {
+      :default => '$vardir/preview',
+      :type     => :directory,
+      :mode     => "0750",
+      :owner    => "service",
+      :group    => "service",
+      :desc    => "The directory where catalog previews per node are generated."
+    }
+  )
+  Puppet.define_settings(:module_tool,
+    :module_repository  => {
+      :default  => 'https://forgeapi.puppetlabs.com',
+      :desc     => "The module repository",
+    },
+    :module_working_dir => {
+        :default  => (Puppet.features.microsoft_windows? ? Dir.tmpdir() : '$vardir/puppet-module'),
+        :desc     => "The directory into which module tool data is stored",
+    },
+    :module_skeleton_dir => {
+        :default  => '$module_working_dir/skeleton',
+        :desc     => "The directory which the skeleton for module tool generate is stored.",
+    },
+    :forge_authorization => {
+        :default  => nil,
+        :desc     => "The authorization key to connect to the Puppet Forge. Leave blank for unauthorized or license based connections",
+    },
+    :module_groups => {
+        :default  => nil,
+        :desc     => "Extra module groups to request from the Puppet Forge",
+    }
+  )
+
+    Puppet.define_settings(
+    :main,
+
+    # We have to downcase the fqdn, because the current ssl stuff (as oppsed to in master) doesn't have good facilities for
+    # manipulating naming.
+    :certname => {
+      :default => lambda { Puppet::Settings.default_certname.downcase },
+      :desc => "The name to use when handling certificates. When a node
+        requests a certificate from the CA puppet master, it uses the value of the
+        `certname` setting as its requested Subject CN.
+
+        This is the name used when managing a node's permissions in
+        [auth.conf](http://docs.puppetlabs.com/puppet/latest/reference/config_file_auth.html).
+        In most cases, it is also used as the node's name when matching
+        [node definitions](http://docs.puppetlabs.com/puppet/latest/reference/lang_node_definitions.html)
+        and requesting data from an ENC. (This can be changed with the `node_name_value`
+        and `node_name_fact` settings, although you should only do so if you have
+        a compelling reason.)
+
+        A node's certname is available in Puppet manifests as `$trusted['certname']`. (See
+        [Facts and Built-In Variables](http://docs.puppetlabs.com/puppet/latest/reference/lang_facts_and_builtin_vars.html)
+        for more details.)
+
+        * For best compatibility, you should limit the value of `certname` to
+          only use letters, numbers, periods, underscores, and dashes. (That is,
+          it should match `/\A[a-z0-9._-]+\Z/`.)
+        * The special value `ca` is reserved, and can't be used as the certname
+          for a normal node.
+
+        Defaults to the node's fully qualified domain name.",
+      :hook => proc { |value| raise(ArgumentError, "Certificate names must be lower case; see #1168") unless value == value.downcase }},
+    :certdnsnames => {
+      :default => '',
+      :hook    => proc do |value|
+        unless value.nil? or value == '' then
+          Puppet.warning <<WARN
+The `certdnsnames` setting is no longer functional,
+after CVE-2011-3872. We ignore the value completely.
+
+For your own certificate request you can set `dns_alt_names` in the
+configuration and it will apply locally.  There is no configuration option to
+set DNS alt names, or any other `subjectAltName` value, for another nodes
+certificate.
+
+Alternately you can use the `--dns_alt_names` command line option to set the
+labels added while generating your own CSR.
+WARN
+        end
+      end,
+      :desc    => <<EOT
+The `certdnsnames` setting is no longer functional,
+after CVE-2011-3872. We ignore the value completely.
+
+For your own certificate request you can set `dns_alt_names` in the
+configuration and it will apply locally.  There is no configuration option to
+set DNS alt names, or any other `subjectAltName` value, for another nodes
+certificate.
+
+Alternately you can use the `--dns_alt_names` command line option to set the
+labels added while generating your own CSR.
+EOT
+    },
+    :dns_alt_names => {
+      :default => '',
+      :desc    => <<EOT,
+The comma-separated list of alternative DNS names to use for the local host.
+
+When the node generates a CSR for itself, these are added to the request
+as the desired `subjectAltName` in the certificate: additional DNS labels
+that the certificate is also valid answering as.
+
+This is generally required if you use a non-hostname `certname`, or if you
+want to use `puppet kick` or `puppet resource -H` and the primary certname
+does not match the DNS name you use to communicate with the host.
+
+This is unnecessary for agents, unless you intend to use them as a server for
+`puppet kick` or remote `puppet resource` management.
+
+It is rarely necessary for servers; it is usually helpful only if you need to
+have a pool of multiple load balanced masters, or for the same master to
+respond on two physically separate networks under different names.
+EOT
+    },
+    :csr_attributes => {
+      :default => "$confdir/csr_attributes.yaml",
+      :type => :file,
+      :desc => <<EOT
+An optional file containing custom attributes to add to certificate signing
+requests (CSRs). You should ensure that this file does not exist on your CA
+puppet master; if it does, unwanted certificate extensions may leak into
+certificates created with the `puppet cert generate` command.
+
+If present, this file must be a YAML hash containing a `custom_attributes` key
+and/or an `extension_requests` key. The value of each key must be a hash, where
+each key is a valid OID and each value is an object that can be cast to a string.
+
+Custom attributes can be used by the CA when deciding whether to sign the
+certificate, but are then discarded. Attribute OIDs can be any OID value except
+the standard CSR attributes (i.e. attributes described in RFC 2985 section 5.4).
+This is useful for embedding a pre-shared key for autosigning policy executables
+(see the `autosign` setting), often by using the `1.2.840.113549.1.9.7`
+("challenge password") OID.
+
+Extension requests will be permanently embedded in the final certificate.
+Extension OIDs must be in the "ppRegCertExt" (`1.3.6.1.4.1.34380.1.1`) or
+"ppPrivCertExt" (`1.3.6.1.4.1.34380.1.2`) OID arcs. The ppRegCertExt arc is
+reserved for four of the most common pieces of data to embed: `pp_uuid` (`.1`),
+`pp_instance_id` (`.2`), `pp_image_name` (`.3`), and `pp_preshared_key` (`.4`)
+--- in the YAML file, these can be referred to by their short descriptive names
+instead of their full OID. The ppPrivCertExt arc is unregulated, and can be used
+for site-specific extensions.
+EOT
+    },
+    :certdir => {
+      :default => "$ssldir/certs",
+      :type   => :directory,
+      :mode => "0755",
+      :owner => "service",
+      :group => "service",
+      :desc => "The certificate directory."
+    },
+    :ssldir => {
+      :default => "$confdir/ssl",
+      :type   => :directory,
+      :mode => "0771",
+      :owner => "service",
+      :group => "service",
+      :desc => "Where SSL certificates are kept."
+    },
+    :publickeydir => {
+      :default => "$ssldir/public_keys",
+      :type   => :directory,
+      :mode => "0755",
+      :owner => "service",
+      :group => "service",
+      :desc => "The public key directory."
+    },
+    :requestdir => {
+      :default => "$ssldir/certificate_requests",
+      :type => :directory,
+      :mode => "0755",
+      :owner => "service",
+      :group => "service",
+      :desc => "Where host certificate requests are stored."
+    },
+    :privatekeydir => {
+      :default => "$ssldir/private_keys",
+      :type   => :directory,
+      :mode => "0750",
+      :owner => "service",
+      :group => "service",
+      :desc => "The private key directory."
+    },
+    :privatedir => {
+      :default => "$ssldir/private",
+      :type   => :directory,
+      :mode => "0750",
+      :owner => "service",
+      :group => "service",
+      :desc => "Where the client stores private certificate information."
+    },
+    :passfile => {
+      :default => "$privatedir/password",
+      :type   => :file,
+      :mode => "0640",
+      :owner => "service",
+      :group => "service",
+      :desc => "Where puppet agent stores the password for its private key.
+        Generally unused."
+    },
+    :hostcsr => {
+      :default => "$ssldir/csr_$certname.pem",
+      :type   => :file,
+      :mode => "0644",
+      :owner => "service",
+      :group => "service",
+      :desc => "Where individual hosts store and look for their certificate requests."
+    },
+    :hostcert => {
+      :default => "$certdir/$certname.pem",
+      :type   => :file,
+      :mode => "0644",
+      :owner => "service",
+      :group => "service",
+      :desc => "Where individual hosts store and look for their certificates."
+    },
+    :hostprivkey => {
+      :default => "$privatekeydir/$certname.pem",
+      :type   => :file,
+      :mode => "0640",
+      :owner => "service",
+      :group => "service",
+      :desc => "Where individual hosts store and look for their private key."
+    },
+    :hostpubkey => {
+      :default => "$publickeydir/$certname.pem",
+      :type   => :file,
+      :mode => "0644",
+      :owner => "service",
+      :group => "service",
+      :desc => "Where individual hosts store and look for their public key."
+    },
+    :localcacert => {
+      :default => "$certdir/ca.pem",
+      :type   => :file,
+      :mode => "0644",
+      :owner => "service",
+      :group => "service",
+      :desc => "Where each client stores the CA certificate."
+    },
+    :ssl_client_ca_auth => {
+      :type  => :file,
+      :mode  => "0644",
+      :owner => "service",
+      :group => "service",
+      :desc  => "Certificate authorities who issue server certificates.  SSL servers will not be
+        considered authentic unless they possess a certificate issued by an authority
+        listed in this file.  If this setting has no value then the Puppet master's CA
+        certificate (localcacert) will be used."
+    },
+    :ssl_server_ca_auth => {
+      :type  => :file,
+      :mode  => "0644",
+      :owner => "service",
+      :group => "service",
+      :desc  => "Certificate authorities who issue client certificates.  SSL clients will not be
+        considered authentic unless they possess a certificate issued by an authority
+        listed in this file.  If this setting has no value then the Puppet master's CA
+        certificate (localcacert) will be used."
+    },
+    :hostcrl => {
+      :default => "$ssldir/crl.pem",
+      :type   => :file,
+      :mode => "0644",
+      :owner => "service",
+      :group => "service",
+      :desc => "Where the host's certificate revocation list can be found.
+        This is distinct from the certificate authority's CRL."
+    },
+    :certificate_revocation => {
+        :default  => true,
+        :type     => :boolean,
+        :desc     => "Whether certificate revocation should be supported by downloading a
+          Certificate Revocation List (CRL)
+          to all clients.  If enabled, CA chaining will almost definitely not work.",
+    },
+    :certificate_expire_warning => {
+      :default  => "60d",
+      :type     => :duration,
+      :desc     => "The window of time leading up to a certificate's expiration that a notification
+        will be logged. This applies to CA, master, and agent certificates. #{AS_DURATION}"
+    },
+    :digest_algorithm => {
+        :default  => 'md5',
+        :type     => :enum,
+        :values => ["md5", "sha256"],
+        :desc     => 'Which digest algorithm to use for file resources and the filebucket.
+                      Valid values are md5, sha256. Default is md5.',
+    }
+  )
+
+    define_settings(
+    :ca,
+    :ca_name => {
+      :default    => "Puppet CA: $certname",
+      :desc       => "The name to use the Certificate Authority certificate.",
+    },
+    :cadir => {
+      :default => "$ssldir/ca",
+      :type => :directory,
+      :owner => "service",
+      :group => "service",
+      :mode => "0755",
+      :desc => "The root directory for the certificate authority."
+    },
+    :cacert => {
+      :default => "$cadir/ca_crt.pem",
+      :type => :file,
+      :owner => "service",
+      :group => "service",
+      :mode => "0644",
+      :desc => "The CA certificate."
+    },
+    :cakey => {
+      :default => "$cadir/ca_key.pem",
+      :type => :file,
+      :owner => "service",
+      :group => "service",
+      :mode => "0640",
+      :desc => "The CA private key."
+    },
+    :capub => {
+      :default => "$cadir/ca_pub.pem",
+      :type => :file,
+      :owner => "service",
+      :group => "service",
+      :mode => "0644",
+      :desc => "The CA public key."
+    },
+    :cacrl => {
+      :default => "$cadir/ca_crl.pem",
+      :type => :file,
+      :owner => "service",
+      :group => "service",
+      :mode => "0644",
+      :desc => "The certificate revocation list (CRL) for the CA. Will be used if present but otherwise ignored.",
+    },
+    :caprivatedir => {
+      :default => "$cadir/private",
+      :type => :directory,
+      :owner => "service",
+      :group => "service",
+      :mode => "0750",
+      :desc => "Where the CA stores private certificate information."
+    },
+    :csrdir => {
+      :default => "$cadir/requests",
+      :type => :directory,
+      :owner => "service",
+      :group => "service",
+      :mode  => "0755",
+      :desc => "Where the CA stores certificate requests"
+    },
+    :signeddir => {
+      :default => "$cadir/signed",
+      :type => :directory,
+      :owner => "service",
+      :group => "service",
+      :mode => "0755",
+      :desc => "Where the CA stores signed certificates."
+    },
+    :capass => {
+      :default => "$caprivatedir/ca.pass",
+      :type => :file,
+      :owner => "service",
+      :group => "service",
+      :mode => "0640",
+      :desc => "Where the CA stores the password for the private key."
+    },
+    :serial => {
+      :default => "$cadir/serial",
+      :type => :file,
+      :owner => "service",
+      :group => "service",
+      :mode => "0644",
+      :desc => "Where the serial number for certificates is stored."
+    },
+    :autosign => {
+      :default => "$confdir/autosign.conf",
+      :type => :autosign,
+      :desc => "Whether (and how) to autosign certificate requests. This setting
+        is only relevant on a puppet master acting as a certificate authority (CA).
+
+        Valid values are true (autosigns all certificate requests; not recommended),
+        false (disables autosigning certificates), or the absolute path to a file.
+
+        The file specified in this setting may be either a **configuration file**
+        or a **custom policy executable.** Puppet will automatically determine
+        what it is: If the Puppet user (see the `user` setting) can execute the
+        file, it will be treated as a policy executable; otherwise, it will be
+        treated as a config file.
+
+        If a custom policy executable is configured, the CA puppet master will run it
+        every time it receives a CSR. The executable will be passed the subject CN of the
+        request _as a command line argument,_ and the contents of the CSR in PEM format
+        _on stdin._ It should exit with a status of 0 if the cert should be autosigned
+        and non-zero if the cert should not be autosigned.
+
+        If a certificate request is not autosigned, it will persist for review. An admin
+        user can use the `puppet cert sign` command to manually sign it, or can delete
+        the request.
+
+        For info on autosign configuration files, see
+        [the guide to Puppet's config files](http://docs.puppetlabs.com/guides/configuring.html).",
+    },
+    :allow_duplicate_certs => {
+      :default    => false,
+      :type       => :boolean,
+      :desc       => "Whether to allow a new certificate
+      request to overwrite an existing certificate.",
+    },
+    :ca_ttl => {
+      :default    => "5y",
+      :type       => :duration,
+      :desc       => "The default TTL for new certificates.
+      #{AS_DURATION}"
+    },
+    :req_bits => {
+      :default    => 4096,
+      :desc       => "The bit length of the certificates.",
+    },
+    :keylength => {
+      :default    => 4096,
+      :desc       => "The bit length of keys.",
+    },
+    :cert_inventory => {
+      :default => "$cadir/inventory.txt",
+      :type => :file,
+      :mode => "0644",
+      :owner => "service",
+      :group => "service",
+      :desc => "The inventory file. This is a text file to which the CA writes a
+        complete listing of all certificates."
+    }
+  )
+
+  # Define the config default.
+
+    define_settings(:application,
+      :config_file_name => {
+          :type     => :string,
+          :default  => Puppet::Settings.default_config_file_name,
+          :desc     => "The name of the puppet config file.",
+      },
+      :config => {
+          :type => :file,
+          :default  => "$confdir/${config_file_name}",
+          :desc     => "The configuration file for the current puppet application.",
+      },
+      :pidfile => {
+          :type => :file,
+          :default  => "$rundir/${run_mode}.pid",
+          :desc     => "The file containing the PID of a running process.
+            This file is intended to be used by service management frameworks
+            and monitoring systems to determine if a puppet process is still in
+            the process table.",
+      },
+      :bindaddress => {
+        :default    => "0.0.0.0",
+        :desc       => "The address a listening server should bind to.",
+      }
+  )
+
+  define_settings(:master,
+    :user => {
+      :default    => "puppet",
+      :desc       => "The user puppet master should run as.",
+    },
+    :group => {
+      :default    => "puppet",
+      :desc       => "The group puppet master should run as.",
+    },
+    :manifestdir => {
+      :default    => "$confdir/manifests",
+      :type       => :directory,
+      :desc       => "Used to build the default value of the `manifest` setting. Has no other purpose.
+
+        This setting is deprecated.",
+      :deprecated => :completely,
+    },
+    :manifest => {
+      :default    => "$manifestdir/site.pp",
+      :type       => :file_or_directory,
+      :desc       => "The entry-point manifest for puppet master. This can be one file
+        or a directory of manifests to be evaluated in alphabetical order. Puppet manages
+        this path as a directory if one exists or if the path ends with a / or \\.
+
+        Setting a global value for `manifest` in puppet.conf is deprecated. Please use
+        directory environments instead. If you need to use something other than the
+        environment's `manifests` directory as the main manifest, you can set
+        `manifest` in environment.conf. For more info, see
+        http://docs.puppetlabs.com/puppet/latest/reference/environments.html",
+      :deprecated => :allowed_on_commandline,
+    },
+    :default_manifest => {
+      :default    => "./manifests",
+      :type       => :string,
+      :desc       => "The default main manifest for directory environments. Any environment that
+        doesn't set the `manifest` setting in its `environment.conf` file will use
+        this manifest.
+
+        This setting's value can be an absolute or relative path. An absolute path
+        will make all environments default to the same main manifest; a relative
+        path will allow each environment to use its own manifest, and Puppet will
+        resolve the path relative to each environment's main directory.
+
+        In either case, the path can point to a single file or to a directory of
+        manifests to be evaluated in alphabetical order.",
+    },
+    :disable_per_environment_manifest => {
+      :default    => false,
+      :type       => :boolean,
+      :desc       => "Whether to disallow an environment-specific main manifest. When set
+        to `true`, Puppet will use the manifest specified in the `default_manifest` setting
+        for all environments. If an environment specifies a different main manifest in its
+        `environment.conf` file, catalog requests for that environment will fail with an error.
+
+        This setting requires `default_manifest` to be set to an absolute path.",
+      :hook       => proc do |value|
+        if value && !Pathname.new(Puppet[:default_manifest]).absolute?
+          raise(Puppet::Settings::ValidationError,
+                "The 'default_manifest' setting must be set to an absolute path when 'disable_per_environment_manifest' is true")
+        end
+      end,
+    },
+    :code => {
+      :default    => "",
+      :desc       => "Code to parse directly.  This is essentially only used
+      by `puppet`, and should only be set if you're writing your own Puppet
+      executable.",
+    },
+    :masterlog => {
+      :default => "$logdir/puppetmaster.log",
+      :type => :file,
+      :owner => "service",
+      :group => "service",
+      :mode => "0660",
+      :desc => "This file is literally never used, although Puppet may create it
+        as an empty file. For more context, see the `puppetdlog` setting and
+        puppet master's `--logdest` command line option.
+
+        This setting is deprecated and will be removed in a future version of Puppet.",
+      :deprecated => :completely
+    },
+    :masterhttplog => {
+      :default => "$logdir/masterhttp.log",
+      :type => :file,
+      :owner => "service",
+      :group => "service",
+      :mode => "0660",
+      :create => true,
+      :desc => "Where the puppet master web server saves its access log. This is
+        only used when running a WEBrick puppet master. When puppet master is
+        running under a Rack server like Passenger, that web server will have
+        its own logging behavior."
+    },
+    :masterport => {
+      :default    => 8140,
+      :desc       => "The port for puppet master traffic. For puppet master,
+      this is the port to listen on; for puppet agent, this is the port
+      to make requests on. Both applications use this setting to get the port.",
+    },
+    :node_name => {
+      :default    => "cert",
+      :desc       => "How the puppet master determines the client's identity
+      and sets the 'hostname', 'fqdn' and 'domain' facts for use in the manifest,
+      in particular for determining which 'node' statement applies to the client.
+      Possible values are 'cert' (use the subject's CN in the client's
+      certificate) and 'facter' (use the hostname that the client
+      reported in its facts)",
+    },
+    :bucketdir => {
+      :default => "$vardir/bucket",
+      :type => :directory,
+      :mode => "0750",
+      :owner => "service",
+      :group => "service",
+      :desc => "Where FileBucket files are stored."
+    },
+    :rest_authconfig => {
+      :default    => "$confdir/auth.conf",
+      :type       => :file,
+      :desc       => "The configuration file that defines the rights to the different
+      rest indirections.  This can be used as a fine-grained
+      authorization system for `puppet master`.",
+    },
+    :ca => {
+      :default    => true,
+      :type       => :boolean,
+      :desc       => "Whether the master should function as a certificate authority.",
+    },
+    :basemodulepath => {
+      :default => "$confdir/modules#{File::PATH_SEPARATOR}/usr/share/puppet/modules",
+      :type => :path,
+      :desc => "The search path for **global** modules. Should be specified as a
+        list of directories separated by the system path separator character. (The
+        POSIX path separator is ':', and the Windows path separator is ';'.)
+
+        If you are using directory environments, these are the modules that will
+        be used by _all_ environments. Note that the `modules` directory of the active
+        environment will have priority over any global directories. For more info, see
+        http://docs.puppetlabs.com/puppet/latest/reference/environments.html
+
+        This setting also provides the default value for the deprecated `modulepath`
+        setting, which is used when directory environments are disabled.",
+    },
+    :modulepath => {
+      :default => "$basemodulepath",
+      :type => :path,
+      :desc => "The search path for modules, as a list of directories separated by the system
+        path separator character. (The POSIX path separator is ':', and the
+        Windows path separator is ';'.)
+
+        Setting a global value for `modulepath` in puppet.conf is deprecated. Please use
+        directory environments instead. If you need to use something other than the
+        default modulepath of `<ACTIVE ENVIRONMENT'S MODULES DIR>:$basemodulepath`,
+        you can set `modulepath` in environment.conf. For more info, see
+        http://docs.puppetlabs.com/puppet/latest/reference/environments.html",
+      :deprecated => :allowed_on_commandline,
+    },
+    :ssl_client_header => {
+      :default    => "HTTP_X_CLIENT_DN",
+      :desc       => "The header containing an authenticated client's SSL DN.
+      This header must be set by the proxy to the authenticated client's SSL
+      DN (e.g., `/CN=puppet.puppetlabs.com`).  Puppet will parse out the Common
+      Name (CN) from the Distinguished Name (DN) and use the value of the CN
+      field for authorization.
+
+      Note that the name of the HTTP header gets munged by the web server
+      common gateway inteface: an `HTTP_` prefix is added, dashes are converted
+      to underscores, and all letters are uppercased.  Thus, to use the
+      `X-Client-DN` header, this setting should be `HTTP_X_CLIENT_DN`.",
+    },
+    :ssl_client_verify_header => {
+      :default    => "HTTP_X_CLIENT_VERIFY",
+      :desc       => "The header containing the status message of the client
+      verification. This header must be set by the proxy to 'SUCCESS' if the
+      client successfully authenticated, and anything else otherwise.
+
+      Note that the name of the HTTP header gets munged by the web server
+      common gateway inteface: an `HTTP_` prefix is added, dashes are converted
+      to underscores, and all letters are uppercased.  Thus, to use the
+      `X-Client-Verify` header, this setting should be
+      `HTTP_X_CLIENT_VERIFY`.",
+    },
+    # To make sure this directory is created before we try to use it on the server, we need
+    # it to be in the server section (#1138).
+    :yamldir => {
+      :default => "$vardir/yaml",
+      :type => :directory,
+      :owner => "service",
+      :group => "service",
+      :mode => "0750",
+      :desc => "The directory in which YAML data is stored, usually in a subdirectory."},
+    :server_datadir => {
+      :default => "$vardir/server_data",
+      :type => :directory,
+      :owner => "service",
+      :group => "service",
+      :mode => "0750",
+      :desc => "The directory in which serialized data is stored, usually in a subdirectory."},
+    :reports => {
+      :default    => "store",
+      :desc       => "The list of report handlers to use. When using multiple report handlers,
+        their names should be comma-separated, with whitespace allowed. (For example,
+        `reports = http, tagmail`.)
+
+        This setting is relevant to puppet master and puppet apply. The puppet
+        master will call these report handlers with the reports it receives from
+        agent nodes, and puppet apply will call them with its own report. (In
+        all cases, the node applying the catalog must have `report = true`.)
+
+        See the report reference for information on the built-in report
+        handlers; custom report handlers can also be loaded from modules.
+        (Report handlers are loaded from the lib directory, at
+        `puppet/reports/NAME.rb`.)",
+    },
+    :reportdir => {
+      :default => "$vardir/reports",
+      :type => :directory,
+      :mode => "0750",
+      :owner => "service",
+      :group => "service",
+      :desc => "The directory in which to store reports. Each node gets
+        a separate subdirectory in this directory. This setting is only
+        used when the `store` report processor is enabled (see the
+        `reports` setting)."},
+    :reporturl => {
+      :default    => "http://localhost:3000/reports/upload",
+      :desc       => "The URL that reports should be forwarded to. This setting
+        is only used when the `http` report processor is enabled (see the
+        `reports` setting).",
+    },
+    :fileserverconfig => {
+      :default    => "$confdir/fileserver.conf",
+      :type       => :file,
+      :desc       => "Where the fileserver configuration is stored.",
+    },
+    :strict_hostname_checking => {
+      :default    => false,
+      :desc       => "Whether to only search for the complete
+            hostname as it is in the certificate when searching for node information
+            in the catalogs.",
+    }
+  )
+
+  define_settings(:metrics,
+    :rrddir => {
+      :type     => :directory,
+      :default  => "$vardir/rrd",
+      :mode     => "0750",
+      :owner    => "service",
+      :group    => "service",
+      :desc     => "The directory where RRD database files are stored.
+        Directories for each reporting host will be created under
+        this directory."
+    },
+    :rrdinterval => {
+      :default  => "$runinterval",
+      :type     => :duration,
+      :desc     => "How often RRD should expect data.
+            This should match how often the hosts report back to the server. #{AS_DURATION}",
+    }
+  )
+
+  define_settings(:device,
+    :devicedir =>  {
+        :default  => "$vardir/devices",
+        :type     => :directory,
+        :mode     => "0750",
+        :desc     => "The root directory of devices' $vardir.",
+    },
+    :deviceconfig => {
+        :default  => "$confdir/device.conf",
+        :desc     => "Path to the device config file for puppet device.",
+    }
+  )
+
+  define_settings(:agent,
+    :node_name_value => {
+      :default => "$certname",
+      :desc => "The explicit value used for the node name for all requests the agent
+        makes to the master. WARNING: This setting is mutually exclusive with
+        node_name_fact.  Changing this setting also requires changes to the default
+        auth.conf configuration on the Puppet Master.  Please see
+        http://links.puppetlabs.com/node_name_value for more information."
+    },
+    :node_name_fact => {
+      :default => "",
+      :desc => "The fact name used to determine the node name used for all requests the agent
+        makes to the master. WARNING: This setting is mutually exclusive with
+        node_name_value.  Changing this setting also requires changes to the default
+        auth.conf configuration on the Puppet Master.  Please see
+        http://links.puppetlabs.com/node_name_fact for more information.",
+      :hook => proc do |value|
+        if !value.empty? and Puppet[:node_name_value] != Puppet[:certname]
+          raise "Cannot specify both the node_name_value and node_name_fact settings"
+        end
+      end
+    },
+    :localconfig => {
+      :default => "$statedir/localconfig",
+      :type => :file,
+      :owner => "root",
+      :mode => "0660",
+      :desc => "Where puppet agent caches the local configuration.  An
+        extension indicating the cache format is added automatically."},
+    :statefile => {
+      :default => "$statedir/state.yaml",
+      :type => :file,
+      :mode => "0660",
+      :desc => "Where puppet agent and puppet master store state associated
+        with the running configuration.  In the case of puppet master,
+        this file reflects the state discovered through interacting
+        with clients."
+      },
+    :clientyamldir => {
+      :default => "$vardir/client_yaml",
+      :type => :directory,
+      :mode => "0750",
+      :desc => "The directory in which client-side YAML data is stored."
+    },
+    :client_datadir => {
+      :default => "$vardir/client_data",
+      :type => :directory,
+      :mode => "0750",
+      :desc => "The directory in which serialized data is stored on the client."
+    },
+    :classfile => {
+      :default => "$statedir/classes.txt",
+      :type => :file,
+      :owner => "root",
+      :mode => "0640",
+      :desc => "The file in which puppet agent stores a list of the classes
+        associated with the retrieved configuration.  Can be loaded in
+        the separate `puppet` executable using the `--loadclasses`
+        option."},
+    :resourcefile => {
+      :default => "$statedir/resources.txt",
+      :type => :file,
+      :owner => "root",
+      :mode => "0640",
+      :desc => "The file in which puppet agent stores a list of the resources
+        associated with the retrieved configuration."  },
+    :puppetdlog => {
+      :default => "$logdir/puppetd.log",
+      :type => :file,
+      :owner => "root",
+      :mode => "0640",
+      :desc => "The fallback log file. This is only used when the `--logdest` option
+        is not specified AND Puppet is running on an operating system where both
+        the POSIX syslog service and the Windows Event Log are unavailable. (Currently,
+        no supported operating systems match that description.)
+
+        Despite the name, both puppet agent and puppet master will use this file
+        as the fallback logging destination.
+
+        For control over logging destinations, see the `--logdest` command line
+        option in the manual pages for puppet master, puppet agent, and puppet
+        apply. You can see man pages by running `puppet <SUBCOMMAND> --help`,
+        or read them online at http://docs.puppetlabs.com/references/latest/man/."
+    },
+    :server => {
+      :default => "puppet",
+      :desc => "The puppet master server to which the puppet agent should connect."
+    },
+    :use_srv_records => {
+      :default    => false,
+      :type       => :boolean,
+      :desc       => "Whether the server will search for SRV records in DNS for the current domain.",
+    },
+    :srv_domain => {
+      :default    => lambda { Puppet::Settings.domain_fact },
+      :desc       => "The domain which will be queried to find the SRV records of servers to use.",
+    },
+    :ignoreschedules => {
+      :default    => false,
+      :type       => :boolean,
+      :desc       => "Boolean; whether puppet agent should ignore schedules.  This is useful
+      for initial puppet agent runs.",
+    },
+    :default_schedules => {
+      :default    => true,
+      :type       => :boolean,
+      :desc       => "Boolean; whether to generate the default schedule resources. Setting this to
+      false is useful for keeping external report processors clean of skipped schedule resources.",
+    },
+    :puppetport => {
+      :default    => 8139,
+      :desc       => "Which port puppet agent listens on.",
+    },
+    :noop => {
+      :default    => false,
+      :type       => :boolean,
+      :desc       => "Whether to apply catalogs in noop mode, which allows Puppet to
+        partially simulate a normal run. This setting affects puppet agent and
+        puppet apply.
+
+        When running in noop mode, Puppet will check whether each resource is in sync,
+        like it does when running normally. However, if a resource attribute is not in
+        the desired state (as declared in the catalog), Puppet will take no
+        action, and will instead report the changes it _would_ have made. These
+        simulated changes will appear in the report sent to the puppet master, or
+        be shown on the console if running puppet agent or puppet apply in the
+        foreground. The simulated changes will not send refresh events to any
+        subscribing or notified resources, although Puppet will log that a refresh
+        event _would_ have been sent.
+
+        **Important note:**
+        [The `noop` metaparameter](http://docs.puppetlabs.com/references/latest/metaparameter.html#noop)
+        allows you to apply individual resources in noop mode, and will override
+        the global value of the `noop` setting. This means a resource with
+        `noop => false` _will_ be changed if necessary, even when running puppet
+        agent with `noop = true` or `--noop`. (Conversely, a resource with
+        `noop => true` will only be simulated, even when noop mode is globally disabled.)",
+    },
+    :runinterval => {
+      :default  => "30m",
+      :type     => :duration,
+      :desc     => "How often puppet agent applies the catalog.
+          Note that a runinterval of 0 means \"run continuously\" rather than
+          \"never run.\" If you want puppet agent to never run, you should start
+          it with the `--no-client` option. #{AS_DURATION}",
+    },
+    :listen => {
+      :default    => false,
+      :type       => :boolean,
+      :desc       => "Whether puppet agent should listen for
+      connections.  If this is true, then puppet agent will accept incoming
+      REST API requests, subject to the default ACLs and the ACLs set in
+      the `rest_authconfig` file. Puppet agent can respond usefully to
+      requests on the `run`, `facts`, `certificate`, and `resource` endpoints.",
+    },
+    :ca_server => {
+      :default    => "$server",
+      :desc       => "The server to use for certificate
+      authority requests.  It's a separate server because it cannot
+      and does not need to horizontally scale.",
+    },
+    :ca_port => {
+      :default    => "$masterport",
+      :desc       => "The port to use for the certificate authority.",
+    },
+    :catalog_format => {
+      :default => "",
+      :desc => "(Deprecated for 'preferred_serialization_format') What format to
+        use to dump the catalog.  Only supports 'marshal' and 'yaml'.  Only
+        matters on the client, since it asks the server for a specific format.",
+      :hook => proc { |value|
+        if value
+          Puppet.deprecation_warning "Setting 'catalog_format' is deprecated; use 'preferred_serialization_format' instead."
+          Puppet.settings.override_default(:preferred_serialization_format, value)
+        end
+      }
+    },
+    :preferred_serialization_format => {
+      :default    => "pson",
+      :desc       => "The preferred means of serializing
+      ruby instances for passing over the wire.  This won't guarantee that all
+      instances will be serialized using this method, since not all classes
+      can be guaranteed to support this format, but it will be used for all
+      classes that support it.",
+    },
+    :report_serialization_format => {
+      :default => "pson",
+      :type => :enum,
+      :values => ["pson", "yaml"],
+      :desc => "The serialization format to use when sending reports to the
+      `report_server`. Possible values are `pson` and `yaml`. This setting
+      affects puppet agent, but not puppet apply (which processes its own
+      reports).
+
+      This should almost always be set to `pson`. It can be temporarily set to
+      `yaml` to let agents using this Puppet version connect to a puppet master
+      running Puppet 3.0.0 through 3.2.x.
+
+      Note that this is set to 'yaml' automatically if the agent detects an
+      older master, so should never need to be set explicitly."
+    },
+    :legacy_query_parameter_serialization => {
+        :default    => false,
+        :type       => :boolean,
+        :desc => "The serialization format to use when sending file_metadata
+      query parameters.  Older versions of puppet master expect certain query
+      parameters to be serialized as yaml, which is deprecated.
+
+      This should almost always be false. It can be temporarily set to true
+      to let agents using this Puppet version connect to a puppet master
+      running Puppet 3.0.0 through 3.2.x.
+
+      Note that this is set to true automatically if the agent detects an
+      older master, so should never need to be set explicitly."
+    },
+    :agent_catalog_run_lockfile => {
+      :default    => "$statedir/agent_catalog_run.lock",
+      :type       => :string, # (#2888) Ensure this file is not added to the settings catalog.
+      :desc       => "A lock file to indicate that a puppet agent catalog run is currently in progress.
+        The file contains the pid of the process that holds the lock on the catalog run.",
+    },
+    :agent_disabled_lockfile => {
+        :default    => "$statedir/agent_disabled.lock",
+        :type       => :file,
+        :desc       => "A lock file to indicate that puppet agent runs have been administratively
+          disabled.  File contains a JSON object with state information.",
+    },
+    :usecacheonfailure => {
+      :default    => true,
+      :type       => :boolean,
+      :desc       => "Whether to use the cached configuration when the remote
+        configuration will not compile.  This option is useful for testing
+        new configurations, where you want to fix the broken configuration
+        rather than reverting to a known-good one.",
+    },
+    :use_cached_catalog => {
+      :default    => false,
+      :type       => :boolean,
+      :desc       => "Whether to only use the cached catalog rather than compiling a new catalog
+        on every run.  Puppet can be run with this enabled by default and then selectively
+        disabled when a recompile is desired.",
+    },
+    :ignoremissingtypes => {
+      :default    => false,
+      :type       => :boolean,
+      :desc       => "Skip searching for classes and definitions that were missing during a
+        prior compilation. The list of missing objects is maintained per-environment and
+        persists until the environment is cleared or the master is restarted.",
+    },
+    :ignorecache => {
+      :default    => false,
+      :type       => :boolean,
+      :desc       => "Ignore cache and always recompile the configuration.  This is
+        useful for testing new configurations, where the local cache may in
+        fact be stale even if the timestamps are up to date - if the facts
+        change or if the server changes.",
+    },
+    :dynamicfacts => {
+      :default    => "memorysize,memoryfree,swapsize,swapfree",
+      :desc       => "(Deprecated) Facts that are dynamic; these facts will be ignored when deciding whether
+        changed facts should result in a recompile.  Multiple facts should be
+        comma-separated.",
+      :hook => proc { |value|
+        if value
+          Puppet.deprecation_warning "The dynamicfacts setting is deprecated and will be ignored."
+        end
+      }
+    },
+    :splaylimit => {
+      :default    => "$runinterval",
+      :type       => :duration,
+      :desc       => "The maximum time to delay before runs.  Defaults to being the same as the
+        run interval. #{AS_DURATION}",
+    },
+    :splay => {
+      :default    => false,
+      :type       => :boolean,
+      :desc       => "Whether to sleep for a pseudo-random (but consistent) amount of time before
+        a run.",
+    },
+    :clientbucketdir => {
+      :default  => "$vardir/clientbucket",
+      :type     => :directory,
+      :mode     => "0750",
+      :desc     => "Where FileBucket files are stored locally."
+    },
+    :configtimeout => {
+      :default  => "2m",
+      :type     => :duration,
+      :desc     => "How long the client should wait for the configuration to be retrieved
+        before considering it a failure.  This can help reduce flapping if too
+        many clients contact the server at one time. #{AS_DURATION}",
+    },
+    :report_server => {
+      :default  => "$server",
+      :desc     => "The server to send transaction reports to.",
+    },
+    :report_port => {
+      :default  => "$masterport",
+      :desc     => "The port to communicate with the report_server.",
+    },
+    :inventory_server => {
+      :default  => "$server",
+      :desc     => "The server to send facts to.",
+    },
+    :inventory_port => {
+      :default  => "$masterport",
+      :desc     => "The port to communicate with the inventory_server.",
+    },
+    :report => {
+      :default  => true,
+      :type     => :boolean,
+      :desc     => "Whether to send reports after every transaction.",
+    },
+    :lastrunfile =>  {
+      :default  => "$statedir/last_run_summary.yaml",
+      :type     => :file,
+      :mode     => "0644",
+      :desc     => "Where puppet agent stores the last run report summary in yaml format."
+    },
+    :lastrunreport =>  {
+      :default  => "$statedir/last_run_report.yaml",
+      :type     => :file,
+      :mode     => "0640",
+      :desc     => "Where puppet agent stores the last run report in yaml format."
+    },
+    :graph => {
+      :default  => false,
+      :type     => :boolean,
+      :desc     => "Whether to create dot graph files for the different
+        configuration graphs.  These dot files can be interpreted by tools
+        like OmniGraffle or dot (which is part of ImageMagick).",
+    },
+    :graphdir => {
+      :default    => "$statedir/graphs",
+      :type       => :directory,
+      :desc       => "Where to store dot-outputted graphs.",
+    },
+    :http_compression => {
+      :default    => false,
+      :type       => :boolean,
+      :desc       => "Allow http compression in REST communication with the master.
+        This setting might improve performance for agent -> master
+        communications over slow WANs. Your puppet master needs to support
+        compression (usually by activating some settings in a reverse-proxy in
+        front of the puppet master, which rules out webrick). It is harmless to
+        activate this settings if your master doesn't support compression, but
+        if it supports it, this setting might reduce performance on high-speed LANs.",
+    },
+    :waitforcert => {
+      :default  => "2m",
+      :type     => :duration,
+      :desc     => "How frequently puppet agent should ask for a signed certificate.
+
+      When starting for the first time, puppet agent will submit a certificate
+      signing request (CSR) to the server named in the `ca_server` setting
+      (usually the puppet master); this may be autosigned, or may need to be
+      approved by a human, depending on the CA server's configuration.
+
+      Puppet agent cannot apply configurations until its approved certificate is
+      available. Since the certificate may or may not be available immediately,
+      puppet agent will repeatedly try to fetch it at this interval. You can
+      turn off waiting for certificates by specifying a time of 0, in which case
+      puppet agent will exit if it cannot get a cert.
+      #{AS_DURATION}",
+    },
+    :ordering => {
+      :type => :enum,
+      :values => ["manifest", "title-hash", "random"],
+      :default => "title-hash",
+      :desc => "How unrelated resources should be ordered when applying a catalog.
+      Allowed values are `title-hash`, `manifest`, and `random`. This
+      setting affects puppet agent and puppet apply, but not puppet master.
+
+      * `title-hash` (the default) will order resources randomly, but will use
+        the same order across runs and across nodes.
+      * `manifest` will use the order in which the resources were declared in
+        their manifest files.
+      * `random` will order resources randomly and change their order with each
+        run. This can work like a fuzzer for shaking out undeclared dependencies.
+
+      Regardless of this setting's value, Puppet will always obey explicit
+      dependencies set with the before/require/notify/subscribe metaparameters
+      and the `->`/`~>` chaining arrows; this setting only affects the relative
+      ordering of _unrelated_ resources."
+    }
+  )
+
+  define_settings(:inspect,
+    :archive_files => {
+        :type     => :boolean,
+        :default  => false,
+        :desc     => "During an inspect run, whether to archive files whose contents are audited to a file bucket.",
+    },
+    :archive_file_server => {
+        :default  => "$server",
+        :desc     => "During an inspect run, the file bucket server to archive files to if archive_files is set.",
+    }
+  )
+
+  # Plugin information.
+
+  define_settings(
+    :main,
+    :plugindest => {
+      :type       => :directory,
+      :default    => "$libdir",
+      :desc       => "Where Puppet should store plugins that it pulls down from the central
+      server.",
+    },
+    :pluginsource => {
+      :default    => "puppet://$server/plugins",
+      :desc       => "From where to retrieve plugins.  The standard Puppet `file` type
+      is used for retrieval, so anything that is a valid file source can
+      be used here.",
+    },
+    :pluginfactdest => {
+      :type     => :directory,
+      :default  => "$vardir/facts.d",
+      :desc     => "Where Puppet should store external facts that are being handled by pluginsync",
+    },
+    :pluginfactsource => {
+      :default  => "puppet://$server/pluginfacts",
+      :desc     => "Where to retrieve external facts for pluginsync",
+    },
+    :pluginsync => {
+      :default    => true,
+      :type       => :boolean,
+      :desc       => "Whether plugins should be synced with the central server.",
+    },
+
+    :pluginsignore => {
+        :default  => ".svn CVS .git",
+        :desc     => "What files to ignore when pulling down plugins.",
+    }
+  )
+
+  # Central fact information.
+
+    define_settings(
+    :main,
+    :factpath => {
+      :type     => :path,
+      :default  => "$vardir/lib/facter#{File::PATH_SEPARATOR}$vardir/facts",
+      :desc     => "Where Puppet should look for facts.  Multiple directories should
+        be separated by the system path separator character. (The POSIX path
+        separator is ':', and the Windows path separator is ';'.)",
+
+      :call_hook => :on_initialize_and_write, # Call our hook with the default value, so we always get the value added to facter.
+      :hook => proc do |value|
+        paths = value.split(File::PATH_SEPARATOR)
+        Facter.search(*paths)
+      end
+    }
+  )
+
+
+    define_settings(
+    :tagmail,
+    :tagmap => {
+      :default    => "$confdir/tagmail.conf",
+      :desc       => "The mapping between reporting tags and email addresses.",
+    },
+    :sendmail => {
+      :default    => which('sendmail') || '',
+      :desc       => "Where to find the sendmail binary with which to send email.",
+    },
+
+    :reportfrom => {
+        :default  => lambda { "report@#{Puppet::Settings.default_certname.downcase}" },
+        :desc     => "The 'from' email address for the reports.",
+    },
+
+    :smtpserver => {
+        :default  => "none",
+        :desc     => "The server through which to send email reports.",
+    },
+    :smtpport => {
+        :default  => 25,
+        :desc     => "The TCP port through which to send email reports.",
+    },
+    :smtphelo => {
+        :default  => lambda { Facter.value 'fqdn' },
+        :desc     => "The name by which we identify ourselves in SMTP HELO for reports.
+          If you send to a smtpserver which does strict HELO checking (as with Postfix's
+          `smtpd_helo_restrictions` access controls), you may need to ensure this resolves.",
+    }
+  )
+
+    define_settings(
+    :rails,
+    :dblocation => {
+      :default  => "$statedir/clientconfigs.sqlite3",
+      :type     => :file,
+      :mode     => "0660",
+      :owner    => "service",
+      :group    => "service",
+      :desc     => "The sqlite database file. #{STORECONFIGS_ONLY}"
+    },
+    :dbadapter => {
+      :default  => "sqlite3",
+      :desc     => "The type of database to use. #{STORECONFIGS_ONLY}",
+    },
+    :dbmigrate => {
+      :default  => false,
+      :type     => :boolean,
+      :desc     => "Whether to automatically migrate the database. #{STORECONFIGS_ONLY}",
+    },
+    :dbname => {
+      :default  => "puppet",
+      :desc     => "The name of the database to use. #{STORECONFIGS_ONLY}",
+    },
+    :dbserver => {
+      :default  => "localhost",
+      :desc     => "The database server for caching. Only
+      used when networked databases are used.",
+    },
+    :dbport => {
+      :default  => "",
+      :desc     => "The database password for caching. Only
+        used when networked databases are used. #{STORECONFIGS_ONLY}",
+    },
+    :dbuser => {
+      :default  => "puppet",
+      :desc     => "The database user for caching. Only
+        used when networked databases are used. #{STORECONFIGS_ONLY}",
+    },
+    :dbpassword => {
+      :default  => "puppet",
+      :desc     => "The database password for caching. Only
+        used when networked databases are used. #{STORECONFIGS_ONLY}",
+    },
+    :dbconnections => {
+      :default  => '',
+      :desc     => "The number of database connections for networked
+        databases.  Will be ignored unless the value is a positive integer. #{STORECONFIGS_ONLY}",
+    },
+    :dbsocket => {
+      :default  => "",
+      :desc     => "The database socket location. Only used when networked
+        databases are used.  Will be ignored if the value is an empty string. #{STORECONFIGS_ONLY}",
+    },
+    :railslog => {
+      :default  => "$logdir/rails.log",
+      :type     => :file,
+      :mode     => "0600",
+      :owner    => "service",
+      :group    => "service",
+      :desc     => "Where Rails-specific logs are sent. #{STORECONFIGS_ONLY}"
+    },
+
+    :rails_loglevel => {
+        :default  => "info",
+        :desc     => "The log level for Rails connections.  The value must be
+          a valid log level within Rails.  Production environments normally use `info`
+          and other environments normally use `debug`. #{STORECONFIGS_ONLY}",
+    }
+  )
+
+    define_settings(
+    :couchdb,
+
+    :couchdb_url => {
+        :default  => "http://127.0.0.1:5984/puppet",
+        :desc     => "The url where the puppet couchdb database will be created.
+          Only used when `facts_terminus` is set to `couch`.",
+    }
+  )
+
+    define_settings(
+    :transaction,
+    :tags => {
+      :default    => "",
+      :desc       => "Tags to use to find resources.  If this is set, then
+        only resources tagged with the specified tags will be applied.
+        Values must be comma-separated.",
+    },
+    :evaltrace => {
+      :default    => false,
+      :type       => :boolean,
+      :desc       => "Whether each resource should log when it is
+        being evaluated.  This allows you to interactively see exactly
+        what is being done.",
+    },
+    :summarize => {
+        :default  => false,
+        :type     => :boolean,
+        :desc     => "Whether to print a transaction summary.",
+    }
+  )
+
+    define_settings(
+    :main,
+    :external_nodes => {
+        :default  => "none",
+        :desc     => "An external command that can produce node information.  The command's output
+          must be a YAML dump of a hash, and that hash must have a `classes` key and/or
+          a `parameters` key, where `classes` is an array or hash and
+          `parameters` is a hash.  For unknown nodes, the command should
+          exit with a non-zero exit code.
+
+          This command makes it straightforward to store your node mapping
+          information in other data sources like databases.",
+    }
+    )
+
+        define_settings(
+        :ldap,
+    :ldapssl => {
+      :default  => false,
+      :type   => :boolean,
+      :desc   => "Whether SSL should be used when searching for nodes.
+        Defaults to false because SSL usually requires certificates
+        to be set up on the client side.",
+    },
+    :ldaptls => {
+      :default  => false,
+      :type     => :boolean,
+      :desc     => "Whether TLS should be used when searching for nodes.
+        Defaults to false because TLS usually requires certificates
+        to be set up on the client side.",
+    },
+    :ldapserver => {
+      :default  => "ldap",
+      :desc     => "The LDAP server.  Only used if `node_terminus` is set to `ldap`.",
+    },
+    :ldapport => {
+      :default  => 389,
+      :desc     => "The LDAP port.  Only used if `node_terminus` is set to `ldap`.",
+    },
+
+    :ldapstring => {
+      :default  => "(&(objectclass=puppetClient)(cn=%s))",
+      :desc     => "The search string used to find an LDAP node.",
+    },
+    :ldapclassattrs => {
+      :default  => "puppetclass",
+      :desc     => "The LDAP attributes to use to define Puppet classes.  Values
+        should be comma-separated.",
+    },
+    :ldapstackedattrs => {
+      :default  => "puppetvar",
+      :desc     => "The LDAP attributes that should be stacked to arrays by adding
+        the values in all hierarchy elements of the tree.  Values
+        should be comma-separated.",
+    },
+    :ldapattrs => {
+      :default  => "all",
+      :desc     => "The LDAP attributes to include when querying LDAP for nodes.  All
+        returned attributes are set as variables in the top-level scope.
+        Multiple values should be comma-separated.  The value 'all' returns
+        all attributes.",
+    },
+    :ldapparentattr => {
+      :default  => "parentnode",
+      :desc     => "The attribute to use to define the parent node.",
+    },
+    :ldapuser => {
+      :default  => "",
+      :desc     => "The user to use to connect to LDAP.  Must be specified as a
+        full DN.",
+    },
+    :ldappassword => {
+      :default  => "",
+      :desc     => "The password to use to connect to LDAP.",
+    },
+    :ldapbase => {
+        :default  => "",
+        :desc     => "The search base for LDAP searches.  It's impossible to provide
+          a meaningful default here, although the LDAP libraries might
+          have one already set.  Generally, it should be the 'ou=Hosts'
+          branch under your main directory.",
+    }
+  )
+
+  define_settings(:master,
+    :storeconfigs => {
+      :default  => false,
+      :type     => :boolean,
+      :desc     => "Whether to store each client's configuration, including catalogs, facts,
+        and related data.  This also enables the import and export of resources in
+        the Puppet language - a mechanism for exchange resources between nodes.
+
+        By default this uses ActiveRecord and an SQL database to store and query
+        the data; this, in turn, will depend on Rails being available.
+
+        You can adjust the backend using the storeconfigs_backend setting.",
+      # Call our hook with the default value, so we always get the libdir set.
+      :call_hook => :on_initialize_and_write,
+      :hook => proc do |value|
+        require 'puppet/node'
+        require 'puppet/node/facts'
+        if value
+          if not Puppet.settings[:async_storeconfigs]
+            Puppet::Resource::Catalog.indirection.cache_class = :store_configs
+            Puppet.settings.override_default(:catalog_cache_terminus, :store_configs)
+          end
+          Puppet::Node::Facts.indirection.cache_class = :store_configs
+
+          Puppet::Resource.indirection.terminus_class = :store_configs
+        end
+      end
+    },
+    :storeconfigs_backend => {
+      :type => :terminus,
+      :default => "active_record",
+      :desc => "Configure the backend terminus used for StoreConfigs.
+        By default, this uses the ActiveRecord store, which directly talks to the
+        database from within the Puppet Master process."
+    }
+  )
+
+  define_settings(:parser,
+    :templatedir => {
+        :default  => "$vardir/templates",
+        :type     => :directory,
+        :desc     => "Where Puppet looks for template files.  Can be a list of colon-separated
+          directories.
+
+          This setting is deprecated. Please put your templates in modules instead.",
+        :deprecated => :completely,
+    },
+
+    :allow_variables_with_dashes => {
+      :default => false,
+      :desc    => <<-'EOT'
+        Permit hyphens (`-`) in variable names and issue deprecation warnings about
+        them. This setting **should always be `false`;** setting it to `true`
+        will cause subtle and wide-ranging bugs. It will be removed in a future version.
+
+        Hyphenated variables caused major problems in the language, but were allowed
+        between Puppet 2.7.3 and 2.7.14. If you used them during this window, we
+        apologize for the inconvenience --- you can temporarily set this to `true`
+        in order to upgrade, and can rename your variables at your leisure. Please
+        revert it to `false` after you have renamed all affected variables.
+      EOT
+    },
+    :parser => {
+      :default => "current",
+      :hook    => proc do |value|
+        envs = Puppet.lookup(:environments) { nil }
+        envs.clear_all unless envs.nil?
+      end,
+      :desc => <<-'EOT'
+        Selects the parser to use for parsing puppet manifests (in puppet DSL
+        language/'.pp' files). Available choices are `current` (the default)
+        and `future`.
+
+        The `current` parser means that the released version of the parser should
+        be used.
+
+        The `future` parser is a "time travel to the future" allowing early
+        exposure to new language features. What these features are will vary from
+        release to release and they may be invididually configurable.
+
+        Available Since Puppet 3.2.
+      EOT
+    },
+   :max_errors => {
+     :default => 10,
+     :desc => <<-'EOT'
+       Sets the max number of logged/displayed parser validation errors in case
+       multiple errors have been detected. A value of 0 is the same as a value of 1; a
+       minimum of one error is always raised.  The count is per manifest.
+     EOT
+   },
+   :max_warnings => {
+     :default => 10,
+     :desc => <<-'EOT'
+       Sets the max number of logged/displayed parser validation warnings in
+       case multiple warnings have been detected. A value of 0 blocks logging of
+       warnings.  The count is per manifest.
+     EOT
+     },
+  :max_deprecations => {
+    :default => 10,
+    :desc => <<-'EOT'
+      Sets the max number of logged/displayed parser validation deprecation
+      warnings in case multiple deprecation warnings have been detected. A value of 0
+      blocks the logging of deprecation warnings.  The count is per manifest.
+    EOT
+    },
+  :strict_variables => {
+    :default => false,
+    :type => :boolean,
+    :desc => <<-'EOT'
+      Makes the parser raise errors when referencing unknown variables. (This does not affect
+      referencing variables that are explicitly set to undef).
+    EOT
+    }
+  )
+  define_settings(:puppetdoc,
+    :document_all => {
+        :default  => false,
+        :type     => :boolean,
+        :desc     => "Whether to document all resources when using `puppet doc` to
+          generate manifest documentation.",
+    }
+  )
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/dsl.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/dsl.rb
new file mode 100644
index 0000000..97a3104
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/dsl.rb
@@ -0,0 +1,7 @@
+require 'puppet'
+
+module Puppet::DSL
+end
+
+require 'puppet/dsl/resource_type_api'
+require 'puppet/dsl/resource_api'
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/dsl/resource_api.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/dsl/resource_api.rb
new file mode 100644
index 0000000..d82373b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/dsl/resource_api.rb
@@ -0,0 +1,120 @@
+# This module adds functionality to a resource to make it
+# capable of evaluating the DSL resource type block and also
+# hooking into the scope system.
+require 'puppet/resource/type_collection_helper'
+
+class Puppet::DSL::ResourceAPI
+  include Puppet::Resource::TypeCollectionHelper
+
+  FUNCTION_MAP = {:acquire => :include}
+
+  attr_reader :scope, :resource, :block
+
+  def environment
+    scope.environment
+  end
+
+  def evaluate
+    set_instance_variables
+    instance_eval(&block)
+  end
+
+  def initialize(resource, scope, block)
+    @scope = scope
+    @resource = resource
+    @block = block
+  end
+
+  # Try to convert a missing method into a resource type or a function.
+  def method_missing(name, *args)
+    raise "MethodMissing loop when searching for #{name} with #{args.inspect}" if searching_for_method?
+    @searching_for_method = true
+    return create_resource(name, args[0], args[1]) if valid_type?(name)
+
+    name = map_function(name)
+
+    return call_function(name, args) if Puppet::Parser::Functions.function(name)
+
+    super
+  ensure
+    @searching_for_method = false
+  end
+
+  def set_instance_variables
+    resource.eachparam do |param|
+      instance_variable_set("@#{param.name}", param.value)
+    end
+    @title = resource.title
+    @name ||= resource.title
+  end
+
+  def create_resource(type, names, arguments = nil)
+    names = [names] unless names.is_a?(Array)
+
+    arguments ||= {}
+    raise ArgumentError, "Resource arguments must be provided as a hash" unless arguments.is_a?(Hash)
+
+    names.collect do |name|
+      resource = Puppet::Parser::Resource.new(type, name, :scope => scope)
+      arguments.each do |param, value|
+        resource[param] = value
+      end
+
+      resource.exported = true if exporting?
+      resource.virtual = true if virtualizing?
+      scope.compiler.add_resource(scope, resource)
+      resource
+    end
+  end
+
+  def call_function(name, args)
+    return false unless method = Puppet::Parser::Functions.function(name)
+    scope.send(method, *args)
+  end
+
+  def export(resources = nil, &block)
+    if resources
+      resources.each { |resource| resource.exported = true }
+      return resources
+    end
+    @exporting = true
+    instance_eval(&block)
+  ensure
+    @exporting = false
+  end
+
+  def virtual(resources = nil, &block)
+    if resources
+      resources.each { |resource| resource.virtual = true }
+      return resources
+    end
+    @virtualizing = true
+    instance_eval(&block)
+  ensure
+    @virtualizing = false
+  end
+
+  def valid_type?(name)
+    return true if [:class, :node].include?(name)
+    return true if Puppet::Type.type(name)
+    return(known_resource_types.definition(name) ? true : false)
+  end
+
+  private
+
+  def exporting?
+    @exporting
+  end
+
+  def map_function(name)
+    FUNCTION_MAP[name] || name
+  end
+
+  def searching_for_method?
+    @searching_for_method
+  end
+
+  def virtualizing?
+    @virtualizing
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/dsl/resource_type_api.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/dsl/resource_type_api.rb
new file mode 100644
index 0000000..8810d53
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/dsl/resource_type_api.rb
@@ -0,0 +1,34 @@
+require 'puppet/resource/type'
+
+# Type of the objects inside of which pure ruby manifest files are
+# executed.  Provides methods for creating defines, hostclasses, and
+# nodes.
+class Puppet::DSL::ResourceTypeAPI
+  def initialize
+    @__created_ast_objects__ = []
+  end
+
+  def define(name, *args, &block)
+    args = args.inject([]) do |result, item|
+      if item.is_a?(Hash)
+        item.each { |p, v| result << [p, v] }
+      else
+        result << item
+      end
+      result
+    end
+    @__created_ast_objects__.push Puppet::Parser::AST::Definition.new(name, {:arguments => args}, &block)
+    nil
+  end
+
+  def hostclass(name, options = {}, &block)
+    @__created_ast_objects__.push Puppet::Parser::AST::Hostclass.new(name, options, &block)
+    nil
+  end
+
+  def node(name, options = {}, &block)
+    name = [name] unless name.is_a?(Array)
+    @__created_ast_objects__.push Puppet::Parser::AST::Node.new(name, options, &block)
+    nil
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/environments.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/environments.rb
new file mode 100644
index 0000000..eff2147
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/environments.rb
@@ -0,0 +1,543 @@
+# @api private
+module Puppet::Environments
+
+  class EnvironmentNotFound < Puppet::Error
+    def initialize(environment_name, original = nil)
+      environmentpath = Puppet[:environmentpath]
+      super("Could not find a directory environment named '#{environment_name}' anywhere in the path: #{environmentpath}. Does the directory exist?", original)
+    end
+  end
+
+  # @api private
+  module EnvironmentCreator
+    # Create an anonymous environment.
+    #
+    # @param module_path [String] A list of module directories separated by the
+    #   PATH_SEPARATOR
+    # @param manifest [String] The path to the manifest
+    # @return A new environment with the `name` `:anonymous`
+    #
+    # @api private
+    def for(module_path, manifest)
+      Puppet::Node::Environment.create(:anonymous,
+                                       module_path.split(File::PATH_SEPARATOR),
+                                       manifest)
+    end
+  end
+
+  # Provide any common methods that loaders should have. It requires that any
+  # classes that include this module implement get
+  # @api private
+  module EnvironmentLoader
+    # @!macro loader_get_or_fail
+    def get!(name)
+      environment = get(name)
+      if environment
+        environment
+      else
+        raise EnvironmentNotFound, name
+      end
+    end
+
+    def clear_all
+      root = Puppet.lookup(:root_environment) { nil }
+      root.instance_variable_set(:@future_parser, nil) unless root.nil?
+    end
+  end
+
+  # @!macro [new] loader_search_paths
+  #   A list of indicators of where the loader is getting its environments from.
+  #   @return [Array<String>] The URIs of the load locations
+  #
+  # @!macro [new] loader_list
+  #   @return [Array<Puppet::Node::Environment>] All of the environments known
+  #     to the loader
+  #
+  # @!macro [new] loader_get
+  #   Find a named environment
+  #
+  #   @param name [String,Symbol] The name of environment to find
+  #   @return [Puppet::Node::Environment, nil] the requested environment or nil
+  #     if it wasn't found
+  #
+  # @!macro [new] loader_get_conf
+  #   Attempt to obtain the initial configuration for the environment.  Not all
+  #   loaders can provide this.
+  #
+  #   @param name [String,Symbol] The name of the environment whose configuration
+  #     we are looking up
+  #   @return [Puppet::Setting::EnvironmentConf, nil] the configuration for the
+  #     requested environment, or nil if not found or no configuration is available
+  #
+  # @!macro [new] loader_get_or_fail
+  #   Find a named environment or raise
+  #   Puppet::Environments::EnvironmentNotFound when the named environment is
+  #   does not exist.
+  #
+  #   @param name [String,Symbol] The name of environment to find
+  #   @return [Puppet::Node::Environment] the requested environment
+
+  # A source of pre-defined environments.
+  #
+  # @api private
+  class Static
+    include EnvironmentCreator
+    include EnvironmentLoader
+
+    def initialize(*environments)
+      @environments = environments
+    end
+
+    # @!macro loader_search_paths
+    def search_paths
+      ["data:text/plain,internal"]
+    end
+
+    # @!macro loader_list
+    def list
+      @environments
+    end
+
+    # @!macro loader_get
+    def get(name)
+      @environments.find do |env|
+        env.name == name.intern
+      end
+    end
+
+    # Returns a basic environment configuration object tied to the environment's
+    # implementation values.  Will not interpolate.
+    #
+    # @!macro loader_get_conf
+    def get_conf(name)
+      env = get(name)
+      if env
+        Puppet::Settings::EnvironmentConf.static_for(env, Puppet[:parser])
+      else
+        nil
+      end
+    end
+  end
+
+  # A source of unlisted pre-defined environments.
+  #
+  # Used only for internal bootstrapping environments which are not relevant
+  # to an end user (such as the fall back 'configured' environment).
+  #
+  # @api private
+  class StaticPrivate < Static
+
+    # Unlisted
+    #
+    # @!macro loader_list
+    def list
+      []
+    end
+  end
+
+  # Old-style environments that come either from explicit stanzas in
+  # puppet.conf or from dynamic environments created from use of `$environment`
+  # in puppet.conf.
+  #
+  # @example Explicit Stanza
+  #   [environment_name]
+  #   modulepath=/var/my_env/modules
+  #
+  # @example Dynamic Environments
+  #   [master]
+  #   modulepath=/var/$environment/modules
+  #
+  # @api private
+  class Legacy
+    include EnvironmentCreator
+
+    # @!macro loader_search_paths
+    def search_paths
+      ["file://#{Puppet[:config]}"]
+    end
+
+    # @note The list of environments for the Legacy environments is always
+    #   empty.
+    #
+    # @!macro loader_list
+    def list
+      []
+    end
+
+    # @note Because the Legacy system cannot list out all of its environments,
+    #   get is able to return environments that are not returned by a call to
+    #   {#list}.
+    #
+    # @!macro loader_get
+    def get(name)
+      Puppet::Node::Environment.new(name)
+    end
+
+    # @note Because the Legacy system cannot list out all of its environments,
+    #   this method will never fail and is only calling get directly.
+    #
+    # @!macro loader_get_or_fail
+    def get!(name)
+      get(name)
+    end
+
+    # @note we could return something here, but since legacy environments
+    #   are deprecated, there is no point.
+    #
+    # @!macro loader_get_conf
+    def get_conf(name)
+      nil
+    end
+  end
+
+  # Reads environments from a directory on disk. Each environment is
+  # represented as a sub-directory. The environment's manifest setting is the
+  # `manifest` directory of the environment directory. The environment's
+  # modulepath setting is the global modulepath (from the `[master]` section
+  # for the master) prepended with the `modules` directory of the environment
+  # directory.
+  #
+  # @api private
+  class Directories
+    include EnvironmentLoader
+
+    def initialize(environment_dir, global_module_path)
+      @environment_dir = environment_dir
+      @global_module_path = global_module_path
+    end
+
+    # Generate an array of directory loaders from a path string.
+    # @param path [String] path to environment directories
+    # @param global_module_path [Array<String>] the global modulepath setting
+    # @return [Array<Puppet::Environments::Directories>] An array
+    #   of configured directory loaders.
+    def self.from_path(path, global_module_path)
+      environments = path.split(File::PATH_SEPARATOR)
+      environments.map do |dir|
+        Puppet::Environments::Directories.new(dir, global_module_path)
+      end
+    end
+
+    # @!macro loader_search_paths
+    def search_paths
+      ["file://#{@environment_dir}"]
+    end
+
+    # @!macro loader_list
+    def list
+      valid_directories.collect do |envdir|
+        name = Puppet::FileSystem.basename_string(envdir).intern
+        create_environment(name)
+      end
+    end
+
+    # @!macro loader_get
+    def get(name)
+      if valid_directory?(File.join(@environment_dir, name.to_s))
+        create_environment(name)
+      end
+    end
+
+    # @!macro loader_get_conf
+    def get_conf(name)
+      envdir = File.join(@environment_dir, name.to_s)
+      if valid_directory?(envdir)
+        return Puppet::Settings::EnvironmentConf.load_from(envdir, @global_module_path)
+      end
+      nil
+    end
+
+    private
+
+    def create_environment(name, setting_values = nil)
+      env_symbol = name.intern
+      setting_values = Puppet.settings.values(env_symbol, Puppet.settings.preferred_run_mode)
+      env = Puppet::Node::Environment.create(
+        env_symbol,
+        Puppet::Node::Environment.split_path(setting_values.interpolate(:modulepath)),
+        setting_values.interpolate(:manifest),
+        setting_values.interpolate(:config_version)
+      )
+      env.watching = false
+      env
+    end
+
+    def valid_directory?(envdir)
+      name = Puppet::FileSystem.basename_string(envdir)
+      Puppet::FileSystem.directory?(envdir) &&
+         Puppet::Node::Environment.valid_name?(name)
+    end
+
+    def valid_directories
+      if Puppet::FileSystem.directory?(@environment_dir)
+        Puppet::FileSystem.children(@environment_dir).select do |child|
+          valid_directory?(child)
+        end
+      else
+        []
+      end
+    end
+  end
+
+  # Combine together multiple loaders to act as one.
+  # @api private
+  class Combined
+    include EnvironmentLoader
+
+    def initialize(*loaders)
+      @loaders = loaders
+    end
+
+    # @!macro loader_search_paths
+    def search_paths
+      @loaders.collect(&:search_paths).flatten
+    end
+
+    # @!macro loader_list
+    def list
+      @loaders.collect(&:list).flatten
+    end
+
+    # @!macro loader_get
+    def get(name)
+      @loaders.each do |loader|
+        if env = loader.get(name)
+          return env
+        end
+      end
+      nil
+    end
+
+    # @!macro loader_get_conf
+    def get_conf(name)
+      @loaders.each do |loader|
+        if conf = loader.get_conf(name)
+          return conf
+        end
+      end
+      nil
+    end
+
+    def clear_all
+      @loaders.each {|loader| loader.clear_all}
+    end
+  end
+
+  class Cached
+    include EnvironmentLoader
+
+    INFINITY = 1.0 / 0.0
+
+    class DefaultCacheExpirationService
+      def created(env)
+      end
+
+      def expired?(env_name)
+        false
+      end
+
+      def evicted(env_name)
+      end
+    end
+
+    def self.cache_expiration_service=(service)
+      @cache_expiration_service = service
+    end
+
+    def self.cache_expiration_service
+      @cache_expiration_service || DefaultCacheExpirationService.new
+    end
+
+    # Returns the end of time (the next Mesoamerican Long Count cycle-end after 2012 (5125+2012) = 7137,
+    # of for a 32 bit machine using Ruby < 1.9.3, the year 2038.
+    def self.end_of_time
+      begin
+        Time.gm(7137)
+      rescue ArgumentError
+        Time.gm(2038)
+      end
+    end
+
+    END_OF_TIME = end_of_time
+    START_OF_TIME = Time.gm(1)
+
+    def initialize(loader)
+      @loader = loader
+      @cache_expiration_service = Puppet::Environments::Cached.cache_expiration_service
+      @cache = {}
+
+      # Holds expiration times in sorted order - next to expire is first
+      @expirations = SortedSet.new
+
+      # Infinity since it there are no entries, this is a cache of the first to expire time
+      @next_expiration = END_OF_TIME
+    end
+
+    # @!macro loader_list
+    def list
+      @loader.list
+    end
+
+    # @!macro loader_search_paths
+    def search_paths
+      @loader.search_paths
+    end
+
+    # @!macro loader_get
+    def get(name)
+      # Aggressively evict all that has expired
+      # This strategy favors smaller memory footprint over environment
+      # retrieval time.
+      clear_all_expired
+      if result = @cache[name]
+        # found in cache
+        return result.value
+      elsif (result = @loader.get(name))
+        # environment loaded, cache it
+        cache_entry = entry(result)
+        @cache_expiration_service.created(result)
+        add_entry(name, cache_entry)
+        result
+      end
+    end
+
+    # Adds a cache entry to the cache
+    def add_entry(name, cache_entry)
+      Puppet.debug("Caching environment '#{name}' #{cache_entry.label}")
+      @cache[name] = cache_entry
+      expires = cache_entry.expires
+      @expirations.add(expires)
+      if @next_expiration > expires
+        @next_expiration = expires
+      end
+    end
+    private :add_entry
+
+    # Clears the cache of the environment with the given name.
+    # (The intention is that this could be used from a MANUAL cache eviction command (TBD)
+    def clear(name)
+      @cache.delete(name)
+    end
+
+    # Clears all cached environments.
+    # (The intention is that this could be used from a MANUAL cache eviction command (TBD)
+    def clear_all()
+      super
+      @cache = {}
+      @expirations.clear
+      @next_expiration = END_OF_TIME
+    end
+
+    # Clears all environments that have expired, either by exceeding their time to live, or
+    # through an explicit eviction determined by the cache expiration service.
+    #
+    def clear_all_expired()
+      t = Time.now
+      return if t < @next_expiration && ! @cache.any? {|name, _| @cache_expiration_service.expired?(name.to_sym) }
+      to_expire = @cache.select { |name, entry| entry.expires < t || @cache_expiration_service.expired?(name.to_sym) }
+      to_expire.each do |name, entry|
+        Puppet.debug("Evicting cache entry for environment '#{name}'")
+        @cache_expiration_service.evicted(name)
+        clear(name)
+        @expirations.delete(entry.expires)
+        Puppet.settings.clear_environment_settings(name)
+      end
+      @next_expiration = @expirations.first || END_OF_TIME
+    end
+
+    # This implementation evicts the cache, and always gets the current
+    # configuration of the environment
+    #
+    # TODO: While this is wasteful since it
+    # needs to go on a search for the conf, it is too disruptive to optimize
+    # this.
+    #
+    # @!macro loader_get_conf
+    def get_conf(name)
+      evict_if_expired(name)
+      @loader.get_conf(name)
+    end
+
+    # Creates a suitable cache entry given the time to live for one environment
+    #
+    def entry(env)
+      ttl = (conf = get_conf(env.name)) ? conf.environment_timeout : Puppet.settings.value(:environment_timeout)
+      case ttl
+      when 0
+        NotCachedEntry.new(env)     # Entry that is always expired (avoids syscall to get time)
+      when INFINITY
+        Entry.new(env)              # Entry that never expires (avoids syscall to get time)
+      else
+        TTLEntry.new(env, ttl)
+      end
+    end
+
+    # Evicts the entry if it has expired
+    # Also clears caches in Settings that may prevent the entry from being updated
+    def evict_if_expired(name)
+      if (result = @cache[name]) && (result.expired? || @cache_expiration_service.expired?(name))
+        @cache.delete(name)
+        @cache_expiration_service.evicted(name)
+
+        Puppet.settings.clear_environment_settings(name)
+      end
+    end
+
+    # Never evicting entry
+    class Entry
+      attr_reader :value
+
+      def initialize(value)
+        @value = value
+      end
+
+      def expired?
+        false
+      end
+
+      def label
+        ""
+      end
+
+      def expires
+        END_OF_TIME
+      end
+    end
+
+    # Always evicting entry
+    class NotCachedEntry < Entry
+      def expired?
+        true
+      end
+
+      def label
+        "(ttl = 0 sec)"
+      end
+
+      def expires
+        START_OF_TIME
+      end
+    end
+
+    # Time to Live eviction policy entry
+    class TTLEntry < Entry
+      def initialize(value, ttl_seconds)
+        super value
+        @ttl = Time.now + ttl_seconds
+        @ttl_seconds = ttl_seconds
+      end
+
+      def expired?
+        Time.now > @ttl
+      end
+
+      def label
+        "(ttl = #{@ttl_seconds} sec)"
+      end
+
+      def expires
+        @ttl
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/error.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/error.rb
new file mode 100644
index 0000000..a9b247c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/error.rb
@@ -0,0 +1,92 @@
+module Puppet
+  # The base class for all Puppet errors. It can wrap another exception
+  class Error < RuntimeError
+    attr_accessor :original
+    def initialize(message, original=nil)
+      super(message)
+      @original = original
+    end
+  end
+
+  module ExternalFileError
+    # This module implements logging with a filename and line number. Use this
+    # for errors that need to report a location in a non-ruby file that we
+    # parse.
+    attr_accessor :line, :file, :pos
+
+    # May be called with 3 arguments for message, file, line, and exception, or
+    # 4 args including the position on the line.
+    #
+    def initialize(message, file=nil, line=nil, pos=nil, original=nil)
+      if pos.kind_of? Exception
+        original = pos
+        pos = nil
+      end
+      super(message, original)
+      @file = file unless (file.is_a?(String) && file.empty?)
+      @line = line
+      @pos = pos
+    end
+    def to_s
+      msg = super
+      @file = nil if (@file.is_a?(String) && @file.empty?)
+      if @file and @line and @pos
+        "#{msg} at #{@file}:#{@line}:#{@pos}"
+      elsif @file and @line
+        "#{msg} at #{@file}:#{@line}"
+      elsif @line and @pos
+          "#{msg} at line #{@line}:#{@pos}"
+      elsif @line
+        "#{msg} at line #{@line}"
+      elsif @file
+        "#{msg} in #{@file}"
+      else
+        msg
+      end
+    end
+  end
+
+  class ParseError < Puppet::Error
+    include ExternalFileError
+  end
+
+  class ResourceError < Puppet::Error
+    include ExternalFileError
+  end
+
+  # Contains an issue code and can be annotated with an environment and a node
+  class ParseErrorWithIssue < Puppet::ParseError
+    attr_reader :issue_code, :basic_message
+    attr_accessor :environment, :node
+
+    # @param message [String] The error message
+    # @param file [String] The path to the file where the error was found
+    # @param line [Integer] The line in the file
+    # @param pos [Integer] The position on the line
+    # @param original [Exception] Original exception
+    # @param issue_code [Symbol] The issue code
+    #
+    def initialize(message, file=nil, line=nil, pos=nil, original=nil, issue_code= nil)
+      super(message, file, line, pos, original)
+      @issue_code = issue_code
+      @basic_message = message
+    end
+
+    def to_s
+      msg = super
+      msg = "Could not parse for environment #{environment}: #{msg}" if environment
+      msg = "#{msg} on node #{node}" if node
+      msg
+    end
+  end
+
+  # An error that already contains location information in the message text
+  class PreformattedError < Puppet::ParseErrorWithIssue
+  end
+
+  # An error class for when I don't know what happened.  Automatically
+  # prints a stack trace when in debug mode.
+  class DevError < Puppet::Error
+    include ExternalFileError
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/dot.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/dot.rb
new file mode 100644
index 0000000..51da1c5
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/dot.rb
@@ -0,0 +1,326 @@
+# rdot.rb
+#
+#
+# This is a modified version of dot.rb from Dave Thomas's rdoc project.  I [Horst Duchene]
+# renamed it to rdot.rb to avoid collision with an installed rdoc/dot.
+#
+# It also supports undirected edges.
+
+module DOT
+
+  # These glogal vars are used to make nice graph source.
+
+  $tab  = '    '
+  $tab2 = $tab * 2
+
+  # if we don't like 4 spaces, we can change it any time
+
+  def change_tab (t)
+    $tab  = t
+    $tab2 = t * 2
+  end
+
+  # options for node declaration
+
+  NODE_OPTS = [
+    # attributes due to
+    # http://www.graphviz.org/Documentation/dotguide.pdf
+    # March, 26, 2005
+    'bottomlabel', # auxiliary label for nodes of shape M*
+    'color',       # default: black; node shape color
+    'comment',     # any string (format-dependent)
+    'distortion',  # default: 0.0; node distortion for shape=polygon
+    'fillcolor',   # default: lightgrey/black; node fill color
+    'fixedsize',   # default: false; label text has no affect on node size
+    'fontcolor',   # default: black; type face color
+    'fontname',    # default: Times-Roman; font family
+    'fontsize',    # default: 14; point size of label
+    'group',       # name of node's group
+    'height',      # default: .5; height in inches
+    'label',       # default: node name; any string
+    'layer',       # default: overlay range; all, id or id:id
+    'orientation', # default: 0.0; node rotation angle
+    'peripheries', # shape-dependent number of node boundaries
+    'regular',     # default: false; force polygon to be regular
+    'shape',       # default: ellipse; node shape; see Section 2.1 and Appendix E
+    'shapefile',   # external EPSF or SVG custom shape file
+    'sides',       # default: 4; number of sides for shape=polygon
+    'skew' ,       # default: 0.0; skewing of node for shape=polygon
+    'style',       # graphics options, e.g. bold, dotted, filled; cf. Section 2.3
+    'toplabel',    # auxiliary label for nodes of shape M*
+    'URL',         # URL associated with node (format-dependent)
+    'width',       # default: .75; width in inches
+    'z',           # default: 0.0; z coordinate for VRML output
+
+    # maintained for backward compatibility or rdot internal
+    'bgcolor',
+    'rank'
+  ]
+
+  # options for edge declaration
+
+  EDGE_OPTS = [
+    'arrowhead',      # default: normal; style of arrowhead at head end
+    'arrowsize',      # default: 1.0; scaling factor for arrowheads
+    'arrowtail',      # default: normal; style of arrowhead at tail end
+    'color',          # default: black; edge stroke color
+    'comment',        # any string (format-dependent)
+    'constraint',     # default: true use edge to affect node ranking
+    'decorate',       # if set, draws a line connecting labels with their edges
+    'dir',            # default: forward; forward, back, both, or none
+    'fontcolor',      # default: black type face color
+    'fontname',       # default: Times-Roman; font family
+    'fontsize',       # default: 14; point size of label
+    'headlabel',      # label placed near head of edge
+    'headport',       # n,ne,e,se,s,sw,w,nw
+    'headURL',        # URL attached to head label if output format is ismap
+    'label',          # edge label
+    'labelangle',     # default: -25.0; angle in degrees which head or tail label is rotated off edge
+    'labeldistance',  # default: 1.0; scaling factor for distance of head or tail label from node
+    'labelfloat',     # default: false; lessen constraints on edge label placement
+    'labelfontcolor', # default: black; type face color for head and tail labels
+    'labelfontname',  # default: Times-Roman; font family for head and tail labels
+    'labelfontsize',  # default: 14 point size for head and tail labels
+    'layer',          # default: overlay range; all, id or id:id
+    'lhead',          # name of cluster to use as head of edge
+    'ltail',          # name of cluster to use as tail of edge
+    'minlen',         # default: 1 minimum rank distance between head and tail
+    'samehead',       # tag for head node; edge heads with the same tag are merged onto the same port
+    'sametail',       # tag for tail node; edge tails with the same tag are merged onto the same port
+    'style',          # graphics options, e.g. bold, dotted, filled; cf. Section 2.3
+    'taillabel',      # label placed near tail of edge
+    'tailport',       # n,ne,e,se,s,sw,w,nw
+    'tailURL',        # URL attached to tail label if output format is ismap
+    'weight',         # default: 1; integer cost of stretching an edge
+
+    # maintained for backward compatibility or rdot internal
+    'id'
+  ]
+
+  # options for graph declaration
+
+  GRAPH_OPTS = [
+    'bgcolor',
+    'center', 'clusterrank', 'color', 'concentrate',
+    'fontcolor', 'fontname', 'fontsize',
+    'label', 'layerseq',
+    'margin', 'mclimit',
+    'nodesep', 'nslimit',
+    'ordering', 'orientation',
+    'page',
+    'rank', 'rankdir', 'ranksep', 'ratio',
+    'size'
+  ]
+
+  # a root class for any element in dot notation
+
+  class DOTSimpleElement
+
+    attr_accessor :name
+
+    def initialize (params = {})
+      @label = params['name'] ? params['name'] : ''
+    end
+
+    def to_s
+      @name
+    end
+  end
+
+  # an element that has options ( node, edge, or graph )
+
+  class DOTElement < DOTSimpleElement
+
+    # attr_reader :parent
+    attr_accessor :name, :options
+
+    def initialize (params = {}, option_list = [])
+      super(params)
+      @name   = params['name']   ? params['name']   : nil
+      @parent = params['parent'] ? params['parent'] : nil
+      @options = {}
+      option_list.each{ |i|
+        @options[i] = params[i] if params[i]
+      }
+      @options['label'] ||= @name if @name != 'node'
+    end
+
+    def each_option
+      @options.each{ |i| yield i }
+    end
+
+    def each_option_pair
+      @options.each_pair{ |key, val| yield key, val }
+    end
+
+    #def parent=( thing )
+    #    @parent.delete( self ) if defined?( @parent ) and @parent
+    #    @parent = thing
+    #end
+
+  end
+
+
+  # This is used when we build nodes that have shape=record
+  # ports don't have options :)
+
+  class DOTPort < DOTSimpleElement
+
+    attr_accessor :label
+
+    def initialize (params = {})
+      super(params)
+      @name = params['label'] ? params['label'] : ''
+    end
+
+    def to_s
+      ( @name && @name != "" ? "<#{@name}>" : "" ) + "#{@label}"
+    end
+  end
+
+  # node element
+
+  class DOTNode < DOTElement
+
+    @ports
+
+    def initialize (params = {}, option_list = NODE_OPTS)
+      super(params, option_list)
+      @ports = params['ports'] ? params['ports'] : []
+    end
+
+    def each_port
+      @ports.each { |i| yield i }
+    end
+
+    def << (thing)
+      @ports << thing
+    end
+
+    def push (thing)
+      @ports.push(thing)
+    end
+
+    def pop
+      @ports.pop
+    end
+
+    def to_s (t = '')
+
+      # This code is totally incomprehensible; it needs to be replaced!
+
+      label = @options['shape'] != 'record' && @ports.length == 0 ?
+          @options['label'] ?
+            t + $tab + "label = \"#{@options['label']}\"\n" :
+            '' :
+          t + $tab + 'label = "' + " \\\n" +
+          t + $tab2 + "#{@options['label']}| \\\n" +
+          @ports.collect{ |i|
+            t + $tab2 + i.to_s
+          }.join( "| \\\n" ) + " \\\n" +
+          t + $tab + '"' + "\n"
+
+        t + "#{@name} [\n" +
+        @options.to_a.collect{ |i|
+          i[1] && i[0] != 'label' ?
+            t + $tab + "#{i[0]} = #{i[1]}" : nil
+        }.compact.join( ",\n" ) + ( label != '' ? ",\n" : "\n" ) +
+        label +
+        t + "]\n"
+    end
+
+  end
+
+  # A subgraph element is the same to graph, but has another header in dot
+  # notation.
+
+  class DOTSubgraph < DOTElement
+
+    @nodes
+    @dot_string
+
+    def initialize (params = {}, option_list = GRAPH_OPTS)
+      super(params, option_list)
+      @nodes      = params['nodes'] ? params['nodes'] : []
+      @dot_string = 'graph'
+    end
+
+    def each_node
+      @nodes.each{ |i| yield i }
+    end
+
+    def << (thing)
+      @nodes << thing
+    end
+
+    def push (thing)
+      @nodes.push( thing )
+    end
+
+    def pop
+      @nodes.pop
+    end
+
+    def to_s (t = '')
+      hdr = t + "#{@dot_string} #{@name} {\n"
+
+      options = @options.to_a.collect{ |name, val|
+        val && name != 'label' ?
+          t + $tab + "#{name} = #{val}" :
+          name ? t + $tab + "#{name} = \"#{val}\"" : nil
+      }.compact.join( "\n" ) + "\n"
+
+      nodes = @nodes.collect{ |i|
+        i.to_s( t + $tab )
+      }.join( "\n" ) + "\n"
+      hdr + options + nodes + t + "}\n"
+    end
+
+  end
+
+  # This is a graph.
+
+  class DOTDigraph < DOTSubgraph
+
+  def initialize (params = {}, option_list = GRAPH_OPTS)
+    super(params, option_list)
+    @dot_string = 'digraph'
+  end
+
+  end
+
+  # This is an edge.
+
+  class DOTEdge < DOTElement
+
+    attr_accessor :from, :to
+
+    def initialize (params = {}, option_list = EDGE_OPTS)
+      super(params, option_list)
+      @from = params['from'] ? params['from'] : nil
+      @to   = params['to'] ? params['to'] : nil
+    end
+
+    def edge_link
+      '--'
+    end
+
+    def to_s (t = '')
+      t + "#{@from} #{edge_link} #{to} [\n" +
+        @options.to_a.collect{ |i|
+          i[1] && i[0] != 'label' ?
+            t + $tab + "#{i[0]} = #{i[1]}" :
+            i[1] ? t + $tab + "#{i[0]} = \"#{i[1]}\"" : nil
+        }.compact.join( "\n" ) + "\n#{t}]\n"
+    end
+
+  end
+
+  class DOTDirectedEdge < DOTEdge
+
+    def edge_link
+      '->'
+    end
+
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/nagios.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/nagios.rb
new file mode 100644
index 0000000..5827794
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/nagios.rb
@@ -0,0 +1,46 @@
+#--------------------
+# A script to retrieve hosts from ldap and create an importable
+# cfservd file from them
+
+require 'digest/md5'
+#require 'ldap'
+require 'puppet/external/nagios/parser.rb'
+require 'puppet/external/nagios/base.rb'
+
+module Nagios
+  NAGIOSVERSION = '1.1'
+  # yay colors
+  PINK = "[0;31m"
+  GREEN = "[0;32m"
+  YELLOW = "[0;33m"
+  SLATE = "[0;34m"
+  ORANGE = "[0;35m"
+  BLUE = "[0;36m"
+  NOCOLOR = "[0m"
+  RESET = "[0m"
+
+  def self.version
+    NAGIOSVERSION
+  end
+
+  class Config
+    def Config.import(config)
+
+      text = String.new
+
+      File.open(config) { |file|
+        file.each { |line|
+          text += line
+        }
+      }
+      parser = Nagios::Parser.new
+      parser.parse(text)
+    end
+
+    def Config.each
+      Nagios::Object.objects.each { |object|
+        yield object
+      }
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/nagios/base.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/nagios/base.rb
new file mode 100644
index 0000000..06f6987
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/nagios/base.rb
@@ -0,0 +1,472 @@
+# The base class for all of our Nagios object types.  Everything else
+# is mostly just data.
+class Nagios::Base
+
+  class UnknownNagiosType < RuntimeError # When an unknown type is asked for by name.
+  end
+
+  include Enumerable
+
+  class << self
+    attr_accessor :parameters, :derivatives, :ocs, :name, :att
+    attr_accessor :ldapbase
+
+    attr_writer :namevar
+
+    attr_reader :superior
+  end
+
+  # Attach one class to another.
+  def self.attach(hash)
+    @attach ||= {}
+    hash.each do |n, v| @attach[n] = v end
+  end
+
+  # Convert a parameter to camelcase
+  def self.camelcase(param)
+    param.gsub(/_./) do |match|
+      match.sub(/_/,'').capitalize
+    end
+  end
+
+  # Uncamelcase a parameter.
+  def self.decamelcase(param)
+    param.gsub(/[A-Z]/) do |match|
+      "_#{match.downcase}"
+    end
+  end
+
+  # Create a new instance of a given class.
+  def self.create(name, args = {})
+    name = name.intern if name.is_a? String
+
+    if @types.include?(name)
+      @types[name].new(args)
+    else
+      raise UnknownNagiosType, "Unknown type #{name}"
+    end
+  end
+
+  # Yield each type in turn.
+  def self.eachtype
+    @types.each do |name, type|
+      yield [name, type]
+    end
+  end
+
+  # Create a mapping.
+  def self.map(hash)
+    @map ||= {}
+    hash.each do |n, v| @map[n] = v end
+  end
+
+  # Return a mapping (or nil) for a param
+  def self.mapping(name)
+    name = name.intern if name.is_a? String
+    if defined?(@map)
+      @map[name]
+    else
+      nil
+    end
+  end
+
+  # Return the namevar for the canonical name.
+  def self.namevar
+    if defined?(@namevar)
+      return @namevar
+    else
+      if parameter?(:name)
+        return :name
+      elsif tmp = (self.name.to_s + "_name").intern and parameter?(tmp)
+        @namevar = tmp
+        return @namevar
+      else
+        raise "Type #{self.name} has no name var"
+      end
+    end
+  end
+
+  # Create a new type.
+  def self.newtype(name, &block)
+    name = name.intern if name.is_a? String
+
+    @types ||= {}
+
+    # Create the class, with the correct name.
+    t = Class.new(self)
+    t.name = name
+
+    # Everyone gets this.  There should probably be a better way, and I
+    # should probably hack the attribute system to look things up based on
+    # this "use" setting, but, eh.
+    t.parameters = [:use]
+
+    const_set(name.to_s.capitalize,t)
+
+    # Evaluate the passed block.  This should usually define all of the work.
+    t.class_eval(&block)
+
+    @types[name] = t
+  end
+
+  # Define both the normal case and camelcase method for a parameter
+  def self.paramattr(name)
+    camel = camelcase(name)
+    param = name
+
+    [name, camel].each do |method|
+      define_method(method) do
+        @parameters[param]
+      end
+
+      define_method(method.to_s + "=") do |value|
+        @parameters[param] = value
+      end
+    end
+
+  end
+
+  # Is the specified name a valid parameter?
+  def self.parameter?(name)
+    name = name.intern if name.is_a? String
+    @parameters.include?(name)
+  end
+
+  # Manually set the namevar
+  def self.setnamevar(name)
+    name = name.intern if name.is_a? String
+    @namevar = name
+  end
+
+  # Set the valid parameters for this class
+  def self.setparameters(*array)
+    @parameters += array
+  end
+
+  # Set the superior ldap object class.  Seems silly to include this
+  # in this class, but, eh.
+  def self.setsuperior(name)
+    @superior = name
+  end
+
+  # Parameters to suppress in output.
+  def self.suppress(name)
+    @suppress ||= []
+    @suppress << name
+  end
+
+  # Whether a given parameter is suppressed.
+  def self.suppress?(name)
+    defined?(@suppress) and @suppress.include?(name)
+  end
+
+  # Return our name as the string.
+  def self.to_s
+    self.name.to_s
+  end
+
+  # Return a type by name.
+  def self.type(name)
+    name = name.intern if name.is_a? String
+
+    @types[name]
+  end
+
+  # Convenience methods.
+  def [](param)
+    send(param)
+  end
+
+  # Convenience methods.
+  def []=(param,value)
+    send(param.to_s + "=", value)
+  end
+
+  # Iterate across all ofour set parameters.
+  def each
+    @parameters.each { |param,value|
+      yield(param,value)
+    }
+  end
+
+  # Initialize our object, optionally with a list of parameters.
+  def initialize(args = {})
+    @parameters = {}
+
+    args.each { |param,value|
+      self[param] = value
+    }
+    if @namevar == :_naginator_name
+      self['_naginator_name'] = self['name']
+    end
+  end
+
+  # Handle parameters like attributes.
+  def method_missing(mname, *args)
+    pname = mname.to_s
+    pname.sub!(/=/, '')
+
+    if self.class.parameter?(pname)
+      if pname =~ /A-Z/
+        pname = self.class.decamelcase(pname)
+      end
+      self.class.paramattr(pname)
+
+      # Now access the parameters directly, to make it at least less
+      # likely we'll end up in an infinite recursion.
+      if mname.to_s =~ /=$/
+        @parameters[pname] = args.first
+      else
+        return @parameters[mname]
+      end
+    else
+      super
+    end
+  end
+
+  # Retrieve our name, through a bit of redirection.
+  def name
+    send(self.class.namevar)
+  end
+
+  # This is probably a bad idea.
+  def name=(value)
+    unless self.class.namevar.to_s == "name"
+      send(self.class.namevar.to_s + "=", value)
+    end
+  end
+
+  def namevar
+    (self.type + "_name").intern
+  end
+
+  def parammap(param)
+    unless defined?(@map)
+      map = {
+        self.namevar => "cn"
+      }
+      map.update(self.class.map) if self.class.map
+    end
+    if map.include?(param)
+      return map[param]
+    else
+      return "nagios-" + param.id2name.gsub(/_/,'-')
+    end
+  end
+
+  def parent
+    unless defined?(self.class.attached)
+      puts "Duh, you called parent on an unattached class"
+      return
+    end
+
+    klass,param = self.class.attached
+    unless @parameters.include?(param)
+      puts "Huh, no attachment param"
+      return
+    end
+    klass[@parameters[param]]
+  end
+
+  # okay, this sucks
+  # how do i get my list of ocs?
+  def to_ldif
+    str = self.dn + "\n"
+    ocs = Array.new
+    if self.class.ocs
+      # i'm storing an array, so i have to flatten it and stuff
+      kocs = self.class.ocs
+      ocs.push(*kocs)
+    end
+    ocs.push "top"
+    oc = self.class.to_s
+    oc.sub!(/Nagios/,'nagios')
+    oc.sub!(/::/,'')
+    ocs.push oc
+    ocs.each { |oc|
+      str += "objectclass: #{oc}\n"
+    }
+    @parameters.each { |name,value|
+      next if self.class.suppress.include?(name)
+      ldapname = self.parammap(name)
+      str += ldapname + ": #{value}\n"
+    }
+    str += "\n"
+  end
+
+  def to_s
+    str = "define #{self.type} {\n"
+
+    @parameters.keys.sort.each { |param|
+      value = @parameters[param]
+      str += %{\t%-30s %s\n} % [ param,
+        if value.is_a? Array
+          value.join(",").sub(';', '\;')
+        else
+          value.to_s.sub(';', '\;')
+        end
+        ]
+    }
+
+    str += "}\n"
+
+    str
+  end
+
+  # The type of object we are.
+  def type
+    self.class.name
+  end
+
+  # object types
+  newtype :host do
+    setparameters :host_name, :alias, :display_name, :address, :parents,
+      :hostgroups, :check_command, :initial_state, :max_check_attempts,
+      :check_interval, :retry_interval, :active_checks_enabled,
+      :passive_checks_enabled, :check_period, :obsess_over_host,
+      :check_freshness, :freshness_threshold, :event_handler,
+      :event_handler_enabled, :low_flap_threshold, :high_flap_threshold,
+      :flap_detection_enabled, :flap_detection_options,
+      :failure_prediction_enabled, :process_perf_data,
+      :retain_status_information, :retain_nonstatus_information, :contacts,
+      :contact_groups, :notification_interval, :first_notification_delay,
+      :notification_period, :notification_options, :notifications_enabled,
+      :stalking_options, :notes, :notes_url, :action_url, :icon_image,
+      :icon_image_alt, :vrml_image, :statusmap_image, "2d_coords".intern,
+      "3d_coords".intern,
+      :register, :use,
+      :realm, :poller_tag, :business_impact
+
+    setsuperior "person"
+    map :address => "ipHostNumber"
+  end
+
+  newtype :hostgroup do
+    setparameters :hostgroup_name, :alias, :members, :hostgroup_members, :notes,
+      :notes_url, :action_url,
+      :register, :use,
+      :realm
+  end
+
+  newtype :service do
+    attach :host => :host_name
+    setparameters :host_name, :hostgroup_name, :service_description,
+      :display_name, :servicegroups, :is_volatile, :check_command,
+      :initial_state, :max_check_attempts, :check_interval, :retry_interval,
+      :normal_check_interval, :retry_check_interval, :active_checks_enabled,
+      :passive_checks_enabled, :parallelize_check, :check_period,
+      :obsess_over_service, :check_freshness, :freshness_threshold,
+      :event_handler, :event_handler_enabled, :low_flap_threshold,
+      :high_flap_threshold, :flap_detection_enabled,:flap_detection_options,
+      :process_perf_data, :failure_prediction_enabled, :retain_status_information,
+      :retain_nonstatus_information, :notification_interval,
+      :first_notification_delay, :notification_period, :notification_options,
+      :notifications_enabled, :contacts, :contact_groups, :stalking_options,
+      :notes, :notes_url, :action_url, :icon_image, :icon_image_alt,
+      :register, :use,
+      :_naginator_name,
+      :poller_tag, :business_impact
+
+    suppress :host_name
+
+    setnamevar :_naginator_name
+  end
+
+  newtype :servicegroup do
+    setparameters :servicegroup_name, :alias, :members, :servicegroup_members,
+      :notes, :notes_url, :action_url,
+      :register, :use
+  end
+
+  newtype :contact do
+    setparameters :contact_name, :alias, :contactgroups,
+      :host_notifications_enabled, :service_notifications_enabled,
+      :host_notification_period, :service_notification_period,
+      :host_notification_options, :service_notification_options,
+      :host_notification_commands, :service_notification_commands,
+      :email, :pager, :address1, :address2, :address3, :address4,
+      :address5, :address6, :can_submit_commands, :retain_status_information,
+      :retain_nonstatus_information,
+      :register, :use
+
+    setsuperior "person"
+  end
+
+  newtype :contactgroup do
+    setparameters :contactgroup_name, :alias, :members, :contactgroup_members,
+      :register, :use
+  end
+
+  # TODO - We should support generic time periods here eg "day 1 - 15"
+  newtype :timeperiod do
+    setparameters :timeperiod_name, :alias, :sunday, :monday, :tuesday,
+      :wednesday, :thursday, :friday, :saturday, :exclude,
+      :register, :use
+  end
+
+  newtype :command do
+    setparameters :command_name, :command_line,
+    :poller_tag
+  end
+
+  newtype :servicedependency do
+    setparameters :dependent_host_name, :dependent_hostgroup_name,
+      :dependent_service_description, :host_name, :hostgroup_name,
+      :service_description, :inherits_parent, :execution_failure_criteria,
+      :notification_failure_criteria, :dependency_period,
+      :register, :use,
+      :_naginator_name
+
+    setnamevar :_naginator_name
+  end
+
+  newtype :serviceescalation do
+    setparameters :host_name, :hostgroup_name, :servicegroup_name,
+      :service_description, :contacts, :contact_groups,
+      :first_notification, :last_notification, :notification_interval,
+      :escalation_period, :escalation_options,
+      :register, :use,
+      :_naginator_name
+
+    setnamevar :_naginator_name
+  end
+
+  newtype :hostdependency do
+    setparameters :dependent_host_name, :dependent_hostgroup_name, :host_name,
+      :hostgroup_name, :inherits_parent, :execution_failure_criteria,
+      :notification_failure_criteria, :dependency_period,
+      :register, :use,
+      :_naginator_name
+
+    setnamevar :_naginator_name
+  end
+
+  newtype :hostescalation do
+    setparameters :host_name, :hostgroup_name, :contacts, :contact_groups,
+      :first_notification, :last_notification, :notification_interval,
+      :escalation_period, :escalation_options,
+      :register, :use,
+      :_naginator_name
+
+    setnamevar :_naginator_name
+  end
+
+  newtype :hostextinfo do
+    setparameters :host_name, :notes, :notes_url, :icon_image, :icon_image_alt,
+      :vrml_image, :statusmap_image, "2d_coords".intern, "3d_coords".intern,
+      :register, :use
+
+    setnamevar :host_name
+  end
+
+  newtype :serviceextinfo do
+
+    setparameters :host_name, :service_description, :notes, :notes_url,
+      :action_url, :icon_image, :icon_image_alt,
+      :register, :use,
+      :_naginator_name
+
+    setnamevar :_naginator_name
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/nagios/grammar.ry b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/nagios/grammar.ry
new file mode 100644
index 0000000..2b756aa
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/nagios/grammar.ry
@@ -0,0 +1,248 @@
+# vim: syntax=ruby
+class Nagios::Parser
+
+token DEFINE NAME PARAM LCURLY RCURLY VALUE RETURN
+
+rule
+decls: decl { return val[0] if val[0] }
+    | decls decl {
+        if val[1].nil?
+            result = val[0]
+        else
+            if val[0].nil?
+                result = val[1]
+            else
+                result = [ val[0], val[1] ].flatten
+            end
+        end
+    }
+    ;
+
+decl: object { result = [val[0]] }
+    | RETURN { result = nil }
+    ;
+
+object: DEFINE NAME LCURLY returns vars RCURLY {
+        result = Nagios::Base.create(val[1],val[4])
+    }
+    ;
+
+vars: var
+    | vars var {
+        val[1].each {|p,v|
+            val[0][p] = v
+        }
+        result = val[0]
+    }
+    ;
+
+var: PARAM VALUE returns { result = {val[0] => val[1]} }
+    | PARAM returns { result = {val[0] => "" } }
+    ;
+
+returns: RETURN
+    | RETURN returns
+    ;
+
+end
+
+----inner
+require 'strscan'
+
+class ::Nagios::Parser::SyntaxError < RuntimeError; end
+
+def parse(src)
+  if src.respond_to?("force_encoding") then
+    src.force_encoding("ASCII-8BIT")
+  end
+  @ss = StringScanner.new(src)
+
+  # state variables
+  @in_parameter_value = false
+  @in_object_definition = false
+  @done = false
+
+  @line = 1
+  @yydebug = true
+
+  do_parse
+end
+
+# This tokenizes the outside of object definitions,
+# and detects when we start defining an object.
+# We ignore whitespaces, comments and inline comments.
+# We yield when finding newlines, the "define" keyword,
+#     the object name and the opening curly bracket.
+def tokenize_outside_definitions
+  case
+  when (chars = @ss.skip(/[ \t]+/))             # ignore whitespace /\s+/
+    ;
+
+  when (text = @ss.scan(/\#.*$/))               # ignore comments
+    ;
+
+  when (text = @ss.scan(/;.*$/))                # ignore inline comments
+    ;
+
+  when (text = @ss.scan(/\n/))                  # newline
+    [:RETURN, text]
+
+  when (text = @ss.scan(/\b(define)\b/))        # the "define" keyword 
+    [:DEFINE, text]
+
+  when (text = @ss.scan(/[^{ \t\n]+/))          # the name of the object being defined (everything not an opening curly bracket or a separator)
+    [:NAME, text]
+
+  when (text = @ss.scan(/\{/))                  # the opening curly bracket - we enter object definition
+    @in_object_definition = true
+    [:LCURLY, text]
+
+  else
+    text = @ss.string[@ss.pos .. -1]
+    raise  ScanError, "can not match: '#{text}'"
+  end  # case
+end
+
+# This tokenizes until we find the parameter name.
+def tokenize_parameter_name
+  case
+  when (chars = @ss.skip(/[ \t]+/))             # ignore whitespace /\s+/
+    ;
+
+  when (text = @ss.scan(/\#.*$/))               # ignore comments
+    ;
+
+  when (text = @ss.scan(/;.*$/))                # ignore inline comments
+    ;
+
+  when (text = @ss.scan(/\n/))                  # newline
+    [:RETURN, text]
+
+  when (text = @ss.scan(/\}/))                  # closing curly bracket : end of definition
+    @in_object_definition = false
+    [:RCURLY, text]
+
+  when (not @in_parameter_value and (text = @ss.scan(/\S+/)))    # This is the name of the parameter
+    @in_parameter_value = true
+    [:PARAM, text]
+
+  else
+    text = @ss.string[@ss.pos .. -1]
+    raise  ScanError, "can not match: '#{text}'"
+  end  # case
+end
+
+# This tokenizes the parameter value.
+# There is a special handling for lines containing semicolons :
+#     - unescaped semicolons are line comments (and should stop parsing of the line)
+#     - escaped (with backslash \) semicolons should be kept in the parameter value (without the backslash)
+def tokenize_parameter_value
+  case
+  when (chars = @ss.skip(/[ \t]+/))             # ignore whitespace /\s+/
+    ;
+
+  when (text = @ss.scan(/\#.*$/))               # ignore comments
+    ;
+
+  when (text = @ss.scan(/\n/))                  # newline
+    @in_parameter_value = false
+    [:RETURN, text]
+
+  when (text = @ss.scan(/.+$/))                 # Value of parameter
+    @in_parameter_value = false
+
+    # Special handling of inline comments (;) and escaped semicolons (\;)
+
+    # We split the string on escaped semicolons (\;),
+    # Then we rebuild it as long as there are no inline comments (;)
+    # We join the rebuilt string with unescaped semicolons (on purpose)
+    array = text.split('\;', 0)
+
+    text = ""
+
+    array.each do |elt|
+
+      # Now we split at inline comments. If we have more than 1 element in the array
+      # it means we have an inline comment, so we are able to stop parsing
+      # However we still want to reconstruct the string with its first part (before the comment)
+      linearray = elt.split(';', 0)
+
+      # Let's reconstruct the string with a (unescaped) semicolon
+      if text != "" then
+        text += ';'
+      end
+      text += linearray[0]
+
+      # Now we can stop
+      if linearray.length > 1 then
+        break                                
+      end
+    end
+
+
+    # We strip the text to remove spaces between end of string and beginning of inline comment
+    [:VALUE, text.strip]
+
+  else
+    text = @ss.string[@ss.pos .. -1]
+    raise  ScanError, "can not match: '#{text}'"
+  end  # case
+end
+
+# This tokenizes inside an object definition.
+# Two cases : parameter name and parameter value
+def tokenize_inside_definitions
+  if @in_parameter_value
+    tokenize_parameter_value
+  else
+    tokenize_parameter_name
+  end
+end
+
+# The lexer.  Very simple.
+def token
+  text = @ss.peek(1)
+  @line  +=  1  if text == "\n"
+
+  token = if @in_object_definition
+    tokenize_inside_definitions
+  else
+    tokenize_outside_definitions
+  end
+  token
+end
+
+def next_token
+  return if @ss.eos?
+
+  # skips empty actions
+  until _next_token = token or @ss.eos?; end
+  _next_token
+end
+
+def yydebug
+  1
+end
+
+def yywrap
+  0
+end
+
+def on_error(token, value, vstack )
+  #    text = @ss.string[@ss.pos .. -1]
+  text = @ss.peek(20)
+  msg = ""
+  unless value.nil?
+    msg = "line #{@line}: syntax error at value '#{value}' : #{text}"
+  else
+    msg = "line #{@line}: syntax error at token '#{token}' : #{text}"
+  end
+  if @ss.eos?
+    msg = "line #{@line}: Unexpected end of file"
+  end
+  if token == '$end'.intern
+    puts "okay, this is silly"
+  else
+    raise ::Nagios::Parser::SyntaxError, msg
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/nagios/makefile b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/nagios/makefile
new file mode 100644
index 0000000..a3c1ba1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/nagios/makefile
@@ -0,0 +1,9 @@
+all: parser.rb
+
+debug: parser.rb setdebug
+
+parser.rb: grammar.ry
+	racc -oparser.rb grammar.ry
+
+setdebug:
+	perl -pi -e 's{\@yydebug =.*$$}{\@yydebug = true}' parser.rb
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/nagios/parser.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/nagios/parser.rb
new file mode 100644
index 0000000..c97e30a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/nagios/parser.rb
@@ -0,0 +1,400 @@
+#
+# DO NOT MODIFY!!!!
+# This file is automatically generated by Racc 1.4.9
+# from Racc grammer file "".
+#
+
+require 'racc/parser.rb'
+module Nagios
+  class Parser < Racc::Parser
+
+module_eval(<<'...end grammar.ry/module_eval...', 'grammar.ry', 50)
+require 'strscan'
+
+class ::Nagios::Parser::SyntaxError < RuntimeError; end
+
+def parse(src)
+  if src.respond_to?("force_encoding") then
+    src.force_encoding("ASCII-8BIT")
+  end
+  @ss = StringScanner.new(src)
+
+  # state variables
+  @in_parameter_value = false
+  @in_object_definition = false
+  @done = false
+
+  @line = 1
+  @yydebug = true
+
+  do_parse
+end
+
+# This tokenizes the outside of object definitions,
+# and detects when we start defining an object.
+# We ignore whitespaces, comments and inline comments.
+# We yield when finding newlines, the "define" keyword,
+#     the object name and the opening curly bracket.
+def tokenize_outside_definitions
+  case
+  when (chars = @ss.skip(/[ \t]+/))             # ignore whitespace /\s+/
+    ;
+
+  when (text = @ss.scan(/\#.*$/))               # ignore comments
+    ;
+
+  when (text = @ss.scan(/;.*$/))                # ignore inline comments
+    ;
+
+  when (text = @ss.scan(/\n/))                  # newline
+    [:RETURN, text]
+
+  when (text = @ss.scan(/\b(define)\b/))        # the "define" keyword 
+    [:DEFINE, text]
+
+  when (text = @ss.scan(/[^{ \t\n]+/))          # the name of the object being defined (everything not an opening curly bracket or a separator)
+    [:NAME, text]
+
+  when (text = @ss.scan(/\{/))                  # the opening curly bracket - we enter object definition
+    @in_object_definition = true
+    [:LCURLY, text]
+
+  else
+    text = @ss.string[@ss.pos .. -1]
+    raise  ScanError, "can not match: '#{text}'"
+  end  # case
+end
+
+# This tokenizes until we find the parameter name.
+def tokenize_parameter_name
+  case
+  when (chars = @ss.skip(/[ \t]+/))             # ignore whitespace /\s+/
+    ;
+
+  when (text = @ss.scan(/\#.*$/))               # ignore comments
+    ;
+
+  when (text = @ss.scan(/;.*$/))                # ignore inline comments
+    ;
+
+  when (text = @ss.scan(/\n/))                  # newline
+    [:RETURN, text]
+
+  when (text = @ss.scan(/\}/))                  # closing curly bracket : end of definition
+    @in_object_definition = false
+    [:RCURLY, text]
+
+  when (not @in_parameter_value and (text = @ss.scan(/\S+/)))    # This is the name of the parameter
+    @in_parameter_value = true
+    [:PARAM, text]
+
+  else
+    text = @ss.string[@ss.pos .. -1]
+    raise  ScanError, "can not match: '#{text}'"
+  end  # case
+end
+
+# This tokenizes the parameter value.
+# There is a special handling for lines containing semicolons :
+#     - unescaped semicolons are line comments (and should stop parsing of the line)
+#     - escaped (with backslash \) semicolons should be kept in the parameter value (without the backslash)
+def tokenize_parameter_value
+  case
+  when (chars = @ss.skip(/[ \t]+/))             # ignore whitespace /\s+/
+    ;
+
+  when (text = @ss.scan(/\#.*$/))               # ignore comments
+    ;
+
+  when (text = @ss.scan(/\n/))                  # newline
+    @in_parameter_value = false
+    [:RETURN, text]
+
+  when (text = @ss.scan(/.+$/))                 # Value of parameter
+    @in_parameter_value = false
+
+    # Special handling of inline comments (;) and escaped semicolons (\;)
+
+    # We split the string on escaped semicolons (\;),
+    # Then we rebuild it as long as there are no inline comments (;)
+    # We join the rebuilt string with unescaped semicolons (on purpose)
+    array = text.split('\;', 0)
+
+    text = ""
+
+    array.each do |elt|
+
+      # Now we split at inline comments. If we have more than 1 element in the array
+      # it means we have an inline comment, so we are able to stop parsing
+      # However we still want to reconstruct the string with its first part (before the comment)
+      linearray = elt.split(';', 0)
+
+      # Let's reconstruct the string with a (unescaped) semicolon
+      if text != "" then
+        text += ';'
+      end
+      text += linearray[0]
+
+      # Now we can stop
+      if linearray.length > 1 then
+        break                                
+      end
+    end
+
+
+    # We strip the text to remove spaces between end of string and beginning of inline comment
+    [:VALUE, text.strip]
+
+  else
+    text = @ss.string[@ss.pos .. -1]
+    raise  ScanError, "can not match: '#{text}'"
+  end  # case
+end
+
+# This tokenizes inside an object definition.
+# Two cases : parameter name and parameter value
+def tokenize_inside_definitions
+  if @in_parameter_value
+    tokenize_parameter_value
+  else
+    tokenize_parameter_name
+  end
+end
+
+# The lexer.  Very simple.
+def token
+  text = @ss.peek(1)
+  @line  +=  1  if text == "\n"
+
+  token = if @in_object_definition
+    tokenize_inside_definitions
+  else
+    tokenize_outside_definitions
+  end
+  token
+end
+
+def next_token
+  return if @ss.eos?
+
+  # skips empty actions
+  until _next_token = token or @ss.eos?; end
+  _next_token
+end
+
+def yydebug
+  1
+end
+
+def yywrap
+  0
+end
+
+def on_error(token, value, vstack )
+  #    text = @ss.string[@ss.pos .. -1]
+  text = @ss.peek(20)
+  msg = ""
+  unless value.nil?
+    msg = "line #{@line}: syntax error at value '#{value}' : #{text}"
+  else
+    msg = "line #{@line}: syntax error at token '#{token}' : #{text}"
+  end
+  if @ss.eos?
+    msg = "line #{@line}: Unexpected end of file"
+  end
+  if token == '$end'.intern
+    puts "okay, this is silly"
+  else
+    raise ::Nagios::Parser::SyntaxError, msg
+  end
+end
+...end grammar.ry/module_eval...
+##### State transition tables begin ###
+
+racc_action_table = [
+     8,     3,     3,    14,    12,    18,    10,     4,     4,    20,
+    12,    14,    12,     9,     6,    12 ]
+
+racc_action_check = [
+     5,     0,     5,    13,     9,    13,     8,     0,     5,    14,
+    14,    11,    12,     6,     3,    20 ]
+
+racc_action_pointer = [
+    -1,   nil,   nil,    11,   nil,     0,     8,   nil,     6,    -4,
+   nil,     7,     4,    -1,     2,   nil,   nil,   nil,   nil,   nil,
+     7,   nil ]
+
+racc_action_default = [
+   -12,    -1,    -3,   -12,    -4,   -12,   -12,    -2,   -12,   -12,
+    22,   -12,   -10,   -12,   -12,    -6,   -11,    -7,    -5,    -9,
+   -12,    -8 ]
+
+racc_goto_table = [
+    11,     1,    15,    16,    17,    19,     7,    13,     5,   nil,
+   nil,    21 ]
+
+racc_goto_check = [
+     4,     2,     6,     4,     6,     4,     2,     5,     1,   nil,
+   nil,     4 ]
+
+racc_goto_pointer = [
+   nil,     8,     1,   nil,    -9,    -4,    -9 ]
+
+racc_goto_default = [
+   nil,   nil,   nil,     2,   nil,   nil,   nil ]
+
+racc_reduce_table = [
+  0, 0, :racc_error,
+  1, 10, :_reduce_1,
+  2, 10, :_reduce_2,
+  1, 11, :_reduce_3,
+  1, 11, :_reduce_4,
+  6, 12, :_reduce_5,
+  1, 14, :_reduce_none,
+  2, 14, :_reduce_7,
+  3, 15, :_reduce_8,
+  2, 15, :_reduce_9,
+  1, 13, :_reduce_none,
+  2, 13, :_reduce_none ]
+
+racc_reduce_n = 12
+
+racc_shift_n = 22
+
+racc_token_table = {
+  false => 0,
+  :error => 1,
+  :DEFINE => 2,
+  :NAME => 3,
+  :PARAM => 4,
+  :LCURLY => 5,
+  :RCURLY => 6,
+  :VALUE => 7,
+  :RETURN => 8 }
+
+racc_nt_base = 9
+
+racc_use_result_var = true
+
+Racc_arg = [
+  racc_action_table,
+  racc_action_check,
+  racc_action_default,
+  racc_action_pointer,
+  racc_goto_table,
+  racc_goto_check,
+  racc_goto_default,
+  racc_goto_pointer,
+  racc_nt_base,
+  racc_reduce_table,
+  racc_token_table,
+  racc_shift_n,
+  racc_reduce_n,
+  racc_use_result_var ]
+
+Racc_token_to_s_table = [
+  "$end",
+  "error",
+  "DEFINE",
+  "NAME",
+  "PARAM",
+  "LCURLY",
+  "RCURLY",
+  "VALUE",
+  "RETURN",
+  "$start",
+  "decls",
+  "decl",
+  "object",
+  "returns",
+  "vars",
+  "var" ]
+
+Racc_debug_parser = false
+
+##### State transition tables end #####
+
+# reduce 0 omitted
+
+module_eval(<<'.,.,', 'grammar.ry', 6)
+  def _reduce_1(val, _values, result)
+     return val[0] if val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ry', 8)
+  def _reduce_2(val, _values, result)
+            if val[1].nil?
+            result = val[0]
+        else
+            if val[0].nil?
+                result = val[1]
+            else
+                result = [ val[0], val[1] ].flatten
+            end
+        end
+    
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ry', 20)
+  def _reduce_3(val, _values, result)
+     result = [val[0]] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ry', 21)
+  def _reduce_4(val, _values, result)
+     result = nil 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ry', 25)
+  def _reduce_5(val, _values, result)
+            result = Nagios::Base.create(val[1],val[4])
+    
+    result
+  end
+.,.,
+
+# reduce 6 omitted
+
+module_eval(<<'.,.,', 'grammar.ry', 31)
+  def _reduce_7(val, _values, result)
+            val[1].each {|p,v|
+            val[0][p] = v
+        }
+        result = val[0]
+    
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ry', 38)
+  def _reduce_8(val, _values, result)
+     result = {val[0] => val[1]} 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ry', 39)
+  def _reduce_9(val, _values, result)
+     result = {val[0] => "" } 
+    result
+  end
+.,.,
+
+# reduce 10 omitted
+
+# reduce 11 omitted
+
+def _reduce_none(val, _values, result)
+  val[0]
+end
+
+  end   # class Parser
+  end   # module Nagios
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/pson/common.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/pson/common.rb
new file mode 100644
index 0000000..832d3f7
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/pson/common.rb
@@ -0,0 +1,385 @@
+require 'puppet/external/pson/version'
+
+module PSON
+  class << self
+    # If _object_ is string-like parse the string and return the parsed result
+    # as a Ruby data structure. Otherwise generate a PSON text from the Ruby
+    # data structure object and return it.
+    #
+    # The _opts_ argument is passed through to generate/parse respectively, see
+    # generate and parse for their documentation.
+    def [](object, opts = {})
+      if object.respond_to? :to_str
+        PSON.parse(object.to_str, opts => {})
+      else
+        PSON.generate(object, opts => {})
+      end
+    end
+
+    # Returns the PSON parser class, that is used by PSON. This might be either
+    # PSON::Ext::Parser or PSON::Pure::Parser.
+    attr_reader :parser
+
+    # Set the PSON parser class _parser_ to be used by PSON.
+    def parser=(parser) # :nodoc:
+      @parser = parser
+      remove_const :Parser if const_defined? :Parser
+      const_set :Parser, parser
+    end
+
+    def registered_document_types
+      @registered_document_types ||= {}
+    end
+
+    # Register a class-constant for deserializaion.
+    def register_document_type(name,klass)
+      registered_document_types[name.to_s] = klass
+    end
+
+    # Return the constant located at _path_.
+    # Anything may be registered as a path by calling register_path, above.
+    # Otherwise, the format of _path_ has to be either ::A::B::C or A::B::C.
+    # In either of these cases A has to be defined in Object (e.g. the path
+    # must be an absolute namespace path.  If the constant doesn't exist at
+    # the given path, an ArgumentError is raised.
+    def deep_const_get(path) # :nodoc:
+      path = path.to_s
+      registered_document_types[path] || path.split(/::/).inject(Object) do |p, c|
+        case
+        when c.empty?             then p
+        when p.const_defined?(c)  then p.const_get(c)
+        else                      raise ArgumentError, "can't find const for unregistered document type #{path}"
+        end
+      end
+    end
+
+    # Set the module _generator_ to be used by PSON.
+    def generator=(generator) # :nodoc:
+      @generator = generator
+      generator_methods = generator::GeneratorMethods
+      for const in generator_methods.constants
+        klass = deep_const_get(const)
+        modul = generator_methods.const_get(const)
+        klass.class_eval do
+          instance_methods(false).each do |m|
+            m.to_s == 'to_pson' and remove_method m
+          end
+          include modul
+        end
+      end
+      self.state = generator::State
+      const_set :State, self.state
+    end
+
+    # Returns the PSON generator modul, that is used by PSON. This might be
+    # either PSON::Ext::Generator or PSON::Pure::Generator.
+    attr_reader :generator
+
+    # Returns the PSON generator state class, that is used by PSON. This might
+    # be either PSON::Ext::Generator::State or PSON::Pure::Generator::State.
+    attr_accessor :state
+
+    # This is create identifier, that is used to decide, if the _pson_create_
+    # hook of a class should be called. It defaults to 'document_type'.
+    attr_accessor :create_id
+  end
+  self.create_id = 'document_type'
+
+  NaN           = (-1.0) ** 0.5
+
+  Infinity      = 1.0/0
+
+  MinusInfinity = -Infinity
+
+  # The base exception for PSON errors.
+  class PSONError < StandardError; end
+
+  # This exception is raised, if a parser error occurs.
+  class ParserError < PSONError; end
+
+  # This exception is raised, if the nesting of parsed datastructures is too
+  # deep.
+  class NestingError < ParserError; end
+
+  # This exception is raised, if a generator or unparser error occurs.
+  class GeneratorError < PSONError; end
+  # For backwards compatibility
+  UnparserError = GeneratorError
+
+  # If a circular data structure is encountered while unparsing
+  # this exception is raised.
+  class CircularDatastructure < GeneratorError; end
+
+  # This exception is raised, if the required unicode support is missing on the
+  # system. Usually this means, that the iconv library is not installed.
+  class MissingUnicodeSupport < PSONError; end
+
+  module_function
+
+  # Parse the PSON string _source_ into a Ruby data structure and return it.
+  #
+  # _opts_ can have the following
+  # keys:
+  # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
+  #   structures. Disable depth checking with :max_nesting => false, it defaults
+  #   to 19.
+  # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
+  #   defiance of RFC 4627 to be parsed by the Parser. This option defaults
+  #   to false.
+  # * *create_additions*: If set to false, the Parser doesn't create
+  #   additions even if a matching class and create_id was found. This option
+  #   defaults to true.
+  def parse(source, opts = {})
+    PSON.parser.new(source, opts).parse
+  end
+
+  # Parse the PSON string _source_ into a Ruby data structure and return it.
+  # The bang version of the parse method, defaults to the more dangerous values
+  # for the _opts_ hash, so be sure only to parse trusted _source_ strings.
+  #
+  # _opts_ can have the following keys:
+  # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
+  #   structures. Enable depth checking with :max_nesting => anInteger. The parse!
+  #   methods defaults to not doing max depth checking: This can be dangerous,
+  #   if someone wants to fill up your stack.
+  # * *allow_nan*: If set to true, allow NaN, Infinity, and -Infinity in
+  #   defiance of RFC 4627 to be parsed by the Parser. This option defaults
+  #   to true.
+  # * *create_additions*: If set to false, the Parser doesn't create
+  #   additions even if a matching class and create_id was found. This option
+  #   defaults to true.
+  def parse!(source, opts = {})
+    opts = {
+      :max_nesting => false,
+      :allow_nan => true
+    }.update(opts)
+    PSON.parser.new(source, opts).parse
+  end
+
+  # Unparse the Ruby data structure _obj_ into a single line PSON string and
+  # return it. _state_ is
+  # * a PSON::State object,
+  # * or a Hash like object (responding to to_hash),
+  # * an object convertible into a hash by a to_h method,
+  # that is used as or to configure a State object.
+  #
+  # It defaults to a state object, that creates the shortest possible PSON text
+  # in one line, checks for circular data structures and doesn't allow NaN,
+  # Infinity, and -Infinity.
+  #
+  # A _state_ hash can have the following keys:
+  # * *indent*: a string used to indent levels (default: ''),
+  # * *space*: a string that is put after, a : or , delimiter (default: ''),
+  # * *space_before*: a string that is put before a : pair delimiter (default: ''),
+  # * *object_nl*: a string that is put at the end of a PSON object (default: ''),
+  # * *array_nl*: a string that is put at the end of a PSON array (default: ''),
+  # * *check_circular*: true if checking for circular data structures
+  #   should be done (the default), false otherwise.
+  # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
+  #   generated, otherwise an exception is thrown, if these values are
+  #   encountered. This options defaults to false.
+  # * *max_nesting*: The maximum depth of nesting allowed in the data
+  #   structures from which PSON is to be generated. Disable depth checking
+  #   with :max_nesting => false, it defaults to 19.
+  #
+  # See also the fast_generate for the fastest creation method with the least
+  # amount of sanity checks, and the pretty_generate method for some
+  # defaults for a pretty output.
+  def generate(obj, state = nil)
+    if state
+      state = State.from_state(state)
+    else
+      state = State.new
+    end
+    obj.to_pson(state)
+  end
+
+  # :stopdoc:
+  # I want to deprecate these later, so I'll first be silent about them, and
+  # later delete them.
+  alias unparse generate
+  module_function :unparse
+  # :startdoc:
+
+  # Unparse the Ruby data structure _obj_ into a single line PSON string and
+  # return it. This method disables the checks for circles in Ruby objects, and
+  # also generates NaN, Infinity, and, -Infinity float values.
+  #
+  # *WARNING*: Be careful not to pass any Ruby data structures with circles as
+  # _obj_ argument, because this will cause PSON to go into an infinite loop.
+  def fast_generate(obj)
+    obj.to_pson(nil)
+  end
+
+  # :stopdoc:
+  # I want to deprecate these later, so I'll first be silent about them, and later delete them.
+  alias fast_unparse fast_generate
+  module_function :fast_unparse
+  # :startdoc:
+
+  # Unparse the Ruby data structure _obj_ into a PSON string and return it. The
+  # returned string is a prettier form of the string returned by #unparse.
+  #
+  # The _opts_ argument can be used to configure the generator, see the
+  # generate method for a more detailed explanation.
+  def pretty_generate(obj, opts = nil)
+
+    state = PSON.state.new(
+
+      :indent     => '  ',
+      :space      => ' ',
+      :object_nl  => "\n",
+      :array_nl   => "\n",
+
+      :check_circular => true
+    )
+    if opts
+      if opts.respond_to? :to_hash
+        opts = opts.to_hash
+      elsif opts.respond_to? :to_h
+        opts = opts.to_h
+      else
+        raise TypeError, "can't convert #{opts.class} into Hash"
+      end
+      state.configure(opts)
+    end
+    obj.to_pson(state)
+  end
+
+  # :stopdoc:
+  # I want to deprecate these later, so I'll first be silent about them, and later delete them.
+  alias pretty_unparse pretty_generate
+  module_function :pretty_unparse
+  # :startdoc:
+
+  # Load a ruby data structure from a PSON _source_ and return it. A source can
+  # either be a string-like object, an IO like object, or an object responding
+  # to the read method. If _proc_ was given, it will be called with any nested
+  # Ruby object as an argument recursively in depth first order.
+  #
+  # This method is part of the implementation of the load/dump interface of
+  # Marshal and YAML.
+  def load(source, proc = nil)
+    if source.respond_to? :to_str
+      source = source.to_str
+    elsif source.respond_to? :to_io
+      source = source.to_io.read
+    else
+      source = source.read
+    end
+    result = parse(source, :max_nesting => false, :allow_nan => true)
+    recurse_proc(result, &proc) if proc
+    result
+  end
+
+  def recurse_proc(result, &proc)
+    case result
+    when Array
+      result.each { |x| recurse_proc x, &proc }
+      proc.call result
+    when Hash
+      result.each { |x, y| recurse_proc x, &proc; recurse_proc y, &proc }
+      proc.call result
+    else
+      proc.call result
+    end
+  end
+  private :recurse_proc
+  module_function :recurse_proc
+
+  alias restore load
+  module_function :restore
+
+  # Dumps _obj_ as a PSON string, i.e. calls generate on the object and returns
+  # the result.
+  #
+  # If anIO (an IO like object or an object that responds to the write method)
+  # was given, the resulting PSON is written to it.
+  #
+  # If the number of nested arrays or objects exceeds _limit_ an ArgumentError
+  # exception is raised. This argument is similar (but not exactly the
+  # same!) to the _limit_ argument in Marshal.dump.
+  #
+  # This method is part of the implementation of the load/dump interface of
+  # Marshal and YAML.
+  def dump(obj, anIO = nil, limit = nil)
+    if anIO and limit.nil?
+      anIO = anIO.to_io if anIO.respond_to?(:to_io)
+      unless anIO.respond_to?(:write)
+        limit = anIO
+        anIO = nil
+      end
+    end
+    limit ||= 0
+    result = generate(obj, :allow_nan => true, :max_nesting => limit)
+    if anIO
+      anIO.write result
+      anIO
+    else
+      result
+    end
+  rescue PSON::NestingError
+    raise ArgumentError, "exceed depth limit", $!.backtrace
+  end
+
+
+  # Provide a smarter wrapper for changing string encoding that works with
+  # both Ruby 1.8 (iconv) and 1.9 (String#encode).  Thankfully they seem to
+  # have compatible input syntax, at least for the encodings we touch.
+  if String.method_defined?("encode")
+    def encode(to, from, string)
+      string.encode(to, from)
+    end
+  else
+    require 'iconv'
+    def encode(to, from, string)
+      Iconv.conv(to, from, string)
+    end
+  end
+end
+
+module ::Kernel
+  private
+
+  # Outputs _objs_ to STDOUT as PSON strings in the shortest form, that is in
+  # one line.
+  def j(*objs)
+    objs.each do |obj|
+      puts PSON::generate(obj, :allow_nan => true, :max_nesting => false)
+    end
+    nil
+  end
+
+  # Ouputs _objs_ to STDOUT as PSON strings in a pretty format, with
+  # indentation and over many lines.
+  def jj(*objs)
+    objs.each do |obj|
+      puts PSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false)
+    end
+    nil
+  end
+
+  # If _object_ is string-like parse the string and return the parsed result as
+  # a Ruby data structure. Otherwise generate a PSON text from the Ruby data
+  # structure object and return it.
+  #
+  # The _opts_ argument is passed through to generate/parse respectively, see
+  # generate and parse for their documentation.
+  def PSON(object, opts = {})
+    if object.respond_to? :to_str
+      PSON.parse(object.to_str, opts)
+    else
+      PSON.generate(object, opts)
+    end
+  end
+end
+
+class ::Class
+  # Returns true, if this class can be used to create an instance
+  # from a serialised PSON string. The class has to implement a class
+  # method _pson_create_ that expects a hash as first parameter, which includes
+  # the required data.
+  def pson_creatable?
+    respond_to?(:pson_create)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/pson/pure.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/pson/pure.rb
new file mode 100644
index 0000000..c2afc50
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/pson/pure.rb
@@ -0,0 +1,15 @@
+require 'puppet/external/pson/common'
+require 'puppet/external/pson/pure/parser'
+require 'puppet/external/pson/pure/generator'
+
+module PSON
+  # This module holds all the modules/classes that implement PSON's
+  # functionality in pure ruby.
+  module Pure
+    $DEBUG and warn "Using pure library for PSON."
+    PSON.parser = Parser
+    PSON.generator = Generator
+  end
+
+  PSON_LOADED = true
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/pson/pure/generator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/pson/pure/generator.rb
new file mode 100644
index 0000000..17c98d5
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/pson/pure/generator.rb
@@ -0,0 +1,394 @@
+module PSON
+  MAP = {
+    "\x0" => '\u0000',
+    "\x1" => '\u0001',
+    "\x2" => '\u0002',
+    "\x3" => '\u0003',
+    "\x4" => '\u0004',
+    "\x5" => '\u0005',
+    "\x6" => '\u0006',
+    "\x7" => '\u0007',
+    "\b"  =>  '\b',
+    "\t"  =>  '\t',
+    "\n"  =>  '\n',
+    "\xb" => '\u000b',
+    "\f"  =>  '\f',
+    "\r"  =>  '\r',
+    "\xe" => '\u000e',
+    "\xf" => '\u000f',
+    "\x10" => '\u0010',
+    "\x11" => '\u0011',
+    "\x12" => '\u0012',
+    "\x13" => '\u0013',
+    "\x14" => '\u0014',
+    "\x15" => '\u0015',
+    "\x16" => '\u0016',
+    "\x17" => '\u0017',
+    "\x18" => '\u0018',
+    "\x19" => '\u0019',
+    "\x1a" => '\u001a',
+    "\x1b" => '\u001b',
+    "\x1c" => '\u001c',
+    "\x1d" => '\u001d',
+    "\x1e" => '\u001e',
+    "\x1f" => '\u001f',
+    '"'   =>  '\"',
+    '\\'  =>  '\\\\',
+  } # :nodoc:
+
+  # Convert a UTF8 encoded Ruby string _string_ to a PSON string, encoded with
+  # UTF16 big endian characters as \u????, and return it.
+  if String.method_defined?(:force_encoding)
+    def utf8_to_pson(string) # :nodoc:
+      string = string.dup
+      string << '' # XXX workaround: avoid buffer sharing
+      string.force_encoding(Encoding::ASCII_8BIT)
+      string.gsub!(/["\\\x0-\x1f]/) { MAP[$MATCH] }
+      string
+    rescue => e
+      raise GeneratorError, "Caught #{e.class}: #{e}", e.backtrace
+    end
+  else
+    def utf8_to_pson(string) # :nodoc:
+      string.gsub(/["\\\x0-\x1f]/n) { MAP[$MATCH] }
+    end
+  end
+  module_function :utf8_to_pson
+
+  module Pure
+    module Generator
+      # This class is used to create State instances, that are use to hold data
+      # while generating a PSON text from a Ruby data structure.
+      class State
+        # Creates a State object from _opts_, which ought to be Hash to create
+        # a new State instance configured by _opts_, something else to create
+        # an unconfigured instance. If _opts_ is a State object, it is just
+        # returned.
+        def self.from_state(opts)
+          case opts
+          when self
+            opts
+          when Hash
+            new(opts)
+          else
+            new
+          end
+        end
+
+        # Instantiates a new State object, configured by _opts_.
+        #
+        # _opts_ can have the following keys:
+        #
+        # * *indent*: a string used to indent levels (default: ''),
+        # * *space*: a string that is put after, a : or , delimiter (default: ''),
+        # * *space_before*: a string that is put before a : pair delimiter (default: ''),
+        # * *object_nl*: a string that is put at the end of a PSON object (default: ''),
+        # * *array_nl*: a string that is put at the end of a PSON array (default: ''),
+        # * *check_circular*: true if checking for circular data structures
+        #   should be done (the default), false otherwise.
+        # * *check_circular*: true if checking for circular data structures
+        #   should be done, false (the default) otherwise.
+        # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
+        #   generated, otherwise an exception is thrown, if these values are
+        #   encountered. This options defaults to false.
+        def initialize(opts = {})
+          @seen = {}
+          @indent         = ''
+          @space          = ''
+          @space_before   = ''
+          @object_nl      = ''
+          @array_nl       = ''
+          @check_circular = true
+          @allow_nan      = false
+          configure opts
+        end
+
+        # This string is used to indent levels in the PSON text.
+        attr_accessor :indent
+
+        # This string is used to insert a space between the tokens in a PSON
+        # string.
+        attr_accessor :space
+
+        # This string is used to insert a space before the ':' in PSON objects.
+        attr_accessor :space_before
+
+        # This string is put at the end of a line that holds a PSON object (or
+        # Hash).
+        attr_accessor :object_nl
+
+        # This string is put at the end of a line that holds a PSON array.
+        attr_accessor :array_nl
+
+        # This integer returns the maximum level of data structure nesting in
+        # the generated PSON, max_nesting = 0 if no maximum is checked.
+        attr_accessor :max_nesting
+
+        def check_max_nesting(depth) # :nodoc:
+          return if @max_nesting.zero?
+          current_nesting = depth + 1
+          current_nesting > @max_nesting and
+            raise NestingError, "nesting of #{current_nesting} is too deep"
+        end
+
+        # Returns true, if circular data structures should be checked,
+        # otherwise returns false.
+        def check_circular?
+          @check_circular
+        end
+
+        # Returns true if NaN, Infinity, and -Infinity should be considered as
+        # valid PSON and output.
+        def allow_nan?
+          @allow_nan
+        end
+
+        # Returns _true_, if _object_ was already seen during this generating
+        # run.
+        def seen?(object)
+          @seen.key?(object.__id__)
+        end
+
+        # Remember _object_, to find out if it was already encountered (if a
+        # cyclic data structure is if a cyclic data structure is rendered).
+        def remember(object)
+          @seen[object.__id__] = true
+        end
+
+        # Forget _object_ for this generating run.
+        def forget(object)
+          @seen.delete object.__id__
+        end
+
+        # Configure this State instance with the Hash _opts_, and return
+        # itself.
+        def configure(opts)
+          @indent         = opts[:indent] if opts.key?(:indent)
+          @space          = opts[:space] if opts.key?(:space)
+          @space_before   = opts[:space_before] if opts.key?(:space_before)
+          @object_nl      = opts[:object_nl] if opts.key?(:object_nl)
+          @array_nl       = opts[:array_nl] if opts.key?(:array_nl)
+          @check_circular = !!opts[:check_circular] if opts.key?(:check_circular)
+          @allow_nan      = !!opts[:allow_nan] if opts.key?(:allow_nan)
+          if !opts.key?(:max_nesting) # defaults to 19
+            @max_nesting = 19
+          elsif opts[:max_nesting]
+            @max_nesting = opts[:max_nesting]
+          else
+            @max_nesting = 0
+          end
+          self
+        end
+
+        # Returns the configuration instance variables as a hash, that can be
+        # passed to the configure method.
+        def to_h
+          result = {}
+          for iv in %w{indent space space_before object_nl array_nl check_circular allow_nan max_nesting}
+            result[iv.intern] = instance_variable_get("@#{iv}")
+          end
+          result
+        end
+      end
+
+      module GeneratorMethods
+        module Object
+          # Converts this object to a string (calling #to_s), converts
+          # it to a PSON string, and returns the result. This is a fallback, if no
+          # special method #to_pson was defined for some object.
+          def to_pson(*) to_s.to_pson end
+        end
+
+        module Hash
+          # Returns a PSON string containing a PSON object, that is unparsed from
+          # this Hash instance.
+          # _state_ is a PSON::State object, that can also be used to configure the
+          # produced PSON string output further.
+          # _depth_ is used to find out nesting depth, to indent accordingly.
+          def to_pson(state = nil, depth = 0, *)
+            if state
+              state = PSON.state.from_state(state)
+              state.check_max_nesting(depth)
+              pson_check_circular(state) { pson_transform(state, depth) }
+            else
+              pson_transform(state, depth)
+            end
+          end
+
+          private
+
+          def pson_check_circular(state)
+            if state and state.check_circular?
+              state.seen?(self) and raise PSON::CircularDatastructure,
+                "circular data structures not supported!"
+              state.remember self
+            end
+            yield
+          ensure
+            state and state.forget self
+          end
+
+          def pson_shift(state, depth)
+            state and not state.object_nl.empty? or return ''
+            state.indent * depth
+          end
+
+          def pson_transform(state, depth)
+            delim = ','
+            if state
+              delim << state.object_nl
+              result = '{'
+              result << state.object_nl
+              result << map { |key,value|
+                s = pson_shift(state, depth + 1)
+                s << key.to_s.to_pson(state, depth + 1)
+                s << state.space_before
+                s << ':'
+                s << state.space
+                s << value.to_pson(state, depth + 1)
+              }.join(delim)
+              result << state.object_nl
+              result << pson_shift(state, depth)
+              result << '}'
+            else
+              result = '{'
+              result << map { |key,value|
+                key.to_s.to_pson << ':' << value.to_pson
+              }.join(delim)
+              result << '}'
+            end
+            result
+          end
+        end
+
+        module Array
+          # Returns a PSON string containing a PSON array, that is unparsed from
+          # this Array instance.
+          # _state_ is a PSON::State object, that can also be used to configure the
+          # produced PSON string output further.
+          # _depth_ is used to find out nesting depth, to indent accordingly.
+          def to_pson(state = nil, depth = 0, *)
+            if state
+              state = PSON.state.from_state(state)
+              state.check_max_nesting(depth)
+              pson_check_circular(state) { pson_transform(state, depth) }
+            else
+              pson_transform(state, depth)
+            end
+          end
+
+          private
+
+          def pson_check_circular(state)
+            if state and state.check_circular?
+              state.seen?(self) and raise PSON::CircularDatastructure,
+                "circular data structures not supported!"
+              state.remember self
+            end
+            yield
+          ensure
+            state and state.forget self
+          end
+
+          def pson_shift(state, depth)
+            state and not state.array_nl.empty? or return ''
+            state.indent * depth
+          end
+
+          def pson_transform(state, depth)
+            delim = ','
+            if state
+              delim << state.array_nl
+              result = '['
+              result << state.array_nl
+              result << map { |value|
+                pson_shift(state, depth + 1) << value.to_pson(state, depth + 1)
+              }.join(delim)
+              result << state.array_nl
+              result << pson_shift(state, depth)
+              result << ']'
+            else
+              '[' << map { |value| value.to_pson }.join(delim) << ']'
+            end
+          end
+        end
+
+        module Integer
+          # Returns a PSON string representation for this Integer number.
+          def to_pson(*) to_s end
+        end
+
+        module Float
+          # Returns a PSON string representation for this Float number.
+          def to_pson(state = nil, *)
+            if infinite? || nan?
+              if !state || state.allow_nan?
+                to_s
+              else
+                raise GeneratorError, "#{self} not allowed in PSON"
+              end
+            else
+              to_s
+            end
+          end
+        end
+
+        module String
+          # This string should be encoded with UTF-8 A call to this method
+          # returns a PSON string encoded with UTF16 big endian characters as
+          # \u????.
+          def to_pson(*)
+            '"' << PSON.utf8_to_pson(self) << '"'
+          end
+
+          # Module that holds the extinding methods if, the String module is
+          # included.
+          module Extend
+            # Raw Strings are PSON Objects (the raw bytes are stored in an array for the
+            # key "raw"). The Ruby String can be created by this module method.
+            def pson_create(o)
+              o['raw'].pack('C*')
+            end
+          end
+
+          # Extends _modul_ with the String::Extend module.
+          def self.included(modul)
+            modul.extend Extend
+          end
+
+          # This method creates a raw object hash, that can be nested into
+          # other data structures and will be unparsed as a raw string. This
+          # method should be used, if you want to convert raw strings to PSON
+          # instead of UTF-8 strings, e.g. binary data.
+          def to_pson_raw_object
+            {
+              PSON.create_id  => self.class.name,
+              'raw'           => self.unpack('C*'),
+            }
+          end
+
+          # This method creates a PSON text from the result of
+          # a call to to_pson_raw_object of this String.
+          def to_pson_raw(*args)
+            to_pson_raw_object.to_pson(*args)
+          end
+        end
+
+        module TrueClass
+          # Returns a PSON string for true: 'true'.
+          def to_pson(*) 'true' end
+        end
+
+        module FalseClass
+          # Returns a PSON string for false: 'false'.
+          def to_pson(*) 'false' end
+        end
+
+        module NilClass
+          # Returns a PSON string for nil: 'null'.
+          def to_pson(*) 'null' end
+        end
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/pson/pure/parser.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/pson/pure/parser.rb
new file mode 100644
index 0000000..43c6c5f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/pson/pure/parser.rb
@@ -0,0 +1,318 @@
+require 'strscan'
+
+module PSON
+  module Pure
+    # This class implements the PSON parser that is used to parse a PSON string
+    # into a Ruby data structure.
+    class Parser < StringScanner
+      STRING                = /" ((?:[^\x0-\x1f"\\] |
+      #                              escaped special characters:
+        \\["\\\/bfnrt] |
+        \\u[0-9a-fA-F]{4} |
+        #                          match all but escaped special characters:
+          \\[\x20-\x21\x23-\x2e\x30-\x5b\x5d-\x61\x63-\x65\x67-\x6d\x6f-\x71\x73\x75-\xff])*)
+            "/nx
+      INTEGER               = /(-?0|-?[1-9]\d*)/
+      FLOAT                 = /(-?
+        (?:0|[1-9]\d*)
+        (?:
+          \.\d+(?i:e[+-]?\d+) |
+          \.\d+ |
+          (?i:e[+-]?\d+)
+            )
+            )/x
+      NAN                   = /NaN/
+      INFINITY              = /Infinity/
+      MINUS_INFINITY        = /-Infinity/
+      OBJECT_OPEN           = /\{/
+      OBJECT_CLOSE          = /\}/
+      ARRAY_OPEN            = /\[/
+      ARRAY_CLOSE           = /\]/
+      PAIR_DELIMITER        = /:/
+      COLLECTION_DELIMITER  = /,/
+      TRUE                  = /true/
+      FALSE                 = /false/
+      NULL                  = /null/
+      IGNORE                = %r(
+        (?:
+        //[^\n\r]*[\n\r]| # line comments
+        /\*               # c-style comments
+        (?:
+        [^*/]|        # normal chars
+        /[^*]|        # slashes that do not start a nested comment
+        \*[^/]|       # asterisks that do not end this comment
+        /(?=\*/)      # single slash before this comment's end
+        )*
+        \*/               # the End of this comment
+        |[ \t\r\n]+       # whitespaces: space, horicontal tab, lf, cr
+      )+
+      )mx
+
+      UNPARSED = Object.new
+
+      # Creates a new PSON::Pure::Parser instance for the string _source_.
+      #
+      # It will be configured by the _opts_ hash. _opts_ can have the following
+      # keys:
+      # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
+      #   structures. Disable depth checking with :max_nesting => false|nil|0,
+      #   it defaults to 19.
+      # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
+      #   defiance of RFC 4627 to be parsed by the Parser. This option defaults
+      #   to false.
+      # * *create_additions*: If set to false, the Parser doesn't create
+      #   additions even if a matching class and create_id was found. This option
+      #   defaults to true.
+      # * *object_class*: Defaults to Hash
+      # * *array_class*: Defaults to Array
+      def initialize(source, opts = {})
+        source = convert_encoding source
+        super source
+        if !opts.key?(:max_nesting) # defaults to 19
+          @max_nesting = 19
+        elsif opts[:max_nesting]
+          @max_nesting = opts[:max_nesting]
+        else
+          @max_nesting = 0
+        end
+        @allow_nan = !!opts[:allow_nan]
+        ca = true
+        ca = opts[:create_additions] if opts.key?(:create_additions)
+        @create_id = ca ? PSON.create_id : nil
+        @object_class = opts[:object_class] || Hash
+        @array_class = opts[:array_class] || Array
+      end
+
+      alias source string
+
+      # Parses the current PSON string _source_ and returns the complete data
+      # structure as a result.
+      def parse
+        reset
+        obj = nil
+        until eos?
+          case
+          when scan(OBJECT_OPEN)
+            obj and raise ParserError, "source '#{peek(20)}' not in PSON!"
+            @current_nesting = 1
+            obj = parse_object
+          when scan(ARRAY_OPEN)
+            obj and raise ParserError, "source '#{peek(20)}' not in PSON!"
+            @current_nesting = 1
+            obj = parse_array
+          when skip(IGNORE)
+            ;
+          else
+            raise ParserError, "source '#{peek(20)}' not in PSON!"
+          end
+        end
+        obj or raise ParserError, "source did not contain any PSON!"
+        obj
+      end
+
+      private
+
+      def convert_encoding(source)
+        if source.respond_to?(:to_str)
+          source = source.to_str
+        else
+          raise TypeError, "#{source.inspect} is not like a string"
+        end
+        if supports_encodings?(source)
+          if source.encoding == ::Encoding::ASCII_8BIT
+            b = source[0, 4].bytes.to_a
+            source =
+              case
+              when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
+                source.dup.force_encoding(::Encoding::UTF_32BE).encode!(::Encoding::UTF_8)
+              when b.size >= 4 && b[0] == 0 && b[2] == 0
+                source.dup.force_encoding(::Encoding::UTF_16BE).encode!(::Encoding::UTF_8)
+              when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
+                source.dup.force_encoding(::Encoding::UTF_32LE).encode!(::Encoding::UTF_8)
+              when b.size >= 4 && b[1] == 0 && b[3] == 0
+                source.dup.force_encoding(::Encoding::UTF_16LE).encode!(::Encoding::UTF_8)
+              else
+                source.dup
+              end
+          else
+            source = source.encode(::Encoding::UTF_8)
+          end
+          source.force_encoding(::Encoding::ASCII_8BIT)
+        else
+          b = source
+          source =
+            case
+            when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
+              PSON.encode('utf-8', 'utf-32be', b)
+            when b.size >= 4 && b[0] == 0 && b[2] == 0
+              PSON.encode('utf-8', 'utf-16be', b)
+            when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
+              PSON.encode('utf-8', 'utf-32le', b)
+            when b.size >= 4 && b[1] == 0 && b[3] == 0
+              PSON.encode('utf-8', 'utf-16le', b)
+            else
+              b
+            end
+        end
+        source
+      end
+
+      def supports_encodings?(string)
+        # Some modules, such as REXML on 1.8.7 (see #22804) can actually create
+        # a top-level Encoding constant when they are misused. Therefore
+        # checking for just that constant is not enough, so we'll be a bit more
+        # robust about if we can actually support encoding transformations.
+        string.respond_to?(:encoding) && defined?(::Encoding)
+      end
+
+      # Unescape characters in strings.
+      UNESCAPE_MAP = Hash.new { |h, k| h[k] = k.chr }
+
+        UNESCAPE_MAP.update(
+          {
+            ?"  => '"',
+            ?\\ => '\\',
+            ?/  => '/',
+            ?b  => "\b",
+            ?f  => "\f",
+            ?n  => "\n",
+            ?r  => "\r",
+            ?t  => "\t",
+            ?u  => nil,
+
+      })
+
+      def parse_string
+        if scan(STRING)
+          return '' if self[1].empty?
+          string = self[1].gsub(%r{(?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff])}n) do |c|
+            if u = UNESCAPE_MAP[$MATCH[1]]
+              u
+            else # \uXXXX
+              bytes = ''
+              i = 0
+              while c[6 * i] == ?\\ && c[6 * i + 1] == ?u
+                bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16)
+                i += 1
+              end
+              PSON.encode('utf-8', 'utf-16be', bytes)
+            end
+          end
+          string.force_encoding(Encoding::UTF_8) if string.respond_to?(:force_encoding)
+          string
+        else
+          UNPARSED
+        end
+      rescue => e
+        raise GeneratorError, "Caught #{e.class}: #{e}", e.backtrace
+      end
+
+      def parse_value
+        case
+        when scan(FLOAT)
+          Float(self[1])
+        when scan(INTEGER)
+          Integer(self[1])
+        when scan(TRUE)
+          true
+        when scan(FALSE)
+          false
+        when scan(NULL)
+          nil
+        when (string = parse_string) != UNPARSED
+          string
+        when scan(ARRAY_OPEN)
+          @current_nesting += 1
+          ary = parse_array
+          @current_nesting -= 1
+          ary
+        when scan(OBJECT_OPEN)
+          @current_nesting += 1
+          obj = parse_object
+          @current_nesting -= 1
+          obj
+        when @allow_nan && scan(NAN)
+          NaN
+        when @allow_nan && scan(INFINITY)
+          Infinity
+        when @allow_nan && scan(MINUS_INFINITY)
+          MinusInfinity
+        else
+          UNPARSED
+        end
+      end
+
+      def parse_array
+        raise NestingError, "nesting of #@current_nesting is too deep" if
+          @max_nesting.nonzero? && @current_nesting > @max_nesting
+        result = @array_class.new
+        delim = false
+        until eos?
+          case
+          when (value = parse_value) != UNPARSED
+            delim = false
+            result << value
+            skip(IGNORE)
+            if scan(COLLECTION_DELIMITER)
+              delim = true
+            elsif match?(ARRAY_CLOSE)
+              ;
+            else
+              raise ParserError, "expected ',' or ']' in array at '#{peek(20)}'!"
+            end
+          when scan(ARRAY_CLOSE)
+            raise ParserError, "expected next element in array at '#{peek(20)}'!" if delim
+            break
+          when skip(IGNORE)
+            ;
+          else
+            raise ParserError, "unexpected token in array at '#{peek(20)}'!"
+          end
+        end
+        result
+      end
+
+      def parse_object
+        raise NestingError, "nesting of #@current_nesting is too deep" if
+          @max_nesting.nonzero? && @current_nesting > @max_nesting
+        result = @object_class.new
+        delim = false
+        until eos?
+          case
+          when (string = parse_string) != UNPARSED
+            skip(IGNORE)
+            raise ParserError, "expected ':' in object at '#{peek(20)}'!" unless scan(PAIR_DELIMITER)
+            skip(IGNORE)
+            unless (value = parse_value).equal? UNPARSED
+              result[string] = value
+              delim = false
+              skip(IGNORE)
+              if scan(COLLECTION_DELIMITER)
+                delim = true
+              elsif match?(OBJECT_CLOSE)
+                ;
+              else
+                raise ParserError, "expected ',' or '}' in object at '#{peek(20)}'!"
+              end
+            else
+              raise ParserError, "expected value in object at '#{peek(20)}'!"
+            end
+          when scan(OBJECT_CLOSE)
+            raise ParserError, "expected next name, value pair in object at '#{peek(20)}'!" if delim
+            if @create_id and klassname = result[@create_id]
+              klass = PSON.deep_const_get klassname
+              break unless klass and klass.pson_creatable?
+              result = klass.pson_create(result)
+            end
+            break
+          when skip(IGNORE)
+            ;
+          else
+            raise ParserError, "unexpected token in object at '#{peek(20)}'!"
+          end
+        end
+        result
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/pson/version.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/pson/version.rb
new file mode 100644
index 0000000..a5a8e47
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/external/pson/version.rb
@@ -0,0 +1,8 @@
+module PSON
+  # PSON version
+  VERSION         = '1.1.9'
+  VERSION_ARRAY   = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
+  VERSION_MAJOR   = VERSION_ARRAY[0] # :nodoc:
+  VERSION_MINOR   = VERSION_ARRAY[1] # :nodoc:
+  VERSION_BUILD   = VERSION_ARRAY[2] # :nodoc:
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face.rb
new file mode 100644
index 0000000..f73b2fc
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face.rb
@@ -0,0 +1,12 @@
+# The public name of this feature is 'face', but we have hidden all the
+# plumbing over in the 'interfaces' namespace to make clear the distinction
+# between the two.
+#
+# This file exists to ensure that the public name is usable without revealing
+# the details of the implementation; you really only need go look at anything
+# under Interfaces if you are looking to extend the implementation.
+#
+# It isn't hidden to gratuitously hide things, just to make it easier to
+# separate out the interests people will have.  --daniel 2011-04-07
+require 'puppet/interface'
+Puppet::Face = Puppet::Interface
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/ca.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/ca.rb
new file mode 100644
index 0000000..9b7cc5e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/ca.rb
@@ -0,0 +1,254 @@
+require 'puppet/face'
+
+Puppet::Face.define(:ca, '0.1.0') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Local Puppet Certificate Authority management."
+
+  description <<-TEXT
+    This provides local management of the Puppet Certificate Authority.
+
+    You can use this subcommand to sign outstanding certificate requests, list
+    and manage local certificates, and inspect the state of the CA.
+  TEXT
+
+  action :list do
+    summary "List certificates and/or certificate requests."
+
+    description <<-TEXT
+      This will list the current certificates and certificate signing requests
+      in the Puppet CA.  You will also get the fingerprint, and any certificate
+      verification failure reported.
+    TEXT
+
+    option "--[no-]all" do
+      summary "Include all certificates and requests."
+    end
+
+    option "--[no-]pending" do
+      summary "Include pending certificate signing requests."
+    end
+
+    option "--[no-]signed" do
+      summary "Include signed certificates."
+    end
+
+    option "--digest ALGORITHM" do
+      summary "The hash algorithm to use when displaying the fingerprint"
+    end
+
+    option "--subject PATTERN" do
+      summary "Only list if the subject matches PATTERN."
+
+      description <<-TEXT
+        Only include certificates or requests where subject matches PATTERN.
+
+        PATTERN is interpreted as a regular expression, allowing complex
+        filtering of the content.
+      TEXT
+    end
+
+    when_invoked do |options|
+      raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
+      unless ca = Puppet::SSL::CertificateAuthority.instance
+        raise "Unable to fetch the CA"
+      end
+      Puppet::SSL::Host.ca_location = :only
+
+      pattern = options[:subject].nil? ? nil :
+        Regexp.new(options[:subject], Regexp::IGNORECASE)
+
+      pending = options[:pending].nil? ? options[:all] : options[:pending]
+      signed  = options[:signed].nil?  ? options[:all] : options[:signed]
+
+      # By default we list pending, so if nothing at all was requested...
+      unless pending or signed then pending = true end
+
+      hosts = []
+
+      pending and hosts += ca.waiting?
+      signed  and hosts += ca.list
+
+      pattern and hosts = hosts.select {|hostname| pattern.match hostname }
+
+      hosts.sort.map {|host| Puppet::SSL::Host.new(host) }
+    end
+
+    when_rendering :console do |hosts, options|
+      unless ca = Puppet::SSL::CertificateAuthority.instance
+        raise "Unable to fetch the CA"
+      end
+
+      length = hosts.map{|x| x.name.length }.max.to_i + 1
+
+      hosts.map do |host|
+        name = host.name.ljust(length)
+        if host.certificate_request then
+          "  #{name} #{host.certificate_request.digest(options[:digest])}"
+        else
+          begin
+            ca.verify(host.name)
+            "+ #{name} #{host.certificate.digest(options[:digest])}"
+          rescue Puppet::SSL::CertificateAuthority::CertificateVerificationError => e
+            "- #{name} #{host.certificate.digest(options[:digest])} (#{e.to_s})"
+          end
+        end
+      end.join("\n")
+    end
+  end
+
+  action :destroy do
+    summary "Destroy named certificate or pending certificate request."
+    when_invoked do |host, options|
+      raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
+      unless ca = Puppet::SSL::CertificateAuthority.instance
+        raise "Unable to fetch the CA"
+      end
+      Puppet::SSL::Host.ca_location = :local
+
+      ca.destroy host
+    end
+  end
+
+  action :revoke do
+    summary "Add certificate to certificate revocation list."
+    when_invoked do |host, options|
+      raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
+      unless ca = Puppet::SSL::CertificateAuthority.instance
+        raise "Unable to fetch the CA"
+      end
+      Puppet::SSL::Host.ca_location = :only
+
+      begin
+        ca.revoke host
+      rescue ArgumentError => e
+        # This is a bit naff, but it makes the behaviour consistent with the
+        # destroy action.  The underlying tools could be nicer for that sort
+        # of thing; they have fairly inconsistent reporting of failures.
+        raise unless e.to_s =~ /Could not find a serial number for /
+        "Nothing was revoked"
+      end
+    end
+  end
+
+  action :generate do
+    summary "Generate a certificate for a named client."
+    option "--dns-alt-names NAMES" do
+      summary "Additional DNS names to add to the certificate request"
+      description Puppet.settings.setting(:dns_alt_names).desc
+    end
+
+    when_invoked do |host, options|
+      raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
+      unless ca = Puppet::SSL::CertificateAuthority.instance
+        raise "Unable to fetch the CA"
+      end
+      Puppet::SSL::Host.ca_location = :local
+
+      begin
+        ca.generate(host, :dns_alt_names => options[:dns_alt_names])
+      rescue RuntimeError => e
+        if e.to_s =~ /already has a requested certificate/
+          "#{host} already has a certificate request; use sign instead"
+        else
+          raise
+        end
+      rescue ArgumentError => e
+        if e.to_s =~ /A Certificate already exists for /
+          "#{host} already has a certificate"
+        else
+          raise
+        end
+      end
+    end
+  end
+
+  action :sign do
+    summary "Sign an outstanding certificate request."
+    option("--[no-]allow-dns-alt-names") do
+      summary "Whether or not to accept DNS alt names in the certificate request"
+    end
+
+    when_invoked do |host, options|
+      raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
+      unless ca = Puppet::SSL::CertificateAuthority.instance
+        raise "Unable to fetch the CA"
+      end
+      Puppet::SSL::Host.ca_location = :only
+
+      begin
+        ca.sign(host, options[:allow_dns_alt_names])
+      rescue ArgumentError => e
+        if e.to_s =~ /Could not find certificate request/
+          e.to_s
+        else
+          raise
+        end
+      end
+    end
+  end
+
+  action :print do
+    summary "Print the full-text version of a host's certificate."
+    when_invoked do |host, options|
+      raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
+      unless ca = Puppet::SSL::CertificateAuthority.instance
+        raise "Unable to fetch the CA"
+      end
+      Puppet::SSL::Host.ca_location = :only
+
+      ca.print host
+    end
+  end
+
+  action :fingerprint do
+    summary "Print the DIGEST (defaults to the signing algorithm) fingerprint of a host's certificate."
+    option "--digest ALGORITHM" do
+      summary "The hash algorithm to use when displaying the fingerprint"
+    end
+
+    when_invoked do |host, options|
+      raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
+      unless Puppet::SSL::CertificateAuthority.instance
+        raise "Unable to fetch the CA"
+      end
+      Puppet::SSL::Host.ca_location = :only
+
+      if cert = (Puppet::SSL::Certificate.indirection.find(host) || Puppet::SSL::CertificateRequest.indirection.find(host))
+        cert.digest(options[:digest]).to_s
+      else
+        nil
+      end
+    end
+  end
+
+  action :verify do
+    summary "Verify the named certificate against the local CA certificate."
+    when_invoked do |host, options|
+      raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
+      unless ca = Puppet::SSL::CertificateAuthority.instance
+        raise "Unable to fetch the CA"
+      end
+      Puppet::SSL::Host.ca_location = :only
+
+      begin
+        ca.verify host
+        { :host => host, :valid => true }
+      rescue ArgumentError => e
+        raise unless e.to_s =~ /Could not find a certificate for/
+        { :host => host, :valid => false, :error => e.to_s }
+      rescue Puppet::SSL::CertificateAuthority::CertificateVerificationError => e
+        { :host => host, :valid => false, :error => e.to_s }
+      end
+    end
+
+    when_rendering :console do |value|
+      if value[:valid]
+        nil
+      else
+        "Could not verify #{value[:host]}: #{value[:error]}"
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/catalog.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/catalog.rb
new file mode 100644
index 0000000..ae2dadc
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/catalog.rb
@@ -0,0 +1,130 @@
+require 'puppet/indirector/face'
+
+Puppet::Indirector::Face.define(:catalog, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Compile, save, view, and convert catalogs."
+  description <<-'EOT'
+    This subcommand deals with catalogs, which are compiled per-node artifacts
+    generated from a set of Puppet manifests. By default, it interacts with the
+    compiling subsystem and compiles a catalog using the default manifest and
+    `certname`, but you can change the source of the catalog with the
+    `--terminus` option. You can also choose to print any catalog in 'dot'
+    format (for easy graph viewing with OmniGraffle or Graphviz) with
+    '--render-as dot'.
+  EOT
+  short_description <<-'EOT'
+    This subcommand deals with catalogs, which are compiled per-node artifacts
+    generated from a set of Puppet manifests. By default, it interacts with the
+    compiling subsystem and compiles a catalog using the default manifest and
+    `certname`; use the `--terminus` option to change the source of the catalog.
+  EOT
+
+  get_action(:destroy).summary "Invalid for this subcommand."
+  get_action(:search).summary "Invalid for this subcommand."
+  find = get_action(:find)
+  find.summary "Retrieve the catalog for a node."
+  find.arguments "<certname>"
+  find.returns <<-'EOT'
+    A serialized catalog. When used from the Ruby API, returns a
+    Puppet::Resource::Catalog object.
+  EOT
+
+  action(:apply) do
+    summary "Find and apply a catalog."
+    description <<-'EOT'
+      Finds and applies a catalog. This action takes no arguments, but
+      the source of the catalog can be managed with the `--terminus` option.
+    EOT
+    returns <<-'EOT'
+      Nothing. When used from the Ruby API, returns a
+      Puppet::Transaction::Report object.
+    EOT
+    examples <<-'EOT'
+      Apply the locally cached catalog:
+
+      $ puppet catalog apply --terminus yaml
+
+      Retrieve a catalog from the master and apply it, in one step:
+
+      $ puppet catalog apply --terminus rest
+
+      From `secret_agent.rb` (API example):
+
+          # ...
+          Puppet::Face[:catalog, '0.0.1'].download
+          # (Termini are singletons; catalog.download has a side effect of
+          # setting the catalog terminus to yaml)
+          report  = Puppet::Face[:catalog, '0.0.1'].apply
+          # ...
+    EOT
+
+    when_invoked do |options|
+      catalog = Puppet::Face[:catalog, "0.0.1"].find(Puppet[:certname]) or raise "Could not find catalog for #{Puppet[:certname]}"
+      catalog = catalog.to_ral
+
+      report = Puppet::Transaction::Report.new("apply")
+      report.configuration_version = catalog.version
+      report.environment = Puppet[:environment]
+
+      Puppet::Util::Log.newdestination(report)
+
+      begin
+        benchmark(:notice, "Finished catalog run") do
+          catalog.apply(:report => report)
+        end
+      rescue => detail
+        Puppet.log_exception(detail, "Failed to apply catalog: #{detail}")
+      end
+
+      report.finalize_report
+      report
+    end
+  end
+
+  action(:download) do
+    summary "Download this node's catalog from the puppet master server."
+    description <<-'EOT'
+      Retrieves a catalog from the puppet master and saves it to the local yaml
+      cache. This action always contacts the puppet master and will ignore
+      alternate termini.
+
+      The saved catalog can be used in any subsequent catalog action by specifying
+      '--terminus yaml' for that action.
+    EOT
+    returns "Nothing."
+    notes <<-'EOT'
+      When used from the Ruby API, this action has a side effect of leaving
+      Puppet::Resource::Catalog.indirection.terminus_class set to yaml. The
+      terminus must be explicitly re-set for subsequent catalog actions.
+    EOT
+    examples <<-'EOT'
+      Retrieve and store a catalog:
+
+      $ puppet catalog download
+
+      From `secret_agent.rb` (API example):
+
+          Puppet::Face[:plugin, '0.0.1'].download
+          Puppet::Face[:facts, '0.0.1'].upload
+          Puppet::Face[:catalog, '0.0.1'].download
+          # ...
+    EOT
+    when_invoked do |options|
+      Puppet::Resource::Catalog.indirection.terminus_class = :rest
+      Puppet::Resource::Catalog.indirection.cache_class = nil
+      catalog = nil
+      retrieval_duration = thinmark do
+        catalog = Puppet::Face[:catalog, '0.0.1'].find(Puppet[:certname])
+      end
+      catalog.retrieval_duration = retrieval_duration
+      catalog.write_class_file
+
+      Puppet::Resource::Catalog.indirection.terminus_class = :yaml
+      Puppet::Face[:catalog, "0.0.1"].save(catalog)
+      Puppet.notice "Saved catalog for #{Puppet[:certname]} to yaml"
+      nil
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/catalog/select.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/catalog/select.rb
new file mode 100644
index 0000000..de2ca80
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/catalog/select.rb
@@ -0,0 +1,49 @@
+# Select and show a list of resources of a given type.
+Puppet::Face.define(:catalog, '0.0.1') do
+  action :select do
+    summary "Retrieve a catalog and filter it for resources of a given type."
+    arguments "<host> <resource_type>"
+    returns <<-'EOT'
+      A list of resource references ("Type[title]"). When used from the API,
+      returns an array of Puppet::Resource objects excised from a catalog.
+    EOT
+    description <<-'EOT'
+      Retrieves a catalog for the specified host, then searches it for all
+      resources of the requested type.
+    EOT
+    notes <<-'NOTES'
+      By default, this action will retrieve a catalog from Puppet's compiler
+      subsystem; you must call the action with `--terminus rest` if you wish
+      to retrieve a catalog from the puppet master.
+
+      FORMATTING ISSUES: This action cannot currently render useful yaml;
+      instead, it returns an entire catalog. Use json instead.
+    NOTES
+    examples <<-'EOT'
+      Ask the puppet master for a list of managed file resources for a node:
+
+      $ puppet catalog select --terminus rest somenode.magpie.lan file
+    EOT
+    when_invoked do |host, type, options|
+      # REVISIT: Eventually, type should have a default value that triggers
+      # the non-specific behaviour.  For now, though, this will do.
+      # --daniel 2011-05-03
+      catalog = Puppet::Resource::Catalog.indirection.find(host)
+
+      if type == '*'
+        catalog.resources
+      else
+        type = type.downcase
+        catalog.resources.reject { |res| res.type.downcase != type }
+      end
+    end
+
+    when_rendering :console do |value|
+      if value.nil? then
+        "no matching resources found"
+      else
+        value.map {|x| x.to_s }.join("\n")
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/certificate.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/certificate.rb
new file mode 100644
index 0000000..7c93e50
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/certificate.rb
@@ -0,0 +1,160 @@
+require 'puppet/indirector/face'
+require 'puppet/ssl/host'
+
+Puppet::Indirector::Face.define(:certificate, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Provide access to the CA for certificate management."
+  description <<-EOT
+    This subcommand interacts with a local or remote Puppet certificate
+    authority. Currently, its behavior is not a full superset of `puppet
+    cert`; specifically, it is unable to mimic puppet cert's "clean" option,
+    and its "generate" action submits a CSR rather than creating a
+    signed certificate.
+  EOT
+
+  option "--ca-location LOCATION" do
+    required
+    summary "Which certificate authority to use (local or remote)."
+    description <<-EOT
+      Whether to act on the local certificate authority or one provided by a
+      remote puppet master. Allowed values are 'local' and 'remote.'
+
+      This option is required.
+    EOT
+
+    before_action do |action, args, options|
+      unless [:remote, :local, :only].include? options[:ca_location].to_sym
+        raise ArgumentError, "Valid values for ca-location are 'remote', 'local', 'only'."
+      end
+      Puppet::SSL::Host.ca_location = options[:ca_location].to_sym
+    end
+  end
+
+  action :generate do
+    summary "Generate a new certificate signing request."
+    arguments "<host>"
+    returns "Nothing."
+    description <<-EOT
+      Generates and submits a certificate signing request (CSR) for the
+      specified host. This CSR will then have to be signed by a user
+      with the proper authorization on the certificate authority.
+
+      Puppet agent usually handles CSR submission automatically. This action is
+      primarily useful for requesting certificates for individual users and
+      external applications.
+    EOT
+    examples <<-EOT
+      Request a certificate for "somenode" from the site's CA:
+
+      $ puppet certificate generate somenode.puppetlabs.lan --ca-location remote
+    EOT
+
+    # Duplicate the option here explicitly to distinguish if it was passed arg
+    # us vs. set in the config file.
+    option "--dns-alt-names NAMES" do
+      summary "Additional DNS names to add to the certificate request"
+      description Puppet.settings.setting(:dns_alt_names).desc
+    end
+
+    when_invoked do |name, options|
+      host = Puppet::SSL::Host.new(name)
+
+      # We have a weird case where we have --dns_alt_names from Puppet, but
+      # this option is --dns-alt-names. Until we can get rid of --dns-alt-names
+      # or do a global tr('-', '_'), we have to support both.
+      # In supporting both, we'll use Puppet[:dns_alt_names] if specified on
+      # command line. We'll use options[:dns_alt_names] if specified on
+      # command line. If both specified, we'll fail.
+      # jeffweiss 17 april 2012
+
+      global_setting_from_cli = Puppet.settings.set_by_cli?(:dns_alt_names) == true
+      raise ArgumentError, "Can't specify both --dns_alt_names and --dns-alt-names" if options[:dns_alt_names] and global_setting_from_cli
+      options[:dns_alt_names] = Puppet[:dns_alt_names] if global_setting_from_cli
+
+      # If dns_alt_names are specified via the command line, we will always add
+      # them. Otherwise, they will default to the config file setting iff this
+      # cert is for the host we're running on.
+
+      host.generate_certificate_request(:dns_alt_names => options[:dns_alt_names])
+    end
+  end
+
+  action :list do
+    summary "List all certificate signing requests."
+    returns <<-EOT
+      An array of #inspect output from CSR objects. This output is
+      currently messy, but does contain the names of nodes requesting
+      certificates. This action returns #inspect strings even when used
+      from the Ruby API.
+    EOT
+
+    when_invoked do |options|
+      Puppet::SSL::Host.indirection.search("*", {
+        :for => :certificate_request,
+      }).map { |h| h.inspect }
+    end
+  end
+
+  action :sign do
+    summary "Sign a certificate signing request for HOST."
+    arguments "<host>"
+    returns <<-EOT
+      A string that appears to be (but isn't) an x509 certificate.
+    EOT
+    examples <<-EOT
+      Sign somenode.puppetlabs.lan's certificate:
+
+      $ puppet certificate sign somenode.puppetlabs.lan --ca-location remote
+    EOT
+
+    option("--[no-]allow-dns-alt-names") do
+      summary "Whether or not to accept DNS alt names in the certificate request"
+    end
+
+    when_invoked do |name, options|
+      host = Puppet::SSL::Host.new(name)
+      if Puppet::SSL::Host.ca_location == :remote
+        if options[:allow_dns_alt_names]
+          raise ArgumentError, "--allow-dns-alt-names may not be specified with a remote CA"
+        end
+
+        host.desired_state = 'signed'
+        Puppet::SSL::Host.indirection.save(host)
+      else
+        # We have to do this case manually because we need to specify
+        # allow_dns_alt_names.
+        unless ca = Puppet::SSL::CertificateAuthority.instance
+          raise ArgumentError, "This process is not configured as a certificate authority"
+        end
+
+        ca.sign(name, options[:allow_dns_alt_names])
+      end
+    end
+  end
+
+  # Indirector action doc overrides
+  find = get_action(:find)
+  find.summary "Retrieve a certificate."
+  find.arguments "<host>"
+  find.render_as = :s
+  find.returns <<-EOT
+    An x509 SSL certificate.
+
+    Note that this action has a side effect of caching a copy of the
+    certificate in Puppet's `ssldir`.
+  EOT
+
+  destroy = get_action(:destroy)
+  destroy.summary "Delete a certificate."
+  destroy.arguments "<host>"
+  destroy.returns "Nothing."
+  destroy.description <<-EOT
+    Deletes a certificate. This action currently only works on the local CA.
+  EOT
+
+  get_action(:search).summary "Invalid for this subcommand."
+  get_action(:save).summary "Invalid for this subcommand."
+  get_action(:save).description "Invalid for this subcommand."
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/certificate_request.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/certificate_request.rb
new file mode 100644
index 0000000..cf342d5
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/certificate_request.rb
@@ -0,0 +1,53 @@
+require 'puppet/indirector/face'
+
+Puppet::Indirector::Face.define(:certificate_request, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Manage certificate requests."
+  description <<-EOT
+    This subcommand retrieves and submits certificate signing requests (CSRs).
+  EOT
+
+  # Per-action doc overrides
+  get_action(:destroy).summary "Invalid for this subcommand."
+
+  find = get_action(:find)
+  find.summary "Retrieve a single CSR."
+  find.arguments "<host>"
+  find.render_as = :s
+  find.returns <<-EOT
+    A single certificate request. When used from the Ruby API, returns a
+    Puppet::SSL::CertificateRequest object.
+  EOT
+  find.examples <<-EOT
+    Retrieve a single CSR from the puppet master's CA:
+
+    $ puppet certificate_request find somenode.puppetlabs.lan --terminus rest
+  EOT
+
+  search = get_action(:search)
+  search.summary "Retrieve all outstanding CSRs."
+  search.arguments "<dummy_text>"
+  search.render_as = :s
+  search.returns <<-EOT
+    A list of certificate requests. When used from the Ruby API, returns an
+    array of Puppet::SSL::CertificateRequest objects.
+  EOT
+  search.short_description <<-EOT
+    Retrieves all outstanding certificate signing requests. Due to a known bug,
+    this action requires a dummy search key, the content of which is irrelevant.
+  EOT
+  search.notes <<-EOT
+    Although this action always returns all CSRs, it requires a dummy search
+    key; this is a known bug.
+  EOT
+  search.examples <<-EOT
+    Retrieve all CSRs from the local CA (similar to 'puppet cert list'):
+
+    $ puppet certificate_request search x --terminus ca
+  EOT
+
+  get_action(:save).summary "API only: submit a certificate signing request."
+  get_action(:save).arguments "<x509_CSR>"
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/certificate_revocation_list.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/certificate_revocation_list.rb
new file mode 100644
index 0000000..022323b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/certificate_revocation_list.rb
@@ -0,0 +1,58 @@
+require 'puppet/indirector/face'
+
+Puppet::Indirector::Face.define(:certificate_revocation_list, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Manage the list of revoked certificates."
+  description <<-EOT
+    This subcommand is primarily for retrieving the certificate revocation
+    list from the CA.
+  EOT
+
+  find = get_action(:find)
+  find.summary "Retrieve the certificate revocation list."
+  find.arguments "<dummy_text>"
+  find.render_as = :s
+  find.returns <<-EOT
+    The certificate revocation list. When used from the Ruby API: returns an
+    OpenSSL::X509::CRL object.
+  EOT
+  find.short_description <<-EOT
+    Retrieves the certificate revocation list. Due to a known bug, this action
+    requires a dummy argument, the content of which is irrelevant.
+  EOT
+  find.notes <<-EOT
+    Although this action always returns the CRL from the specified terminus, it
+    requires a dummy argument; this is a known bug.
+  EOT
+  find.examples <<-EXAMPLES
+    Retrieve a copy of the puppet master's CRL:
+
+    $ puppet certificate_revocation_list find crl --terminus rest
+  EXAMPLES
+
+  destroy = get_action(:destroy)
+  destroy.summary "Delete the certificate revocation list."
+  destroy.arguments "<dummy_text>"
+  destroy.returns "Nothing."
+  destroy.description <<-EOT
+    Deletes the certificate revocation list. This cannot be done over REST, but
+    it is possible to delete the locally cached copy or the local CA's copy of
+    the CRL.
+  EOT
+  destroy.short_description <<-EOT
+    Deletes the certificate revocation list. This cannot be done over REST, but
+    it is possible to delete the locally cached copy or the local CA's copy of
+    the CRL. Due to a known bug, this action requires a dummy argument, the
+    content of which is irrelevant.
+  EOT
+  destroy.notes <<-EOT
+    Although this action always deletes the CRL from the specified terminus, it
+    requires a dummy argument; this is a known bug.
+  EOT
+
+  get_action(:search).summary "Invalid for this subcommand."
+  get_action(:save).summary "Invalid for this subcommand."
+  get_action(:save).description "Invalid for this subcommand."
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/config.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/config.rb
new file mode 100644
index 0000000..ce77cc2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/config.rb
@@ -0,0 +1,119 @@
+require 'puppet/face'
+require 'puppet/settings/ini_file'
+
+Puppet::Face.define(:config, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Interact with Puppet's settings."
+
+  description "This subcommand can inspect and modify settings from Puppet's
+    'puppet.conf' configuration file. For documentation about individual settings,
+    see http://docs.puppetlabs.com/references/latest/configuration.html."
+
+  option "--section SECTION_NAME" do
+    default_to { "main" }
+    summary "The section of the configuration file to interact with."
+    description <<-EOT
+      The section of the puppet.conf configuration file to interact with.
+
+      The three most commonly used sections are 'main', 'master', and 'agent'.
+      'Main' is the default, and is used by all Puppet applications. Other
+      sections can override 'main' values for specific applications --- the
+      'master' section affects puppet master and puppet cert, and the 'agent'
+      section affects puppet agent.
+
+      Less commonly used is the 'user' section, which affects puppet apply. Any
+      other section will be treated as the name of a legacy environment
+      (a deprecated feature), and can only include the 'manifest' and
+      'modulepath' settings.
+    EOT
+  end
+
+  action(:print) do
+    summary "Examine Puppet's current settings."
+    arguments "(all | <setting> [<setting> ...]"
+    description <<-'EOT'
+      Prints the value of a single setting or a list of settings.
+
+      This action is an alternate interface to the information available with
+      `puppet <subcommand> --configprint`.
+    EOT
+    notes <<-'EOT'
+      By default, this action reads the general configuration in the 'main'
+      section. Use the '--section' and '--environment' flags to examine other
+      configuration domains.
+    EOT
+    examples <<-'EOT'
+      Get puppet's runfile directory:
+
+      $ puppet config print rundir
+
+      Get a list of important directories from the master's config:
+
+      $ puppet config print all --section master | grep -E "(path|dir)"
+    EOT
+
+    when_invoked do |*args|
+      options = args.pop
+
+      args = Puppet.settings.to_a.collect(&:first) if args.empty? || args == ['all']
+
+      values_from_the_selected_section =
+        Puppet.settings.values(nil, options[:section].to_sym)
+
+      loader_settings = {
+        :environmentpath => values_from_the_selected_section.interpolate(:environmentpath),
+        :basemodulepath => values_from_the_selected_section.interpolate(:basemodulepath),
+      }
+
+      Puppet.override(Puppet.base_context(loader_settings),
+                     "New environment loaders generated from the requested section.") do
+        # And now we can lookup values that include those from environments configured from
+        # the requested section
+        values = Puppet.settings.values(Puppet[:environment].to_sym, options[:section].to_sym)
+        if args.length == 1
+          puts values.interpolate(args[0].to_sym)
+        else
+          args.each do |setting_name|
+            puts "#{setting_name} = #{values.interpolate(setting_name.to_sym)}"
+          end
+        end
+      end
+      nil
+    end
+  end
+
+  action(:set) do
+    summary "Set Puppet's settings."
+    arguments "[setting_name] [setting_value]"
+    description <<-'EOT'
+      Updates values in the `puppet.conf` configuration file.
+    EOT
+    notes <<-'EOT'
+      By default, this action manipulates the configuration in the
+      'main' section. Use the '--section' flag to manipulate other
+      configuration domains.
+    EOT
+    examples <<-'EOT'
+      Set puppet's runfile directory:
+
+      $ puppet config set rundir /var/run/puppet
+
+      Set the vardir for only the agent:
+
+      $ puppet config set vardir /var/lib/puppetagent --section agent
+    EOT
+
+    when_invoked do |name, value, options|
+      path = Puppet::FileSystem.pathname(Puppet.settings.which_configuration_file)
+      Puppet::FileSystem.touch(path)
+      Puppet::FileSystem.open(path, nil, 'r+') do |file|
+        Puppet::Settings::IniFile.update(file) do |config|
+          config.set(options[:section], name, value)
+        end
+      end
+      nil
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/facts.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/facts.rb
new file mode 100644
index 0000000..a36f765
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/facts.rb
@@ -0,0 +1,81 @@
+require 'puppet/indirector/face'
+require 'puppet/node/facts'
+
+Puppet::Indirector::Face.define(:facts, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Retrieve and store facts."
+  description <<-'EOT'
+    This subcommand manages facts, which are collections of normalized system
+    information used by Puppet. It can read facts directly from the local system
+    (with the default `facter` terminus), look up facts reported by other
+    systems, and submit facts to the puppet master.
+
+    When used with the `rest` terminus, this subcommand is essentially a front-end
+    to the inventory service REST API. See the inventory service documentation at
+    <http://docs.puppetlabs.com/guides/inventory_service.html> for more detail.
+  EOT
+
+  find = get_action(:find)
+  find.summary "Retrieve a node's facts."
+  find.arguments "<node_certname>"
+  find.returns <<-'EOT'
+    A hash containing some metadata and (under the "values" key) the set
+    of facts for the requested node. When used from the Ruby API: A
+    Puppet::Node::Facts object.
+
+    RENDERING ISSUES: Facts cannot currently be rendered as a string; use yaml
+    or json.
+  EOT
+  find.notes <<-'EOT'
+    When using the `facter` terminus, the host argument is ignored.
+  EOT
+  find.examples <<-'EOT'
+    Get facts from the local system:
+
+    $ puppet facts find x
+
+    Ask the puppet master for facts for an arbitrary node:
+
+    $ puppet facts find somenode.puppetlabs.lan --terminus rest
+
+    Query a DB-backed inventory directly (bypassing the REST API):
+
+    $ puppet facts find somenode.puppetlabs.lan --terminus inventory_active_record --run_mode master
+  EOT
+
+  get_action(:destroy).summary "Invalid for this subcommand."
+  get_action(:search).summary "Invalid for this subcommand."
+
+  action(:upload) do
+    summary "Upload local facts to the puppet master."
+    description <<-'EOT'
+      Reads facts from the local system using the `facter` terminus, then
+      saves the returned facts using the rest terminus.
+    EOT
+    returns "Nothing."
+    notes <<-'EOT'
+      This action requires that the puppet master's `auth.conf` file
+      allow save access to the `facts` REST terminus. Puppet agent does
+      not use this facility, and it is turned off by default. See
+      <http://docs.puppetlabs.com/guides/rest_auth_conf.html> for more details.
+    EOT
+    examples <<-'EOT'
+      Upload facts:
+
+      $ puppet facts upload
+    EOT
+
+    render_as :yaml
+
+    when_invoked do |options|
+      Puppet::Node::Facts.indirection.terminus_class = :facter
+      facts = Puppet::Node::Facts.indirection.find(Puppet[:certname])
+      Puppet::Node::Facts.indirection.terminus_class = :rest
+      Puppet::Node::Facts.indirection.save(facts)
+      Puppet.notice "Uploaded facts for '#{Puppet[:certname]}'"
+      nil
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/file.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/file.rb
new file mode 100644
index 0000000..f63350e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/file.rb
@@ -0,0 +1,47 @@
+require 'puppet/indirector/face'
+
+Puppet::Indirector::Face.define(:file, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Retrieve and store files in a filebucket"
+  description <<-'EOT'
+    This subcommand interacts with objects stored in a local or remote
+    filebucket. File objects are accessed by their MD5 sum; see the
+    examples for the relevant syntax.
+  EOT
+  notes <<-'EOT'
+    To retrieve the unmunged contents of a file, you must call find with
+    --render-as s. Rendering as yaml will return a hash of metadata
+    about the file, including its contents.
+
+    This subcommand does not interact with the `clientbucketdir` (the default
+    local filebucket for puppet agent); it interacts with the primary
+    "master"-type filebucket located in the `bucketdir`. If you wish to
+    interact with puppet agent's default filebucket, you'll need to set
+    the <--bucketdir> option appropriately when invoking actions.
+  EOT
+
+  file = get_action(:find)
+  file.summary "Retrieve a file from the filebucket."
+  file.arguments "md5/<md5sum>"
+  file.returns <<-'EOT'
+    The file object with the specified checksum.
+
+    RENDERING ISSUES: Rendering as a string returns the contents of the
+    file object; rendering as yaml returns a hash of metadata about said
+    file, including but not limited to its contents. Rendering as json
+    is currently broken, and returns a hash containing only the contents
+    of the file.
+  EOT
+  file.examples <<-'EOT'
+    Retrieve the contents of a file:
+
+    $ puppet file find md5/9aedba7f413c97dc65895b1cd9421f2c --render-as s
+  EOT
+
+  get_action(:search).summary "Invalid for this subcommand."
+  get_action(:destroy).summary "Invalid for this subcommand."
+
+  set_indirection_name :file_bucket_file
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/file/download.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/file/download.rb
new file mode 100644
index 0000000..3ab28b1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/file/download.rb
@@ -0,0 +1,57 @@
+# Download a specified file into the local filebucket.
+Puppet::Face.define(:file, '0.0.1') do
+  action :download do |*args|
+    summary "Download a file into the local filebucket."
+    arguments "( {md5}<checksum> | <puppet_url> )"
+    returns "Nothing."
+    description <<-EOT
+      Downloads a file from the puppet master's filebucket and duplicates it in
+      the local filebucket. This action's checksum syntax differs from `find`'s,
+      and it can accept a <puppet:///> URL.
+    EOT
+    examples <<-'EOT'
+      Download a file by URL:
+
+      $ puppet file download puppet:///modules/editors/vim/.vimrc
+
+      Download a file by MD5 sum:
+
+      $ puppet file download {md5}8f798d4e754db0ac89186bbaeaf0af18
+    EOT
+
+    when_invoked do |sum, options|
+      if sum =~ /^puppet:\/\// # it's a puppet url
+        require 'puppet/file_serving'
+        require 'puppet/file_serving/content'
+        unless content = Puppet::FileServing::Content.indirection.find(sum)
+          raise "Could not find metadata for #{sum}"
+        end
+        pathname = Puppet::FileSystem.pathname(content.full_path())
+        file = Puppet::FileBucket::File.new(pathname)
+      else
+        tester = Object.new
+        tester.extend(Puppet::Util::Checksums)
+
+        type    = tester.sumtype(sum)
+        sumdata = tester.sumdata(sum)
+
+        key = "#{type}/#{sumdata}"
+
+        Puppet::FileBucket::File.indirection.terminus_class = :file
+        if Puppet::FileBucket::File.indirection.head(key)
+          Puppet.info "Content for '#{sum}' already exists"
+          return
+        end
+
+        Puppet::FileBucket::File.indirection.terminus_class = :rest
+        raise "Could not download content for '#{sum}'" unless file = Puppet::FileBucket::File.indirection.find(key)
+      end
+
+
+      Puppet::FileBucket::File.indirection.terminus_class = :file
+      Puppet.notice "Saved #{sum} to filebucket"
+      Puppet::FileBucket::File.indirection.save file
+      return nil
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/file/store.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/file/store.rb
new file mode 100644
index 0000000..dc4c73b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/file/store.rb
@@ -0,0 +1,21 @@
+# Store a specified file in our filebucket.
+Puppet::Face.define(:file, '0.0.1') do
+  action :store do |*args|
+    summary "Store a file in the local filebucket."
+    arguments "<file>"
+    returns "Nothing."
+    examples <<-EOT
+      Store a file:
+
+      $ puppet file store /root/.bashrc
+    EOT
+
+    when_invoked do |path, options|
+      file = Puppet::FileBucket::File.new(Puppet::FileSystem.pathname(path))
+
+      Puppet::FileBucket::File.indirection.terminus_class = :file
+      Puppet::FileBucket::File.indirection.save file
+      file.checksum
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/help.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/help.rb
new file mode 100644
index 0000000..e9dfe90
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/help.rb
@@ -0,0 +1,194 @@
+require 'puppet/face'
+require 'puppet/application/face_base'
+require 'puppet/util/constant_inflector'
+require 'pathname'
+require 'erb'
+
+Puppet::Face.define(:help, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Display Puppet help."
+
+  action(:help) do
+    summary "Display help about Puppet subcommands and their actions."
+    arguments "[<subcommand>] [<action>]"
+    returns "Short help text for the specified subcommand or action."
+    examples <<-'EOT'
+      Get help for an action:
+
+      $ puppet help
+    EOT
+
+    option "--version VERSION" do
+      summary "The version of the subcommand for which to show help."
+    end
+
+    default
+    when_invoked do |*args|
+      # Check our invocation, because we want varargs and can't do defaults
+      # yet.  REVISIT: when we do option defaults, and positional options, we
+      # should rewrite this to use those. --daniel 2011-04-04
+      options = args.pop
+      if options.nil? or args.length > 2 then
+        if args.select { |x| x == 'help' }.length > 2 then
+          c = "\n %'(),-./=ADEFHILORSTUXY\\_`gnv|".split('')
+          i = <<-'EOT'.gsub(/\s*/, '').to_i(36)
+            3he6737w1aghshs6nwrivl8mz5mu9nywg9tbtlt081uv6fq5kvxse1td3tj1wvccmte806nb
+            cy6de2ogw0fqjymbfwi6a304vd56vlq71atwmqsvz3gpu0hj42200otlycweufh0hylu79t3
+            gmrijm6pgn26ic575qkexyuoncbujv0vcscgzh5us2swklsp5cqnuanlrbnget7rt3956kam
+            j8adhdrzqqt9bor0cv2fqgkloref0ygk3dekiwfj1zxrt13moyhn217yy6w4shwyywik7w0l
+            xtuevmh0m7xp6eoswin70khm5nrggkui6z8vdjnrgdqeojq40fya5qexk97g4d8qgw0hvokr
+            pli1biaz503grqf2ycy0ppkhz1hwhl6ifbpet7xd6jjepq4oe0ofl575lxdzjeg25217zyl4
+            nokn6tj5pq7gcdsjre75rqylydh7iia7s3yrko4f5ud9v8hdtqhu60stcitirvfj6zphppmx
+            7wfm7i9641d00bhs44n6vh6qvx39pg3urifgr6ihx3e0j1ychzypunyou7iplevitkyg6gbg
+            wm08oy1rvogcjakkqc1f7y1awdfvlb4ego8wrtgu9vzw4vmj59utwifn2ejcs569dh1oaavi
+            sc581n7jjg1dugzdu094fdobtx6rsvk3sfctvqnr36xctold
+          EOT
+          353.times{i,x=i.divmod(1184);a,b=x.divmod(37);print(c[a]*b)}
+        end
+        raise ArgumentError, "Puppet help only takes two (optional) arguments: a subcommand and an action"
+      end
+
+      version = :current
+      if options.has_key? :version then
+        if options[:version].to_s !~ /^current$/i then
+          version = options[:version]
+        else
+          if args.length == 0 then
+            raise ArgumentError, "Version only makes sense when a Faces subcommand is given"
+          end
+        end
+      end
+
+      return erb('global.erb').result(binding) if args.empty?
+
+      facename, actionname = args
+      if legacy_applications.include? facename then
+        if actionname then
+          raise ArgumentError, "Legacy subcommands don't take actions"
+        end
+        return render_application_help(facename)
+      else
+        return render_face_help(facename, actionname, version)
+      end
+    end
+  end
+
+  def render_application_help(applicationname)
+    return Puppet::Application[applicationname].help
+  end
+
+  def render_face_help(facename, actionname, version)
+    face, action = load_face_help(facename, actionname, version)
+    return template_for(face, action).result(binding)
+  end
+
+  def load_face_help(facename, actionname, version)
+    begin
+      face = Puppet::Face[facename.to_sym, version]
+    rescue Puppet::Error => detail
+      msg = <<-MSG
+Could not load help for the face #{facename}.
+Please check the error logs for more information.
+
+Detail: "#{detail.message}"
+      MSG
+      fail ArgumentError, msg, detail.backtrace
+    end
+    if actionname
+      action = face.get_action(actionname.to_sym)
+      if not action
+        fail ArgumentError, "Unable to load action #{actionname} from #{face}"
+      end
+    end
+
+    [face, action]
+  end
+
+  def template_for(face, action)
+    if action.nil?
+      erb('face.erb')
+    else
+      erb('action.erb')
+    end
+  end
+
+  def erb(name)
+    template = (Pathname(__FILE__).dirname + "help" + name)
+    erb = ERB.new(template.read, nil, '-')
+    erb.filename = template.to_s
+    return erb
+  end
+
+  # Return a list of applications that are not simply just stubs for Faces.
+  def legacy_applications
+    Puppet::Application.available_application_names.reject do |appname|
+      (is_face_app?(appname)) or (exclude_from_docs?(appname))
+    end.sort
+  end
+
+  # Return a list of all applications (both legacy and Face applications), along with a summary
+  #  of their functionality.
+  # @return [Array] An Array of Arrays.  The outer array contains one entry per application; each
+  #  element in the outer array is a pair whose first element is a String containing the application
+  #  name, and whose second element is a String containing the summary for that application.
+  def all_application_summaries()
+    Puppet::Application.available_application_names.sort.inject([]) do |result, appname|
+      next result if exclude_from_docs?(appname)
+
+      if (is_face_app?(appname))
+        begin
+          face = Puppet::Face[appname, :current]
+          result << [appname, face.summary]
+        rescue Puppet::Error
+          result << [ "! #{appname}", "! Subcommand unavailable due to error. Check error logs." ]
+        end
+      else
+        result << [appname, horribly_extract_summary_from(appname)]
+      end
+    end
+  end
+
+  def horribly_extract_summary_from(appname)
+    begin
+      help = Puppet::Application[appname].help.split("\n")
+      # Now we find the line with our summary, extract it, and return it.  This
+      # depends on the implementation coincidence of how our pages are
+      # formatted.  If we can't match the pattern we expect we return the empty
+      # string to ensure we don't blow up in the summary. --daniel 2011-04-11
+      while line = help.shift do
+        if md = /^puppet-#{appname}\([^\)]+\) -- (.*)$/.match(line) then
+          return md[1]
+        end
+      end
+    rescue Exception
+      # Damn, but I hate this: we just ignore errors here, no matter what
+      # class they are.  Meh.
+    end
+    return ''
+  end
+  # This should absolutely be a private method, but for some reason it appears
+  #  that you can't use the 'private' keyword inside of a Face definition.
+  #  See #14205.
+  #private :horribly_extract_summary_from
+
+  def exclude_from_docs?(appname)
+    %w{face_base indirection_base}.include? appname
+  end
+  # This should absolutely be a private method, but for some reason it appears
+  #  that you can't use the 'private' keyword inside of a Face definition.
+  #  See #14205.
+  #private :exclude_from_docs?
+
+  def is_face_app?(appname)
+    clazz = Puppet::Application.find(appname)
+
+    clazz.ancestors.include?(Puppet::Application::FaceBase)
+  end
+  # This should probably be a private method, but for some reason it appears
+  #  that you can't use the 'private' keyword inside of a Face definition.
+  #  See #14205.
+  #private :is_face_app?
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/help/action.erb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/help/action.erb
new file mode 100644
index 0000000..bdac243
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/help/action.erb
@@ -0,0 +1,86 @@
+<%# encoding: UTF-8%>
+<% if action.synopsis -%>
+USAGE: <%= action.synopsis %>
+
+<% end -%>
+<%= action.short_description || action.summary || face.summary || "undocumented subcommand" %>
+
+<% if action.returns -%>
+RETURNS: <%= action.returns.strip %>
+
+<% end -%>
+OPTIONS:
+<%# Remove these options once we can introspect them normally. -%>
+  --render-as FORMAT             - The rendering format to use.
+  --verbose                      - Whether to log verbosely.
+  --debug                        - Whether to log debug information.
+<%  optionroom = 30
+	summaryroom = 80 - 5 - optionroom
+
+	disp_glob_opts = action.display_global_options.uniq
+ 	unless disp_glob_opts.empty?
+		disp_glob_opts.sort.each do |name|
+			option = name
+			desc = Puppet.settings.setting(option).desc
+			type = Puppet.settings.setting(option).default
+			type ||= Puppet.settings.setting(option).type.to_s.upcase -%>
+  <%= 		"--#{option} #{type}".ljust(optionroom) + ' - ' -%>
+<%			if !(desc) -%>
+undocumented option
+<%     		elsif desc.length <= summaryroom -%>
+<%= 			desc %>
+<%
+       		else
+				words = desc.split
+				wrapped = ['']
+				i = 0
+				words.each do |word|
+					if wrapped[i].length + word.length <= summaryroom
+						wrapped[i] << word + ' '
+					else
+						i += 1
+						wrapped[i] = word + ' '
+					end
+				end -%>
+<%= 			wrapped.shift.strip %>
+<%				wrapped.each do |line| -%>
+<%= 				(' ' * (optionroom + 5) ) + line.strip %>
+<%				end
+		 	end
+	  	end
+	end
+	unless action.options.empty?
+      action.options.sort.each do |name|
+        option = action.get_option name -%>
+<%= "  " + option.optparse.join(" | ")[0,(optionroom - 1)].ljust(optionroom) + ' - ' -%>
+<%     if !(option.summary) -%>
+undocumented option
+<%     elsif option.summary.length <= summaryroom -%>
+<%= option.summary %>
+<%
+        else
+          words = option.summary.split
+          wrapped = ['']
+          i = 0
+          words.each do |word|
+            if wrapped[i].length + word.length <= summaryroom
+              wrapped[i] << word + ' '
+            else
+              i += 1
+              wrapped[i] = word + ' '
+            end
+          end
+-%>
+<%= wrapped.shift.strip %>
+<%       wrapped.each do |line| -%>
+<%= (' ' * (optionroom + 5) ) + line.strip %>
+<%       end
+        end
+      end -%>
+<% end -%>
+
+<% if face.respond_to? :indirection -%>
+TERMINI: <%= face.class.terminus_classes(face.indirection.name).join(", ") %>
+
+<% end -%>
+See 'puppet man <%= face.name %>' or 'man puppet-<%= face.name %>' for full help.
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/help/face.erb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/help/face.erb
new file mode 100644
index 0000000..becdb04
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/help/face.erb
@@ -0,0 +1,111 @@
+<%# encoding: UTF-8%>
+<% if face.synopsis -%>
+USAGE: <%= face.synopsis %>
+
+<% end -%>
+<%= (face.short_description || face.summary || "undocumented subcommand").strip %>
+
+OPTIONS:
+<%# Remove these options once we can introspect them normally. -%>
+  --render-as FORMAT             - The rendering format to use.
+  --verbose                      - Whether to log verbosely.
+  --debug                        - Whether to log debug information.
+<%	optionroom = 30
+	summaryroom = 80 - 5 - optionroom
+	
+	disp_glob_opts = face.display_global_options.uniq
+ 	unless disp_glob_opts.empty?
+		disp_glob_opts.sort.each do |name|
+			option = name
+			desc = Puppet.settings.setting(option).desc
+			type = Puppet.settings.setting(option).default
+			type ||= Puppet.settings.setting(option).type.to_s.upcase -%>
+  <%= 		"--#{option} #{type}".ljust(optionroom) + ' - ' -%>
+<%			if !(desc) -%>
+undocumented option
+<%     		elsif desc.length <= summaryroom -%>
+<%= 			desc %>
+<%			else
+				words = desc.split
+				wrapped = ['']
+				i = 0
+				words.each do |word|
+					if wrapped[i].length + word.length <= summaryroom
+						wrapped[i] << word + ' '
+					else
+						i += 1
+						wrapped[i] = word + ' '
+					end
+				end -%>
+<%= 			wrapped.shift.strip %>
+<%				wrapped.each do |line| -%>
+<%= 				(' ' * (optionroom + 5) ) + line.strip %>
+<%				end
+		 	end
+	  	end
+	end
+ 	unless face.options.empty?
+      face.options.sort.each do |name|
+        option = face.get_option name -%>
+<%= "  " + option.optparse.join(" | ")[0,(optionroom - 1)].ljust(optionroom) + ' - ' -%>
+<%     if !(option.summary) -%>
+undocumented option
+<%     elsif option.summary.length <= summaryroom -%>
+<%= option.summary %>
+<%
+       else
+         words = option.summary.split
+         wrapped = ['']
+         i = 0
+         words.each do |word|
+           if wrapped[i].length + word.length <= summaryroom
+             wrapped[i] << word + ' '
+           else
+             i += 1
+             wrapped[i] = word + ' '
+           end
+         end
+-%>
+<%= wrapped.shift.strip %>
+<%       wrapped.each do |line| -%>
+<%= (' ' * (optionroom + 5) ) + line.strip %>
+<%       end
+        end
+      end -%>
+<% end -%>
+
+ACTIONS:
+<% padding = face.actions.map{|x| x.to_s.length}.max + 2
+   summaryroom = 80 - (padding + 4)
+   face.actions.each do |actionname|
+     action = face.get_action(actionname) -%>
+  <%= action.name.to_s.ljust(padding) + '  ' -%>
+<% if !(action.summary) -%>
+undocumented action
+<% elsif action.summary.length <= summaryroom -%>
+<%= action.summary %>
+<% else
+          words = action.summary.split
+          wrapped = ['']
+          i = 0
+          words.each do |word|
+            if wrapped[i].length + word.length <= summaryroom
+              wrapped[i] << word + ' '
+            else
+              i += 1
+              wrapped[i] = word + ' '
+            end
+          end
+-%>
+<%= wrapped.shift.strip %>
+<%       wrapped.each do |line| -%>
+<%= (' ' * (padding + 4) ) + line.strip %>
+<%       end
+        end
+end -%>
+
+<% if face.respond_to? :indirection -%>
+TERMINI: <%= face.class.terminus_classes(face.indirection.name).join(", ") %>
+
+<% end -%>
+See 'puppet man <%= face.name %>' or 'man puppet-<%= face.name %>' for full help.
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/help/global.erb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/help/global.erb
new file mode 100644
index 0000000..9756ea5
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/help/global.erb
@@ -0,0 +1,16 @@
+<%# encoding: UTF-8%>
+Usage: puppet <subcommand> [options] <action> [options]
+
+Available subcommands:
+    <%# NOTE: this is probably not a good long-term solution for this.  We're only iterating over
+        applications to find the list of things we need to show help for... this works for now
+        because faces can't be run without an application stub.  However, when #6753 is resolved,
+        all of the application stubs for faces will go away, and this will need to be updated
+        to reflect that.  --cprice 2012-04-26 %>
+<% all_application_summaries.each do |appname, summary| -%>
+  <%= appname.to_s.ljust(16) %>  <%= summary %>
+<% end -%>
+
+See 'puppet help <subcommand> <action>' for help on a specific subcommand action.
+See 'puppet help <subcommand>' for help on a specific subcommand.
+Puppet v<%= Puppet.version %>
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/help/man.erb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/help/man.erb
new file mode 100644
index 0000000..e835da0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/help/man.erb
@@ -0,0 +1,152 @@
+<%# encoding: UTF-8%>
+puppet-<%= face.name %>(8) -- <%= face.summary || "Undocumented subcommand." %>
+<%= '=' * (_erbout.length - 1) %>
+
+<% if face.synopsis -%>
+SYNOPSIS
+--------
+<%= face.synopsis %>
+
+<% end
+   if face.description -%>
+DESCRIPTION
+-----------
+<%= face.description.strip %>
+
+<% end -%>
+OPTIONS
+-------
+Note that any setting that's valid in the configuration
+file is also a valid long argument, although it may or may not be
+relevant to the present action. For example, `server` and `run_mode` are valid
+settings, so you can specify `--server <servername>`, or
+`--run_mode <runmode>` as an argument.
+
+See the configuration file documentation at
+<http://docs.puppetlabs.com/references/stable/configuration.html> for the
+full list of acceptable parameters. A commented list of all
+configuration options can also be generated by running puppet with
+`--genconfig`.
+
+* --render-as FORMAT:
+  The format in which to render output. The most common formats are `json`,
+  `s` (string), `yaml`, and `console`, but other options such as `dot` are
+  sometimes available.
+* --verbose:
+  Whether to log verbosely.
+* --debug:
+  Whether to log debug information.
+<% unless face.display_global_options.empty?
+     face.display_global_options.uniq.sort.each do |name|
+		option = name
+		desc = Puppet::Util::Docs.scrub(Puppet.settings.setting(option).desc)
+		type = Puppet.settings.setting(option).default
+		type ||= Puppet.settings.setting(option).type.to_s.upcase -%>
+<%= "* --#{option} #{type}" %>:
+<%= (desc || 'Undocumented setting.').gsub(/^/, '  ') %>
+<%   end
+   end -%>
+<% unless face.options.empty?
+     face.options.sort.each do |name|
+       option = face.get_option name -%>
+<%= "* " + option.optparse.join(" | " ) %>:
+<%= (option.description || option.summary || "Undocumented option.").gsub(/^/, '  ') %>
+<%   end
+   end -%>
+
+ACTIONS
+-------
+<% face.actions.each do |actionname|
+     action = face.get_action(actionname) -%>
+* `<%= action.name.to_s %>` - <%= action.summary %>:
+<%   if action.synopsis -%>
+  `SYNOPSIS`
+
+  <%= action.synopsis %>
+
+<%   end -%>
+  `DESCRIPTION`
+
+<%   if action.description -%>
+<%= action.description.gsub(/^/, '  ') %>
+<% else -%>
+  <%= action.summary || "Undocumented action." %>
+<%   end -%>
+
+<%   unique_options = action.options - face.options
+	 unique_display_global_options = action.display_global_options - face.display_global_options
+     unless unique_options.empty? and unique_display_global_options.empty? -%>
+  `OPTIONS`
+<%      unique_display_global_options.uniq.sort.each do |name|
+		  option = name
+		  desc = Puppet::Util::Docs.scrub(Puppet.settings.setting(option).desc)
+		  type = Puppet.settings.setting(option).default
+		  type ||= Puppet.settings.setting(option).type.to_s.upcase -%>
+  <%= "<--#{option} #{type}>" %> -
+<%= (desc || "Undocumented setting.").gsub(/^/, '  ') %>
+<%      end -%>
+<%     unique_options.sort.each do |name|
+         option = action.get_option name
+         text = (option.description || option.summary || "Undocumented option.").chomp + "\n" -%>
+  <%= '<' + option.optparse.join("> | <") + '>' %> -
+<%= text.gsub(/^/, '  ') %>
+<%     end -%>
+
+<%   end -%>
+<%   if action.returns -%>
+  `RETURNS`
+
+<%= action.returns.gsub(/^/, '  ') %>
+
+<%   end
+     if action.notes -%>
+  `NOTES`
+
+<%= action.notes.gsub(/^/, '  ') %>
+
+<%   end
+   end
+   if face.examples or face.actions.any? {|actionname| face.get_action(actionname).examples} -%>
+EXAMPLES
+--------
+<% end
+   if face.examples -%>
+<%= face.examples %>
+
+<% end
+   face.actions.each do |actionname|
+     action = face.get_action(actionname)
+     if action.examples -%>
+`<%= action.name.to_s %>`
+
+<%= action.examples.strip %>
+
+<%   end
+   end -%>
+
+<% if face.notes or face.respond_to? :indirection -%>
+NOTES
+-----
+<% if face.notes -%>
+<%= face.notes.strip %>
+
+<% end # notes
+if face.respond_to? :indirection -%>
+This subcommand is an indirector face, which exposes `find`, `search`, `save`,
+and `destroy` actions for an indirected subsystem of Puppet. Valid termini for
+this face include:
+
+* `<%= face.class.terminus_classes(face.indirection.name).join("`\n* `") %>`
+
+<% end # indirection
+   end # notes or indirection
+   unless face.authors.empty? -%>
+AUTHOR
+------
+<%= face.authors.join("\n").gsub(/^/, ' * ') %>
+
+<% end -%>
+COPYRIGHT AND LICENSE
+---------------------
+<%= face.copyright %>
+<%= face.license %>
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/instrumentation_data.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/instrumentation_data.rb
new file mode 100644
index 0000000..05eb4fd
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/instrumentation_data.rb
@@ -0,0 +1,30 @@
+require 'puppet/indirector/face'
+require 'puppet/util/instrumentation/data'
+
+Puppet::Indirector::Face.define(:instrumentation_data, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Manage instrumentation listener accumulated data. DEPRECATED."
+  description <<-EOT
+    This subcommand allows to retrieve the various listener data.
+    (DEPRECATED) This subcommand will be removed in Puppet 4.0.
+  EOT
+
+  get_action(:destroy).summary "Invalid for this subcommand."
+  get_action(:save).summary "Invalid for this subcommand."
+  get_action(:search).summary "Invalid for this subcommand."
+
+  find = get_action(:find)
+  find.summary "Retrieve listener data."
+  find.render_as = :pson
+  find.returns <<-EOT
+    The data of an instrumentation listener
+  EOT
+  find.examples <<-EOT
+    Retrieve listener data:
+
+    $ puppet instrumentation_data find performance --terminus rest
+  EOT
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/instrumentation_listener.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/instrumentation_listener.rb
new file mode 100644
index 0000000..e11ef40
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/instrumentation_listener.rb
@@ -0,0 +1,98 @@
+require 'puppet/indirector/face'
+require 'puppet/util/instrumentation/listener'
+
+Puppet::Indirector::Face.define(:instrumentation_listener, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Manage instrumentation listeners. DEPRECATED."
+  description <<-EOT
+    This subcommand enables/disables or list instrumentation listeners.
+    (DEPRECATED) This subcommand will be removed in Puppet 4.0.
+  EOT
+
+  get_action(:destroy).summary "Invalid for this subcommand."
+
+  find = get_action(:find)
+  find.summary "Retrieve a single listener."
+  find.render_as = :pson
+  find.returns <<-EOT
+    The status of an instrumentation listener
+  EOT
+  find.examples <<-EOT
+    Retrieve a given listener:
+
+    $ puppet instrumentation_listener find performance --terminus rest
+  EOT
+
+  search = get_action(:search)
+  search.summary "Retrieve all instrumentation listeners statuses."
+  search.arguments "<dummy_text>"
+  search.render_as = :pson
+  search.returns <<-EOT
+    The statuses of all instrumentation listeners
+  EOT
+  search.short_description <<-EOT
+    This retrieves all instrumentation listeners
+  EOT
+  search.notes <<-EOT
+    Although this action always returns all instrumentation listeners, it requires a dummy search
+    key; this is a known bug.
+  EOT
+  search.examples <<-EOT
+    Retrieve the state of the listeners running in the remote puppet master:
+
+    $ puppet instrumentation_listener search x --terminus rest
+  EOT
+
+  def manage(name, activate)
+    Puppet::Util::Instrumentation::Listener.indirection.terminus_class = :rest
+    listener = Puppet::Face[:instrumentation_listener, '0.0.1'].find(name)
+    if listener
+      listener.enabled = activate
+      Puppet::Face[:instrumentation_listener, '0.0.1'].save(listener)
+    end
+  end
+
+  action :enable do
+    summary "Enable a given instrumentation listener."
+    arguments "<listener>"
+    returns "Nothing."
+    description <<-EOT
+      Enable a given instrumentation listener. After being enabled the listener
+      will start receiving instrumentation notifications from the probes if those
+      are enabled.
+    EOT
+    examples <<-EOT
+      Enable the "performance" listener in the running master:
+
+      $ puppet instrumentation_listener enable performance --terminus rest
+    EOT
+
+    when_invoked do |name, options|
+      manage(name, true)
+    end
+  end
+
+  action :disable do
+    summary "Disable a given instrumentation listener."
+    arguments "<listener>"
+    returns "Nothing."
+    description <<-EOT
+      Disable a given instrumentation listener. After being disabled the listener
+      will stop receiving instrumentation notifications from the probes.
+    EOT
+    examples <<-EOT
+      Disable the "performance" listener in the running master:
+
+      $ puppet instrumentation_listener disable performance --terminus rest
+    EOT
+
+    when_invoked do |name, options|
+      manage(name, false)
+    end
+  end
+
+  get_action(:save).summary "API only: modify an instrumentation listener status."
+  get_action(:save).arguments "<listener>"
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/instrumentation_probe.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/instrumentation_probe.rb
new file mode 100644
index 0000000..b77f5e9
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/instrumentation_probe.rb
@@ -0,0 +1,79 @@
+require 'puppet/indirector/face'
+require 'puppet/util/instrumentation/indirection_probe'
+
+Puppet::Indirector::Face.define(:instrumentation_probe, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Manage instrumentation probes. Deprecated"
+  description <<-EOT
+    This subcommand enables/disables or list instrumentation listeners.
+    (DEPRECATED) This subcommand will be removed in Puppet 4.0.
+  EOT
+
+  get_action(:find).summary "Invalid for this subcommand."
+
+  search = get_action(:search)
+  search.summary "Retrieve all probe statuses."
+  search.arguments "<dummy_text>"
+  search.render_as = :pson
+  search.returns <<-EOT
+    The statuses of all instrumentation probes
+  EOT
+  search.short_description <<-EOT
+    This retrieves all instrumentation probes
+  EOT
+  search.notes <<-EOT
+    Although this action always returns all instrumentation probes, it requires a dummy search
+    key; this is a known bug.
+  EOT
+  search.examples <<-EOT
+    Retrieve the state of the probes running in the remote puppet master:
+
+    $ puppet instrumentation_probe search x --terminus rest
+  EOT
+
+  action :enable do
+    summary "Enable all instrumentation probes."
+    arguments "<dummy>"
+    returns "Nothing."
+    description <<-EOT
+      Enable all instrumentation probes. After being enabled, all enabled listeners
+      will start receiving instrumentation notifications from the probes.
+    EOT
+    examples <<-EOT
+      Enable the probes for the running master:
+
+      $ puppet instrumentation_probe enable x --terminus rest
+    EOT
+
+    when_invoked do |name, options|
+      Puppet::Face[:instrumentation_probe, '0.0.1'].save(nil)
+    end
+  end
+
+  action :disable do
+    summary "Disable all instrumentation probes."
+    arguments "<dummy>"
+    returns "Nothing."
+    description <<-EOT
+      Disable all instrumentation probes. After being disabled, no listeners
+      will receive instrumentation notifications.
+    EOT
+    examples <<-EOT
+      Disable the probes for the running master:
+
+      $ puppet instrumentation_probe disable x --terminus rest
+    EOT
+
+    when_invoked do |name, options|
+      Puppet::Face[:instrumentation_probe, '0.0.1'].destroy(nil)
+    end
+  end
+
+  get_action(:save).summary "API only: enable all instrumentation probes."
+  get_action(:save).arguments "<dummy>"
+
+  get_action(:destroy).summary "API only: disable all instrumentation probes."
+  get_action(:destroy).arguments "<dummy>"
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/key.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/key.rb
new file mode 100644
index 0000000..96cfebe
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/key.rb
@@ -0,0 +1,15 @@
+require 'puppet/indirector/face'
+
+Puppet::Indirector::Face.define(:key, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Create, save, and remove certificate keys."
+  description <<-'EOT'
+    This subcommand manages certificate private keys. Keys are created
+    automatically by puppet agent and when certificate requests are generated
+    with 'puppet certificate generate'; it should not be necessary to use this
+    subcommand directly.
+  EOT
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/man.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/man.rb
new file mode 100644
index 0000000..8042da8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/man.rb
@@ -0,0 +1,99 @@
+require 'puppet/face'
+require 'puppet/util'
+require 'pathname'
+require 'erb'
+
+Puppet::Face.define(:man, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Display Puppet manual pages."
+
+  description <<-EOT
+    This subcommand displays manual pages for all Puppet subcommands. If the
+    `ronn` gem (<https://github.com/rtomayko/ronn/>) is installed on your
+    system, puppet man will display fully-formated man pages. If `ronn` is not
+    available, puppet man will display the raw (but human-readable) source text
+    in a pager.
+  EOT
+
+  notes <<-EOT
+    The pager used for display will be the first found of `$MANPAGER`, `$PAGER`,
+    `less`, `most`, or `more`.
+  EOT
+
+  action(:man) do
+    summary "Display the manual page for a Puppet subcommand."
+    arguments "<subcommand>"
+    returns <<-'EOT'
+      The man data, in Markdown format, suitable for consumption by Ronn.
+
+      RENDERING ISSUES: To skip fancy formatting and output the raw Markdown
+      text (e.g. for use in a pipeline), call this action with '--render-as s'.
+    EOT
+    examples <<-'EOT'
+      View the manual page for a subcommand:
+
+      $ puppet man facts
+    EOT
+
+    default
+    when_invoked do |name, options|
+      if legacy_applications.include? name then
+        return Puppet::Application[name].help
+      end
+
+      face = Puppet::Face[name.to_sym, :current]
+
+      file = (Pathname(__FILE__).dirname + "help" + 'man.erb')
+      erb = ERB.new(file.read, nil, '-')
+      erb.filename = file.to_s
+
+      # Run the ERB template in our current binding, including all the local
+      # variables we established just above. --daniel 2011-04-11
+      return erb.result(binding)
+    end
+
+
+    when_rendering :console do |text|
+      # OK, if we have Ronn on the path we can delegate to it and override the
+      # normal output process.  Otherwise delegate to a pager on the raw text,
+      # otherwise we finally just delegate to our parent.  Oh, well.
+
+      # These are the same options for less that git normally uses.
+      # -R : Pass through color control codes (allows display of colors)
+      # -X : Don't init/deinit terminal (leave display on screen on exit)
+      # -F : automatically exit if display fits entirely on one screen
+      # -S : don't wrap long lines
+      ENV['LESS'] ||= 'FRSX'
+
+      ronn  = Puppet::Util.which('ronn')
+      pager = [ENV['MANPAGER'], ENV['PAGER'], 'less', 'most', 'more'].
+        detect {|x| x and x.length > 0 and Puppet::Util.which(x) }
+
+      if ronn then
+        # ronn is a stupid about pager selection, we can be smarter. :)
+        if pager then ENV['PAGER'] = pager end
+
+        args  = "--man --manual='Puppet Manual' --organization='Puppet Labs, LLC'"
+        IO.popen("#{ronn} #{args}", 'w') do |fh| fh.write text end
+
+        ''                      # suppress local output, neh?
+      elsif pager then
+        IO.popen(pager, 'w') do |fh| fh.write text end
+        ''
+      else
+        text
+      end
+    end
+  end
+
+  def legacy_applications
+    # The list of applications, less those that are duplicated as a face.
+    Puppet::Application.available_application_names.reject do |appname|
+      Puppet::Face.face? appname.to_sym, :current or
+        # ...this is a nasty way to exclude non-applications. :(
+        %w{face_base indirection_base}.include? appname
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module.rb
new file mode 100644
index 0000000..111be0a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module.rb
@@ -0,0 +1,19 @@
+require 'puppet/face'
+require 'puppet/module_tool'
+require 'puppet/util/colors'
+
+Puppet::Face.define(:module, '1.0.0') do
+  extend Puppet::Util::Colors
+
+  copyright "Puppet Labs", 2012
+  license   "Apache 2 license; see COPYING"
+
+  summary "Creates, installs and searches for modules on the Puppet Forge."
+  description <<-EOT
+    This subcommand can find, install, and manage modules from the Puppet Forge,
+    a repository of user-contributed Puppet code. It can also generate empty
+    modules, and prepare locally developed modules for release on the Forge.
+  EOT
+
+  display_global_options "environment", "modulepath"
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/build.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/build.rb
new file mode 100644
index 0000000..5ee8b23
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/build.rb
@@ -0,0 +1,63 @@
+Puppet::Face.define(:module, '1.0.0') do
+  action(:build) do
+    summary "Build a module release package."
+    description <<-EOT
+      Prepares a local module for release on the Puppet Forge by building a
+      ready-to-upload archive file.
+
+      This action uses the Modulefile in the module directory to set metadata
+      used by the Forge. See <http://links.puppetlabs.com/modulefile> for more
+      about writing modulefiles.
+
+      After being built, the release archive file can be found in the module's
+      `pkg` directory.
+    EOT
+
+    returns "Pathname object representing the path to the release archive."
+
+    examples <<-EOT
+      Build a module release:
+
+      $ puppet module build puppetlabs-apache
+      notice: Building /Users/kelseyhightower/puppetlabs-apache for release
+      Module built: /Users/kelseyhightower/puppetlabs-apache/pkg/puppetlabs-apache-0.0.1.tar.gz
+
+      Build the module in the current working directory:
+
+      $ cd /Users/kelseyhightower/puppetlabs-apache
+      $ puppet module build
+      notice: Building /Users/kelseyhightower/puppetlabs-apache for release
+      Module built: /Users/kelseyhightower/puppetlabs-apache/pkg/puppetlabs-apache-0.0.1.tar.gz
+    EOT
+
+    arguments "[<path>]"
+
+    when_invoked do |*args|
+      options = args.pop
+      if options.nil? or args.length > 1 then
+        raise ArgumentError, "puppet module build only accepts 0 or 1 arguments"
+      end
+
+      module_path = args.first
+      if module_path.nil?
+        pwd = Dir.pwd
+        module_path = Puppet::ModuleTool.find_module_root(pwd)
+        if module_path.nil?
+          raise "Unable to find metadata.json or Modulefile in module root #{pwd} or parent directories. See <http://links.puppetlabs.com/modulefile> for required file format."
+        end
+      else
+        unless Puppet::ModuleTool.is_module_root?(module_path)
+          raise "Unable to find metadata.json or Modulefile in module root #{module_path}. See <http://links.puppetlabs.com/modulefile> for required file format."
+        end
+      end
+
+      Puppet::ModuleTool.set_option_defaults options
+      Puppet::ModuleTool::Applications::Builder.run(module_path, options)
+    end
+
+    when_rendering :console do |return_value|
+      # Get the string representation of the Pathname object.
+      "Module built: " + return_value.expand_path.to_s
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/changes.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/changes.rb
new file mode 100644
index 0000000..fdf7991
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/changes.rb
@@ -0,0 +1,41 @@
+Puppet::Face.define(:module, '1.0.0') do
+  action(:changes) do
+    summary "Show modified files of an installed module."
+    description <<-EOT
+      Shows any files in a module that have been modified since it was
+      installed. This action compares the files on disk to the md5 checksums
+      included in the module's metadata.
+    EOT
+
+    returns "Array of strings representing paths of modified files."
+
+    examples <<-EOT
+      Show modified files of an installed module:
+
+      $ puppet module changes /etc/puppet/modules/vcsrepo/
+      warning: 1 files modified
+      lib/puppet/provider/vcsrepo.rb
+    EOT
+
+    arguments "<path>"
+
+    when_invoked do |path, options|
+      Puppet::ModuleTool.set_option_defaults options
+      unless root_path = Puppet::ModuleTool.find_module_root(path)
+        raise ArgumentError, "Could not find a valid module at #{path.inspect}"
+      end
+      Puppet::ModuleTool::Applications::Checksummer.run(root_path, options)
+    end
+
+    when_rendering :console do |return_value|
+      if return_value.empty?
+        Puppet.notice "No modified files"
+      else
+        Puppet.warning "#{return_value.size} files modified"
+      end
+      return_value.map do |changed_file|
+        "#{changed_file}"
+      end.join("\n")
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/generate.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/generate.rb
new file mode 100644
index 0000000..9b88a8c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/generate.rb
@@ -0,0 +1,251 @@
+Puppet::Face.define(:module, '1.0.0') do
+  action(:generate) do
+    summary "Generate boilerplate for a new module."
+    description <<-EOT
+      Generates boilerplate for a new module by creating the directory
+      structure and files recommended for the Puppet community's best practices.
+
+      A module may need additional directories beyond this boilerplate
+      if it provides plugins, files, or templates.
+    EOT
+
+    returns "Array of Pathname objects representing paths of generated files."
+
+    examples <<-EOT
+      Generate a new module in the current directory:
+
+      $ puppet module generate puppetlabs-ssh
+      We need to create a metadata.json file for this module.  Please answer the
+      following questions; if the question is not applicable to this module, feel free
+      to leave it blank.
+
+      Puppet uses Semantic Versioning (semver.org) to version modules.
+      What version is this module?  [0.1.0]
+      -->
+
+      Who wrote this module?  [puppetlabs]
+      -->
+
+      What license does this module code fall under?  [Apache 2.0]
+      -->
+
+      How would you describe this module in a single sentence?
+      -->
+
+      Where is this module's source code repository?
+      -->
+
+      Where can others go to learn more about this module?
+      -->
+
+      Where can others go to file issues about this module?
+      -->
+
+      ----------------------------------------
+      {
+        "name": "puppetlabs-ssh",
+        "version": "0.1.0",
+        "author": "puppetlabs",
+        "summary": null,
+        "license": "Apache 2.0",
+        "source": "",
+        "project_page": null,
+        "issues_url": null,
+        "dependencies": [
+          {
+            "name": "puppetlabs-stdlib",
+            "version_requirement": ">= 1.0.0"
+          }
+        ]
+      }
+      ----------------------------------------
+
+      About to generate this metadata; continue? [n/Y]
+      -->
+
+      Notice: Generating module at /Users/username/Projects/puppet/puppetlabs-ssh...
+      Notice: Populating ERB templates...
+      Finished; module generated in puppetlabs-ssh.
+      puppetlabs-ssh/manifests
+      puppetlabs-ssh/manifests/init.pp
+      puppetlabs-ssh/metadata.json
+      puppetlabs-ssh/README.md
+      puppetlabs-ssh/spec
+      puppetlabs-ssh/spec/spec_helper.rb
+      puppetlabs-ssh/tests
+      puppetlabs-ssh/tests/init.pp
+    EOT
+
+    option "--skip-interview" do
+      summary "Bypass the interactive metadata interview"
+      description <<-EOT
+        Do not attempt to perform a metadata interview.  Primarily useful for automatic
+        execution of `puppet module generate`.
+      EOT
+    end
+
+    arguments "<name>"
+
+    when_invoked do |name, options|
+      # Since we only want to interview if it's being rendered to the console
+      # (i.e. when invoked with `puppet module generate`), we can't do any work
+      # here in the when_invoked block. The result of this block is then
+      # passed to each renderer, which will handle it appropriately; by
+      # returning a simple message like this, every renderer will simply output
+      # the string.
+      # Our `when_rendering :console` handler will ignore this value and
+      # actually generate the module.
+      #
+      # All this is necessary because it is not possible at this point in time
+      # to know what the destination of the output is.
+      "This format is not supported by this action."
+    end
+
+    when_rendering :console do |_, name, options|
+      Puppet::ModuleTool.set_option_defaults options
+
+      begin
+        # A default dependency for all newly generated modules is being
+        # introduced as a substitute for the comments we used to include in the
+        # Modulefile. While introducing a default dependency is less than
+        # perfectly desirable, the cost is low, and the syntax is obtuse enough
+        # to justify its inclusion.
+        metadata = Puppet::ModuleTool::Metadata.new.update(
+          'name' => name,
+          'version' => '0.1.0',
+          'dependencies' => [
+            { 'name' => 'puppetlabs-stdlib', 'version_requirement' => '>= 1.0.0' }
+          ]
+        )
+      rescue ArgumentError
+        msg = "Could not generate directory #{name.inspect}, you must specify a dash-separated username and module name."
+        raise ArgumentError, msg, $!.backtrace
+      end
+
+      dest = Puppet::ModuleTool::Generate.destination(metadata)
+      result = Puppet::ModuleTool::Generate.generate(metadata, options[:skip_interview])
+
+      path = dest.relative_path_from(Pathname.pwd)
+      puts "Finished; module generated in #{path}."
+      result.join("\n")
+    end
+  end
+end
+
+module Puppet::ModuleTool::Generate
+  module_function
+
+  def generate(metadata, skip_interview = false)
+    interview(metadata) unless skip_interview
+    destination = duplicate_skeleton(metadata)
+    all_files = destination.basename + '**/*'
+
+    return Dir[all_files.to_s]
+  end
+
+  def interview(metadata)
+    puts "We need to create a metadata.json file for this module.  Please answer the"
+    puts "following questions; if the question is not applicable to this module, feel free"
+    puts "to leave it blank."
+
+    begin
+      puts
+      puts "Puppet uses Semantic Versioning (semver.org) to version modules."
+      puts "What version is this module?  [#{metadata.version}]"
+      metadata.update 'version' => user_input(metadata.version)
+    rescue
+      Puppet.err "We're sorry, we could not parse that as a Semantic Version."
+      retry
+    end
+
+    puts
+    puts "Who wrote this module?  [#{metadata.author}]"
+    metadata.update 'author' => user_input(metadata.author)
+
+    puts
+    puts "What license does this module code fall under?  [#{metadata.license}]"
+    metadata.update 'license' => user_input(metadata.license)
+
+    puts
+    puts "How would you describe this module in a single sentence?"
+    metadata.update 'summary' => user_input(metadata.summary)
+
+    puts
+    puts "Where is this module's source code repository?"
+    metadata.update 'source' => user_input(metadata.source)
+
+    puts
+    puts "Where can others go to learn more about this module?#{ metadata.project_page && "  [#{metadata.project_page}]" }"
+    metadata.update 'project_page' => user_input(metadata.project_page)
+
+    puts
+    puts "Where can others go to file issues about this module?#{ metadata.issues_url && "  [#{metadata.issues_url}]" }"
+    metadata.update 'issues_url' => user_input(metadata.issues_url)
+
+    puts
+    puts '-' * 40
+    puts metadata.to_json
+    puts '-' * 40
+    puts
+    puts "About to generate this metadata; continue? [n/Y]"
+
+    if user_input('Y') !~ /^y(es)?$/i
+      puts "Aborting..."
+      exit 0
+    end
+  end
+
+  def user_input(default=nil)
+    print '--> '
+    input = STDIN.gets.chomp.strip
+    input = default if input == ''
+    return input
+  end
+
+  def destination(metadata)
+    return @dest if defined? @dest
+    @dest = Pathname.pwd + metadata.dashed_name
+    raise ArgumentError, "#{@dest} already exists." if @dest.exist?
+    return @dest
+  end
+
+  def duplicate_skeleton(metadata)
+    dest = destination(metadata)
+
+    puts
+    Puppet.notice "Generating module at #{dest}..."
+    FileUtils.cp_r skeleton_path, dest
+
+    populate_templates(metadata, dest)
+    return dest
+  end
+
+  def populate_templates(metadata, destination)
+    Puppet.notice "Populating templates..."
+
+    formatters = {
+      :erb      => proc { |data, ctx| ERB.new(data).result(ctx) },
+      :template => proc { |data, _| data },
+    }
+
+    formatters.each do |type, block|
+      templates = destination + "**/*.#{type}"
+
+      Dir.glob(templates.to_s, File::FNM_DOTMATCH).each do |erb|
+        path = Pathname.new(erb)
+        content = block[path.read, binding]
+
+        target = path.parent + path.basename(".#{type}")
+        target.open('w') { |f| f.write(content) }
+        path.unlink
+      end
+    end
+  end
+
+  def skeleton_path
+    return @path if defined? @path
+    path = Pathname(Puppet.settings[:module_skeleton_dir])
+    path = Pathname(__FILE__).dirname + '../../module_tool/skeleton/templates/generator' unless path.directory?
+    @path = path
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/install.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/install.rb
new file mode 100644
index 0000000..0644d05
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/install.rb
@@ -0,0 +1,145 @@
+# encoding: UTF-8
+require 'puppet/forge'
+require 'puppet/module_tool/install_directory'
+require 'pathname'
+
+Puppet::Face.define(:module, '1.0.0') do
+  action(:install) do
+    summary "Install a module from the Puppet Forge or a release archive."
+    description <<-EOT
+      Installs a module from the Puppet Forge or from a release archive file.
+
+      The specified module will be installed into the directory
+      specified with the `--target-dir` option, which defaults to the first
+      directory in the modulepath.
+    EOT
+
+    returns "Pathname object representing the path to the installed module."
+
+    examples <<-'EOT'
+      Install a module:
+
+      $ puppet module install puppetlabs-vcsrepo
+      Preparing to install into /etc/puppet/modules ...
+      Downloading from http://forgeapi.puppetlabs.com ...
+      Installing -- do not interrupt ...
+      /etc/puppet/modules
+      └── puppetlabs-vcsrepo (v0.0.4)
+
+      Install a module to a specific environment:
+
+      $ puppet module install puppetlabs-vcsrepo --environment development
+      Preparing to install into /etc/puppet/environments/development/modules ...
+      Downloading from http://forgeapi.puppetlabs.com ...
+      Installing -- do not interrupt ...
+      /etc/puppet/environments/development/modules
+      └── puppetlabs-vcsrepo (v0.0.4)
+
+      Install a specific module version:
+
+      $ puppet module install puppetlabs-vcsrepo -v 0.0.4
+      Preparing to install into /etc/puppet/modules ...
+      Downloading from http://forgeapi.puppetlabs.com ...
+      Installing -- do not interrupt ...
+      /etc/puppet/modules
+      └── puppetlabs-vcsrepo (v0.0.4)
+
+      Install a module into a specific directory:
+
+      $ puppet module install puppetlabs-vcsrepo --target-dir=/usr/share/puppet/modules
+      Preparing to install into /usr/share/puppet/modules ...
+      Downloading from http://forgeapi.puppetlabs.com ...
+      Installing -- do not interrupt ...
+      /usr/share/puppet/modules
+      └── puppetlabs-vcsrepo (v0.0.4)
+
+      Install a module into a specific directory and check for dependencies in other directories:
+
+      $ puppet module install puppetlabs-vcsrepo --target-dir=/usr/share/puppet/modules --modulepath /etc/puppet/modules
+      Preparing to install into /usr/share/puppet/modules ...
+      Downloading from http://forgeapi.puppetlabs.com ...
+      Installing -- do not interrupt ...
+      /usr/share/puppet/modules
+      └── puppetlabs-vcsrepo (v0.0.4)
+
+      Install a module from a release archive:
+
+      $ puppet module install puppetlabs-vcsrepo-0.0.4.tar.gz
+      Preparing to install into /etc/puppet/modules ...
+      Downloading from http://forgeapi.puppetlabs.com ...
+      Installing -- do not interrupt ...
+      /etc/puppet/modules
+      └── puppetlabs-vcsrepo (v0.0.4)
+
+      Install a module from a release archive and ignore dependencies:
+
+      $ puppet module install puppetlabs-vcsrepo-0.0.4.tar.gz --ignore-dependencies
+      Preparing to install into /etc/puppet/modules ...
+      Installing -- do not interrupt ...
+      /etc/puppet/modules
+      └── puppetlabs-vcsrepo (v0.0.4)
+
+    EOT
+
+    arguments "<name>"
+
+    option "--force", "-f" do
+      summary "Force overwrite of existing module, if any. (Implies --ignore-dependencies.)"
+      description <<-EOT
+        Force overwrite of existing module, if any.
+        Implies --ignore-dependencies.
+      EOT
+    end
+
+    option "--target-dir DIR", "-i DIR" do
+      summary "The directory into which modules are installed."
+      description <<-EOT
+        The directory into which modules are installed; defaults to the first
+        directory in the modulepath.
+
+        Specifying this option will change the installation directory, and
+        will use the existing modulepath when checking for dependencies. If
+        you wish to check a different set of directories for dependencies, you
+        must also use the `--environment` or `--modulepath` options.
+      EOT
+    end
+
+    option "--ignore-dependencies" do
+      summary "Do not attempt to install dependencies. (Implied by --force.)"
+      description <<-EOT
+        Do not attempt to install dependencies. Implied by --force.
+      EOT
+    end
+
+    option "--version VER", "-v VER" do
+      summary "Module version to install."
+      description <<-EOT
+        Module version to install; can be an exact version or a requirement string,
+        eg '>= 1.0.3'. Defaults to latest version.
+      EOT
+    end
+
+    when_invoked do |name, options|
+      Puppet::ModuleTool.set_option_defaults options
+      Puppet.notice "Preparing to install into #{options[:target_dir]} ..."
+
+      install_dir = Puppet::ModuleTool::InstallDirectory.new(Pathname.new(options[:target_dir]))
+      Puppet::ModuleTool::Applications::Installer.run(name, install_dir, options)
+    end
+
+    when_rendering :console do |return_value, name, options|
+      if return_value[:result] == :noop
+        Puppet.notice "Module #{name} #{return_value[:version]} is already installed."
+        exit 0
+      elsif return_value[:result] == :failure
+        Puppet.err(return_value[:error][:multiline])
+        exit 1
+      else
+        tree = Puppet::ModuleTool.build_tree(return_value[:graph], return_value[:install_dir])
+
+        "#{return_value[:install_dir]}\n" +
+        Puppet::ModuleTool.format_tree(tree)
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/list.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/list.rb
new file mode 100644
index 0000000..a6e9c56
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/list.rb
@@ -0,0 +1,275 @@
+# encoding: UTF-8
+
+Puppet::Face.define(:module, '1.0.0') do
+  action(:list) do
+    summary "List installed modules"
+    description <<-HEREDOC
+      Lists the installed puppet modules. By default, this action scans the
+      modulepath from puppet.conf's `[main]` block; use the --modulepath
+      option to change which directories are scanned.
+
+      The output of this action includes information from the module's
+      metadata, including version numbers and unmet module dependencies.
+    HEREDOC
+    returns "hash of paths to module objects"
+
+    option "--tree" do
+      summary "Whether to show dependencies as a tree view"
+    end
+
+    examples <<-'EOT'
+      List installed modules:
+
+      $ puppet module list
+        /etc/puppet/modules
+        ├── bodepd-create_resources (v0.0.1)
+        ├── puppetlabs-bacula (v0.0.2)
+        ├── puppetlabs-mysql (v0.0.1)
+        ├── puppetlabs-sqlite (v0.0.1)
+        └── puppetlabs-stdlib (v2.2.1)
+        /usr/share/puppet/modules (no modules installed)
+
+      List installed modules in a tree view:
+
+      $ puppet module list --tree
+        /etc/puppet/modules
+        └─┬ puppetlabs-bacula (v0.0.2)
+          ├── puppetlabs-stdlib (v2.2.1)
+          ├─┬ puppetlabs-mysql (v0.0.1)
+          │ └── bodepd-create_resources (v0.0.1)
+          └── puppetlabs-sqlite (v0.0.1)
+        /usr/share/puppet/modules (no modules installed)
+
+      List installed modules from a specified environment:
+
+      $ puppet module list --environment production
+        /etc/puppet/modules
+        ├── bodepd-create_resources (v0.0.1)
+        ├── puppetlabs-bacula (v0.0.2)
+        ├── puppetlabs-mysql (v0.0.1)
+        ├── puppetlabs-sqlite (v0.0.1)
+        └── puppetlabs-stdlib (v2.2.1)
+        /usr/share/puppet/modules (no modules installed)
+
+      List installed modules from a specified modulepath:
+
+      $ puppet module list --modulepath /usr/share/puppet/modules
+        /usr/share/puppet/modules (no modules installed)
+    EOT
+
+    when_invoked do |options|
+      Puppet::ModuleTool.set_option_defaults(options)
+      environment = options[:environment_instance]
+
+      {
+        :environment     => environment,
+        :modules_by_path => environment.modules_by_path,
+      }
+    end
+
+    when_rendering :console do |result, options|
+      environment     = result[:environment]
+      modules_by_path = result[:modules_by_path]
+
+      output = ''
+
+      warn_unmet_dependencies(environment)
+
+      environment.modulepath.each do |path|
+        modules = modules_by_path[path]
+        no_mods = modules.empty? ? ' (no modules installed)' : ''
+        output << "#{path}#{no_mods}\n"
+
+        if options[:tree]
+          # The modules with fewest things depending on them will be the
+          # parent of the tree.  Can't assume to start with 0 dependencies
+          # since dependencies may be cyclical.
+          modules_by_num_requires = modules.sort_by {|m| m.required_by.size}
+          @seen = {}
+          tree = list_build_tree(modules_by_num_requires, [], nil,
+            :label_unmet => true, :path => path, :label_invalid => false)
+        else
+          tree = []
+          modules.sort_by { |mod| mod.forge_name or mod.name  }.each do |mod|
+            tree << list_build_node(mod, path, :label_unmet => false,
+                      :path => path, :label_invalid => true)
+          end
+        end
+
+        output << Puppet::ModuleTool.format_tree(tree)
+      end
+
+      output
+    end
+  end
+
+  def warn_unmet_dependencies(environment)
+    error_types = {
+      :non_semantic_version => {
+        :title => "Non semantic version dependency"
+      },
+      :missing => {
+        :title => "Missing dependency"
+      },
+      :version_mismatch => {
+        :title => "Module '%s' (v%s) fails to meet some dependencies:"
+      }
+    }
+
+    @unmet_deps = {}
+    error_types.each_key do |type|
+      @unmet_deps[type] = Hash.new do |hash, key|
+        hash[key] = { :errors => [], :parent => nil }
+      end
+    end
+
+    # Prepare the unmet dependencies for display on the console.
+    environment.modules.sort_by {|mod| mod.name}.each do |mod|
+      unmet_grouped = Hash.new { |h,k| h[k] = [] }
+      unmet_grouped = mod.unmet_dependencies.inject(unmet_grouped) do |acc, dep|
+        acc[dep[:reason]] << dep
+        acc
+      end
+      unmet_grouped.each do |type, deps|
+        unless deps.empty?
+          unmet_grouped[type].sort_by { |dep| dep[:name] }.each do |dep|
+            dep_name           = dep[:name].gsub('/', '-')
+            installed_version  = dep[:mod_details][:installed_version]
+            version_constraint = dep[:version_constraint]
+            parent_name        = dep[:parent][:name].gsub('/', '-')
+            parent_version     = dep[:parent][:version]
+
+            msg = "'#{parent_name}' (#{parent_version})"
+            msg << " requires '#{dep_name}' (#{version_constraint})"
+            @unmet_deps[type][dep[:name]][:errors] << msg
+            @unmet_deps[type][dep[:name]][:parent] = {
+              :name    => dep[:parent][:name],
+              :version => parent_version
+            }
+            @unmet_deps[type][dep[:name]][:version] = installed_version
+          end
+        end
+      end
+    end
+
+    # Display unmet dependencies by category.
+    error_display_order = [:non_semantic_version, :version_mismatch, :missing]
+    error_display_order.each do |type|
+      unless @unmet_deps[type].empty?
+        @unmet_deps[type].keys.sort_by {|dep| dep }.each do |dep|
+          name    = dep.gsub('/', '-')
+          title   = error_types[type][:title]
+          errors  = @unmet_deps[type][dep][:errors]
+          version = @unmet_deps[type][dep][:version]
+
+          msg = case type
+                when :version_mismatch
+                  title % [name, version] + "\n"
+                when :non_semantic_version
+                  title + " '#{name}' (v#{version}):\n"
+                else
+                  title + " '#{name}':\n"
+                end
+
+          errors.each { |error_string| msg << "  #{error_string}\n" }
+          Puppet.warning msg.chomp
+        end
+      end
+    end
+  end
+
+  # Prepare a list of module objects and their dependencies for print in a
+  # tree view.
+  #
+  # Returns an Array of Hashes
+  #
+  # Example:
+  #
+  #   [
+  #     {
+  #       :text => "puppetlabs-bacula (v0.0.2)",
+  #       :dependencies=> [
+  #         { :text => "puppetlabs-stdlib (v2.2.1)", :dependencies => [] },
+  #         {
+  #           :text => "puppetlabs-mysql (v1.0.0)"
+  #           :dependencies => [
+  #             {
+  #               :text => "bodepd-create_resources (v0.0.1)",
+  #               :dependencies => []
+  #             }
+  #           ]
+  #         },
+  #         { :text => "puppetlabs-sqlite (v0.0.1)", :dependencies => [] },
+  #       ]
+  #     }
+  #   ]
+  #
+  # When the above data structure is passed to Puppet::ModuleTool.build_tree
+  # you end up with something like this:
+  #
+  #   /etc/puppet/modules
+  #   └─┬ puppetlabs-bacula (v0.0.2)
+  #     ├── puppetlabs-stdlib (v2.2.1)
+  #     ├─┬ puppetlabs-mysql (v1.0.0)
+  #     │ └── bodepd-create_resources (v0.0.1)
+  #     └── puppetlabs-sqlite (v0.0.1)
+  #
+  def list_build_tree(list, ancestors=[], parent=nil, params={})
+    list.map do |mod|
+      next if @seen[(mod.forge_name or mod.name)]
+      node = list_build_node(mod, parent, params)
+      @seen[(mod.forge_name or mod.name)] = true
+
+      unless ancestors.include?(mod)
+        node[:dependencies] ||= []
+        missing_deps = mod.unmet_dependencies.select do |dep|
+          dep[:reason] == :missing
+        end
+        missing_deps.map do |mis_mod|
+          str = "#{colorize(:bg_red, 'UNMET DEPENDENCY')} #{mis_mod[:name].gsub('/', '-')} "
+          str << "(#{colorize(:cyan, mis_mod[:version_constraint])})"
+          node[:dependencies] << { :text => str }
+        end
+        node[:dependencies] += list_build_tree(mod.dependencies_as_modules,
+          ancestors + [mod], mod, params)
+      end
+
+      node
+    end.compact
+  end
+
+  # Prepare a module object for print in a tree view.  Each node in the tree
+  # must be a Hash in the following format:
+  #
+  #    { :text => "puppetlabs-mysql (v1.0.0)" }
+  #
+  # The value of a module's :text is affected by three (3) factors: the format
+  # of the tree, its dependency status, and the location in the modulepath
+  # relative to its parent.
+  #
+  # Returns a Hash
+  #
+  def list_build_node(mod, parent, params)
+    str = ''
+    str << (mod.forge_name ? mod.forge_name.gsub('/', '-') : mod.name)
+    str << ' (' + colorize(:cyan, mod.version ? "v#{mod.version}" : '???') + ')'
+
+    unless File.dirname(mod.path) == params[:path]
+      str << " [#{File.dirname(mod.path)}]"
+    end
+
+    if @unmet_deps[:version_mismatch].include?(mod.forge_name)
+      if params[:label_invalid]
+        str << '  ' + colorize(:red, 'invalid')
+      elsif parent.respond_to?(:forge_name)
+        unmet_parent = @unmet_deps[:version_mismatch][mod.forge_name][:parent]
+        if (unmet_parent[:name] == parent.forge_name &&
+            unmet_parent[:version] == "v#{parent.version}")
+          str << '  ' + colorize(:red, 'invalid')
+        end
+      end
+    end
+
+    { :text => str }
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/search.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/search.rb
new file mode 100644
index 0000000..90ee550
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/search.rb
@@ -0,0 +1,94 @@
+require 'puppet/util/terminal'
+require 'puppet/forge'
+
+Puppet::Face.define(:module, '1.0.0') do
+  action(:search) do
+    summary "Search the Puppet Forge for a module."
+    description <<-EOT
+      Searches a repository for modules whose names, descriptions, or keywords
+      match the provided search term.
+    EOT
+
+    returns "Array of module metadata hashes"
+
+    examples <<-EOT
+      Search the Puppet Forge for a module:
+
+      $ puppet module search puppetlabs
+      NAME          DESCRIPTION                          AUTHOR             KEYWORDS
+      bacula        This is a generic Apache module      @puppetlabs        backups
+    EOT
+
+    arguments "<search_term>"
+
+    when_invoked do |term, options|
+      Puppet::ModuleTool.set_option_defaults options
+      Puppet::ModuleTool::Applications::Searcher.new(term, Puppet::Forge.new, options).run
+    end
+
+    when_rendering :console do |results, term, options|
+      if results[:result] == :failure
+        raise results[:error][:multiline]
+      end
+
+      return "No results found for '#{term}'." if results[:answers].empty?
+
+      padding = '  '
+      headers = {
+        'full_name' => 'NAME',
+        'desc'      => 'DESCRIPTION',
+        'author'    => 'AUTHOR',
+        'tag_list'  => 'KEYWORDS',
+      }
+
+      min_widths = Hash[ *headers.map { |k,v| [k, v.length] }.flatten ]
+      min_widths['full_name'] = min_widths['author'] = 12
+
+      min_width = min_widths.inject(0) { |sum,pair| sum += pair.last } + (padding.length * (headers.length - 1))
+
+      terminal_width = [Puppet::Util::Terminal.width, min_width].max
+
+      columns = results[:answers].inject(min_widths) do |hash, result|
+        {
+          'full_name' => [ hash['full_name'], result['full_name'].length          ].max,
+          'desc'      => [ hash['desc'],      result['desc'].length               ].max,
+          'author'    => [ hash['author'],    "@#{result['author']}".length       ].max,
+          'tag_list'  => [ hash['tag_list'],  result['tag_list'].join(' ').length ].max,
+        }
+      end
+
+      flex_width = terminal_width - columns['full_name'] - columns['author'] - (padding.length * (headers.length - 1))
+      tag_lists = results[:answers].map { |r| r['tag_list'] }
+
+      while (columns['tag_list'] > flex_width / 3)
+        longest_tag_list = tag_lists.sort_by { |tl| tl.join(' ').length }.last
+        break if [ [], [term] ].include? longest_tag_list
+        longest_tag_list.delete(longest_tag_list.sort_by { |t| t == term ? -1 : t.length }.last)
+        columns['tag_list'] =  tag_lists.map { |tl| tl.join(' ').length }.max
+      end
+
+      columns['tag_list'] = [
+        flex_width / 3,
+        tag_lists.map { |tl| tl.join(' ').length }.max,
+      ].max
+      columns['desc'] = flex_width - columns['tag_list']
+
+      format = %w{full_name desc author tag_list}.map do |k|
+        "%-#{ [ columns[k], min_widths[k] ].max }s"
+      end.join(padding) + "\n"
+
+      highlight = proc do |s|
+        s = s.gsub(term, colorize(:green, term))
+        s = s.gsub(term.gsub('/', '-'), colorize(:green, term.gsub('/', '-'))) if term =~ /\//
+        s
+      end
+
+      format % [ headers['full_name'], headers['desc'], headers['author'], headers['tag_list'] ] +
+      results[:answers].map do |match|
+        name, desc, author, keywords = %w{full_name desc author tag_list}.map { |k| match[k] }
+        desc = desc[0...(columns['desc'] - 3)] + '...' if desc.length > columns['desc']
+        highlight[format % [ name.sub('/', '-'), desc, "@#{author}", [keywords].flatten.join(' ') ]]
+      end.join
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/uninstall.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/uninstall.rb
new file mode 100644
index 0000000..2a5e675
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/uninstall.rb
@@ -0,0 +1,78 @@
+Puppet::Face.define(:module, '1.0.0') do
+  action(:uninstall) do
+    summary "Uninstall a puppet module."
+    description <<-EOT
+      Uninstalls a puppet module from the modulepath (or a specific
+      target directory).
+    EOT
+
+    returns "Hash of module objects representing uninstalled modules and related errors."
+
+    examples <<-'EOT'
+      Uninstall a module:
+
+      $ puppet module uninstall puppetlabs-ssh
+      Removed /etc/puppet/modules/ssh (v1.0.0)
+
+      Uninstall a module from a specific directory:
+
+      $ puppet module uninstall puppetlabs-ssh --modulepath /usr/share/puppet/modules
+      Removed /usr/share/puppet/modules/ssh (v1.0.0)
+
+      Uninstall a module from a specific environment:
+
+      $ puppet module uninstall puppetlabs-ssh --environment development
+      Removed /etc/puppet/environments/development/modules/ssh (v1.0.0)
+
+      Uninstall a specific version of a module:
+
+      $ puppet module uninstall puppetlabs-ssh --version 2.0.0
+      Removed /etc/puppet/modules/ssh (v2.0.0)
+    EOT
+
+    arguments "<name>"
+
+    option "--force", "-f" do
+      summary "Force uninstall of an installed module."
+      description <<-EOT
+        Force the uninstall of an installed module even if there are local
+        changes or the possibility of causing broken dependencies.
+      EOT
+    end
+
+    option "--ignore-changes", "-c" do
+      summary "Ignore any local changes made. (Implied by --force.)"
+      description <<-EOT
+        Uninstall an installed module even if there are local changes to it.  (Implied by --force.)
+      EOT
+    end
+
+    option "--version=" do
+      summary "The version of the module to uninstall"
+      description <<-EOT
+        The version of the module to uninstall. When using this option, a module
+        matching the specified version must be installed or else an error is raised.
+      EOT
+    end
+
+    when_invoked do |name, options|
+      name = name.gsub('/', '-')
+
+      Puppet::ModuleTool.set_option_defaults options
+      Puppet.notice "Preparing to uninstall '#{name}'" << (options[:version] ? " (#{colorize(:cyan, options[:version].sub(/^(?=\d)/, 'v'))})" : '') << " ..."
+      Puppet::ModuleTool::Applications::Uninstaller.run(name, options)
+    end
+
+    when_rendering :console do |return_value|
+      if return_value[:result] == :failure
+        Puppet.err(return_value[:error][:multiline])
+        exit 1
+      else
+        mod = return_value[:affected_modules].first
+        "Removed '#{return_value[:module_name]}'" <<
+        (mod.version ? " (#{colorize(:cyan, mod.version.to_s.sub(/^(?=\d)/, 'v'))})" : '') <<
+        " from #{mod.modulepath}"
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/upgrade.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/upgrade.rb
new file mode 100644
index 0000000..f671887
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/module/upgrade.rb
@@ -0,0 +1,86 @@
+# encoding: UTF-8
+
+Puppet::Face.define(:module, '1.0.0') do
+  action(:upgrade) do
+    summary "Upgrade a puppet module."
+    description <<-EOT
+      Upgrades a puppet module.
+    EOT
+
+    returns "Hash"
+
+    examples <<-EOT
+      upgrade an installed module to the latest version
+
+      $ puppet module upgrade puppetlabs-apache
+      /etc/puppet/modules
+      └── puppetlabs-apache (v1.0.0 -> v2.4.0)
+
+      upgrade an installed module to a specific version
+
+      $ puppet module upgrade puppetlabs-apache --version 2.1.0
+      /etc/puppet/modules
+      └── puppetlabs-apache (v1.0.0 -> v2.1.0)
+
+      upgrade an installed module for a specific environment
+
+      $ puppet module upgrade puppetlabs-apache --environment test
+      /usr/share/puppet/environments/test/modules
+      └── puppetlabs-apache (v1.0.0 -> v2.4.0)
+    EOT
+
+    arguments "<name>"
+
+    option "--force", "-f" do
+      summary "Force upgrade of an installed module. (Implies --ignore-dependencies.)"
+      description <<-EOT
+        Force the upgrade of an installed module even if there are local
+        changes or the possibility of causing broken dependencies.
+        Implies --ignore-dependencies.
+      EOT
+    end
+
+    option "--ignore-dependencies" do
+      summary "Do not attempt to install dependencies. (Implied by --force.)"
+      description <<-EOT
+        Do not attempt to install dependencies. Implied by --force.
+      EOT
+    end
+
+    option "--ignore-changes", "-c" do
+      summary "Ignore and overwrite any local changes made. (Implied by --force.)"
+      description <<-EOT
+        Upgrade an installed module even if there are local changes to it.  (Implied by --force.)
+      EOT
+    end
+
+    option "--version=" do
+      summary "The version of the module to upgrade to."
+      description <<-EOT
+        The version of the module to upgrade to.
+      EOT
+    end
+
+    when_invoked do |name, options|
+      name = name.gsub('/', '-')
+      Puppet.notice "Preparing to upgrade '#{name}' ..."
+      Puppet::ModuleTool.set_option_defaults options
+      Puppet::ModuleTool::Applications::Upgrader.new(name, options).run
+    end
+
+    when_rendering :console do |return_value|
+      if return_value[:result] == :noop
+        Puppet.notice return_value[:error][:multiline]
+        exit 0
+      elsif return_value[:result] == :failure
+        Puppet.err(return_value[:error][:multiline])
+        exit 1
+      else
+        tree = Puppet::ModuleTool.build_tree(return_value[:graph], return_value[:base_dir])
+
+        "#{return_value[:base_dir]}\n" +
+        Puppet::ModuleTool.format_tree(tree)
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/node.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/node.rb
new file mode 100644
index 0000000..d9c1522
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/node.rb
@@ -0,0 +1,43 @@
+require 'puppet/indirector/face'
+Puppet::Indirector::Face.define(:node, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "View and manage node definitions."
+  description <<-'EOT'
+    This subcommand interacts with node objects, which are used by Puppet to
+    build a catalog. A node object consists of the node's facts, environment,
+    node parameters (exposed in the parser as top-scope variables), and classes.
+  EOT
+
+  get_action(:destroy).summary "Invalid for this subcommand."
+  get_action(:search).summary "Invalid for this subcommand."
+  get_action(:save).summary "Invalid for this subcommand."
+  get_action(:save).description "Invalid for this subcommand."
+
+  find = get_action(:find)
+  find.summary "Retrieve a node object."
+  find.arguments "<host>"
+  find.returns <<-'EOT'
+    A hash containing the node's `classes`, `environment`, `expiration`, `name`,
+    `parameters` (its facts, combined with any ENC-set parameters), and `time`.
+    When used from the Ruby API: a Puppet::Node object.
+
+    RENDERING ISSUES: Rendering as string and json are currently broken;
+    node objects can only be rendered as yaml.
+  EOT
+  find.examples <<-'EOT'
+    Retrieve an "empty" (no classes, no ENC-imposed parameters, and an
+    environment of "production") node:
+
+    $ puppet node find somenode.puppetlabs.lan --terminus plain --render-as yaml
+
+    Retrieve a node using the puppet master's configured ENC:
+
+    $ puppet node find somenode.puppetlabs.lan --terminus exec --run_mode master --render-as yaml
+
+    Retrieve the same node from the puppet master:
+
+    $ puppet node find somenode.puppetlabs.lan --terminus rest --render-as yaml
+  EOT
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/node/clean.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/node/clean.rb
new file mode 100644
index 0000000..f1c3c34
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/node/clean.rb
@@ -0,0 +1,159 @@
+Puppet::Face.define(:node, '0.0.1') do
+  action(:clean) do
+    option "--[no-]unexport" do
+      summary "Whether to remove this node's exported resources from other nodes"
+    end
+
+    summary "Clean up everything a puppetmaster knows about a node."
+    arguments "<host1> [<host2> ...]"
+    description <<-'EOT'
+      Clean up everything a puppet master knows about a node, including certificates
+      and storeconfigs data.
+
+      The full list of info cleaned by this action is:
+
+      <Signed certificates> - ($vardir/ssl/ca/signed/node.domain.pem)
+
+      <Cached facts> - ($vardir/yaml/facts/node.domain.yaml)
+
+      <Cached node objects> - ($vardir/yaml/node/node.domain.yaml)
+
+      <Reports> - ($vardir/reports/node.domain)
+
+      <Stored configs> - (in database) The clean action can either remove all
+      data from a host in your storeconfigs database, or, with the
+      <--unexport> option, turn every exported resource supporting ensure to
+      absent so that any other host that collected those resources can remove
+      them. Without unexporting, a removed node's exported resources become
+      unmanaged by Puppet, and may linger as cruft unless you are purging
+      that resource type.
+    EOT
+
+    when_invoked do |*args|
+      nodes = args[0..-2]
+      options = args.last
+      raise "At least one node should be passed" if nodes.empty? || nodes == options
+
+      # This seems really bad; run_mode should be set as part of a class
+      # definition, and should not be modifiable beyond that.  This is one of
+      # the only places left in the code that tries to manipulate it. Other
+      # parts of code that handle certificates behave differently if the
+      # run_mode is master. Those other behaviors are needed for cleaning the
+      # certificates correctly.
+      Puppet.settings.preferred_run_mode = "master"
+
+      if Puppet::SSL::CertificateAuthority.ca?
+        Puppet::SSL::Host.ca_location = :local
+      else
+        Puppet::SSL::Host.ca_location = :none
+      end
+
+      Puppet::Node::Facts.indirection.terminus_class = :yaml
+      Puppet::Node::Facts.indirection.cache_class = :yaml
+      Puppet::Node.indirection.terminus_class = :yaml
+      Puppet::Node.indirection.cache_class = :yaml
+
+      nodes.each { |node| cleanup(node.downcase, options[:unexport]) }
+    end
+  end
+
+  def cleanup(node, unexport)
+    clean_cert(node)
+    clean_cached_facts(node)
+    clean_cached_node(node)
+    clean_reports(node)
+    clean_storeconfigs(node, unexport)
+  end
+
+  # clean signed cert for +host+
+  def clean_cert(node)
+    if Puppet::SSL::CertificateAuthority.ca?
+      Puppet::Face[:ca, :current].revoke(node)
+      Puppet::Face[:ca, :current].destroy(node)
+      Puppet.info "#{node} certificates removed from ca"
+    else
+      Puppet.info "Not managing #{node} certs as this host is not a CA"
+    end
+  end
+
+  # clean facts for +host+
+  def clean_cached_facts(node)
+    Puppet::Node::Facts.indirection.destroy(node)
+    Puppet.info "#{node}'s facts removed"
+  end
+
+  # clean cached node +host+
+  def clean_cached_node(node)
+    Puppet::Node.indirection.destroy(node)
+    Puppet.info "#{node}'s cached node removed"
+  end
+
+  # clean node reports for +host+
+  def clean_reports(node)
+    Puppet::Transaction::Report.indirection.destroy(node)
+    Puppet.info "#{node}'s reports removed"
+  end
+
+  # clean storeconfig for +node+
+  def clean_storeconfigs(node, do_unexport=false)
+    return unless Puppet[:storeconfigs] && Puppet.features.rails?
+    require 'puppet/rails'
+    Puppet::Rails.connect
+    unless rails_node = Puppet::Rails::Host.find_by_name(node)
+      Puppet.notice "No entries found for #{node} in storedconfigs."
+      return
+    end
+
+    if do_unexport
+      unexport(rails_node)
+      Puppet.notice "Force #{node}'s exported resources to absent"
+      Puppet.warning "Please wait until all other hosts have checked out their configuration before finishing the cleanup with:"
+      Puppet.warning "$ puppet node clean #{node}"
+    else
+      rails_node.destroy
+      Puppet.notice "#{node} storeconfigs removed"
+    end
+  end
+
+  def unexport(node)
+    # fetch all exported resource
+    query = {:include => {:param_values => :param_name}}
+    query[:conditions] = [ "exported=? AND host_id=?", true, node.id ]
+    Puppet::Rails::Resource.find(:all, query).each do |resource|
+      if type_is_ensurable(resource)
+        line = 0
+        param_name = Puppet::Rails::ParamName.find_or_create_by_name("ensure")
+
+        if ensure_param = resource.param_values.find(
+          :first,
+          :conditions => [ 'param_name_id = ?', param_name.id ]
+        )
+          line = ensure_param.line.to_i
+          Puppet::Rails::ParamValue.delete(ensure_param.id);
+        end
+
+        # force ensure parameter to "absent"
+        resource.param_values.create(
+          :value => "absent",
+          :line => line,
+          :param_name => param_name
+        )
+        Puppet.info("#{resource.name} has been marked as \"absent\"")
+      end
+    end
+  end
+
+  def environment
+    @environment ||= Puppet.lookup(:current_environment)
+  end
+
+  def type_is_ensurable(resource)
+    if (type = Puppet::Type.type(resource.restype)) && type.validattr?(:ensure)
+      return true
+    else
+      type = environment.known_resource_types.find_definition('', resource.restype)
+      return true if type && type.arguments.keys.include?('ensure')
+    end
+    return false
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/parser.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/parser.rb
new file mode 100644
index 0000000..b3dec4e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/parser.rb
@@ -0,0 +1,160 @@
+require 'puppet/face'
+require 'puppet/parser'
+
+Puppet::Face.define(:parser, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Interact directly with the parser."
+
+  action :validate do
+    summary "Validate the syntax of one or more Puppet manifests."
+    arguments "[<manifest>] [<manifest> ...]"
+    returns "Nothing, or the first syntax error encountered."
+    description <<-'EOT'
+      This action validates Puppet DSL syntax without compiling a catalog or
+      syncing any resources. If no manifest files are provided, it will
+      validate the default site manifest.
+
+      When validating with --parser current, the validation stops after the first
+      encountered issue.
+
+      When validating with --parser future, multiple issues per file are reported up
+      to the settings of max_error, and max_warnings. The processing stops
+      after having reported issues for the first encountered file with errors.
+    EOT
+    examples <<-'EOT'
+      Validate the default site manifest at /etc/puppet/manifests/site.pp:
+
+      $ puppet parser validate
+
+      Validate two arbitrary manifest files:
+
+      $ puppet parser validate init.pp vhost.pp
+
+      Validate from STDIN:
+
+      $ cat init.pp | puppet parser validate
+    EOT
+    when_invoked do |*args|
+      args.pop
+      files = args
+      if files.empty?
+        if not STDIN.tty?
+          Puppet[:code] = STDIN.read
+          validate_manifest
+        else
+          manifest = Puppet.lookup(:current_environment).manifest
+          files << manifest
+          Puppet.notice "No manifest specified. Validating the default manifest #{manifest}"
+        end
+      end
+      missing_files = []
+      files.each do |file|
+        if Puppet::FileSystem.exist?(file)
+          validate_manifest(file)
+        else
+          missing_files << file
+        end
+      end
+      unless missing_files.empty?
+        raise Puppet::Error, "One or more file(s) specified did not exist:\n#{missing_files.collect {|f| " " * 3 + f + "\n"}}"
+      end
+      nil
+    end
+  end
+
+
+  action (:dump) do
+    summary "Outputs a dump of the internal parse tree for debugging"
+    arguments "-e <source>| [<manifest> ...] "
+    returns "A dump of the resulting AST model unless there are syntax or validation errors."
+    description <<-'EOT'
+      This action parses and validates the Puppet DSL syntax without compiling a catalog
+      or syncing any resources. It automatically turns on the future parser for the parsing.
+
+      The command accepts one or more manifests (.pp) files, or an -e followed by the puppet
+      source text.
+      If no arguments are given, the stdin is read (unless it is attached to a terminal)
+
+      The output format of the dumped tree is not API, it may change from time to time.
+    EOT
+
+    option "--e <source>" do
+      default_to { nil }
+      summary "dump one source expression given on the command line."
+    end
+
+    option("--[no-]validate") do
+      summary "Whether or not to validate the parsed result, if no-validate only syntax errors are reported"
+    end
+
+    when_invoked do |*args|
+      require 'puppet/pops'
+      options = args.pop
+      if options[:e]
+        dump_parse(options[:e], 'command-line-string', options, false)
+      elsif args.empty?
+        if ! STDIN.tty?
+          dump_parse(STDIN.read, 'stdin', options, false)
+        else
+          raise Puppet::Error, "No input to parse given on command line or stdin"
+        end
+      else
+        missing_files = []
+        files = args
+        available_files = files.select do |file|
+          Puppet::FileSystem.exist?(file)
+        end
+        missing_files = files - available_files
+
+        dumps = available_files.collect do |file|
+          dump_parse(File.read(file), file, options)
+        end.join("")
+
+        if missing_files.empty?
+          dumps
+        else
+          dumps + "One or more file(s) specified did not exist:\n" + missing_files.collect { |f| "   #{f}" }.join("\n")
+        end
+      end
+    end
+  end
+
+  def dump_parse(source, filename, options, show_filename = true)
+    output = ""
+    dumper = Puppet::Pops::Model::ModelTreeDumper.new
+    evaluating_parser = Puppet::Pops::Parser::EvaluatingParser.new
+    begin
+      if options[:validate]
+        parse_result = evaluating_parser.parse_string(source, filename)
+      else
+        # side step the assert_and_report step
+        parse_result = evaluating_parser.parser.parse_string(source)
+      end
+      if show_filename
+        output << "--- #{filename}"
+      end
+      output << dumper.dump(parse_result) << "\n"
+    rescue Puppet::ParseError => detail
+      if show_filename
+        Puppet.err("--- #{filename}")
+      end
+      Puppet.err(detail.message)
+      ""
+    end
+  end
+
+  # @api private
+  def validate_manifest(manifest = nil)
+    env = Puppet.lookup(:current_environment)
+    validation_environment = manifest ? env.override_with(:manifest => manifest) : env
+
+    validation_environment.check_for_reparse
+    validation_environment.known_resource_types.clear
+
+  rescue => detail
+    Puppet.log_exception(detail)
+    exit(1)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/plugin.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/plugin.rb
new file mode 100644
index 0000000..7710b98
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/plugin.rb
@@ -0,0 +1,65 @@
+require 'puppet/face'
+Puppet::Face.define(:plugin, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Interact with the Puppet plugin system."
+  description <<-'EOT'
+    This subcommand provides network access to the puppet master's store of
+    plugins.
+
+    The puppet master serves Ruby code collected from the `lib` directories
+    of its modules. These plugins can be used on agent nodes to extend
+    Facter and implement custom types and providers. Plugins are normally
+    downloaded by puppet agent during the course of a run.
+  EOT
+
+  action :download do
+    summary "Download plugins from the puppet master."
+    description <<-'EOT'
+      Downloads plugins from the configured puppet master. Any plugins
+      downloaded in this way will be used in all subsequent Puppet activity.
+      This action modifies files on disk.
+    EOT
+    returns <<-'EOT'
+      A list of the files downloaded, or a confirmation that no files were
+      downloaded. When used from the Ruby API, this action returns an array of
+      the files downloaded, which will be empty if none were retrieved.
+    EOT
+    examples <<-'EOT'
+      Retrieve plugins from the puppet master:
+
+      $ puppet plugin download
+
+      Retrieve plugins from the puppet master (API example):
+
+      $ Puppet::Face[:plugin, '0.0.1'].download
+    EOT
+
+    when_invoked do |options|
+      require 'puppet/configurer/downloader'
+      remote_environment_for_plugins = Puppet::Node::Environment.remote(Puppet[:environment])
+      result = Puppet::Configurer::Downloader.new("plugin",
+                                         Puppet[:plugindest],
+                                         Puppet[:pluginsource],
+                                         Puppet[:pluginsignore],
+                                         remote_environment_for_plugins).evaluate
+      if Puppet.features.external_facts?
+          result += Puppet::Configurer::Downloader.new("pluginfacts",
+                                             Puppet[:pluginfactdest],
+                                             Puppet[:pluginfactsource],
+                                             Puppet[:pluginsignore],
+                                             remote_environment_for_plugins).evaluate
+      end
+      result
+    end
+
+    when_rendering :console do |value|
+      if value.empty? then
+        "No plugins downloaded."
+      else
+        "Downloaded these plugins: #{value.join(', ')}"
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/report.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/report.rb
new file mode 100644
index 0000000..55288cc
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/report.rb
@@ -0,0 +1,54 @@
+require 'puppet/indirector/face'
+
+Puppet::Indirector::Face.define(:report, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Create, display, and submit reports."
+
+  get_action(:find).summary "Invalid for this face."
+  get_action(:search).summary "Invalid for this face."
+  get_action(:destroy).summary "Invalid for this face."
+  save = get_action(:save)
+  save.summary "API only: submit a report."
+  save.arguments "<report>"
+  save.returns "Nothing."
+  save.examples <<-'EOT'
+    From the implementation of `puppet report submit` (API example):
+
+        begin
+          Puppet::Transaction::Report.indirection.terminus_class = :rest
+          Puppet::Face[:report, "0.0.1"].save(report)
+          Puppet.notice "Uploaded report for #{report.name}"
+        rescue => detail
+          Puppet.log_exception(detail, "Could not send report: #{detail}")
+        end
+  EOT
+
+  action(:submit) do
+    summary "API only: submit a report with error handling."
+    description <<-'EOT'
+      API only: Submits a report to the puppet master. This action is
+      essentially a shortcut and wrapper for the `save` action with the `rest`
+      terminus, and provides additional details in the event of a failure.
+    EOT
+    arguments "<report>"
+    examples <<-'EOT'
+      From secret_agent.rb (API example):
+
+          # ...
+          report  = Puppet::Face[:catalog, '0.0.1'].apply
+          Puppet::Face[:report, '0.0.1'].submit(report)
+          return report
+    EOT
+    when_invoked do |report, options|
+      begin
+        Puppet::Transaction::Report.indirection.terminus_class = :rest
+        Puppet::Face[:report, "0.0.1"].save(report)
+        Puppet.notice "Uploaded report for #{report.name}"
+      rescue => detail
+        Puppet.log_exception(detail, "Could not send report: #{detail}")
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/resource.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/resource.rb
new file mode 100644
index 0000000..99e9bec
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/resource.rb
@@ -0,0 +1,53 @@
+require 'puppet/indirector/face'
+
+Puppet::Indirector::Face.define(:resource, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "API only: interact directly with resources via the RAL."
+  description <<-'EOT'
+    API only: this face provides a Ruby API with functionality similar to the
+    puppet resource subcommand.
+  EOT
+
+  get_action(:destroy).summary "Invalid for this subcommand."
+
+  search = get_action(:search)
+  search.summary "API only: get all resources of a single type."
+  search.arguments "<resource_type>"
+  search.returns "An array of Puppet::Resource objects."
+  search.examples <<-'EOT'
+    Get a list of all user resources (API example):
+
+        all_users = Puppet::Face[:resource, '0.0.1'].search("user")
+  EOT
+
+  find = get_action(:find)
+  find.summary "API only: get a single resource."
+  find.arguments "<type>/<title>"
+  find.returns "A Puppet::Resource object."
+  find.examples <<-'EOT'
+    Print information about a user on this system (API example):
+
+        puts Puppet::Face[:resource, '0.0.1'].find("user/luke").to_pson
+  EOT
+
+  save = get_action(:save)
+  save.summary "API only: create a new resource."
+  save.description <<-EOT
+    API only: creates a new resource.
+  EOT
+  save.arguments "<resource_object>"
+  save.returns "The same resource object passed as an argument."
+  save.examples <<-'EOT'
+    Create a new file resource (API example):
+
+        my_resource = Puppet::Resource.new(
+          :file,
+          "/tmp/demonstration",
+          :parameters => {:ensure => :present, :content => "some\nthing\n"}
+        )
+
+        Puppet::Face[:resource, '0.0.1'].save(my_resource)
+  EOT
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/resource_type.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/resource_type.rb
new file mode 100644
index 0000000..3cd28da
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/resource_type.rb
@@ -0,0 +1,81 @@
+require 'puppet/indirector/face'
+
+Puppet::Indirector::Face.define(:resource_type, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "View classes, defined resource types, and nodes from all manifests."
+  description <<-'EOT'
+    This subcommand reads information about the resource collections (classes,
+    nodes, and defined types) available in Puppet's site manifest and
+    modules.
+
+    It will eventually be extended to examine native resource types.
+  EOT
+  notes <<-'EOT'
+    The `find` and `search` actions return similar hashes of resource collection
+    info. These hashes will include the following four keys:
+
+    * `file` (a string)
+    * `name` (a string)
+    * `type` (<hostclass>, <definition>, or <node>)
+    * `line` (an integer)
+
+    They may optionally include the following keys:
+
+    * `parent`    (<name_of_resource_collection>)
+    * `arguments` (a hash of parameters and default values)
+    * `doc`       (a string)
+  EOT
+
+  # Action documentation overrides:
+  get_action(:save).summary = "Invalid for this subcommand."
+  get_action(:save).description "Invalid for this subcommand."
+  get_action(:destroy).summary = "Invalid for this subcommand."
+
+  find = get_action(:find)
+  find.summary "Retrieve info about a resource collection."
+  find.arguments "<collection_name>"
+  find.returns <<-'EOT'
+    A hash of info about the requested resource collection. When used from the
+    Ruby API: returns a Puppet::Resource::Type object.
+
+    RENDERING ISSUES: yaml and string output for this indirection are currently
+    unusable; use json instead.
+  EOT
+  find.notes <<-'EOT'
+    If two resource collections share the same name (e.g. you have both a node
+    and a class named "default"), `find` will only return one of them. This can
+    be worked around by using `search` instead.
+  EOT
+  find.examples <<-'EOT'
+    Retrieve info about a specific locally-defined class:
+
+    $ puppet resource_type find ntp::disabled
+
+    Retrieve info from the puppet master about a specific class:
+
+    $ puppet resource_type find ntp --terminus rest
+  EOT
+
+  search = get_action(:search)
+  search.summary "Search for collections matching a regular expression."
+  search.arguments "<regular_expression>"
+  search.returns <<-'EOT'
+    An array of hashes of resource collection info. When used from the Ruby API:
+    returns an array of Puppet::Resource::Type objects.
+
+    RENDERING ISSUES: yaml and string output for this indirection are currently
+    unusable; use json instead.
+  EOT
+  search.examples <<-'EOT'
+    Retrieve all classes, nodes, and defined types:
+
+    $ puppet resource_type search '.*'
+
+    Search for classes related to Nagios:
+
+    $ puppet resource_type search nagios
+  EOT
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/secret_agent.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/secret_agent.rb
new file mode 100644
index 0000000..7771d57
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/secret_agent.rb
@@ -0,0 +1,54 @@
+require 'puppet/face'
+
+Puppet::Face.define(:secret_agent, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Mimics puppet agent."
+  description <<-'EOT'
+    This subcommand currently functions as a proof of concept, demonstrating how
+    the Faces API exposes Puppet's internal systems to application logic;
+    compare the actual code for puppet agent. It will eventually replace puppet
+    agent entirely, and can provide a template for users who wish to implement
+    agent-like functionality with non-standard application logic.
+  EOT
+
+  action(:synchronize) do
+    default
+    summary "Run secret_agent once."
+    description <<-'EOT'
+      Mimics a single run of puppet agent. This action does not currently
+      daemonize, but can download plugins, submit facts, retrieve and apply a
+      catalog, and submit a report to the puppet master.
+    EOT
+    returns <<-'EOT'
+      Verbose logging from the completed run. When used from the Ruby API:
+      returns a Puppet::Transaction::Report object.
+    EOT
+    examples <<-'EOT'
+      Trigger a Puppet run with the configured puppet master:
+
+      $ puppet secret_agent
+    EOT
+    notes <<-'EOT'
+      This action requires that the puppet master's `auth.conf` file allow save
+      access to the `facts` REST terminus. Puppet agent does not use this
+      facility, and it is turned off by default. See
+      <http://docs.puppetlabs.com/guides/rest_auth_conf.html> for more details.
+    EOT
+
+    when_invoked do |options|
+      Puppet::Face[:plugin, '0.0.1'].download
+
+      Puppet::Face[:facts, '0.0.1'].upload
+
+      Puppet::Face[:catalog, '0.0.1'].download
+
+      report  = Puppet::Face[:catalog, '0.0.1'].apply
+
+      Puppet::Face[:report, '0.0.1'].submit(report)
+
+      return report
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/status.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/status.rb
new file mode 100644
index 0000000..ffc44a3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/face/status.rb
@@ -0,0 +1,53 @@
+require 'puppet/indirector/face'
+
+Puppet::Indirector::Face.define(:status, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "View puppet server status."
+
+  get_action(:destroy).summary "Invalid for this subcommand."
+  get_action(:save).summary "Invalid for this subcommand."
+  get_action(:save).description "Invalid for this subcommand."
+  get_action(:search).summary "Invalid for this subcommand."
+
+  find = get_action(:find)
+  find.default = true
+  find.summary "Check status of puppet master server."
+  find.arguments "<dummy_text>"
+  find.returns <<-'EOT'
+    A "true" response or a low-level connection error. When used from the Ruby
+    API: returns a Puppet::Status object.
+  EOT
+  find.description <<-'EOT'
+    Checks whether a Puppet server is properly receiving and processing
+    HTTP requests. This action is only useful when used with '--terminus
+    rest'; when invoked with the `local` terminus, `find` will always
+    return true.
+
+    Over REST, this action will query the configured puppet master by default.
+    To query other servers, including puppet agent nodes started with the
+    <--listen> option, you can set the global <--server> and <--masterport>
+    options on the command line; note that agent nodes listen on port 8139.
+  EOT
+  find.short_description <<-EOT
+    Checks whether a Puppet server is properly receiving and processing HTTP
+    requests. Due to a known bug, this action requires a dummy argument, the
+    content of which is irrelevant. This action is only useful when used with
+    '--terminus rest', and will always return true when invoked locally.
+  EOT
+  find.notes <<-'EOT'
+    This action requires that the server's `auth.conf` file allow find
+    access to the `status` REST terminus. Puppet agent does not use this
+    facility, and it is turned off by default. See
+    <http://docs.puppetlabs.com/guides/rest_auth_conf.html> for more details.
+
+    Although this action always returns an unnamed status object, it requires a
+    dummy argument. This is a known bug.
+  EOT
+  find.examples <<-'EOT'
+    Check the status of the configured puppet master:
+
+    $ puppet status find x --terminus rest
+  EOT
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/base.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/base.rb
new file mode 100644
index 0000000..b410297
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/base.rb
@@ -0,0 +1,94 @@
+require 'puppet/util/feature'
+
+# Add the simple features, all in one file.
+
+# Order is important as some features depend on others
+
+# We have a syslog implementation
+Puppet.features.add(:syslog, :libs => ["syslog"])
+
+# We can use POSIX user functions
+Puppet.features.add(:posix) do
+  require 'etc'
+  !Etc.getpwuid(0).nil? && Puppet.features.syslog?
+end
+
+# We can use Microsoft Windows functions
+Puppet.features.add(:microsoft_windows) do
+  begin
+    # ruby
+    require 'Win32API'          # case matters in this require!
+    require 'win32ole'
+    # gems
+    require 'win32/process'
+    require 'win32/dir'
+    require 'win32/service'
+    true
+  rescue LoadError => err
+    warn "Cannot run on Microsoft Windows without the win32-process, win32-dir and win32-service gems: #{err}" unless Puppet.features.posix?
+  end
+end
+
+raise Puppet::Error,"Cannot determine basic system flavour" unless Puppet.features.posix? or Puppet.features.microsoft_windows?
+
+# We've got LDAP available.
+Puppet.features.add(:ldap, :libs => ["ldap"])
+
+# We have the Rdoc::Usage library.
+Puppet.features.add(:usage, :libs => %w{rdoc/ri/ri_paths rdoc/usage})
+
+# We have libshadow, useful for managing passwords.
+Puppet.features.add(:libshadow, :libs => ["shadow"])
+
+# We're running as root.
+Puppet.features.add(:root) { require 'puppet/util/suidmanager'; Puppet::Util::SUIDManager.root? }
+
+# We have lcs diff
+Puppet.features.add :diff, :libs => %w{diff/lcs diff/lcs/hunk}
+
+# We have augeas
+Puppet.features.add(:augeas, :libs => ["augeas"])
+
+# We have RRD available
+Puppet.features.add(:rrd_legacy, :libs => ["RRDtool"])
+Puppet.features.add(:rrd, :libs => ["RRD"])
+
+# We have OpenSSL
+Puppet.features.add(:openssl, :libs => ["openssl"])
+
+# We have CouchDB
+Puppet.features.add(:couchdb, :libs => ["couchrest"])
+
+# We have sqlite
+Puppet.features.add(:sqlite, :libs => ["sqlite3"])
+
+# We have Hiera
+Puppet.features.add(:hiera, :libs => ["hiera"])
+
+Puppet.features.add(:minitar, :libs => ["archive/tar/minitar"])
+
+# We can manage symlinks
+Puppet.features.add(:manages_symlinks) do
+  if ! Puppet::Util::Platform.windows?
+    true
+  else
+    module WindowsSymlink
+      require 'ffi'
+      extend FFI::Library
+
+      def self.is_implemented
+        begin
+          ffi_lib :kernel32
+          attach_function :CreateSymbolicLinkW, [:lpwstr, :lpwstr, :dword], :win32_bool
+
+          true
+        rescue LoadError => err
+          Puppet.debug("CreateSymbolicLink is not available")
+          false
+        end
+      end
+    end
+
+    WindowsSymlink.is_implemented
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/cfacter.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/cfacter.rb
new file mode 100644
index 0000000..18924a9
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/cfacter.rb
@@ -0,0 +1,14 @@
+require 'facter'
+require 'puppet/util/feature'
+
+Puppet.features.add :cfacter do
+  begin
+    require 'cfacter'
+
+    # The first release of cfacter didn't have the necessary interface to work with Puppet
+    # Therefore, if the version is 0.1.0, treat the feature as not present
+    CFacter.version != '0.1.0'
+  rescue LoadError
+    false
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/eventlog.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/eventlog.rb
new file mode 100644
index 0000000..14a1d93
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/eventlog.rb
@@ -0,0 +1,5 @@
+require 'puppet/util/feature'
+
+if Puppet.features.microsoft_windows?
+  Puppet.features.add(:eventlog, :libs => %{win32/eventlog})
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/external_facts.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/external_facts.rb
new file mode 100644
index 0000000..fb0b414
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/external_facts.rb
@@ -0,0 +1,5 @@
+require 'facter'
+
+Puppet.features.add(:external_facts) {
+  Facter.respond_to?(:search_external)
+}
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/libuser.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/libuser.rb
new file mode 100644
index 0000000..5d8f868
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/libuser.rb
@@ -0,0 +1,8 @@
+require 'puppet/util/feature'
+require 'puppet/util/libuser'
+
+Puppet.features.add(:libuser) {
+   File.executable?("/usr/sbin/lgroupadd") and
+   File.executable?("/usr/sbin/luseradd")  and
+   Puppet::FileSystem.exist?(Puppet::Util::Libuser.getconf)
+}
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/msgpack.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/msgpack.rb
new file mode 100644
index 0000000..3971a5e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/msgpack.rb
@@ -0,0 +1,3 @@
+require 'puppet/util/feature'
+
+Puppet.features.add(:msgpack, :libs => ["msgpack"])
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/pe_license.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/pe_license.rb
new file mode 100644
index 0000000..cdb66c1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/pe_license.rb
@@ -0,0 +1,4 @@
+require 'puppet/util/feature'
+
+#Is the pe license library installed providing the ability to read licenses.
+Puppet.features.add(:pe_license, :libs => %{pe_license})
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/pson.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/pson.rb
new file mode 100644
index 0000000..64c15f1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/pson.rb
@@ -0,0 +1,4 @@
+Puppet.features.add(:pson) do
+  Puppet.deprecation_warning "There is no need to check for pson support. It is always available."
+  true
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/rack.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/rack.rb
new file mode 100644
index 0000000..68b779b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/rack.rb
@@ -0,0 +1,19 @@
+require 'puppet/util/feature'
+
+# See if we have rack available, an HTTP Application Stack
+# Explicitly depend on rack library version >= 1.0.0
+Puppet.features.add(:rack) do
+  require 'rack'
+
+  if ! (defined?(::Rack) and defined?(::Rack.release))
+    false
+  else
+    major_version = ::Rack.release.split('.')[0].to_i
+    if major_version >= 1
+      true
+    else
+      false
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/rails.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/rails.rb
new file mode 100644
index 0000000..b76b7c1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/rails.rb
@@ -0,0 +1,47 @@
+require 'puppet/util/feature'
+
+Puppet.features.add(:rails) do
+  begin
+    # Turn off the constant watching parts of ActiveSupport, which have a huge
+    # cost in terms of the system watching loaded code to figure out if it was
+    # a missing content, and which we don't actually *use* anywhere.
+    #
+    # In fact, we *can't* depend on the feature: we don't require
+    # ActiveSupport, just load it if we use rails, if we depend on a feature
+    # that it offers. --daniel 2012-07-16
+    require 'active_support'
+    begin
+      require 'active_support/dependencies'
+      ActiveSupport::Dependencies.unhook!
+      ActiveSupport::Dependencies.mechanism = :require
+    rescue LoadError, ScriptError, StandardError => e
+      # ignore any failure - worst case we run without disabling the CPU
+      # sucking features, so are slower but ... not actually failed, just
+      # because some random future version of ActiveRecord changes.
+      Puppet.debug("disabling ActiveSupport::Dependencies failed: #{e}")
+    end
+
+    require 'active_record'
+    require 'active_record/version'
+  rescue LoadError
+    if Puppet::FileSystem.exist?("/usr/share/rails")
+      count = 0
+      Dir.entries("/usr/share/rails").each do |dir|
+        libdir = File.join("/usr/share/rails", dir, "lib")
+        if Puppet::FileSystem.exist?(libdir) and ! $LOAD_PATH.include?(libdir)
+          count += 1
+          $LOAD_PATH << libdir
+        end
+      end
+
+      retry if count > 0
+    end
+  end
+
+  unless (Puppet::Util.activerecord_version >= 2.1)
+    Puppet.info "ActiveRecord 2.1 or later required for StoreConfigs"
+    false
+  else
+    true
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/rdoc1.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/rdoc1.rb
new file mode 100644
index 0000000..a7e65c2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/rdoc1.rb
@@ -0,0 +1,16 @@
+require 'puppet/util/feature'
+
+# We have a version of RDoc compatible with our module documentation tool.
+# That is to say, we have the version that comes with Ruby 1.8.7 and earlier,
+# and not the version that comes with Ruby 1.9.1 or later.
+#
+# 1.8 => require 'rdoc/rdoc'; p RDoc::RDoc::VERSION_STRING
+#        => "RDoc V1.0.1 - 20041108"
+# 1.9 => require 'rdoc'; p RDoc::VERSION
+#        => "3.9.4"  # 1.9.2 has 2.5, 1.9.3 has 3.9
+#
+# Anything above that whole 1.0.1 thing is no good for us, and since that
+# ships with anything in the 1.8 series that we care about (eg: .5, ,7) we can
+# totally just use that as a proxy for the correct version of rdoc being
+# available. --daniel 2012-03-08
+Puppet.features.add(:rdoc1) { RUBY_VERSION[0,3] == "1.8" }
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/rubygems.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/rubygems.rb
new file mode 100644
index 0000000..e1b27bc
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/rubygems.rb
@@ -0,0 +1,7 @@
+require 'puppet/util/feature'
+
+Puppet.features.add(:rubygems) do
+  Puppet.deprecation_warning "Puppet.features.rubygems? is deprecated. Require rubygems in your application's entry point if you need it."
+
+  require 'rubygems'
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/selinux.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/selinux.rb
new file mode 100644
index 0000000..84be239
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/selinux.rb
@@ -0,0 +1,3 @@
+require 'puppet/util/feature'
+
+Puppet.features.add(:selinux, :libs => ["selinux"])
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/ssh.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/ssh.rb
new file mode 100644
index 0000000..ab2cc1d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/ssh.rb
@@ -0,0 +1,3 @@
+require 'puppet/util/feature'
+
+Puppet.features.add(:ssh, :libs => %{net/ssh})
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/stomp.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/stomp.rb
new file mode 100644
index 0000000..01fb1be
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/stomp.rb
@@ -0,0 +1,5 @@
+require 'puppet/util/feature'
+
+# We want this to load if possible, but it's not automatically
+# required.
+Puppet.features.add(:stomp, :libs => %{stomp})
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/zlib.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/zlib.rb
new file mode 100644
index 0000000..0366e21
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/feature/zlib.rb
@@ -0,0 +1,5 @@
+require 'puppet/util/feature'
+
+# We want this to load if possible, but it's not automatically
+# required.
+Puppet.features.add(:zlib, :libs => %{zlib})
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_bucket.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_bucket.rb
new file mode 100644
index 0000000..5eafcd2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_bucket.rb
@@ -0,0 +1,4 @@
+# stub
+module Puppet::FileBucket
+  class BucketError < RuntimeError; end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_bucket/dipper.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_bucket/dipper.rb
new file mode 100644
index 0000000..b627ce0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_bucket/dipper.rb
@@ -0,0 +1,119 @@
+require 'pathname'
+require 'puppet/file_bucket'
+require 'puppet/file_bucket/file'
+require 'puppet/indirector/request'
+
+class Puppet::FileBucket::Dipper
+  include Puppet::Util::Checksums
+  # This is a transitional implementation that uses REST
+  # to access remote filebucket files.
+
+  attr_accessor :name
+
+  # Creates a bucket client
+  def initialize(hash = {})
+    # Emulate the XMLRPC client
+    server      = hash[:Server]
+    port        = hash[:Port] || Puppet[:masterport]
+    environment = Puppet[:environment]
+
+    if hash.include?(:Path)
+      @local_path = hash[:Path]
+      @rest_path  = nil
+    else
+      @local_path = nil
+      @rest_path = "https://#{server}:#{port}/#{environment}/file_bucket_file/"
+    end
+    @checksum_type = Puppet[:digest_algorithm].to_sym
+    @digest = method(@checksum_type)
+  end
+
+  def local?
+    !! @local_path
+  end
+
+  # Backs up a file to the file bucket
+  def backup(file)
+    file_handle = Puppet::FileSystem.pathname(file)
+    raise(ArgumentError, "File #{file} does not exist") unless Puppet::FileSystem.exist?(file_handle)
+    begin
+      file_bucket_file = Puppet::FileBucket::File.new(file_handle, :bucket_path => @local_path)
+      files_original_path = absolutize_path(file)
+      dest_path = "#{@rest_path}#{file_bucket_file.name}/#{files_original_path}"
+      file_bucket_path = "#{@rest_path}#{file_bucket_file.checksum_type}/#{file_bucket_file.checksum_data}/#{files_original_path}"
+
+      # Make a HEAD request for the file so that we don't waste time
+      # uploading it if it already exists in the bucket.
+      unless Puppet::FileBucket::File.indirection.head(file_bucket_path)
+        Puppet::FileBucket::File.indirection.save(file_bucket_file, dest_path)
+      end
+
+      return file_bucket_file.checksum_data
+    rescue => detail
+      message = "Could not back up #{file}: #{detail}"
+      Puppet.log_exception(detail, message)
+      raise Puppet::Error, message, detail.backtrace
+    end
+  end
+
+  # Retrieves a file by sum.
+  def getfile(sum)
+    get_bucket_file(sum).to_s
+  end
+
+  # Retrieves a FileBucket::File by sum.
+  def get_bucket_file(sum)
+    source_path = "#{@rest_path}#{@checksum_type}/#{sum}"
+    file_bucket_file = Puppet::FileBucket::File.indirection.find(source_path, :bucket_path => @local_path)
+
+    raise Puppet::Error, "File not found" unless file_bucket_file
+    file_bucket_file
+  end
+
+  # Restores the file
+  def restore(file, sum)
+    restore = true
+    file_handle = Puppet::FileSystem.pathname(file)
+    if Puppet::FileSystem.exist?(file_handle)
+      cursum = Puppet::FileBucket::File.new(file_handle).checksum_data()
+
+      # if the checksum has changed...
+      # this might be extra effort
+      if cursum == sum
+        restore = false
+      end
+    end
+
+    if restore
+      if newcontents = get_bucket_file(sum)
+        newsum = newcontents.checksum_data
+        changed = nil
+        if Puppet::FileSystem.exist?(file_handle) and ! Puppet::FileSystem.writable?(file_handle)
+          changed = Puppet::FileSystem.stat(file_handle).mode
+          ::File.chmod(changed | 0200, file)
+        end
+        ::File.open(file, ::File::WRONLY|::File::TRUNC|::File::CREAT) { |of|
+          of.binmode
+          source_stream = newcontents.stream do |source_stream|
+            FileUtils.copy_stream(source_stream, of)
+          end
+          #of.print(newcontents)
+        }
+        ::File.chmod(changed, file) if changed
+      else
+        Puppet.err "Could not find file with checksum #{sum}"
+        return nil
+      end
+      return newsum
+    else
+      return nil
+    end
+  end
+
+  private
+  def absolutize_path( path )
+    Pathname.new(path).realpath
+  end
+
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_bucket/file.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_bucket/file.rb
new file mode 100644
index 0000000..9c9d2eb
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_bucket/file.rb
@@ -0,0 +1,157 @@
+require 'puppet/file_bucket'
+require 'puppet/indirector'
+require 'puppet/util/checksums'
+require 'digest/md5'
+require 'stringio'
+
+class Puppet::FileBucket::File
+  # This class handles the abstract notion of a file in a filebucket.
+  # There are mechanisms to save and load this file locally and remotely in puppet/indirector/filebucketfile/*
+  # There is a compatibility class that emulates pre-indirector filebuckets in Puppet::FileBucket::Dipper
+  extend Puppet::Indirector
+  indirects :file_bucket_file, :terminus_class => :selector
+
+  attr :bucket_path
+
+  def self.supported_formats
+    [:s, :pson]
+  end
+
+  def self.default_format
+    # This should really be :raw, like is done for Puppet::FileServing::Content
+    # but this class hasn't historically supported `from_raw`, so switching
+    # would break compatibility between newer 3.x agents talking to older 3.x
+    # masters. However, to/from_s has been supported and achieves the desired
+    # result without breaking compatibility.
+    :s
+  end
+
+  def initialize(contents, options = {})
+    case contents
+    when String
+      @contents = StringContents.new(contents)
+    when Pathname
+      @contents = FileContents.new(contents)
+    else
+      raise ArgumentError.new("contents must be a String or Pathname, got a #{contents.class}")
+    end
+
+    @bucket_path = options.delete(:bucket_path)
+    @checksum_type = Puppet[:digest_algorithm].to_sym
+    raise ArgumentError.new("Unknown option(s): #{options.keys.join(', ')}") unless options.empty?
+  end
+
+  # @return [Num] The size of the contents
+  def size
+    @contents.size()
+  end
+
+  # @return [IO] A stream that reads the contents
+  def stream(&block)
+    @contents.stream(&block)
+  end
+
+  def checksum_type
+    @checksum_type.to_s
+  end
+
+  def checksum
+    "{#{checksum_type}}#{checksum_data}"
+  end
+
+  def checksum_data
+    @checksum_data ||= @contents.checksum_data(@checksum_type)
+  end
+
+  def to_s
+    @contents.to_s
+  end
+
+  def contents
+    to_s
+  end
+
+  def name
+    "#{checksum_type}/#{checksum_data}"
+  end
+
+  def self.from_s(contents)
+    self.new(contents)
+  end
+
+  def to_data_hash
+    # Note that this serializes the entire data to a string and places it in a hash.
+    { "contents" => contents.to_s }
+  end
+
+  def self.from_data_hash(data)
+    self.new(data["contents"])
+  end
+
+  def to_pson
+    Puppet.deprecation_warning("Serializing Puppet::FileBucket::File objects to pson is deprecated.")
+    to_data_hash.to_pson
+  end
+
+  # This method is deprecated, but cannot be removed for awhile, otherwise
+  # older agents sending pson couldn't backup to filebuckets on newer masters
+  def self.from_pson(pson)
+    Puppet.deprecation_warning("Deserializing Puppet::FileBucket::File objects from pson is deprecated. Upgrade to a newer version.")
+    self.from_data_hash(pson)
+  end
+
+  private
+
+  class StringContents
+    def initialize(content)
+      @contents = content;
+    end
+
+    def stream(&block)
+      s = StringIO.new(@contents)
+      begin
+        block.call(s)
+      ensure
+        s.close
+      end
+    end
+
+    def size
+      @contents.size
+    end
+
+    def checksum_data(base_method)
+      Puppet.info("Computing checksum on string")
+      Puppet::Util::Checksums.method(base_method).call(@contents)
+    end
+
+    def to_s
+      # This is not so horrible as for FileContent, but still possible to mutate the content that the
+      # checksum is based on... so semi horrible...
+      return @contents;
+    end
+  end
+
+  class FileContents
+    def initialize(path)
+      @path = path
+    end
+
+    def stream(&block)
+      Puppet::FileSystem.open(@path, nil, 'rb', &block)
+    end
+
+    def size
+      Puppet::FileSystem.size(@path)
+    end
+
+    def checksum_data(base_method)
+      Puppet.info("Computing checksum on file #{@path}")
+      Puppet::Util::Checksums.method(:"#{base_method}_file").call(@path)
+    end
+
+    def to_s
+      Puppet::FileSystem::binread(@path)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_collection.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_collection.rb
new file mode 100644
index 0000000..42ebfd4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_collection.rb
@@ -0,0 +1,19 @@
+# This was a simple way to turn file names into singletons,
+#
+# The theory was, like:
+# 1. Turn filenames into singletons.
+# 2. ????
+# 3. Huge memory savings!
+#
+# In practice it used several MB more memory overall, and it cost more CPU
+# time, and it added complexity to the code.  Which was awesome.
+#
+# So, I gutted it.  It doesn't do anything any more, but we retain the
+# external form that people included so that they don't explode so much.
+#
+# This should be removed from the system after a graceful deprecation period,
+# probably about the time that a version of Puppet containing this change is
+# the last supported version. --daniel 2012-07-17
+class Puppet::FileCollection
+  require 'puppet/file_collection/lookup'
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_collection/lookup.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_collection/lookup.rb
new file mode 100644
index 0000000..598b184
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_collection/lookup.rb
@@ -0,0 +1,10 @@
+require 'puppet/file_collection'
+
+module Puppet::FileCollection::Lookup
+  # Yeah, this is all the external interface that was added to the folks who
+  # included this really was.  Thankfully.
+  #
+  # See the comments in `puppet/file_collection.rb` for the annotated version,
+  # or just port your code away from this by adding the accessors on your own.
+  attr_accessor :line, :file
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving.rb
new file mode 100644
index 0000000..0adbac9
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving.rb
@@ -0,0 +1,3 @@
+# Just a stub class.
+class Puppet::FileServing # :nodoc:
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/base.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/base.rb
new file mode 100644
index 0000000..c2e2c1e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/base.rb
@@ -0,0 +1,95 @@
+require 'puppet/file_serving'
+require 'puppet/util'
+require 'puppet/util/methodhelper'
+
+# The base class for Content and Metadata; provides common
+# functionality like the behaviour around links.
+class Puppet::FileServing::Base
+  include Puppet::Util::MethodHelper
+
+  # This is for external consumers to store the source that was used
+  # to retrieve the metadata.
+  attr_accessor :source
+
+  # Does our file exist?
+  def exist?
+      stat
+      return true
+  rescue
+      return false
+  end
+
+  # Return the full path to our file.  Fails if there's no path set.
+  def full_path(dummy_argument=:work_arround_for_ruby_GC_bug)
+    if relative_path.nil? or relative_path == "" or relative_path == "."
+       full_path = path
+     else
+       full_path = File.join(path, relative_path)
+     end
+
+     if Puppet.features.microsoft_windows?
+       # Replace multiple slashes as long as they aren't at the beginning of a filename
+       full_path.gsub(%r{(./)/+}, '\1')
+     else
+       full_path.gsub(%r{//+}, '/')
+     end
+  end
+
+  def initialize(path, options = {})
+    self.path = path
+    @links = :manage
+    set_options(options)
+  end
+
+  # Determine how we deal with links.
+  attr_reader :links
+  def links=(value)
+    value = value.to_sym
+    value = :manage if value == :ignore
+    raise(ArgumentError, ":links can only be set to :manage or :follow") unless [:manage, :follow].include?(value)
+    @links = value
+  end
+
+  # Set our base path.
+  attr_reader :path
+  def path=(path)
+    raise ArgumentError.new("Paths must be fully qualified") unless Puppet::FileServing::Base.absolute?(path)
+    @path = path
+  end
+
+  # Set a relative path; this is used for recursion, and sets
+  # the file's path relative to the initial recursion point.
+  attr_reader :relative_path
+  def relative_path=(path)
+    raise ArgumentError.new("Relative paths must not be fully qualified") if Puppet::FileServing::Base.absolute?(path)
+    @relative_path = path
+  end
+
+  # Stat our file, using the appropriate link-sensitive method.
+  def stat
+    @stat_method ||= self.links == :manage ? :lstat : :stat
+    Puppet::FileSystem.send(@stat_method, full_path)
+  end
+
+  def to_data_hash
+    {
+      'path'          => @path,
+      'relative_path' => @relative_path,
+      'links'         => @links
+    }
+  end
+
+  def to_pson_data_hash
+    {
+      # No 'document_type' since we don't send these bare
+      'data'       => to_data_hash,
+      'metadata' => {
+        'api_version' => 1
+        }
+    }
+  end
+
+  def self.absolute?(path)
+    Puppet::Util.absolute_path?(path, :posix) or (Puppet.features.microsoft_windows? and Puppet::Util.absolute_path?(path, :windows))
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/configuration.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/configuration.rb
new file mode 100644
index 0000000..4ac8973
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/configuration.rb
@@ -0,0 +1,109 @@
+require 'puppet'
+require 'puppet/file_serving'
+require 'puppet/file_serving/mount'
+require 'puppet/file_serving/mount/file'
+require 'puppet/file_serving/mount/modules'
+require 'puppet/file_serving/mount/plugins'
+require 'puppet/file_serving/mount/pluginfacts'
+
+class Puppet::FileServing::Configuration
+  require 'puppet/file_serving/configuration/parser'
+
+  def self.configuration
+    @configuration ||= new
+  end
+
+  Mount = Puppet::FileServing::Mount
+
+  private_class_method  :new
+
+  attr_reader :mounts
+  #private :mounts
+
+  # Find the right mount.  Does some shenanigans to support old-style module
+  # mounts.
+  def find_mount(mount_name, environment)
+    # Reparse the configuration if necessary.
+    readconfig
+    # This can be nil.
+    mounts[mount_name]
+  end
+
+  def initialize
+    @mounts = {}
+    @config_file = nil
+
+    # We don't check to see if the file is modified the first time,
+    # because we always want to parse at first.
+    readconfig(false)
+  end
+
+  # Is a given mount available?
+  def mounted?(name)
+    @mounts.include?(name)
+  end
+
+  # Split the path into the separate mount point and path.
+  def split_path(request)
+    # Reparse the configuration if necessary.
+    readconfig
+
+    mount_name, path = request.key.split(File::Separator, 2)
+
+    raise(ArgumentError, "Cannot find file: Invalid mount '#{mount_name}'") unless mount_name =~ %r{^[-\w]+$}
+    raise(ArgumentError, "Cannot find file: Invalid relative path '#{path}'") if path and path.split('/').include?('..')
+
+    return nil unless mount = find_mount(mount_name, request.environment)
+    if mount.name == "modules" and mount_name != "modules"
+      # yay backward-compatibility
+      path = "#{mount_name}/#{path}"
+    end
+
+    if path == ""
+      path = nil
+    elsif path
+      # Remove any double slashes that might have occurred
+      path = path.gsub(/\/+/, "/")
+    end
+
+    return mount, path
+  end
+
+  def umount(name)
+    @mounts.delete(name) if @mounts.include? name
+  end
+
+  private
+
+  def mk_default_mounts
+    @mounts["modules"] ||= Mount::Modules.new("modules")
+    @mounts["modules"].allow('*') if @mounts["modules"].empty?
+    @mounts["plugins"] ||= Mount::Plugins.new("plugins")
+    @mounts["plugins"].allow('*') if @mounts["plugins"].empty?
+    @mounts["pluginfacts"] ||= Mount::PluginFacts.new("pluginfacts")
+    @mounts["pluginfacts"].allow('*') if @mounts["pluginfacts"].empty?
+  end
+
+  # Read the configuration file.
+  def readconfig(check = true)
+    config = Puppet[:fileserverconfig]
+
+    return unless Puppet::FileSystem.exist?(config)
+
+    @parser ||= Puppet::FileServing::Configuration::Parser.new(config)
+
+    return if check and ! @parser.changed?
+
+    # Don't assign the mounts hash until we're sure the parsing succeeded.
+    begin
+      newmounts = @parser.parse
+      @mounts = newmounts
+    rescue => detail
+      Puppet.log_exception(detail, "Error parsing fileserver configuration: #{detail}; using old configuration")
+    end
+
+  ensure
+    # Make sure we've got our plugins and modules.
+    mk_default_mounts
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/configuration/parser.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/configuration/parser.rb
new file mode 100644
index 0000000..2ae8313
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/configuration/parser.rb
@@ -0,0 +1,121 @@
+require 'puppet/file_serving/configuration'
+require 'puppet/util/watched_file'
+
+class Puppet::FileServing::Configuration::Parser
+  Mount = Puppet::FileServing::Mount
+  MODULES = 'modules'
+
+  # Parse our configuration file.
+  def parse
+    raise("File server configuration #{@file} does not exist") unless Puppet::FileSystem.exist?(@file)
+    raise("Cannot read file server configuration #{@file}") unless FileTest.readable?(@file)
+
+    @mounts = {}
+    @count = 0
+
+    File.open(@file) { |f|
+      mount = nil
+      f.each_line { |line|
+        # Have the count increment at the top, in case we throw exceptions.
+        @count += 1
+
+        case line
+        when /^\s*#/; next # skip comments
+        when /^\s*$/; next # skip blank lines
+        when /\[([-\w]+)\]/
+          mount = newmount($1)
+        when /^\s*(\w+)\s+(.+?)(\s*#.*)?$/
+          var = $1
+          value = $2
+          value.strip!
+          raise(ArgumentError, "Fileserver configuration file does not use '=' as a separator") if value =~ /^=/
+          case var
+          when "path"
+            path(mount, value)
+          when "allow"
+            allow(mount, value)
+          when "deny"
+            deny(mount, value)
+          else
+            raise ArgumentError.new("Invalid argument '#{var}' in #{@file.filename}, line #{@count}")
+          end
+        else
+          raise ArgumentError.new("Invalid line '#{line.chomp}' at #{@file.filename}, line #{@count}")
+        end
+      }
+    }
+
+    validate
+
+    @mounts
+  end
+
+  def initialize(filename)
+    @file = Puppet::Util::WatchedFile.new(filename)
+  end
+
+  def changed?
+    @file.changed?
+  end
+
+  private
+
+  # Allow a given pattern access to a mount.
+  def allow(mount, value)
+    value.split(/\s*,\s*/).each { |val|
+      begin
+        mount.info "allowing #{val} access"
+        mount.allow(val)
+      rescue Puppet::AuthStoreError => detail
+        raise ArgumentError.new("#{detail.to_s} in #{@file}, line #{@count}")
+      end
+    }
+  end
+
+  # Deny a given pattern access to a mount.
+  def deny(mount, value)
+    value.split(/\s*,\s*/).each { |val|
+      begin
+        mount.info "denying #{val} access"
+        mount.deny(val)
+      rescue Puppet::AuthStoreError => detail
+        raise ArgumentError.new("#{detail.to_s} in #{@file}, line #{@count}")
+      end
+    }
+  end
+
+  # Create a new mount.
+  def newmount(name)
+    raise ArgumentError.new("#{@mounts[name]} is already mounted at #{name} in #{@file}, line #{@count}") if @mounts.include?(name)
+    case name
+    when "modules"
+      mount = Mount::Modules.new(name)
+    when "plugins"
+      mount = Mount::Plugins.new(name)
+    else
+      mount = Mount::File.new(name)
+    end
+    @mounts[name] = mount
+    mount
+  end
+
+  # Set the path for a mount.
+  def path(mount, value)
+    if mount.respond_to?(:path=)
+      begin
+        mount.path = value
+      rescue ArgumentError => detail
+        Puppet.log_exception(detail, "Removing mount \"#{mount.name}\": #{detail}")
+        @mounts.delete(mount.name)
+      end
+    else
+      Puppet.warning "The '#{mount.name}' module can not have a path. Ignoring attempt to set it"
+    end
+  end
+
+  # Make sure all of our mounts are valid.  We have to do this after the fact
+  # because details are added over time as the file is parsed.
+  def validate
+    @mounts.each { |name, mount| mount.validate }
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/content.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/content.rb
new file mode 100644
index 0000000..00e9dc8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/content.rb
@@ -0,0 +1,45 @@
+require 'puppet/indirector'
+require 'puppet/file_serving'
+require 'puppet/file_serving/base'
+
+# A class that handles retrieving file contents.
+# It only reads the file when its content is specifically
+# asked for.
+class Puppet::FileServing::Content < Puppet::FileServing::Base
+  extend Puppet::Indirector
+  indirects :file_content, :terminus_class => :selector
+
+  attr_writer :content
+
+  def self.supported_formats
+    [:raw]
+  end
+
+  def self.from_raw(content)
+    instance = new("/this/is/a/fake/path")
+    instance.content = content
+    instance
+  end
+
+  # BF: we used to fetch the file content here, but this is counter-productive
+  # for puppetmaster streaming of file content. So collect just returns itself
+  def collect(source_permissions = nil)
+    return if stat.ftype == "directory"
+    self
+  end
+
+  # Read the content of our file in.
+  def content
+    unless @content
+      # This stat can raise an exception, too.
+      raise(ArgumentError, "Cannot read the contents of links unless following links") if stat.ftype == "symlink"
+
+      @content = Puppet::FileSystem.binread(full_path)
+    end
+    @content
+  end
+
+  def to_raw
+    File.new(full_path, "rb")
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/fileset.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/fileset.rb
new file mode 100644
index 0000000..a1d9d54
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/fileset.rb
@@ -0,0 +1,172 @@
+require 'find'
+require 'puppet/file_serving'
+require 'puppet/file_serving/metadata'
+
+# Operate recursively on a path, returning a set of file paths.
+class Puppet::FileServing::Fileset
+  attr_reader :path, :ignore, :links
+  attr_accessor :recurse, :recurselimit, :checksum_type
+
+  # Produce a hash of files, with merged so that earlier files
+  # with the same postfix win.  E.g., /dir1/subfile beats /dir2/subfile.
+  # It's a hash because we need to know the relative path of each file,
+  # and the base directory.
+  #   This will probably only ever be used for searching for plugins.
+  def self.merge(*filesets)
+    result = {}
+
+    filesets.each do |fileset|
+      fileset.files.each do |file|
+        result[file] ||= fileset.path
+      end
+    end
+
+    result
+  end
+
+  def initialize(path, options = {})
+    if Puppet.features.microsoft_windows?
+      # REMIND: UNC path
+      path = path.chomp(File::SEPARATOR) unless path =~ /^[A-Za-z]:\/$/
+    else
+      path = path.chomp(File::SEPARATOR) unless path == File::SEPARATOR
+    end
+    raise ArgumentError.new("Fileset paths must be fully qualified: #{path}") unless Puppet::Util.absolute_path?(path)
+
+    @path = path
+
+    # Set our defaults.
+    self.ignore = []
+    self.links = :manage
+    @recurse = false
+    @recurselimit = :infinite
+
+    if options.is_a?(Puppet::Indirector::Request)
+      initialize_from_request(options)
+    else
+      initialize_from_hash(options)
+    end
+
+    raise ArgumentError.new("Fileset paths must exist") unless valid?(path)
+    raise ArgumentError.new("Fileset recurse parameter must not be a number anymore, please use recurselimit") if @recurse.is_a?(Integer)
+  end
+
+  # Return a list of all files in our fileset.  This is different from the
+  # normal definition of find in that we support specific levels
+  # of recursion, which means we need to know when we're going another
+  # level deep, which Find doesn't do.
+  def files
+    files = perform_recursion
+
+    # Now strip off the leading path, so each file becomes relative, and remove
+    # any slashes that might end up at the beginning of the path.
+    result = files.collect { |file| file.sub(%r{^#{Regexp.escape(@path)}/*}, '') }
+
+    # And add the path itself.
+    result.unshift(".")
+
+    result
+  end
+
+  def ignore=(values)
+    values = [values] unless values.is_a?(Array)
+    @ignore = values.collect(&:to_s)
+  end
+
+  def links=(links)
+    links = links.to_sym
+    raise(ArgumentError, "Invalid :links value '#{links}'") unless [:manage, :follow].include?(links)
+    @links = links
+    @stat_method = @links == :manage ? :lstat : :stat
+  end
+
+  private
+
+  def initialize_from_hash(options)
+    options.each do |option, value|
+      method = option.to_s + "="
+      begin
+        send(method, value)
+      rescue NoMethodError
+        raise ArgumentError, "Invalid option '#{option}'", $!.backtrace
+      end
+    end
+  end
+
+  def initialize_from_request(request)
+    [:links, :ignore, :recurse, :recurselimit, :checksum_type].each do |param|
+      if request.options.include?(param) # use 'include?' so the values can be false
+        value = request.options[param]
+      elsif request.options.include?(param.to_s)
+        value = request.options[param.to_s]
+      end
+      next if value.nil?
+      value = true if value == "true"
+      value = false if value == "false"
+      value = Integer(value) if value.is_a?(String) and value =~ /^\d+$/
+      send(param.to_s + "=", value)
+    end
+  end
+
+  FileSetEntry = Struct.new(:depth, :path, :ignored, :stat_method) do
+    def down_level(to)
+      FileSetEntry.new(depth + 1, File.join(path, to), ignored, stat_method)
+    end
+
+    def basename
+      File.basename(path)
+    end
+
+    def children
+      return [] unless directory?
+
+      Dir.entries(path).
+        reject { |child| ignore?(child) }.
+        collect { |child| down_level(child) }
+    end
+
+    def ignore?(child)
+      return true if child == "." || child == ".."
+      return false if ignored == [nil]
+
+      ignored.any? { |pattern| File.fnmatch?(pattern, child) }
+    end
+
+    def directory?
+      Puppet::FileSystem.send(stat_method, path).directory?
+    rescue Errno::ENOENT, Errno::EACCES
+      false
+    end
+  end
+
+  # Pull the recursion logic into one place.  It's moderately hairy, and this
+  # allows us to keep the hairiness apart from what we do with the files.
+  def perform_recursion
+    current_dirs = [FileSetEntry.new(0, @path, @ignore, @stat_method)]
+
+    result = []
+
+    while entry = current_dirs.shift
+      if continue_recursion_at?(entry.depth + 1)
+        entry.children.each do |child|
+          result << child.path
+          current_dirs << child
+        end
+      end
+    end
+
+    result
+  end
+
+  def valid?(path)
+    Puppet::FileSystem.send(@stat_method, path)
+    true
+  rescue Errno::ENOENT, Errno::EACCES
+    false
+  end
+
+  def continue_recursion_at?(depth)
+    # recurse if told to, and infinite recursion or current depth not at the limit
+    self.recurse && (self.recurselimit == :infinite || depth <= self.recurselimit)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/metadata.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/metadata.rb
new file mode 100644
index 0000000..6e8c786
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/metadata.rb
@@ -0,0 +1,199 @@
+require 'puppet'
+require 'puppet/indirector'
+require 'puppet/file_serving'
+require 'puppet/file_serving/base'
+require 'puppet/util/checksums'
+
+# A class that handles retrieving file metadata.
+class Puppet::FileServing::Metadata < Puppet::FileServing::Base
+
+  include Puppet::Util::Checksums
+
+  extend Puppet::Indirector
+  indirects :file_metadata, :terminus_class => :selector
+
+  attr_reader :path, :owner, :group, :mode, :checksum_type, :checksum, :ftype, :destination
+
+  PARAM_ORDER = [:mode, :ftype, :owner, :group]
+
+  def checksum_type=(type)
+    raise(ArgumentError, "Unsupported checksum type #{type}") unless respond_to?("#{type}_file")
+
+    @checksum_type = type
+  end
+
+  class MetaStat
+    extend Forwardable
+
+    def initialize(stat, source_permissions = nil)
+      @stat = stat
+      @source_permissions_ignore = source_permissions == :ignore
+    end
+
+    def owner
+      @source_permissions_ignore ? Process.euid : @stat.uid
+    end
+
+    def group
+      @source_permissions_ignore ? Process.egid : @stat.gid
+    end
+
+    def mode
+      @source_permissions_ignore ? 0644 : @stat.mode
+    end
+
+    def_delegators :@stat, :ftype
+  end
+
+  class WindowsStat < MetaStat
+    if Puppet.features.microsoft_windows?
+      require 'puppet/util/windows/security'
+    end
+
+    def initialize(stat, path, source_permissions = nil)
+      super(stat, source_permissions)
+      @path = path
+    end
+
+    { :owner => 'S-1-5-32-544',
+      :group => 'S-1-0-0',
+      :mode => 0644
+    }.each do |method, default_value|
+      define_method method do
+        return default_value if @source_permissions_ignore
+
+        # this code remains for when source_permissions is not set to :ignore
+        begin
+          Puppet::Util::Windows::Security.send("get_#{method}", @path) || default_value
+        rescue Puppet::Util::Windows::Error => detail
+          # Very carefully catch only this specific error that result from
+          # trying to read permissions on a symlinked file that is on a volume
+          # that does not support ACLs.
+          #
+          # Unfortunately readlink method will not return the target path when
+          # the given path is not the symlink.
+          #
+          # For instance, consider:
+          #   symlink c:\link points to c:\target
+          #   FileSystem.readlink('c:/link') returns 'c:/target'
+          #   FileSystem.readlink('c:/link/file') will NOT return 'c:/target/file'
+          #
+          # Since detecting this up front is costly, since the path in question
+          # needs to be recursively split and tested at each depth in the path,
+          # we catch the standard error that will result from trying to read a
+          # file that doesn't have a DACL - 1336 is ERROR_INVALID_DACL
+          #
+          # Note that this affects any manually created symlinks as well as
+          # paths like puppet:///modules
+          return default_value if detail.code == 1336
+
+          # Also handle a VirtualBox bug where ERROR_INVALID_FUNCTION is
+          # returned when following a symlink to a volume that is not NTFS.
+          # It appears that the VirtualBox file system is not propagating
+          # the standard Win32 error code above like it should.
+          #
+          # Apologies to all who enter this code path at a later date
+          if detail.code == 1 && Facter.value(:virtual) == 'virtualbox'
+            return default_value
+          end
+
+          raise
+        end
+      end
+    end
+  end
+
+  def collect_stat(path, source_permissions)
+    stat = stat()
+
+    if Puppet.features.microsoft_windows?
+      WindowsStat.new(stat, path, source_permissions)
+    else
+      MetaStat.new(stat, source_permissions)
+    end
+  end
+
+  # Retrieve the attributes for this file, relative to a base directory.
+  # Note that Puppet::FileSystem.stat(path) raises Errno::ENOENT
+  # if the file is absent and this method does not catch that exception.
+  def collect(source_permissions = nil)
+    real_path = full_path
+
+    stat = collect_stat(real_path, source_permissions)
+    @owner = stat.owner
+    @group = stat.group
+    @ftype = stat.ftype
+
+    # We have to mask the mode, yay.
+    @mode = stat.mode & 007777
+
+    case stat.ftype
+    when "file"
+      @checksum = ("{#{@checksum_type}}") + send("#{@checksum_type}_file", real_path).to_s
+    when "directory" # Always just timestamp the directory.
+      @checksum_type = "ctime"
+      @checksum = ("{#{@checksum_type}}") + send("#{@checksum_type}_file", path).to_s
+    when "link"
+      @destination = Puppet::FileSystem.readlink(real_path)
+      @checksum = ("{#{@checksum_type}}") + send("#{@checksum_type}_file", real_path).to_s rescue nil
+    else
+      raise ArgumentError, "Cannot manage files of type #{stat.ftype}"
+    end
+  end
+
+  def initialize(path,data={})
+    @owner       = data.delete('owner')
+    @group       = data.delete('group')
+    @mode        = data.delete('mode')
+    if checksum = data.delete('checksum')
+      @checksum_type = checksum['type']
+      @checksum      = checksum['value']
+    end
+    @checksum_type ||= Puppet[:digest_algorithm]
+    @ftype       = data.delete('type')
+    @destination = data.delete('destination')
+    super(path,data)
+  end
+
+  def to_data_hash
+    super.update(
+      {
+        'owner'        => owner,
+        'group'        => group,
+        'mode'         => mode,
+        'checksum'     => {
+          'type'   => checksum_type,
+          'value'  => checksum
+        },
+        'type'         => ftype,
+        'destination'  => destination,
+
+      }
+    )
+  end
+
+  def self.from_data_hash(data)
+    new(data.delete('path'), data)
+  end
+
+  PSON.register_document_type('FileMetadata',self)
+  def to_pson_data_hash
+    {
+      'document_type' => 'FileMetadata',
+      'data'          => to_data_hash,
+      'metadata'      => {
+        'api_version' => 1
+        }
+    }
+  end
+
+  def to_pson(*args)
+    to_pson_data_hash.to_pson(*args)
+  end
+
+  def self.from_pson(data)
+    Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
+    self.from_data_hash(data)
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/mount.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/mount.rb
new file mode 100644
index 0000000..da7102f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/mount.rb
@@ -0,0 +1,39 @@
+require 'puppet/network/authstore'
+require 'puppet/util/logging'
+require 'puppet/file_serving'
+require 'puppet/file_serving/metadata'
+require 'puppet/file_serving/content'
+
+# Broker access to the filesystem, converting local URIs into metadata
+# or content objects.
+class Puppet::FileServing::Mount < Puppet::Network::AuthStore
+  include Puppet::Util::Logging
+
+  attr_reader :name
+
+  def find(path, options)
+    raise NotImplementedError
+  end
+
+  # Create our object.  It must have a name.
+  def initialize(name)
+    unless name =~ %r{^[-\w]+$}
+      raise ArgumentError, "Invalid mount name format '#{name}'"
+    end
+    @name = name
+
+    super()
+  end
+
+  def search(path, options)
+    raise NotImplementedError
+  end
+
+  def to_s
+    "mount[#{@name}]"
+  end
+
+  # A noop.
+  def validate
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/mount/file.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/mount/file.rb
new file mode 100644
index 0000000..2b48c88
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/mount/file.rb
@@ -0,0 +1,121 @@
+require 'puppet/file_serving/mount'
+
+class Puppet::FileServing::Mount::File < Puppet::FileServing::Mount
+  def self.localmap
+    @localmap ||= {
+      "h" => Facter.value("hostname"),
+      "H" => [
+               Facter.value("hostname"),
+               Facter.value("domain")
+             ].join("."),
+      "d" => Facter.value("domain")
+    }
+  end
+
+  def complete_path(relative_path, node)
+    full_path = path(node)
+
+    raise ArgumentError.new("Mounts without paths are not usable") unless full_path
+
+    # If there's no relative path name, then we're serving the mount itself.
+    return full_path unless relative_path
+
+    file = ::File.join(full_path, relative_path)
+
+    if !(Puppet::FileSystem.exist?(file) or Puppet::FileSystem.symlink?(file))
+      Puppet.info("File does not exist or is not accessible: #{file}")
+      return nil
+    end
+
+    file
+  end
+
+  # Return an instance of the appropriate class.
+  def find(short_file, request)
+    complete_path(short_file, request.node)
+  end
+
+  # Return the path as appropriate, expanding as necessary.
+  def path(node = nil)
+    if expandable?
+      return expand(@path, node)
+    else
+      return @path
+    end
+  end
+
+  # Set the path.
+  def path=(path)
+    # FIXME: For now, just don't validate paths with replacement
+    # patterns in them.
+    if path =~ /%./
+      # Mark that we're expandable.
+      @expandable = true
+    else
+      raise ArgumentError, "#{path} does not exist or is not a directory" unless FileTest.directory?(path)
+      raise ArgumentError, "#{path} is not readable" unless FileTest.readable?(path)
+      @expandable = false
+    end
+    @path = path
+  end
+
+  def search(path, request)
+    return nil unless path = complete_path(path, request.node)
+    [path]
+  end
+
+  # Verify our configuration is valid.  This should really check to
+  # make sure at least someone will be allowed, but, eh.
+  def validate
+    raise ArgumentError.new("Mounts without paths are not usable") if @path.nil?
+  end
+
+  private
+
+  # Create a map for a specific node.
+  def clientmap(node)
+    {
+      "h" => node.sub(/\..*$/, ""),
+      "H" => node,
+      "d" => node.sub(/[^.]+\./, "") # domain name
+    }
+  end
+
+  # Replace % patterns as appropriate.
+  def expand(path, node = nil)
+    # This map should probably be moved into a method.
+    map = nil
+
+    if node
+      map = clientmap(node)
+    else
+      Puppet.notice "No client; expanding '#{path}' with local host"
+      # Else, use the local information
+      map = localmap
+    end
+
+    path.gsub(/%(.)/) do |v|
+      key = $1
+      if key == "%"
+        "%"
+      else
+        map[key] || v
+      end
+    end
+  end
+
+  # Do we have any patterns in our path, yo?
+  def expandable?
+    if defined?(@expandable)
+      @expandable
+    else
+      false
+    end
+  end
+
+  # Cache this manufactured map, since if it's used it's likely
+  # to get used a lot.
+  def localmap
+    self.class.localmap
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/mount/modules.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/mount/modules.rb
new file mode 100644
index 0000000..3cbacb2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/mount/modules.rb
@@ -0,0 +1,24 @@
+require 'puppet/file_serving/mount'
+
+# This is the modules-specific mount: it knows how to search through
+# modules for files.  Yay.
+class Puppet::FileServing::Mount::Modules < Puppet::FileServing::Mount
+  # Return an instance of the appropriate class.
+  def find(path, request)
+    raise "No module specified" if path.to_s.empty?
+    module_name, relative_path = path.split("/", 2)
+    return nil unless mod = request.environment.module(module_name)
+
+    mod.file(relative_path)
+  end
+
+  def search(path, request)
+    if result = find(path, request)
+      [result]
+    end
+  end
+
+  def valid?
+    true
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/mount/pluginfacts.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/mount/pluginfacts.rb
new file mode 100644
index 0000000..5ba8f71
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/mount/pluginfacts.rb
@@ -0,0 +1,35 @@
+require 'puppet/file_serving/mount'
+
+# Find files in the modules' pluginfacts directories.
+# This is a very strange mount because it merges
+# many directories into one.
+class Puppet::FileServing::Mount::PluginFacts < Puppet::FileServing::Mount
+  # Return an instance of the appropriate class.
+  def find(relative_path, request)
+    return nil unless mod = request.environment.modules.find { |mod|  mod.pluginfact(relative_path) }
+
+    path = mod.pluginfact(relative_path)
+
+    path
+  end
+
+  def search(relative_path, request)
+    # We currently only support one kind of search on plugins - return
+    # them all.
+    Puppet.debug("Warning: calling Plugins.search with empty module path.") if request.environment.modules.empty?
+    paths = request.environment.modules.find_all { |mod| mod.pluginfacts? }.collect { |mod| mod.plugin_fact_directory }
+    if paths.empty?
+      # If the modulepath is valid then we still need to return a valid root
+      # directory for the search, but make sure nothing inside it is
+      # returned.
+      request.options[:recurse] = false
+      request.environment.modulepath.empty? ? nil : request.environment.modulepath
+    else
+      paths
+    end
+  end
+
+  def valid?
+    true
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/mount/plugins.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/mount/plugins.rb
new file mode 100644
index 0000000..1e5dcef
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/mount/plugins.rb
@@ -0,0 +1,35 @@
+require 'puppet/file_serving/mount'
+
+# Find files in the modules' plugins directories.
+# This is a very strange mount because it merges
+# many directories into one.
+class Puppet::FileServing::Mount::Plugins < Puppet::FileServing::Mount
+  # Return an instance of the appropriate class.
+  def find(relative_path, request)
+    return nil unless mod = request.environment.modules.find { |mod|  mod.plugin(relative_path) }
+
+    path = mod.plugin(relative_path)
+
+    path
+  end
+
+  def search(relative_path, request)
+    # We currently only support one kind of search on plugins - return
+    # them all.
+    Puppet.debug("Warning: calling Plugins.search with empty module path.") if request.environment.modules.empty?
+    paths = request.environment.modules.find_all { |mod| mod.plugins? }.collect { |mod| mod.plugin_directory }
+    if paths.empty?
+      # If the modulepath is valid then we still need to return a valid root
+      # directory for the search, but make sure nothing inside it is
+      # returned.
+      request.options[:recurse] = false
+      request.environment.modulepath.empty? ? nil : request.environment.modulepath
+    else
+      paths
+    end
+  end
+
+  def valid?
+    true
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/terminus_helper.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/terminus_helper.rb
new file mode 100644
index 0000000..b36ec55
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/terminus_helper.rb
@@ -0,0 +1,21 @@
+require 'puppet/file_serving'
+require 'puppet/file_serving/fileset'
+
+# Define some common methods for FileServing termini.
+module Puppet::FileServing::TerminusHelper
+  # Create model instances for all files in a fileset.
+  def path2instances(request, *paths)
+    filesets = paths.collect do |path|
+      # Filesets support indirector requests as an options collection
+      Puppet::FileServing::Fileset.new(path, request)
+    end
+
+    Puppet::FileServing::Fileset.merge(*filesets).collect do |file, base_path|
+      inst = model.new(base_path, :relative_path => file)
+      inst.checksum_type = request.options[:checksum_type] if request.options[:checksum_type]
+      inst.links = request.options[:links] if request.options[:links]
+      inst.collect
+      inst
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/terminus_selector.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/terminus_selector.rb
new file mode 100644
index 0000000..74ae145
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_serving/terminus_selector.rb
@@ -0,0 +1,30 @@
+require 'puppet/file_serving'
+
+# This module is used to pick the appropriate terminus
+# in file-serving indirections.  This is necessary because
+# the terminus varies based on the URI asked for.
+module Puppet::FileServing::TerminusSelector
+  def select(request)
+    # We rely on the request's parsing of the URI.
+
+    # Short-circuit to :file if it's a fully-qualified path or specifies a 'file' protocol.
+    if Puppet::Util.absolute_path?(request.key)
+      return :file
+    end
+
+    case request.protocol
+    when "file"
+      :file
+    when "puppet"
+      if request.server
+        :rest
+      else
+        Puppet[:default_file_terminus]
+      end
+    when nil
+      :file_server
+    else
+      raise ArgumentError, "URI protocol '#{request.protocol}' is not currently supported for file serving"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system.rb
new file mode 100644
index 0000000..738b140
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system.rb
@@ -0,0 +1,379 @@
+module Puppet::FileSystem
+  require 'puppet/file_system/path_pattern'
+  require 'puppet/file_system/file_impl'
+  require 'puppet/file_system/memory_file'
+  require 'puppet/file_system/memory_impl'
+  require 'puppet/file_system/uniquefile'
+
+  # create instance of the file system implementation to use for the current platform
+  @impl = if RUBY_VERSION =~ /^1\.8/
+           require 'puppet/file_system/file18'
+           Puppet::FileSystem::File18
+         elsif Puppet::Util::Platform.windows?
+           require 'puppet/file_system/file19windows'
+           Puppet::FileSystem::File19Windows
+         else
+           require 'puppet/file_system/file19'
+           Puppet::FileSystem::File19
+         end.new()
+
+  # Allows overriding the filesystem for the duration of the given block.
+  # The filesystem will only contain the given file(s).
+  #
+  # @param files [Puppet::FileSystem::MemoryFile] the files to have available
+  #
+  # @api private
+  #
+  def self.overlay(*files, &block)
+    old_impl = @impl
+    @impl = Puppet::FileSystem::MemoryImpl.new(*files)
+    yield
+  ensure
+    @impl = old_impl
+  end
+
+  # Opens the given path with given mode, and options and optionally yields it to the given block.
+  #
+  # @api public
+  #
+  def self.open(path, mode, options, &block)
+    @impl.open(assert_path(path), mode, options, &block)
+  end
+
+  # @return [Object] The directory of this file as an opaque handle
+  #
+  # @api public
+  #
+  def self.dir(path)
+    @impl.dir(assert_path(path))
+  end
+
+  # @return [String] The directory of this file as a String
+  #
+  # @api public
+  #
+  def self.dir_string(path)
+    @impl.path_string(@impl.dir(assert_path(path)))
+  end
+
+  # @return [Boolean] Does the directory of the given path exist?
+  def self.dir_exist?(path)
+    @impl.exist?(@impl.dir(assert_path(path)))
+  end
+
+  # Creates all directories down to (inclusive) the dir of the given path
+  def self.dir_mkpath(path)
+    @impl.mkpath(@impl.dir(assert_path(path)))
+  end
+
+  # @return [Object] the name of the file as a opaque handle
+  #
+  # @api public
+  #
+  def self.basename(path)
+    @impl.basename(assert_path(path))
+  end
+
+  # @return [String] the name of the file
+  #
+  # @api public
+  #
+  def self.basename_string(path)
+    @impl.path_string(@impl.basename(assert_path(path)))
+  end
+
+  # @return [Integer] the size of the file
+  #
+  # @api public
+  #
+  def self.size(path)
+    @impl.size(assert_path(path))
+  end
+
+  # Allows exclusive updates to a file to be made by excluding concurrent
+  # access using flock. This means that if the file is on a filesystem that
+  # does not support flock, this method will provide no protection.
+  #
+  # While polling to aquire the lock the process will wait ever increasing
+  # amounts of time in order to prevent multiple processes from wasting
+  # resources.
+  #
+  # @param path [Pathname] the path to the file to operate on
+  # @param mode [Integer] The mode to apply to the file if it is created
+  # @param options [Integer] Extra file operation mode information to use
+  #   (defaults to read-only mode)
+  # @param timeout [Integer] Number of seconds to wait for the lock (defaults to 300)
+  # @yield The file handle, in read-write mode
+  # @return [Void]
+  # @raise [Timeout::Error] If the timeout is exceeded while waiting to acquire the lock
+  #
+  # @api public
+  #
+  def self.exclusive_open(path, mode, options = 'r', timeout = 300, &block)
+    @impl.exclusive_open(assert_path(path), mode, options, timeout, &block)
+  end
+
+  # Processes each line of the file by yielding it to the given block
+  #
+  # @api public
+  #
+  def self.each_line(path, &block)
+    @impl.each_line(assert_path(path), &block)
+  end
+
+  # @return [String] The contents of the file
+  #
+  # @api public
+  #
+  def self.read(path)
+    @impl.read(assert_path(path))
+  end
+
+  # Read a file keeping the original line endings intact. This
+  # attempts to open files using binary mode using some encoding
+  # overrides and falling back to IO.read when none of the
+  # encodings are valid.
+  #
+  # @return [String] The contents of the file
+  #
+  # @api public
+  #
+  def self.read_preserve_line_endings(path)
+    @impl.read_preserve_line_endings(assert_path(path))
+  end
+
+  # @return [String] The binary contents of the file
+  #
+  # @api public
+  #
+  def self.binread(path)
+    @impl.binread(assert_path(path))
+  end
+
+  # Determines if a file exists by verifying that the file can be stat'd.
+  # Will follow symlinks and verify that the actual target path exists.
+  #
+  # @return [Boolean] true if the named file exists.
+  #
+  # @api public
+  #
+  def self.exist?(path)
+    @impl.exist?(assert_path(path))
+  end
+
+  # Determines if a file is a directory.
+  #
+  # @return [Boolean] true if the given file is a directory.
+  #
+  # @api public
+  def self.directory?(path)
+    @impl.directory?(assert_path(path))
+  end
+
+  # Determines if a file is a file.
+  #
+  # @return [Boolean] true if the given file is a file.
+  #
+  # @api public
+  def self.file?(path)
+    @impl.file?(assert_path(path))
+  end
+
+  # Determines if a file is executable.
+  #
+  # @todo Should this take into account extensions on the windows platform?
+  #
+  # @return [Boolean] true if this file can be executed
+  #
+  # @api public
+  #
+  def self.executable?(path)
+    @impl.executable?(assert_path(path))
+  end
+
+  # @return [Boolean] Whether the file is writable by the current process
+  #
+  # @api public
+  #
+  def self.writable?(path)
+    @impl.writable?(assert_path(path))
+  end
+
+  # Touches the file. On most systems this updates the mtime of the file.
+  #
+  # @api public
+  #
+  def self.touch(path)
+    @impl.touch(assert_path(path))
+  end
+
+  # Creates directories for all parts of the given path.
+  #
+  # @api public
+  #
+  def self.mkpath(path)
+    @impl.mkpath(assert_path(path))
+  end
+
+  # @return [Array<Object>] references to all of the children of the given
+  #   directory path, excluding `.` and `..`.
+  # @api public
+  def self.children(path)
+    @impl.children(assert_path(path))
+  end
+
+  # Creates a symbolic link dest which points to the current file.
+  # If dest already exists:
+  #
+  # * and is a file, will raise Errno::EEXIST
+  # * and is a directory, will return 0 but perform no action
+  # * and is a symlink referencing a file, will raise Errno::EEXIST
+  # * and is a symlink referencing a directory, will return 0 but perform no action
+  #
+  # With the :force option set to true, when dest already exists:
+  #
+  # * and is a file, will replace the existing file with a symlink (DANGEROUS)
+  # * and is a directory, will return 0 but perform no action
+  # * and is a symlink referencing a file, will modify the existing symlink
+  # * and is a symlink referencing a directory, will return 0 but perform no action
+  #
+  # @param dest [String] The path to create the new symlink at
+  # @param [Hash] options the options to create the symlink with
+  # @option options [Boolean] :force overwrite dest
+  # @option options [Boolean] :noop do not perform the operation
+  # @option options [Boolean] :verbose verbose output
+  #
+  # @raise [Errno::EEXIST] dest already exists as a file and, :force is not set
+  #
+  # @return [Integer] 0
+  #
+  # @api public
+  #
+  def self.symlink(path, dest, options = {})
+    @impl.symlink(assert_path(path), dest, options)
+  end
+
+  # @return [Boolean] true if the file is a symbolic link.
+  #
+  # @api public
+  #
+  def self.symlink?(path)
+    @impl.symlink?(assert_path(path))
+  end
+
+  # @return [String] the name of the file referenced by the given link.
+  #
+  # @api public
+  #
+  def self.readlink(path)
+    @impl.readlink(assert_path(path))
+  end
+
+  # Deletes the given paths, returning the number of names passed as arguments.
+  # See also Dir::rmdir.
+  #
+  # @raise an exception on any error.
+  #
+  # @return [Integer] the number of paths passed as arguments
+  #
+  # @api public
+  #
+  def self.unlink(*paths)
+    @impl.unlink(*(paths.map {|p| assert_path(p) }))
+  end
+
+  # @return [File::Stat] object for the named file.
+  #
+  # @api public
+  #
+  def self.stat(path)
+    @impl.stat(assert_path(path))
+  end
+
+  # @return [Integer] the size of the file
+  #
+  # @api public
+  #
+  def self.size(path)
+    @impl.size(assert_path(path))
+  end
+
+  # @return [File::Stat] Same as stat, but does not follow the last symbolic
+  # link. Instead, reports on the link itself.
+  #
+  # @api public
+  #
+  def self.lstat(path)
+    @impl.lstat(assert_path(path))
+  end
+
+  # Compares the contents of this file against the contents of a stream.
+  #
+  # @param stream [IO] The stream to compare the contents against
+  # @return [Boolean] Whether the contents were the same
+  #
+  # @api public
+  #
+  def self.compare_stream(path, stream)
+    @impl.compare_stream(assert_path(path), stream)
+  end
+
+  # Produces an opaque pathname "handle" object representing the given path.
+  # Different implementations of the underlying file system may use different runtime
+  # objects. The produced "handle" should be used in all other operations
+  # that take a "path". No operation should be directly invoked on the returned opaque object
+  #
+  # @param path [String] The string representation of the path
+  # @return [Object] An opaque path handle on which no operations should be directly performed
+  #
+  # @api public
+  #
+  def self.pathname(path)
+    @impl.pathname(path)
+  end
+
+  # Asserts that the given path is of the expected type produced by #pathname
+  #
+  # @raise [ArgumentError] when path is not of the expected type
+  #
+  # @api public
+  #
+  def self.assert_path(path)
+    @impl.assert_path(path)
+  end
+
+  # Produces a string representation of the opaque path handle.
+  #
+  # @param path [Object] a path handle produced by {#pathname}
+  # @return [String] a string representation of the path
+  #
+  def self.path_string(path)
+    @impl.path_string(path)
+  end
+
+  # Create and open a file for write only if it doesn't exist.
+  #
+  # @see Puppet::FileSystem::open
+  #
+  # @raise [Errno::EEXIST] path already exists.
+  #
+  # @api public
+  #
+  def self.exclusive_create(path, mode, &block)
+    @impl.exclusive_create(assert_path(path), mode, &block)
+  end
+
+  # Changes permission bits on the named path to the bit pattern represented
+  # by mode.
+  #
+  # @param mode [Integer] The mode to apply to the file if it is created
+  # @param path [String] The path to the file, can also accept [PathName]
+  #
+  # @raise [Errno::ENOENT]: path doesn't exist
+  #
+  # @api public
+  #
+  def self.chmod(mode, path)
+    @impl.chmod(mode, path)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/file18.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/file18.rb
new file mode 100644
index 0000000..aa4889c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/file18.rb
@@ -0,0 +1,5 @@
+class Puppet::FileSystem::File18 < Puppet::FileSystem::FileImpl
+  def binread(path)
+    ::File.open(path, 'rb') { |f| f.read }
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/file19.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/file19.rb
new file mode 100644
index 0000000..8872ba6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/file19.rb
@@ -0,0 +1,46 @@
+class Puppet::FileSystem::File19 < Puppet::FileSystem::FileImpl
+  def binread(path)
+    path.binread
+  end
+
+  # Provide an encoding agnostic version of compare_stream
+  #
+  # The FileUtils implementation in Ruby 2.0+ was modified in a manner where
+  # it cannot properly compare File and StringIO instances. To sidestep that
+  # issue this method reimplements the faster 2.0 version that will correctly
+  # compare binary File and StringIO streams.
+  def compare_stream(path, stream)
+    open(path, 0, 'rb') do |this|
+      bsize = stream_blksize(this, stream)
+      sa = "".force_encoding('ASCII-8BIT')
+      sb = "".force_encoding('ASCII-8BIT')
+      begin
+        this.read(bsize, sa)
+        stream.read(bsize, sb)
+        return true if sa.empty? && sb.empty?
+      end while sa == sb
+      false
+    end
+  end
+
+  private
+  def stream_blksize(*streams)
+    streams.each do |s|
+      next unless s.respond_to?(:stat)
+      size = blksize(s.stat)
+      return size if size
+    end
+    default_blksize()
+  end
+
+  def blksize(st)
+    s = st.blksize
+    return nil unless s
+    return nil if s == 0
+    s
+  end
+
+  def default_blksize
+    1024
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/file19windows.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/file19windows.rb
new file mode 100644
index 0000000..9078d33
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/file19windows.rb
@@ -0,0 +1,115 @@
+require 'puppet/file_system/file19'
+require 'puppet/util/windows'
+
+class Puppet::FileSystem::File19Windows < Puppet::FileSystem::File19
+
+  def exist?(path)
+    if ! Puppet.features.manages_symlinks?
+      return ::File.exist?(path)
+    end
+
+    path = path.to_str if path.respond_to?(:to_str) # support WatchedFile
+    path = path.to_s # support String and Pathname
+
+    begin
+      if Puppet::Util::Windows::File.symlink?(path)
+        path = Puppet::Util::Windows::File.readlink(path)
+      end
+      ! Puppet::Util::Windows::File.stat(path).nil?
+    rescue # generally INVALID_HANDLE_VALUE which means 'file not found'
+      false
+    end
+  end
+
+  def symlink(path, dest, options = {})
+    raise_if_symlinks_unsupported
+
+    dest_exists = exist?(dest) # returns false on dangling symlink
+    dest_stat = Puppet::Util::Windows::File.stat(dest) if dest_exists
+
+    # silent fail to preserve semantics of original FileUtils
+    return 0 if dest_exists && dest_stat.ftype == 'directory'
+
+    if dest_exists && dest_stat.ftype == 'file' && options[:force] != true
+      raise(Errno::EEXIST, "#{dest} already exists and the :force option was not specified")
+    end
+
+    if options[:noop] != true
+      ::File.delete(dest) if dest_exists # can only be file
+      Puppet::Util::Windows::File.symlink(path, dest)
+    end
+
+    0
+  end
+
+  def symlink?(path)
+    return false if ! Puppet.features.manages_symlinks?
+    Puppet::Util::Windows::File.symlink?(path)
+  end
+
+  def readlink(path)
+    raise_if_symlinks_unsupported
+    Puppet::Util::Windows::File.readlink(path)
+  end
+
+  def unlink(*file_names)
+    if ! Puppet.features.manages_symlinks?
+      return ::File.unlink(*file_names)
+    end
+
+    file_names.each do |file_name|
+      file_name = file_name.to_s # handle PathName
+      stat = Puppet::Util::Windows::File.stat(file_name) rescue nil
+
+      # sigh, Ruby + Windows :(
+      if stat && stat.ftype == 'directory'
+        if Puppet::Util::Windows::File.symlink?(file_name)
+          Dir.rmdir(file_name)
+        else
+          raise Errno::EPERM.new(file_name)
+        end
+      else
+        ::File.unlink(file_name)
+      end
+    end
+
+    file_names.length
+  end
+
+  def stat(path)
+    Puppet::Util::Windows::File.stat(path)
+  end
+
+  def lstat(path)
+    if ! Puppet.features.manages_symlinks?
+      return Puppet::Util::Windows::File.stat(path)
+    end
+    Puppet::Util::Windows::File.lstat(path)
+  end
+
+  def chmod(mode, path)
+    Puppet::Util::Windows::Security.set_mode(mode, path.to_s)
+  end
+
+  def read_preserve_line_endings(path)
+    contents = path.read( :mode => 'rb', :encoding => Encoding::UTF_8)
+    contents = path.read( :mode => 'rb', :encoding => Encoding::default_external) unless contents.valid_encoding?
+    contents = path.read unless contents.valid_encoding?
+
+    contents
+  end
+
+  private
+
+  def raise_if_symlinks_unsupported
+    if ! Puppet.features.manages_symlinks?
+      msg = "This version of Windows does not support symlinks.  Windows Vista / 2008 or higher is required."
+      raise Puppet::Util::Windows::Error.new(msg)
+    end
+
+    if ! Puppet::Util::Windows::Process.process_privilege_symlink?
+      Puppet.warning "The current user does not have the necessary permission to manage symlinks."
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/file_impl.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/file_impl.rb
new file mode 100644
index 0000000..d89e78d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/file_impl.rb
@@ -0,0 +1,149 @@
+# Abstract implementation of the Puppet::FileSystem
+#
+class Puppet::FileSystem::FileImpl
+
+  def pathname(path)
+    path.is_a?(Pathname) ? path : Pathname.new(path)
+  end
+
+  def assert_path(path)
+    return path if path.is_a?(Pathname)
+
+    # Some paths are string, or in the case of WatchedFile, it pretends to be
+    # one by implementing to_str.
+    if path.respond_to?(:to_str)
+      Pathname.new(path)
+    else
+      raise ArgumentError, "FileSystem implementation expected Pathname, got: '#{path.class}'"
+    end
+  end
+
+  def path_string(path)
+    path.to_s
+  end
+
+  def open(path, mode, options, &block)
+    ::File.open(path, options, mode, &block)
+  end
+
+  def dir(path)
+    path.dirname
+  end
+
+  def basename(path)
+    path.basename.to_s
+  end
+
+  def size(path)
+    path.size
+  end
+
+  def exclusive_create(path, mode, &block)
+    opt = File::CREAT | File::EXCL | File::WRONLY
+    self.open(path, mode, opt, &block)
+  end
+
+  def exclusive_open(path, mode, options = 'r', timeout = 300, &block)
+    wait = 0.001 + (Kernel.rand / 1000)
+    written = false
+    while !written
+      ::File.open(path, options, mode) do |rf|
+        if rf.flock(::File::LOCK_EX|::File::LOCK_NB)
+          yield rf
+          written = true
+        else
+          sleep wait
+          timeout -= wait
+          wait *= 2
+          if timeout < 0
+            raise Timeout::Error, "Timeout waiting for exclusive lock on #{@path}"
+          end
+        end
+      end
+    end
+  end
+
+  def each_line(path, &block)
+    ::File.open(path) do |f|
+      f.each_line do |line|
+        yield line
+      end
+    end
+  end
+
+  def read(path)
+    path.read
+  end
+
+  def read_preserve_line_endings(path)
+    read(path)
+  end
+
+  def binread(path)
+    raise NotImplementedError
+  end
+
+  def exist?(path)
+    ::File.exist?(path)
+  end
+
+  def directory?(path)
+    ::File.directory?(path)
+  end
+
+  def file?(path)
+    ::File.file?(path)
+  end
+
+  def executable?(path)
+    ::File.executable?(path)
+  end
+
+  def writable?(path)
+    path.writable?
+  end
+
+  def touch(path)
+    ::FileUtils.touch(path)
+  end
+
+  def mkpath(path)
+    path.mkpath
+  end
+
+  def children(path)
+    path.children
+  end
+
+  def symlink(path, dest, options = {})
+    FileUtils.symlink(path, dest, options)
+  end
+
+  def symlink?(path)
+    File.symlink?(path)
+  end
+
+  def readlink(path)
+    File.readlink(path)
+  end
+
+  def unlink(*paths)
+    File.unlink(*paths)
+  end
+
+  def stat(path)
+    File.stat(path)
+  end
+
+  def lstat(path)
+    File.lstat(path)
+  end
+
+  def compare_stream(path, stream)
+    open(path, 0, 'rb') { |this| FileUtils.compare_stream(this, stream) }
+  end
+
+  def chmod(mode, path)
+    FileUtils.chmod(mode, path)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/memory_file.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/memory_file.rb
new file mode 100644
index 0000000..2f6555c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/memory_file.rb
@@ -0,0 +1,71 @@
+# An in-memory file abstraction. Commonly used with Puppet::FileSystem::File#overlay
+# @api private
+class Puppet::FileSystem::MemoryFile
+  attr_reader :path, :children
+
+  def self.a_missing_file(path)
+    new(path, :exist? => false, :executable? => false)
+  end
+
+  def self.a_regular_file_containing(path, content)
+    new(path, :exist? => true, :executable? => false, :content => content)
+  end
+
+  def self.an_executable(path)
+    new(path, :exist? => true, :executable? => true)
+  end
+
+  def self.a_directory(path, children = [])
+    new(path,
+        :exist? => true,
+        :excutable? => true,
+        :directory? => true,
+        :children => children)
+  end
+
+  def initialize(path, properties)
+    @path = path
+    @properties = properties
+    @children = (properties[:children] || []).collect do |child|
+      child.duplicate_as(File.join(@path, child.path))
+    end
+  end
+
+  def directory?; @properties[:directory?]; end
+  def exist?; @properties[:exist?]; end
+  def executable?; @properties[:executable?]; end
+
+  def each_line(&block)
+    handle.each_line(&block)
+  end
+
+  def handle
+    raise Errno::ENOENT unless exist?
+    StringIO.new(@properties[:content] || '')
+  end
+
+  def duplicate_as(other_path)
+    self.class.new(other_path, @properties)
+  end
+
+  def absolute?
+    Pathname.new(path).absolute?
+  end
+
+  def to_path
+    path
+  end
+
+  def to_s
+    to_path
+  end
+
+  # Used by Ruby 1.8.7 file system abstractions when operating on Pathname like things.
+  def to_str
+    to_path
+  end
+
+  def inspect
+    "<Puppet::FileSystem::MemoryFile:#{to_s}>"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/memory_impl.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/memory_impl.rb
new file mode 100644
index 0000000..12c63cd
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/memory_impl.rb
@@ -0,0 +1,82 @@
+class Puppet::FileSystem::MemoryImpl
+  def initialize(*files)
+    @files = files + all_children_of(files)
+  end
+
+  def exist?(path)
+    path.exist?
+  end
+
+  def directory?(path)
+    path.directory?
+  end
+
+  def file?(path)
+    path.file?
+  end
+
+  def executable?(path)
+    path.executable?
+  end
+
+  def children(path)
+    path.children
+  end
+
+  def each_line(path, &block)
+    path.each_line(&block)
+  end
+
+  def pathname(path)
+    find(path) || Puppet::FileSystem::MemoryFile.a_missing_file(path)
+  end
+
+  def basename(path)
+    path.duplicate_as(File.basename(path_string(path)))
+  end
+
+  def path_string(object)
+    object.path
+  end
+
+  def read(path)
+    handle = assert_path(path).handle
+    handle.read
+  end
+
+  def read_preserve_line_endings(path)
+    read(path)
+  end
+
+  def open(path, *args, &block)
+    handle = assert_path(path).handle
+    if block_given?
+      yield handle
+    else
+      return handle
+    end
+  end
+
+  def assert_path(path)
+    if path.is_a?(Puppet::FileSystem::MemoryFile)
+      path
+    else
+      find(path) or raise ArgumentError, "Unable to find registered object for #{path.inspect}"
+    end
+  end
+
+  private
+
+  def find(path)
+    @files.find { |file| file.path == path }
+  end
+
+  def all_children_of(files)
+    children = files.collect(&:children).flatten
+    if children.empty?
+      []
+    else
+      children + all_children_of(children)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/path_pattern.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/path_pattern.rb
new file mode 100644
index 0000000..b6d7925
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/path_pattern.rb
@@ -0,0 +1,97 @@
+require 'pathname'
+
+module Puppet::FileSystem
+  class PathPattern
+    class InvalidPattern < Puppet::Error; end
+
+    TRAVERSAL = /^\.\.$/
+    ABSOLUTE_UNIX = /^\//
+    ABSOLUTE_WINDOWS = /^[a-z]:/i
+    #ABSOLUT_VODKA #notappearinginthisclass
+    CURRENT_DRIVE_RELATIVE_WINDOWS = /^\\/
+
+    def self.relative(pattern)
+      RelativePathPattern.new(pattern)
+    end
+
+    def self.absolute(pattern)
+      AbsolutePathPattern.new(pattern)
+    end
+
+    class << self
+      protected :new
+    end
+
+    # @param prefix [AbsolutePathPattern] An absolute path pattern instance
+    # @return [AbsolutePathPattern] A new AbsolutePathPattern prepended with
+    #   the passed prefix's pattern.
+    def prefix_with(prefix)
+      new_pathname = prefix.pathname + pathname
+      self.class.absolute(new_pathname.to_s)
+    end
+
+    def glob
+      Dir.glob(pathname.to_s)
+    end
+
+    def to_s
+      pathname.to_s
+    end
+
+    protected
+
+    attr_reader :pathname
+
+    private
+
+    def validate
+      @pathname.each_filename do |e|
+        if e =~ TRAVERSAL
+          raise(InvalidPattern, "PathPatterns cannot be created with directory traversals.")
+        end
+      end
+      case @pathname.to_s
+      when CURRENT_DRIVE_RELATIVE_WINDOWS
+        raise(InvalidPattern, "A PathPattern cannot be a Windows current drive relative path.")
+      end
+    end
+
+    def initialize(pattern)
+      begin
+        @pathname = Pathname.new(pattern.strip)
+      rescue ArgumentError => error
+        raise InvalidPattern.new("PathPatterns cannot be created with a zero byte.", error)
+      end
+      validate
+    end
+  end
+
+  class RelativePathPattern < PathPattern
+    def absolute?
+      false
+    end
+
+    def validate
+      super
+      case @pathname.to_s
+      when ABSOLUTE_WINDOWS
+        raise(InvalidPattern, "A relative PathPattern cannot be prefixed with a drive.")
+      when ABSOLUTE_UNIX
+        raise(InvalidPattern, "A relative PathPattern cannot be an absolute path.")
+      end
+    end
+  end
+
+  class AbsolutePathPattern < PathPattern
+    def absolute?
+      true
+    end
+
+    def validate
+      super
+      if @pathname.to_s !~ ABSOLUTE_UNIX and @pathname.to_s !~ ABSOLUTE_WINDOWS
+        raise(InvalidPattern, "An absolute PathPattern cannot be a relative path.")
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/uniquefile.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/uniquefile.rb
new file mode 100644
index 0000000..2b13115
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/file_system/uniquefile.rb
@@ -0,0 +1,190 @@
+require 'puppet/file_system'
+require 'delegate'
+require 'tmpdir'
+
+# A class that provides `Tempfile`-like capabilities, but does not attempt to
+# manage the deletion of the file for you.  API is identical to the
+# normal `Tempfile` class.
+#
+# @api public
+class Puppet::FileSystem::Uniquefile < DelegateClass(File)
+  # Convenience method which ensures that the file is closed and
+  # unlinked before returning
+  #
+  # @param identifier [String] additional part of generated pathname
+  # @yieldparam file [File] the temporary file object
+  # @return result of the passed block
+  # @api private
+  def self.open_tmp(identifier)
+    f = new(identifier)
+    yield f
+  ensure
+    if f
+      f.close!
+    end
+  end
+
+  def initialize(basename, *rest)
+    create_tmpname(basename, *rest) do |tmpname, n, opts|
+      mode = File::RDWR|File::CREAT|File::EXCL
+      perm = 0600
+      if opts
+        mode |= opts.delete(:mode) || 0
+        opts[:perm] = perm
+        perm = nil
+      else
+        opts = perm
+      end
+      self.class.locking(tmpname) do
+        @tmpfile = File.open(tmpname, mode, opts)
+        @tmpname = tmpname
+      end
+      @mode = mode & ~(File::CREAT|File::EXCL)
+      perm or opts.freeze
+      @opts = opts
+    end
+
+    super(@tmpfile)
+  end
+
+  # Opens or reopens the file with mode "r+".
+  def open
+    @tmpfile.close if @tmpfile
+    @tmpfile = File.open(@tmpname, @mode, @opts)
+    __setobj__(@tmpfile)
+  end
+
+  def _close
+    begin
+      @tmpfile.close if @tmpfile
+    ensure
+      @tmpfile = nil
+    end
+  end
+  protected :_close
+
+  def close(unlink_now=false)
+    if unlink_now
+      close!
+    else
+      _close
+    end
+  end
+
+  def close!
+    _close
+    unlink
+  end
+
+  def unlink
+    return unless @tmpname
+    begin
+      File.unlink(@tmpname)
+    rescue Errno::ENOENT
+    rescue Errno::EACCES
+      # may not be able to unlink on Windows; just ignore
+      return
+    end
+    @tmpname = nil
+  end
+  alias delete unlink
+
+  # Returns the full path name of the temporary file.
+  # This will be nil if #unlink has been called.
+  def path
+    @tmpname
+  end
+
+  private
+
+  def make_tmpname(prefix_suffix, n)
+    case prefix_suffix
+      when String
+        prefix = prefix_suffix
+        suffix = ""
+      when Array
+        prefix = prefix_suffix[0]
+        suffix = prefix_suffix[1]
+      else
+        raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}"
+    end
+    t = Time.now.strftime("%Y%m%d")
+    path = "#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}"
+    path << "-#{n}" if n
+    path << suffix
+  end
+
+  def create_tmpname(basename, *rest)
+    if opts = try_convert_to_hash(rest[-1])
+      opts = opts.dup if rest.pop.equal?(opts)
+      max_try = opts.delete(:max_try)
+      opts = [opts]
+    else
+      opts = []
+    end
+    tmpdir, = *rest
+    if $SAFE > 0 and tmpdir.tainted?
+      tmpdir = '/tmp'
+    else
+      tmpdir ||= tmpdir()
+    end
+    n = nil
+    begin
+      path = File.expand_path(make_tmpname(basename, n), tmpdir)
+      yield(path, n, *opts)
+    rescue Errno::EEXIST
+      n ||= 0
+      n += 1
+      retry if !max_try or n < max_try
+      raise "cannot generate temporary name using `#{basename}' under `#{tmpdir}'"
+    end
+    path
+  end
+
+  def try_convert_to_hash(h)
+    begin
+      h.to_hash
+    rescue NoMethodError => e
+      nil
+    end
+  end
+
+  @@systmpdir ||= defined?(Etc.systmpdir) ? Etc.systmpdir : '/tmp'
+
+  def tmpdir
+    tmp = '.'
+    if $SAFE > 0
+      tmp = @@systmpdir
+    else
+      for dir in [ENV['TMPDIR'], ENV['TMP'], ENV['TEMP'], @@systmpdir, '/tmp']
+        if dir and stat = File.stat(dir) and stat.directory? and stat.writable?
+          tmp = dir
+          break
+        end rescue nil
+      end
+      File.expand_path(tmp)
+    end
+  end
+
+
+  class << self
+    # yields with locking for +tmpname+ and returns the result of the
+    # block.
+    def locking(tmpname)
+      lock = tmpname + '.lock'
+      mkdir(lock)
+      yield
+    ensure
+      rmdir(lock) if lock
+    end
+
+    def mkdir(*args)
+      Dir.mkdir(*args)
+    end
+
+    def rmdir(*args)
+      Dir.rmdir(*args)
+    end
+  end
+
+end
\ No newline at end of file
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/forge.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/forge.rb
new file mode 100644
index 0000000..a7cdd42
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/forge.rb
@@ -0,0 +1,226 @@
+require 'puppet/vendor'
+Puppet::Vendor.load_vendored
+
+require 'net/http'
+require 'tempfile'
+require 'uri'
+require 'pathname'
+require 'json'
+require 'semantic'
+
+class Puppet::Forge < Semantic::Dependency::Source
+  require 'puppet/forge/cache'
+  require 'puppet/forge/repository'
+  require 'puppet/forge/errors'
+
+  include Puppet::Forge::Errors
+
+  USER_AGENT = "PMT/1.1.1 (v3; Net::HTTP)".freeze
+
+  attr_reader :host, :repository
+
+  def initialize(host = Puppet[:module_repository])
+    @host = host
+    @repository = Puppet::Forge::Repository.new(host, USER_AGENT)
+  end
+
+  # Return a list of module metadata hashes that match the search query.
+  # This return value is used by the module_tool face install search,
+  # and displayed to on the console.
+  #
+  # Example return value:
+  #
+  # [
+  #   {
+  #     "author"      => "puppetlabs",
+  #     "name"        => "bacula",
+  #     "tag_list"    => ["backup", "bacula"],
+  #     "releases"    => [{"version"=>"0.0.1"}, {"version"=>"0.0.2"}],
+  #     "full_name"   => "puppetlabs/bacula",
+  #     "version"     => "0.0.2",
+  #     "project_url" => "http://github.com/puppetlabs/puppetlabs-bacula",
+  #     "desc"        => "bacula"
+  #   }
+  # ]
+  #
+  # @param term [String] search term
+  # @return [Array] modules found
+  # @raise [Puppet::Forge::Errors::CommunicationError] if there is a network
+  #   related error
+  # @raise [Puppet::Forge::Errors::SSLVerifyError] if there is a problem
+  #   verifying the remote SSL certificate
+  # @raise [Puppet::Forge::Errors::ResponseError] if the repository returns a
+  #   bad HTTP response
+  def search(term)
+    matches = []
+    uri = "/v3/modules?query=#{URI.escape(term)}"
+    if Puppet[:module_groups]
+      uri += "&module_groups=#{Puppet[:module_groups]}"
+    end
+
+    while uri
+      response = make_http_request(uri)
+
+      if response.code == '200'
+        result = JSON.parse(response.body)
+        uri = result['pagination']['next']
+        matches.concat result['results']
+      else
+        raise ResponseError.new(:uri => URI.parse(@host).merge(uri), :response => response)
+      end
+    end
+
+    matches.each do |mod|
+      mod['author'] = mod['owner']['username']
+      mod['tag_list'] = mod['current_release']['tags']
+      mod['full_name'] = "#{mod['author']}/#{mod['name']}"
+      mod['version'] = mod['current_release']['version']
+      mod['project_url'] = mod['homepage_url']
+      mod['desc'] = mod['current_release']['metadata']['summary'] || ''
+    end
+  end
+
+  # Fetches {ModuleRelease} entries for each release of the named module.
+  #
+  # @param input [String] the module name to look up
+  # @return [Array<Semantic::Dependency::ModuleRelease>] a list of releases for
+  #         the given name
+  # @see Semantic::Dependency::Source#fetch
+  def fetch(input)
+    name = input.tr('/', '-')
+    uri = "/v3/releases?module=#{name}"
+    if Puppet[:module_groups]
+      uri += "&module_groups=#{Puppet[:module_groups]}"
+    end
+    releases = []
+
+    while uri
+      response = make_http_request(uri)
+
+      if response.code == '200'
+        response = JSON.parse(response.body)
+      else
+        raise ResponseError.new(:uri => URI.parse(@host).merge(uri), :response => response)
+      end
+
+      releases.concat(process(response['results']))
+      uri = response['pagination']['next']
+    end
+
+    return releases
+  end
+
+  def make_http_request(*args)
+    @repository.make_http_request(*args)
+  end
+
+  class ModuleRelease < Semantic::Dependency::ModuleRelease
+    attr_reader :install_dir, :metadata
+
+    def initialize(source, data)
+      @data = data
+      @metadata = meta = data['metadata']
+
+      name = meta['name'].tr('/', '-')
+      version = Semantic::Version.parse(meta['version'])
+      release = "#{name}@#{version}"
+
+      if meta['dependencies']
+        dependencies = meta['dependencies'].collect do |dep|
+          begin
+            Puppet::ModuleTool::Metadata.new.add_dependency(dep['name'], dep['version_requirement'], dep['repository'])
+            Puppet::ModuleTool.parse_module_dependency(release, dep)[0..1]
+          rescue ArgumentError => e
+            raise ArgumentError, "Malformed dependency: #{dep['name']}. Exception was: #{e}"
+          end
+        end
+      else
+        dependencies = []
+      end
+
+      super(source, name, version, Hash[dependencies])
+    end
+
+    def install(dir)
+      staging_dir = self.prepare
+
+      module_dir = dir + name[/-(.*)/, 1]
+      module_dir.rmtree if module_dir.exist?
+
+      # Make sure unpacked module has the same ownership as the folder we are moving it into.
+      Puppet::ModuleTool::Applications::Unpacker.harmonize_ownership(dir, staging_dir)
+
+      FileUtils.mv(staging_dir, module_dir)
+      @install_dir = dir
+
+      # Return the Pathname object representing the directory where the
+      # module release archive was unpacked the to.
+      return module_dir
+    ensure
+      staging_dir.rmtree if staging_dir.exist?
+    end
+
+    def prepare
+      return @unpacked_into if @unpacked_into
+
+      download(@data['file_uri'], tmpfile)
+      validate_checksum(tmpfile, @data['file_md5'])
+      unpack(tmpfile, tmpdir)
+
+      @unpacked_into = Pathname.new(tmpdir)
+    end
+
+    private
+
+    # Obtain a suitable temporary path for unpacking tarballs
+    #
+    # @return [Pathname] path to temporary unpacking location
+    def tmpdir
+      @dir ||= Dir.mktmpdir(name, Puppet::Forge::Cache.base_path)
+    end
+
+    def tmpfile
+      @file ||= Tempfile.new(name, Puppet::Forge::Cache.base_path).tap do |f|
+        f.binmode
+      end
+    end
+
+    def download(uri, destination)
+      response = @source.make_http_request(uri, destination)
+      destination.flush and destination.close
+      unless response.code == '200'
+        raise Puppet::Forge::Errors::ResponseError.new(:uri => uri, :response => response)
+      end
+    end
+
+    def validate_checksum(file, checksum)
+      if Digest::MD5.file(file.path).hexdigest != checksum
+        raise RuntimeError, "Downloaded release for #{name} did not match expected checksum"
+      end
+    end
+
+    def unpack(file, destination)
+      begin
+        Puppet::ModuleTool::Applications::Unpacker.unpack(file.path, destination)
+      rescue Puppet::ExecutionFailure => e
+        raise RuntimeError, "Could not extract contents of module archive: #{e.message}"
+      end
+    end
+  end
+
+  private
+
+  def process(list)
+    l = list.map do |release|
+      metadata = release['metadata']
+      begin
+        ModuleRelease.new(self, release)
+      rescue ArgumentError => e
+        Puppet.warning "Cannot consider release #{metadata['name']}-#{metadata['version']}: #{e}"
+        false
+      end
+    end
+
+    l.select { |r| r }
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/forge/cache.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/forge/cache.rb
new file mode 100644
index 0000000..fcf9396
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/forge/cache.rb
@@ -0,0 +1,59 @@
+require 'uri'
+
+require 'puppet/forge'
+
+class Puppet::Forge
+  # = Cache
+  #
+  # Provides methods for reading files from local cache, filesystem or network.
+  class Cache
+
+    # Instantiate new cache for the +repository+ instance.
+    def initialize(repository, options = {})
+      @repository = repository
+      @options = options
+    end
+
+    # Return filename retrieved from +uri+ instance. Will download this file and
+    # cache it if needed.
+    #
+    # TODO: Add checksum support.
+    # TODO: Add error checking.
+    def retrieve(url)
+      (path + File.basename(url.to_s)).tap do |cached_file|
+        uri = url.is_a?(::URI) ? url : ::URI.parse(url)
+        unless cached_file.file?
+          if uri.scheme == 'file'
+            FileUtils.cp(URI.unescape(uri.path), cached_file)
+          else
+            # TODO: Handle HTTPS; probably should use repository.contact
+            data = read_retrieve(uri)
+            cached_file.open('wb') { |f| f.write data }
+          end
+        end
+      end
+    end
+
+    # Return contents of file at the given URI's +uri+.
+    def read_retrieve(uri)
+      return uri.read
+    end
+
+    # Return Pathname for repository's cache directory, create it if needed.
+    def path
+      (self.class.base_path + @repository.cache_key).tap{ |o| o.mkpath }
+    end
+
+    # Return the base Pathname for all the caches.
+    def self.base_path
+      (Pathname(Puppet.settings[:module_working_dir]) + 'cache').tap do |o|
+        o.mkpath unless o.exist?
+      end
+    end
+
+    # Clean out all the caches.
+    def self.clean
+      base_path.rmtree if base_path.exist?
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/forge/errors.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/forge/errors.rb
new file mode 100644
index 0000000..54041f5
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/forge/errors.rb
@@ -0,0 +1,112 @@
+require 'json'
+require 'puppet/error'
+require 'puppet/forge'
+
+# Puppet::Forge specific exceptions
+module Puppet::Forge::Errors
+
+  # This exception is the parent for all Forge API errors
+  class ForgeError < Puppet::Error
+    # This is normally set by the child class, but if it is not this will
+    # fall back to displaying the message as a multiline.
+    #
+    # @return [String] the multiline version of the error message
+    def multiline
+      self.message
+    end
+  end
+
+  # This exception is raised when there is an SSL verification error when
+  # communicating with the forge.
+  class SSLVerifyError < ForgeError
+    # @option options [String] :uri The URI that failed
+    # @option options [String] :original the original exception
+    def initialize(options)
+      @uri     = options[:uri]
+      original = options[:original]
+
+      super("Unable to verify the SSL certificate at #{@uri}", original)
+    end
+
+    # Return a multiline version of the error message
+    #
+    # @return [String] the multiline version of the error message
+    def multiline
+      <<-EOS.chomp
+Could not connect via HTTPS to #{@uri}
+  Unable to verify the SSL certificate
+    The certificate may not be signed by a valid CA
+    The CA bundle included with OpenSSL may not be valid or up to date
+      EOS
+    end
+  end
+
+  # This exception is raised when there is a communication error when connecting
+  # to the forge
+  class CommunicationError < ForgeError
+    # @option options [String] :uri The URI that failed
+    # @option options [String] :original the original exception
+    def initialize(options)
+      @uri     = options[:uri]
+      original = options[:original]
+      @detail  = original.message
+
+      message = "Unable to connect to the server at #{@uri}. Detail: #{@detail}."
+      super(message, original)
+    end
+
+    # Return a multiline version of the error message
+    #
+    # @return [String] the multiline version of the error message
+    def multiline
+      <<-EOS.chomp
+Could not connect to #{@uri}
+  There was a network communications problem
+    The error we caught said '#{@detail}'
+    Check your network connection and try again
+      EOS
+    end
+  end
+
+  # This exception is raised when there is a bad HTTP response from the forge
+  # and optionally a message in the response.
+  class ResponseError < ForgeError
+    # @option options [String] :uri The URI that failed
+    # @option options [String] :input The user's input (e.g. module name)
+    # @option options [String] :message Error from the API response (optional)
+    # @option options [Net::HTTPResponse] :response The original HTTP response
+    def initialize(options)
+      @uri     = options[:uri]
+      @message = options[:message]
+      response = options[:response]
+      @response = "#{response.code} #{response.message.strip}"
+
+      begin
+        body = JSON.parse(response.body)
+        if body['message']
+          @message ||= body['message'].strip
+        end
+      rescue JSON::ParserError
+      end
+
+      message = "Request to Puppet Forge failed. Detail: "
+      message << @message << " / " if @message
+      message << @response << "."
+      super(message, original)
+    end
+
+    # Return a multiline version of the error message
+    #
+    # @return [String] the multiline version of the error message
+    def multiline
+      message = <<-EOS.chomp
+Request to Puppet Forge failed.
+  The server being queried was #{@uri}
+  The HTTP response we received was '#{@response}'
+      EOS
+      message << "\n  The message we received said '#{@message}'" if @message
+      message
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/forge/repository.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/forge/repository.rb
new file mode 100644
index 0000000..a96faf3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/forge/repository.rb
@@ -0,0 +1,182 @@
+require 'net/https'
+require 'digest/sha1'
+require 'uri'
+require 'puppet/util/http_proxy'
+require 'puppet/forge'
+require 'puppet/forge/errors'
+
+if Puppet.features.zlib? && Puppet[:zlib]
+  require 'zlib'
+end
+
+class Puppet::Forge
+  # = Repository
+  #
+  # This class is a file for accessing remote repositories with modules.
+  class Repository
+    include Puppet::Forge::Errors
+
+    attr_reader :uri, :cache
+
+    # List of Net::HTTP exceptions to catch
+    NET_HTTP_EXCEPTIONS = [
+      EOFError,
+      Errno::ECONNABORTED,
+      Errno::ECONNREFUSED,
+      Errno::ECONNRESET,
+      Errno::EINVAL,
+      Errno::ETIMEDOUT,
+      Net::HTTPBadResponse,
+      Net::HTTPHeaderSyntaxError,
+      Net::ProtocolError,
+      SocketError,
+    ]
+
+    if Puppet.features.zlib? && Puppet[:zlib]
+      NET_HTTP_EXCEPTIONS << Zlib::GzipFile::Error
+    end
+
+    # Instantiate a new repository instance rooted at the +url+.
+    # The library will report +for_agent+ in the User-Agent to the repository.
+    def initialize(host, for_agent)
+      @host  = host
+      @agent = for_agent
+      @cache = Cache.new(self)
+      @uri   = URI.parse(host)
+    end
+
+    # Return a Net::HTTPResponse read for this +path+.
+    def make_http_request(path, io = nil)
+      Puppet.debug "HTTP GET #{@host}#{path}"
+      request = get_request_object(path)
+      return read_response(request, io)
+    end
+
+    def forge_authorization
+      if Puppet[:forge_authorization]
+        Puppet[:forge_authorization]
+      elsif Puppet.features.pe_license?
+        PELicense.load_license_key.authorization_token
+      end
+    end
+
+    def get_request_object(path)
+      headers = {
+        "User-Agent" => user_agent,
+      }
+
+      if Puppet.features.zlib? && Puppet[:zlib] && RUBY_VERSION >= "1.9"
+        headers = headers.merge({
+          "Accept-Encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3",
+        })
+      end
+
+      if forge_authorization
+        headers = headers.merge({"Authorization" => forge_authorization})
+      end
+
+      request = Net::HTTP::Get.new(URI.escape(path), headers)
+
+      unless @uri.user.nil? || @uri.password.nil? || forge_authorization
+        request.basic_auth(@uri.user, @uri.password)
+      end
+
+      return request
+    end
+
+    # Return a Net::HTTPResponse read from this HTTPRequest +request+.
+    #
+    # @param request [Net::HTTPRequest] request to make
+    # @return [Net::HTTPResponse] response from request
+    # @raise [Puppet::Forge::Errors::CommunicationError] if there is a network
+    #   related error
+    # @raise [Puppet::Forge::Errors::SSLVerifyError] if there is a problem
+    #  verifying the remote SSL certificate
+    def read_response(request, io = nil)
+      http_object = get_http_object
+
+      http_object.start do |http|
+        response = http.request(request)
+
+        if Puppet.features.zlib? && Puppet[:zlib]
+          if response && response.key?("content-encoding")
+            case response["content-encoding"]
+            when "gzip"
+              response.body = Zlib::GzipReader.new(StringIO.new(response.read_body), :encoding => "ASCII-8BIT").read
+              response.delete("content-encoding")
+            when "deflate"
+              response.body = Zlib::Inflate.inflate(response.read_body)
+              response.delete("content-encoding")
+            end
+          end
+        end
+
+        io.write(response.body) if io.respond_to? :write
+        response
+      end
+    rescue *NET_HTTP_EXCEPTIONS => e
+      raise CommunicationError.new(:uri => @uri.to_s, :original => e)
+    rescue OpenSSL::SSL::SSLError => e
+      if e.message =~ /certificate verify failed/
+        raise SSLVerifyError.new(:uri => @uri.to_s, :original => e)
+      else
+        raise e
+      end
+    end
+
+    # Return a Net::HTTP::Proxy object constructed from the settings provided
+    # accessing the repository.
+    #
+    # This method optionally configures SSL correctly if the URI scheme is
+    # 'https', including setting up the root certificate store so remote server
+    # SSL certificates can be validated.
+    #
+    # @return [Net::HTTP::Proxy] object constructed from repo settings
+    def get_http_object
+      proxy_class = Net::HTTP::Proxy(Puppet::Util::HttpProxy.http_proxy_host, Puppet::Util::HttpProxy.http_proxy_port, Puppet::Util::HttpProxy.http_proxy_user, Puppet::Util::HttpProxy.http_proxy_password)
+      proxy = proxy_class.new(@uri.host, @uri.port)
+
+      if @uri.scheme == 'https'
+        cert_store = OpenSSL::X509::Store.new
+        cert_store.set_default_paths
+
+        proxy.use_ssl = true
+        proxy.verify_mode = OpenSSL::SSL::VERIFY_PEER
+        proxy.cert_store = cert_store
+      end
+
+      proxy
+    end
+
+    # Return the local file name containing the data downloaded from the
+    # repository at +release+ (e.g. "myuser-mymodule").
+    def retrieve(release)
+      path = @host.chomp('/') + release
+      return cache.retrieve(path)
+    end
+
+    # Return the URI string for this repository.
+    def to_s
+      "#<#{self.class} #{@host}>"
+    end
+
+    # Return the cache key for this repository, this a hashed string based on
+    # the URI.
+    def cache_key
+      return @cache_key ||= [
+        @host.to_s.gsub(/[^[:alnum:]]+/, '_').sub(/_$/, ''),
+        Digest::SHA1.hexdigest(@host.to_s)
+      ].join('-').freeze
+    end
+
+    private
+
+    def user_agent
+      @user_agent ||= [
+        @agent,
+        "Puppet/#{Puppet.version}",
+        "Ruby/#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} (#{RUBY_PLATFORM})",
+      ].join(' ').freeze
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions.rb
new file mode 100644
index 0000000..fb441e3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions.rb
@@ -0,0 +1,630 @@
+# @note WARNING: This new function API is still under development and may change at any time
+#
+# Functions in the puppet language can be written in Ruby and distributed in
+# puppet modules. The function is written by creating a file in the module's
+# `lib/puppet/functions/<modulename>` directory, where `<modulename>` is
+# replaced with the module's name. The file should have the name of the function.
+# For example, to create a function named `min` in a module named `math` create
+# a file named `lib/puppet/functions/math/min.rb` in the module.
+#
+# A function is implemented by calling {Puppet::Functions.create_function}, and
+# passing it a block that defines the implementation of the function.
+#
+# Functions are namespaced inside the module that contains them. The name of
+# the function is prefixed with the name of the module. For example,
+# `math::min`.
+#
+# @example A simple function
+#   Puppet::Functions.create_function('math::min') do
+#     def min(a, b)
+#       a <= b ? a : b
+#     end
+#   end
+#
+# Anatomy of a function
+# ---
+#
+# Functions are composed of four parts: the name, the implementation methods,
+# the signatures, and the dispatches.
+#
+# The name is the string given to the {Puppet::Functions.create_function}
+# method. It specifies the name to use when calling the function in the puppet
+# language, or from other functions.
+#
+# The implementation methods are ruby methods (there can be one or more) that
+# provide that actual implementation of the function's behavior. In the
+# simplest case the name of the function (excluding any namespace) and the name
+# of the method are the same. When that is done no other parts (signatures and
+# dispatches) need to be used.
+#
+# Signatures are a way of specifying the types of the function's parameters.
+# The types of any arguments will be checked against the types declared in the
+# signature and an error will be produced if they don't match. The types are
+# defined by using the same syntax for types as in the puppet language.
+#
+# Dispatches are how signatures and implementation methods are tied together.
+# When the function is called, puppet searches the signatures for one that
+# matches the supplied arguments. Each signature is part of a dispatch, which
+# specifies the method that should be called for that signature. When a
+# matching signature is found, the corrosponding method is called.
+#
+# Documentation for the function should be placed as comments to the
+# implementation method(s).
+#
+# @todo Documentation for individual instances of these new functions is not
+#   yet tied into the puppet doc system.
+#
+# @example Dispatching to different methods by type
+#   Puppet::Functions.create_function('math::min') do
+#     dispatch :numeric_min do
+#       param 'Numeric', :a
+#       param 'Numeric', :b
+#     end
+#
+#     dispatch :string_min do
+#       param 'String', :a
+#       param 'String', :b
+#     end
+#
+#     def numeric_min(a, b)
+#       a <= b ? a : b
+#     end
+#
+#     def string_min(a, b)
+#       a.downcase <= b.downcase ? a : b
+#     end
+#   end
+#
+# Specifying Signatures
+# ---
+#
+# If nothing is specified, the number of arguments given to the function must
+# be the same as the number of parameters, and all of the parameters are of
+# type 'Any'.
+#
+# The following methods can be used to define a parameter
+#
+#  - _param_ - the argument must be given in the call.
+#  - _optional_param_ - the argument may be missing in the call. May not be followed by a required parameter
+#  - _repeated_param_ - the type specifies a repeating type that occurs 0 to "infinite" number of times. It may only appear last or just before a block parameter.
+#  - _block_param_ - a block must be given in the call. May only appear last.
+#  - _optional_block_param_ - a block may be given in the call. May only appear last.
+#
+# The method name _required_param_ is an alias for _param_ and _required_block_param_ is an alias for _block_param_
+#
+# A parameter definition takes 2 arguments:
+#  - _type_ A string that must conform to a type in the puppet language
+#  - _name_ A symbol denoting the parameter name
+#
+# Both arguments are optional when defining a block parameter. The _type_ defaults to "Callable"
+# and the _name_ to :block.
+#
+# Note that the dispatch definition is used to match arguments given in a call to the function with the defined
+# parameters. It then dispatches the call to the implementation method simply passing the given arguments on to
+# that method without any further processing and it is the responsibility of that method's implementor to ensure
+# that it can handle those arguments.
+#
+# @example Variable number of arguments
+#   Puppet::Functions.create_function('foo') do
+#     dispatch :foo do
+#       param 'Numeric', :first
+#       repeated_param 'Numeric', :values
+#     end
+#
+#     def foo(first, *values)
+#       # do something
+#     end
+#   end
+#
+# There is no requirement for direct mapping between parameter definitions and the parameters in the
+# receiving implementation method so the following example is also legal. Here the dispatch will ensure
+# that `*values` in the receiver will be an array with at least one entry of type String and that any
+# remaining entries are of type Numeric:
+#
+# @example Inexact mapping or parameters
+#   Puppet::Functions.create_function('foo') do
+#     dispatch :foo do
+#       param 'String', :first
+#       repeated_param 'Numeric', :values
+#     end
+#
+#     def foo(*values)
+#       # do something
+#     end
+#   end
+#
+# Access to Scope
+# ---
+# In general, functions should not need access to scope; they should be
+# written to act on their given input only. If they absolutely must look up
+# variable values, they should do so via the closure scope (the scope where
+# they are defined) - this is done by calling `closure_scope()`.
+#
+# Calling other Functions
+# ---
+# Calling other functions by name is directly supported via
+# {Puppet::Pops::Functions::Function#call_function}. This allows a function to
+# call other functions visible from its loader.
+#
+# @api public
+module Puppet::Functions
+  # @param func_name [String, Symbol] a simple or qualified function name
+  # @param block [Proc] the block that defines the methods and dispatch of the
+  #   Function to create
+  # @return [Class<Function>] the newly created Function class
+  #
+  # @api public
+  def self.create_function(func_name, function_base = Function, &block)
+    if function_base.ancestors.none? { |s| s == Puppet::Pops::Functions::Function }
+      raise ArgumentError, "Functions must be based on Puppet::Pops::Functions::Function. Got #{function_base}"
+    end
+
+    func_name = func_name.to_s
+    # Creates an anonymous class to represent the function
+    # The idea being that it is garbage collected when there are no more
+    # references to it.
+    #
+    the_class = Class.new(function_base, &block)
+
+    # Make the anonymous class appear to have the class-name <func_name>
+    # Even if this class is not bound to such a symbol in a global ruby scope and
+    # must be resolved via the loader.
+    # This also overrides any attempt to define a name method in the given block
+    # (Since it redefines it)
+    #
+    # TODO, enforce name in lower case (to further make it stand out since Ruby
+    # class names are upper case)
+    #
+    the_class.instance_eval do
+      @func_name = func_name
+      def name
+        @func_name
+      end
+    end
+
+    # Automatically create an object dispatcher based on introspection if the
+    # loaded user code did not define any dispatchers. Fail if function name
+    # does not match a given method name in user code.
+    #
+    if the_class.dispatcher.empty?
+      simple_name = func_name.split(/::/)[-1]
+      type, names = default_dispatcher(the_class, simple_name)
+      last_captures_rest = (type.size_range[1] == Puppet::Pops::Types::INFINITY)
+      the_class.dispatcher.add_dispatch(type, simple_name, names, nil, nil, nil, last_captures_rest)
+    end
+
+    # The function class is returned as the result of the create function method
+    the_class
+  end
+
+  # Creates a default dispatcher configured from a method with the same name as the function
+  #
+  # @api private
+  def self.default_dispatcher(the_class, func_name)
+    unless the_class.method_defined?(func_name)
+      raise ArgumentError, "Function Creation Error, cannot create a default dispatcher for function '#{func_name}', no method with this name found"
+    end
+    any_signature(*min_max_param(the_class.instance_method(func_name)))
+  end
+
+  # @api private
+  def self.min_max_param(method)
+    # Ruby 1.8.7 does not have support for details about parameters
+    if method.respond_to?(:parameters)
+      result = {:req => 0, :opt => 0, :rest => 0 }
+      # TODO: Optimize into one map iteration that produces names map, and sets
+      # count as side effect
+      method.parameters.each { |p| result[p[0]] += 1 }
+      from = result[:req]
+      to = result[:rest] > 0 ? :default : from + result[:opt]
+      names = method.parameters.map {|p| p[1].to_s }
+    else
+      # Cannot correctly compute the signature in Ruby 1.8.7 because arity for
+      # optional values is screwed up (there is no way to get the upper limit),
+      # an optional looks the same as a varargs In this case - the failure will
+      # simply come later when the call fails
+      #
+      arity = method.arity
+      from = arity >= 0 ? arity : -arity -1
+      to = arity >= 0 ? arity : :default  # i.e. infinite (which is wrong when there are optional - flaw in 1.8.7)
+      names = [] # no names available
+    end
+    [from, to, names]
+  end
+
+  # Construct a signature consisting of Object type, with min, and max, and given names.
+  # (there is only one type entry).
+  #
+  # @api private
+  def self.any_signature(from, to, names)
+    # Construct the type for the signature
+    # Tuple[Object, from, to]
+    factory = Puppet::Pops::Types::TypeFactory
+    [factory.callable(factory.any, from, to), names]
+  end
+
+  # Function
+  # ===
+  # This class is the base class for all Puppet 4x Function API functions. A
+  # specialized class is created for each puppet function.
+  #
+  # @api public
+  class Function < Puppet::Pops::Functions::Function
+
+    # @api private
+    def self.builder
+      @type_parser ||= Puppet::Pops::Types::TypeParser.new
+      @all_callables ||= Puppet::Pops::Types::TypeFactory.all_callables
+      DispatcherBuilder.new(dispatcher, @type_parser, @all_callables)
+    end
+
+    # Dispatch any calls that match the signature to the provided method name.
+    #
+    # @param meth_name [Symbol] The name of the implementation method to call
+    #   when the signature defined in the block matches the arguments to a call
+    #   to the function.
+    # @return [Void]
+    #
+    # @api public
+    def self.dispatch(meth_name, &block)
+      builder().instance_eval do
+        dispatch(meth_name, &block)
+      end
+    end
+  end
+
+  # Public api methods of the DispatcherBuilder are available within dispatch()
+  # blocks declared in a Puppet::Function.create_function() call.
+  #
+  # @api public
+  class DispatcherBuilder
+    # @api private
+    def initialize(dispatcher, type_parser, all_callables)
+      @type_parser = type_parser
+      @all_callables = all_callables
+      @dispatcher = dispatcher
+    end
+
+    # Defines a required positional parameter with _type_ and _name_.
+    #
+    # @param type [String] The type specification for the parameter.
+    # @param name [Symbol] The name of the parameter. This is primarily used
+    #   for error message output and does not have to match an implementation
+    #   method parameter.
+    # @return [Void]
+    #
+    # @api public
+    def param(type, name)
+      internal_param(type, name)
+      raise ArgumentError, 'A required parameter cannot be added after an optional parameter' if @min != @max
+      @min += 1
+      @max += 1
+    end
+    alias required_param param
+
+    # Defines an optional positional parameter with _type_ and _name_.
+    # May not be followed by a required parameter.
+    #
+    # @param type [String] The type specification for the parameter.
+    # @param name [Symbol] The name of the parameter. This is primarily used
+    #   for error message output and does not have to match an implementation
+    #   method parameter.
+    # @return [Void]
+    #
+    # @api public
+    def optional_param(type, name)
+      internal_param(type, name)
+      @max += 1
+    end
+
+    # Defines a repeated positional parameter with _type_ and _name_ that may occur 0 to "infinite" number of times.
+    # It may only appear last or just before a block parameter.
+    #
+    # @param type [String] The type specification for the parameter.
+    # @param name [Symbol] The name of the parameter. This is primarily used
+    #   for error message output and does not have to match an implementation
+    #   method parameter.
+    # @return [Void]
+    #
+    # @api public
+    def repeated_param(type, name)
+      internal_param(type, name, true)
+      @max = :default
+    end
+    alias optional_repeated_param repeated_param
+
+    # Defines a repeated positional parameter with _type_ and _name_ that may occur 1 to "infinite" number of times.
+    # It may only appear last or just before a block parameter.
+    #
+    # @param type [String] The type specification for the parameter.
+    # @param name [Symbol] The name of the parameter. This is primarily used
+    #   for error message output and does not have to match an implementation
+    #   method parameter.
+    # @return [Void]
+    #
+    # @api public
+    def required_repeated_param(type, name)
+      internal_param(type, name, true)
+      raise ArgumentError, 'A required repeated parameter cannot be added after an optional parameter' if @min != @max
+      @min += 1
+      @max = :default
+    end
+
+    # Defines one required block parameter that may appear last. If type and name is missing the
+    # default type is "Callable", and the name is "block". If only one
+    # parameter is given, then that is the name and the type is "Callable".
+    #
+    # @api public
+    def block_param(*type_and_name)
+      case type_and_name.size
+      when 0
+        # the type must be an independent instance since it will be contained in another type
+        type = @all_callables.copy
+        name = 'block'
+      when 1
+        # the type must be an independent instance since it will be contained in another type
+        type = @all_callables.copy
+        name = type_and_name[0]
+      when 2
+        type_string, name = type_and_name
+        type = @type_parser.parse(type_string)
+      else
+        raise ArgumentError, "block_param accepts max 2 arguments (type, name), got #{type_and_name.size}."
+      end
+
+      unless Puppet::Pops::Types::TypeCalculator.is_kind_of_callable?(type, false)
+        raise ArgumentError, "Expected PCallableType or PVariantType thereof, got #{type.class}"
+      end
+
+      unless name.is_a?(String) || name.is_a?(Symbol)
+        raise ArgumentError, "Expected block_param name to be a String or Symbol, got #{name.class}"
+      end
+
+      if @block_type.nil?
+        @block_type = type
+        @block_name = name
+      else
+        raise ArgumentError, 'Attempt to redefine block'
+      end
+    end
+    alias required_block_param block_param
+
+    # Defines one optional block parameter that may appear last. If type or name is missing the
+    # defaults are "any callable", and the name is "block". The implementor of the dispatch target
+    # must use block = nil when it is optional (or an error is raised when the call is made).
+    #
+    # @api public
+    def optional_block_param(*type_and_name)
+      # same as required, only wrap the result in an optional type
+      required_block_param(*type_and_name)
+      @block_type = Puppet::Pops::Types::TypeFactory.optional(@block_type)
+    end
+
+    private
+
+    # @api private
+    def internal_param(type, name, repeat = false)
+      raise ArgumentError, 'Parameters cannot be added after a block parameter' unless @block_type.nil?
+      raise ArgumentError, 'Parameters cannot be added after a repeated parameter' if @max == :default
+      if type.is_a?(String)
+        @types << type
+        @names << name
+        # mark what should be picked for this position when dispatching
+        if repeat
+          @weaving << -@names.size()
+        else
+          @weaving << @names.size()-1
+        end
+      else
+        raise ArgumentError, "Parameter 'type' must be a String reference to a Puppet Data Type. Got #{type.class}"
+      end
+    end
+
+    # @api private
+    def dispatch(meth_name, &block)
+      # an array of either an index into names/types, or an array with
+      # injection information [type, name, injection_name] used when the call
+      # is being made to weave injections into the given arguments.
+      #
+      @types = []
+      @names = []
+      @weaving = []
+      @injections = []
+      @min = 0
+      @max = 0
+      @block_type = nil
+      @block_name = nil
+      self.instance_eval &block
+      callable_t = create_callable(@types, @block_type, @min, @max)
+      @dispatcher.add_dispatch(callable_t, meth_name, @names, @block_name, @injections, @weaving, @max == :default)
+    end
+
+    # Handles creation of a callable type from strings specifications of puppet
+    # types and allows the min/max occurs of the given types to be given as one
+    # or two integer values at the end.  The given block_type should be
+    # Optional[Callable], Callable, or nil.
+    #
+    # @api private
+    def create_callable(types, block_type, from, to)
+      mapped_types = types.map do |t|
+        @type_parser.parse(t)
+      end
+
+      if from != to
+        # :optional and/or :repeated parameters are present.
+        mapped_types << from
+        mapped_types << to
+      end
+
+      if block_type
+        mapped_types << block_type
+      end
+
+      Puppet::Pops::Types::TypeFactory.callable(*mapped_types)
+    end
+  end
+
+  private
+
+  # @note WARNING: This style of creating functions is not public. It is a system
+  #   under development that will be used for creating "system" functions.
+  #
+  # This is a private, internal, system for creating functions. It supports
+  # everything that the public function definition system supports as well as a
+  # few extra features.
+  #
+  # Injection Support
+  # ===
+  # The Function API supports injection of data and services. It is possible to
+  # make injection that takes effect when the function is loaded (for services
+  # and runtime configuration that does not change depending on how/from where
+  # in what context the function is called. It is also possible to inject and
+  # weave argument values into a call.
+  #
+  # Injection of attributes
+  # ---
+  # Injection of attributes is performed by one of the methods `attr_injected`,
+  # and `attr_injected_producer`.  The injected attributes are available via
+  # accessor method calls.
+  #
+  # @example using injected attributes
+  #   Puppet::Functions.create_function('test') do
+  #     attr_injected String, :larger, 'message_larger'
+  #     attr_injected String, :smaller, 'message_smaller'
+  #     def test(a, b)
+  #       a > b ? larger() : smaller()
+  #     end
+  #   end
+  #
+  # @api private
+  class InternalFunction < Function
+    # @api private
+    def self.builder
+      @type_parser ||= Puppet::Pops::Types::TypeParser.new
+      @all_callables ||= Puppet::Pops::Types::TypeFactory.all_callables
+      InternalDispatchBuilder.new(dispatcher, @type_parser, @all_callables)
+    end
+
+    # Defines class level injected attribute with reader method
+    #
+    # @api private
+    def self.attr_injected(type, attribute_name, injection_name = nil)
+      define_method(attribute_name) do
+        ivar = :"@#{attribute_name.to_s}"
+        unless instance_variable_defined?(ivar)
+          injector = Puppet.lookup(:injector)
+          instance_variable_set(ivar, injector.lookup(closure_scope, type, injection_name))
+        end
+        instance_variable_get(ivar)
+      end
+    end
+
+    # Defines class level injected producer attribute with reader method
+    #
+    # @api private
+    def self.attr_injected_producer(type, attribute_name, injection_name = nil)
+      define_method(attribute_name) do
+        ivar = :"@#{attribute_name.to_s}"
+        unless instance_variable_defined?(ivar)
+          injector = Puppet.lookup(:injector)
+          instance_variable_set(ivar, injector.lookup_producer(closure_scope, type, injection_name))
+        end
+        instance_variable_get(ivar)
+      end
+    end
+
+    # Allows the implementation of a function to call other functions by name and pass the caller
+    # scope. The callable functions are those visible to the same loader that loaded this function
+    # (the calling function).
+    #
+    # @param scope [Puppet::Parser::Scope] The caller scope
+    # @param function_name [String] The name of the function
+    # @param *args [Object] splat of arguments
+    # @return [Object] The result returned by the called function
+    #
+    # @api public
+    def call_function_with_scope(scope, function_name, *args)
+      internal_call_function(scope, function_name, args)
+    end
+  end
+
+  # @note WARNING: This style of creating functions is not public. It is a system
+  #   under development that will be used for creating "system" functions.
+  #
+  # Injection and Weaving of parameters
+  # ---
+  # It is possible to inject and weave parameters into a call. These extra
+  # parameters are not part of the parameters passed from the Puppet logic, and
+  # they can not be overridden by parameters given as arguments in the call.
+  # They are invisible to the Puppet Language.
+  #
+  # @example using injected parameters
+  #   Puppet::Functions.create_function('test') do
+  #     dispatch :test do
+  #       param 'Scalar', 'a'
+  #       param 'Scalar', 'b'
+  #       injected_param 'String', 'larger', 'message_larger'
+  #       injected_param 'String', 'smaller', 'message_smaller'
+  #     end
+  #     def test(a, b, larger, smaller)
+  #       a > b ? larger : smaller
+  #     end
+  #   end
+  #
+  # The function in the example above is called like this:
+  #
+  #     test(10, 20)
+  #
+  # Using injected value as default
+  # ---
+  # Default value assignment is handled by using the regular Ruby mechanism (a
+  # value is assigned to the variable).  The dispatch simply indicates that the
+  # value is optional. If the default value should be injected, it can be
+  # handled different ways depending on what is desired:
+  #
+  # * by calling the accessor method for an injected Function class attribute.
+  #   This is suitable if the value is constant across all instantiations of the
+  #   function, and across all calls.
+  # * by injecting a parameter into the call
+  #   to the left of the parameter, and then assigning that as the default value.
+  # * One of the above forms, but using an injected producer instead of a
+  #   directly injected value.
+  #
+  # @example method with injected default values
+  #   Puppet::Functions.create_function('test') do
+  #     dispatch :test do
+  #       injected_param String, 'b_default', 'b_default_value_key'
+  #       param 'Scalar', 'a'
+  #       param 'Scalar', 'b'
+  #     end
+  #     def test(b_default, a, b = b_default)
+  #       # ...
+  #     end
+  #   end
+  #
+  # @api private
+  class InternalDispatchBuilder < DispatcherBuilder
+    def scope_param()
+      @injections << [:scope, 'scope', '', :dispatcher_internal]
+      # mark what should be picked for this position when dispatching
+      @weaving << [@injections.size()-1]
+    end
+    # TODO: is param name really needed? Perhaps for error messages? (it is unused now)
+    #
+    # @api private
+    def injected_param(type, name, injection_name = '')
+      @injections << [type, name, injection_name]
+      # mark what should be picked for this position when dispatching
+      @weaving << [@injections.size() -1]
+    end
+
+    # TODO: is param name really needed? Perhaps for error messages? (it is unused now)
+    #
+    # @api private
+    def injected_producer_param(type, name, injection_name = '')
+      @injections << [type, name, injection_name, :producer]
+      # mark what should be picked for this position when dispatching
+      @weaving << [@injections.size()-1]
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/assert_type.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/assert_type.rb
new file mode 100644
index 0000000..f51cddc
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/assert_type.rb
@@ -0,0 +1,59 @@
+# Returns the given value if it is an instance of the given type, and raises an error otherwise.
+# Optionally, if a block is given (accepting two parameters), it will be called instead of raising
+# an error. This to enable giving the user richer feedback, or to supply a default value.
+#
+# @example how to assert type
+#   # assert that `$b` is a non empty `String` and assign to `$a`
+#   $a = assert_type(String[1], $b)
+#
+# @example using custom error message
+#   $a = assert_type(String[1], $b) |$expected, $actual| { fail("The name cannot be empty") }
+#
+# @example using a warning and a default
+#   $a = assert_type(String[1], $b) |$expected, $actual| { warning("Name is empty, using default") 'anonymous' }
+#
+# See the documentation for "The Puppet Type System" for more information about types.
+#
+Puppet::Functions.create_function(:assert_type) do
+  dispatch :assert_type do
+    param 'Type', 'type'
+    param 'Any', 'value'
+    optional_block_param 'Callable[Type, Type]', 'block'
+  end
+
+  dispatch :assert_type_s do
+    param 'String', 'type_string'
+    param 'Any', 'value'
+    optional_block_param 'Callable[Type, Type]', 'block'
+  end
+
+  # @param type [Type] the type the value must be an instance of
+  # @param value [Object] the value to assert
+  #
+  def assert_type(type, value)
+    unless Puppet::Pops::Types::TypeCalculator.instance?(type,value)
+      inferred_type = Puppet::Pops::Types::TypeCalculator.infer(value)
+      if block_given?
+        # Give the inferred type to allow richer comparisson in the given block (if generalized
+        # information is lost).
+        #
+        value = yield(type, inferred_type)
+      else
+        # Do not give all the details - i.e. format as Integer, instead of Integer[n, n] for exact value, which
+        # is just confusing. (OTOH: may need to revisit, or provide a better "type diff" output.
+        #
+        actual = Puppet::Pops::Types::TypeCalculator.generalize!(inferred_type)
+        raise Puppet::ParseError, "assert_type(): Expected type #{type} does not match actual: #{actual}"
+      end
+    end
+    value
+  end
+
+  # @param type_string [String] the type the value must be an instance of given in String form
+  # @param value [Object] the value to assert
+  #
+  def assert_type_s(type_string, value, &proc)
+    t = Puppet::Pops::Types::TypeParser.new.parse(type_string)
+    block_given? ? assert_type(t, value, &proc) : assert_type(t, value)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/defined.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/defined.rb
new file mode 100644
index 0000000..d7c50b0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/defined.rb
@@ -0,0 +1,130 @@
+# Determines whether
+# a given class or resource type is defined. This function can also determine whether a
+# specific resource has been declared, or whether a variable has been assigned a value
+# (including undef...as opposed to never having been assigned anything). Returns true
+# or false. Accepts class names, type names, resource references, and variable
+# reference strings of the form '$name'.  When more than one argument is
+# supplied, defined() returns true if any are defined.
+#
+# The `defined` function checks both native and defined types, including types
+# provided as plugins via modules. Types and classes are both checked using their names:
+#
+#     defined("file")
+#     defined("customtype")
+#     defined("foo")
+#     defined("foo::bar")
+#     defined('$name')
+#
+# Resource declarations are checked using resource references, e.g.
+# `defined( File['/tmp/myfile'] )`, or `defined( Class[myclass] )`.
+# Checking whether a given resource
+# has been declared is, unfortunately, dependent on the evaluation order of
+# the configuration, and the following code will not work:
+#
+#     if defined(File['/tmp/foo']) {
+#         notify { "This configuration includes the /tmp/foo file.":}
+#     }
+#     file { "/tmp/foo":
+#         ensure => present,
+#     }
+#
+# However, this order requirement refers to evaluation order only, and ordering of
+# resources in the configuration graph (e.g. with `before` or `require`) does not
+# affect the behavior of `defined`.
+#
+# You may also search using types:
+#
+#     defined(Resource['file','/some/file'])
+#     defined(File['/some/file'])
+#     defined(Class['foo'])
+#
+# The `defined` function does not answer if data types (e.g. `Integer`) are defined. If
+# given the string 'integer' the result is false, and if given a non CatalogEntry type,
+# an error is raised.
+#
+# The rules for asking for undef, empty strings, and the main class are different from 3.x
+# (non future parser) and 4.x (with future parser or in Puppet 4.0.0 and later):
+#
+#     defined('')     # 3.x => true,  4.x => false
+#     defined(undef)  # 3.x => true,  4.x => error
+#     defined('main') # 3.x => false, 4.x => true
+#
+# With the future parser, it is also possible to ask specifically if a name is
+# a resource type (built in or defined), or a class, by giving its type:
+#
+#     defined(Type[Class['foo']])
+#     defined(Type[Resource['foo']])
+#
+# Which is different from asking:
+#
+#     defined('foo')
+#
+# Since the later returns true if 'foo' is either a class, a built-in resource type, or a user defined
+# resource type, and a specific request like `Type[Class['foo']]` only returns true if `'foo'` is a class.
+#
+# @since 2.7.0
+# @since 3.6.0 variable reference and future parser types")
+# @since 3.8.1 type specific requests with future parser
+#
+Puppet::Functions.create_function(:'defined', Puppet::Functions::InternalFunction) do
+
+  dispatch :is_defined do
+    scope_param
+    required_repeated_param 'Variant[String, Type[CatalogEntry], Type[Type[CatalogEntry]]]', :vals
+  end
+
+  def is_defined(scope, *vals)
+    vals.any? do |val|
+      case val
+      when String
+        if val =~ /^\$(.+)$/
+          scope.exist?($1)
+        else
+          case val
+          when ''
+            next nil
+          when 'main'
+            # Find the main class (known as ''), it does not have to be in the catalog
+            scope.find_hostclass('')
+          else
+            # Find a resource type, definition or class definition
+            scope.find_resource_type(val) || scope.find_definition(val) || scope.find_hostclass(val)
+            #scope.compiler.findresource(:class, val)
+          end
+        end
+      when Puppet::Resource
+        # Find instance of given resource type and title that is in the catalog
+        scope.compiler.findresource(val.type, val.title)
+
+      when Puppet::Pops::Types::PResourceType
+        raise ArgumentError, 'The given resource type is a reference to all kind of types' if val.type_name.nil?
+        if val.title.nil?
+          scope.find_builtin_resource_type(val.type_name) || scope.find_definition(val.type_name)
+        else
+          scope.compiler.findresource(val.type_name, val.title)
+        end
+
+      when Puppet::Pops::Types::PHostClassType
+        raise  ArgumentError, 'The given class type is a reference to all classes' if val.class_name.nil?
+        scope.compiler.findresource(:class, val.class_name)
+
+      when Puppet::Pops::Types::PType
+        case val.type
+        when Puppet::Pops::Types::PResourceType
+          # It is most reasonable to take Type[File] and Type[File[foo]] to mean the same as if not wrapped in a Type
+          # Since the difference between File and File[foo] already captures the distinction of type vs instance.
+          is_defined(scope, val.type)
+
+        when Puppet::Pops::Types::PHostClassType
+          # Interpreted as asking if a class (and nothing else) is defined without having to be included in the catalog
+          # (this is the same as asking for just the class' name, but with the added certainty that it cannot be a defined type.
+          #
+          raise  ArgumentError, 'The given class type is a reference to all classes' if val.type.class_name.nil?
+          scope.find_hostclass(val.type.class_name)
+        end
+      else
+        raise ArgumentError, "Invalid argument of type '#{val.class}' to 'defined'"
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/each.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/each.rb
new file mode 100644
index 0000000..c52aeaa
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/each.rb
@@ -0,0 +1,111 @@
+#  Applies a parameterized block to each element in a sequence of selected entries from the first
+#  argument and returns the first argument.
+#
+# This function takes two mandatory arguments: the first should be an Array or a Hash or something that is
+# of enumerable type (integer, Integer range, or String), and the second
+# a parameterized block as produced by the puppet syntax:
+#
+#       $a.each |$x| { ... }
+#       each($a) |$x| { ... }
+#
+# When the first argument is an Array (or of enumerable type other than Hash), the parameterized block
+# should define one or two block parameters.
+# For each application of the block, the next element from the array is selected, and it is passed to
+# the block if the block has one parameter. If the block has two parameters, the first is the elements
+# index, and the second the value. The index starts from 0.
+#
+#       $a.each |$index, $value| { ... }
+#       each($a) |$index, $value| { ... }
+#
+# When the first argument is a Hash, the parameterized block should define one or two parameters.
+# When one parameter is defined, the iteration is performed with each entry as an array of `[key, value]`,
+# and when two parameters are defined the iteration is performed with key and value.
+#
+#       $a.each |$entry|       { ..."key ${$entry[0]}, value ${$entry[1]}" }
+#       $a.each |$key, $value| { ..."key ${key}, value ${value}" }
+#
+# @example using each
+#
+#       [1,2,3].each |$val| { ... }                       # 1, 2, 3
+#       [5,6,7].each |$index, $val| { ... }               # (0, 5), (1, 6), (2, 7)
+#       {a=>1, b=>2, c=>3}].each |$val| { ... }           # ['a', 1], ['b', 2], ['c', 3]
+#       {a=>1, b=>2, c=>3}.each |$key, $val| { ... }      # ('a', 1), ('b', 2), ('c', 3)
+#       Integer[ 10, 20 ].each |$index, $value| { ... }   # (0, 10), (1, 11) ...
+#       "hello".each |$char| { ... }                      # 'h', 'e', 'l', 'l', 'o'
+#       3.each |$number| { ... }                          # 0, 1, 2
+#
+# @since 3.2 for Array and Hash
+# @since 3.5 for other enumerables
+# @note requires `parser = future`
+#
+Puppet::Functions.create_function(:each) do
+  dispatch :foreach_Hash_2 do
+    param 'Hash[Any, Any]', :hash
+    block_param 'Callable[2,2]', :block
+  end
+
+  dispatch :foreach_Hash_1 do
+    param 'Hash[Any, Any]', :hash
+    block_param 'Callable[1,1]', :block
+  end
+
+  dispatch :foreach_Enumerable_2 do
+    param 'Any', :enumerable
+    block_param 'Callable[2,2]', :block
+  end
+
+  dispatch :foreach_Enumerable_1 do
+    param 'Any', :enumerable
+    block_param 'Callable[1,1]', :block
+  end
+
+  def foreach_Hash_1(hash)
+    enumerator = hash.each_pair
+    hash.size.times do
+      yield(enumerator.next)
+    end
+    # produces the receiver
+    hash
+  end
+
+  def foreach_Hash_2(hash)
+    enumerator = hash.each_pair
+    hash.size.times do
+      yield(*enumerator.next)
+    end
+    # produces the receiver
+    hash
+  end
+
+  def foreach_Enumerable_1(enumerable)
+    enum = asserted_enumerable(enumerable)
+      begin
+        loop { yield(enum.next) }
+      rescue StopIteration
+      end
+    # produces the receiver
+    enumerable
+  end
+
+  def foreach_Enumerable_2(enumerable)
+    enum = asserted_enumerable(enumerable)
+    index = 0
+    begin
+      loop do
+        yield(index, enum.next)
+        index += 1
+      end
+    rescue StopIteration
+    end
+    # produces the receiver
+    enumerable
+  end
+
+  def asserted_enumerable(obj)
+    unless enum = Puppet::Pops::Types::Enumeration.enumerator(obj)
+      raise ArgumentError, ("#{self.class.name}(): wrong argument type (#{obj.class}; must be something enumerable.")
+    end
+    enum
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/epp.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/epp.rb
new file mode 100644
index 0000000..2477a1e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/epp.rb
@@ -0,0 +1,53 @@
+# Evaluates an Embedded Puppet Template (EPP) file and returns the rendered text result as a String.
+#
+# The first argument to this function should be a `<MODULE NAME>/<TEMPLATE FILE>`
+# reference, which will load `<TEMPLATE FILE>` from a module's `templates`
+# directory. (For example, the reference `apache/vhost.conf.epp` will load the
+# file `<MODULES DIRECTORY>/apache/templates/vhost.conf.epp`.)
+#
+# The second argument is optional; if present, it should be a hash containing parameters for the
+# template. (See below.)
+#
+# EPP supports the following tags:
+#
+# * `<%= puppet expression %>` - This tag renders the value of the expression it contains.
+# * `<% puppet expression(s) %>` - This tag will execute the expression(s) it contains, but renders nothing.
+# * `<%# comment %>` - The tag and its content renders nothing.
+# * `<%%` or `%%>` - Renders a literal `<%` or `%>` respectively.
+# * `<%-` - Same as `<%` but suppresses any leading whitespace.
+# * `-%>` - Same as `%>` but suppresses any trailing whitespace on the same line (including line break).
+# * `<%- |parameters| -%>` - When placed as the first tag declares the template's parameters.
+#
+# File based EPP supports the following visibilities of variables in scope:
+#
+# * Global scope (i.e. top + node scopes) - global scope is always visible
+# * Global + all given arguments - if the EPP template does not declare parameters, and arguments are given
+# * Global + declared parameters - if the EPP declares parameters, given argument names must match
+#
+# EPP supports parameters by placing an optional parameter list as the very first element in the EPP. As an example,
+# `<%- |$x, $y, $z = 'unicorn'| -%>` when placed first in the EPP text declares that the parameters `x` and `y` must be
+# given as template arguments when calling `inline_epp`, and that `z` if not given as a template argument
+# defaults to `'unicorn'`. Template parameters are available as variables, e.g.arguments `$x`, `$y` and `$z` in the example.
+# Note that `<%-` must be used or any leading whitespace will be interpreted as text
+#
+# Arguments are passed to the template by calling `epp` with a Hash as the last argument, where parameters
+# are bound to values, e.g. `epp('...', {'x'=>10, 'y'=>20})`. Excess arguments may be given
+# (i.e. undeclared parameters) only if the EPP templates does not declare any parameters at all.
+# Template parameters shadow variables in outer scopes. File based epp does never have access to variables in the
+# scope where the `epp` function is called from.
+#
+# @see function inline_epp for examples of EPP
+# @since 3.5
+# @note Requires Future Parser
+Puppet::Functions.create_function(:epp, Puppet::Functions::InternalFunction) do
+
+  dispatch :epp do
+    scope_param
+    param 'String', :path
+    optional_param 'Hash[Pattern[/^\w+$/], Any]', :parameters
+  end
+
+  def epp(scope, path, parameters = nil)
+    Puppet::Pops::Evaluator::EppEvaluator.epp(scope, path, scope.compiler.environment, parameters)
+  end
+end
\ No newline at end of file
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/filter.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/filter.rb
new file mode 100644
index 0000000..e8ba2c6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/filter.rb
@@ -0,0 +1,113 @@
+# Applies a parameterized block to each element in a sequence of entries from the first
+# argument and returns an array or hash (same type as left operand for array/hash, and array for
+# other enumerable types) with the entries for which the block evaluates to `true`.
+#
+# This function takes two mandatory arguments: the first should be an Array, a Hash, or an
+# Enumerable object (integer, Integer range, or String),
+# and the second a parameterized block as produced by the puppet syntax:
+#
+#       $a.filter |$x| { ... }
+#       filter($a) |$x| { ... }
+#
+# When the first argument is something other than a Hash, the block is called with each entry in turn.
+# When the first argument is a Hash the entry is an array with `[key, value]`.
+#
+# @example Using filter with one parameter
+#
+#       # selects all that end with berry
+#       $a = ["raspberry", "blueberry", "orange"]
+#       $a.filter |$x| { $x =~ /berry$/ }          # rasberry, blueberry
+#
+# If the block defines two parameters, they will be set to `index, value` (with index starting at 0) for all
+# enumerables except Hash, and to `key, value` for a Hash.
+#
+# @example Using filter with two parameters
+#
+#      # selects all that end with 'berry' at an even numbered index
+#      $a = ["raspberry", "blueberry", "orange"]
+#      $a.filter |$index, $x| { $index % 2 == 0 and $x =~ /berry$/ } # raspberry
+#
+#      # selects all that end with 'berry' and value >= 1
+#      $a = {"raspberry"=>0, "blueberry"=>1, "orange"=>1}
+#      $a.filter |$key, $x| { $x =~ /berry$/ and $x >= 1 } # blueberry
+#
+# @since 3.4 for Array and Hash
+# @since 3.5 for other enumerables
+# @note requires `parser = future`
+#
+Puppet::Functions.create_function(:filter) do
+  dispatch :filter_Hash_2 do
+    param 'Hash[Any, Any]', :hash
+    block_param 'Callable[2,2]', :block
+  end
+
+  dispatch :filter_Hash_1 do
+    param 'Hash[Any, Any]', :hash
+    block_param 'Callable[1,1]', :block
+  end
+
+  dispatch :filter_Enumerable_2 do
+    param 'Any', :enumerable
+    block_param 'Callable[2,2]', :block
+  end
+
+  dispatch :filter_Enumerable_1 do
+    param 'Any', :enumerable
+    block_param 'Callable[1,1]', :block
+  end
+
+  def filter_Hash_1(hash)
+    result = hash.select {|x, y| yield([x, y]) == true }
+    # Ruby 1.8.7 returns Array
+    result = Hash[result] unless result.is_a? Hash
+    result
+  end
+
+  def filter_Hash_2(hash)
+    result = hash.select {|x, y| yield(x, y) == true }
+    # Ruby 1.8.7 returns Array
+    result = Hash[result] unless result.is_a? Hash
+    result
+  end
+
+  def filter_Enumerable_1(enumerable)
+    result = []
+    index = 0
+    enum = asserted_enumerable(enumerable)
+    begin
+      loop do
+        it = enum.next
+        if yield(it) == true
+          result << it
+        end
+      end
+    rescue StopIteration
+    end
+    result
+  end
+
+  def filter_Enumerable_2(enumerable)
+    result = []
+    index = 0
+    enum = asserted_enumerable(enumerable)
+    begin
+      loop do
+        it = enum.next
+        if yield(index, it) == true
+          result << it
+        end
+        index += 1
+      end
+    rescue StopIteration
+    end
+    result
+  end
+
+  def asserted_enumerable(obj)
+    unless enum = Puppet::Pops::Types::Enumeration.enumerator(obj)
+      raise ArgumentError, ("#{self.class.name}(): wrong argument type (#{obj.class}; must be something enumerable.")
+    end
+    enum
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/hiera.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/hiera.rb
new file mode 100644
index 0000000..ec8690a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/hiera.rb
@@ -0,0 +1,29 @@
+require 'hiera/puppet_function'
+
+#  Performs a standard priority lookup and returns the most specific value for a given key.
+#  The returned value can be data of any type (strings, arrays, or hashes).
+#
+#  The function can be called in one of three ways:
+#  1. Using 1 to 3 arguments where the arguments are:
+#     'key'      [String] Required
+#           The key to lookup.
+#     'default`  [Any] Optional
+#           A value to return when there's no match for `key`. Optional
+#     `override` [Any] Optional
+#           An argument in the third position, providing a data source
+#           to consult for matching values, even if it would not ordinarily be
+#           part of the matched hierarchy. If Hiera doesn't find a matching key
+#           in the named override data source, it will continue to search through the
+#           rest of the hierarchy.
+#
+#  2. Using a 'key' and an optional 'override' parameter like in #1 but with a block to
+#     provide the default value. The block is called with one parameter (the key) and
+#     should return the value.
+#
+#  3. Like #1 but with all arguments passed in an array.
+#
+#  More thorough examples of `hiera` are available at:
+#  <http://docs.puppetlabs.com/hiera/1/puppet.html#hiera-lookup-functions>
+Puppet::Functions.create_function(:hiera, Hiera::PuppetFunction) do
+  init_dispatch
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/hiera_array.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/hiera_array.rb
new file mode 100644
index 0000000..ce34520
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/hiera_array.rb
@@ -0,0 +1,34 @@
+require 'hiera/puppet_function'
+
+# Returns all matches throughout the hierarchy --- not just the first match --- as a flattened array of unique values.
+#  If any of the matched values are arrays, they're flattened and included in the results.
+#
+#  The function can be called in one of three ways:
+#  1. Using 1 to 3 arguments where the arguments are:
+#     'key'      [String] Required
+#           The key to lookup.
+#     'default`  [Any] Optional
+#           A value to return when there's no match for `key`. Optional
+#     `override` [Any] Optional
+#           An argument in the third position, providing a data source
+#           to consult for matching values, even if it would not ordinarily be
+#           part of the matched hierarchy. If Hiera doesn't find a matching key
+#           in the named override data source, it will continue to search through the
+#           rest of the hierarchy.
+#
+#  2. Using a 'key' and an optional 'override' parameter like in #1 but with a block to
+#     provide the default value. The block is called with one parameter (the key) and
+#     should return the value.
+#
+#  3. Like #1 but with all arguments passed in an array.
+#  If any matched value is a hash, puppet will raise a type mismatch error.
+#
+#  More thorough examples of `hiera` are available at:
+#  <http://docs.puppetlabs.com/hiera/1/puppet.html#hiera-lookup-functions>
+Puppet::Functions.create_function(:hiera_array, Hiera::PuppetFunction) do
+  init_dispatch
+
+  def merge_type
+    :array
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/hiera_hash.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/hiera_hash.rb
new file mode 100644
index 0000000..28b73c0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/hiera_hash.rb
@@ -0,0 +1,36 @@
+require 'hiera/puppet_function'
+
+# Returns a merged hash of matches from throughout the hierarchy. In cases where two or
+# more hashes share keys, the hierarchy  order determines which key/value pair will be
+#  used in the returned hash, with the pair in the highest priority data source winning.
+#
+#  The function can be called in one of three ways:
+#  1. Using 1 to 3 arguments where the arguments are:
+#     'key'      [String] Required
+#           The key to lookup.
+#     'default`  [Any] Optional
+#           A value to return when there's no match for `key`. Optional
+#     `override` [Any] Optional
+#           An argument in the third position, providing a data source
+#           to consult for matching values, even if it would not ordinarily be
+#           part of the matched hierarchy. If Hiera doesn't find a matching key
+#           in the named override data source, it will continue to search through the
+#           rest of the hierarchy.
+#
+#  2. Using a 'key' and an optional 'override' parameter like in #1 but with a block to
+#     provide the default value. The block is called with one parameter (the key) and
+#     should return the value.
+#
+#  3. Like #1 but with all arguments passed in an array.
+#  `hiera_hash` expects that all values returned will be hashes. If any of the values
+#  found in the data sources are strings or arrays, puppet will raise a type mismatch error.
+#
+#  More thorough examples of `hiera_hash` are available at:
+#  <http://docs.puppetlabs.com/hiera/1/puppet.html#hiera-lookup-functions>
+Puppet::Functions.create_function(:hiera_hash, Hiera::PuppetFunction) do
+  init_dispatch
+
+  def merge_type
+    :hash
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/hiera_include.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/hiera_include.rb
new file mode 100644
index 0000000..5bee62f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/hiera_include.rb
@@ -0,0 +1,50 @@
+require 'hiera/puppet_function'
+
+# Assigns classes to a node using an array merge lookup that retrieves the value for a user-specified key
+#   from a Hiera data source.
+#
+#  To use `hiera_include`, the following configuration is required:
+#  - A key name to use for classes, e.g. `classes`.
+#  - A line in the puppet `sites.pp` file (e.g. `/etc/puppet/manifests/sites.pp`)
+#    reading `hiera_include('classes')`. Note that this line must be outside any node
+#    definition and below any top-scope variables in use for Hiera lookups.
+#  - Class keys in the appropriate data sources. In a data source keyed to a node's role,
+#    one might have:
+#
+#            ---
+#            classes:
+#              - apache
+#              - apache::passenger
+#  The function can be called in one of three ways:
+#  1. Using 1 to 3 arguments where the arguments are:
+#     'key'      [String] Required
+#           The key to lookup.
+#     'default`  [Any] Optional
+#           A value to return when there's no match for `key`. Optional
+#     `override` [Any] Optional
+#           An argument in the third position, providing a data source
+#           to consult for matching values, even if it would not ordinarily be
+#           part of the matched hierarchy. If Hiera doesn't find a matching key
+#           in the named override data source, it will continue to search through the
+#          rest of the hierarchy.
+#
+#  2. Using a 'key' and an optional 'override' parameter like in #1 but with a block to
+#     provide the default value. The block is called with one parameter (the key) and
+#     should return the array to be used in the subsequent call to include.
+#
+#  3. Like #1 but with all arguments passed in an array.
+#
+#  More thorough examples of `hiera_include` are available at:
+#  <http://docs.puppetlabs.com/hiera/1/puppet.html#hiera-lookup-functions>
+Puppet::Functions.create_function(:hiera_include, Hiera::PuppetFunction) do
+  init_dispatch
+
+  def merge_type
+    :array
+  end
+
+  def post_lookup(scope, key, value)
+    raise Puppet::ParseError, "Could not find data item #{key}" if value.nil?
+    call_function_with_scope(scope, 'include', value) unless value.empty?
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/import.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/import.rb
new file mode 100644
index 0000000..fb94d7c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/import.rb
@@ -0,0 +1,7 @@
+# The import function raises an error when called to inform the user that import is no longer supported.
+#
+Puppet::Functions.create_function(:import) do
+  def import(*args)
+    raise Puppet::Pops::SemanticError.new(Puppet::Pops::Issues::DISCONTINUED_IMPORT)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/inline_epp.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/inline_epp.rb
new file mode 100644
index 0000000..06c7e38
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/inline_epp.rb
@@ -0,0 +1,87 @@
+# Evaluates an Embedded Puppet Template (EPP) string and returns the rendered text result as a String.
+#
+# EPP support the following tags:
+#
+# * `<%= puppet expression %>` - This tag renders the value of the expression it contains.
+# * `<% puppet expression(s) %>` - This tag will execute the expression(s) it contains, but renders nothing.
+# * `<%# comment %>` - The tag and its content renders nothing.
+# * `<%%` or `%%>` - Renders a literal `<%` or `%>` respectively.
+# * `<%-` - Same as `<%` but suppresses any leading whitespace.
+# * `-%>` - Same as `%>` but suppresses any trailing whitespace on the same line (including line break).
+# * `<%- |parameters| -%>` - When placed as the first tag declares the template's parameters.
+#
+# Inline EPP supports the following visibilities of variables in scope which depends on how EPP parameters
+# are used - see further below:
+#
+# * Global scope (i.e. top + node scopes) - global scope is always visible
+# * Global + Enclosing scope - if the EPP template does not declare parameters, and no arguments are given
+# * Global + all given arguments - if the EPP template does not declare parameters, and arguments are given
+# * Global + declared parameters - if the EPP declares parameters, given argument names must match
+#
+# EPP supports parameters by placing an optional parameter list as the very first element in the EPP. As an example,
+# `<%- |$x, $y, $z='unicorn'| -%>` when placed first in the EPP text declares that the parameters `x` and `y` must be
+# given as template arguments when calling `inline_epp`, and that `z` if not given as a template argument
+# defaults to `'unicorn'`. Template parameters are available as variables, e.g.arguments `$x`, `$y` and `$z` in the example.
+# Note that `<%-` must be used or any leading whitespace will be interpreted as text
+#
+# Arguments are passed to the template by calling `inline_epp` with a Hash as the last argument, where parameters
+# are bound to values, e.g. `inline_epp('...', {'x'=>10, 'y'=>20})`. Excess arguments may be given
+# (i.e. undeclared parameters) only if the EPP templates does not declare any parameters at all.
+# Template parameters shadow variables in outer scopes.
+#
+# Note: An inline template is best stated using a single-quoted string, or a heredoc since a double-quoted string
+# is subject to expression interpolation before the string is parsed as an EPP template. Here are examples
+# (using heredoc to define the EPP text):
+#
+# @example Various Examples using `inline_epp`
+#
+#     # produces 'Hello local variable world!'
+#     $x ='local variable'
+#     inline_epptemplate(@(END:epp))
+#     <%- |$x| -%>
+#     Hello <%= $x %> world!
+#     END
+# 
+#     # produces 'Hello given argument world!'
+#     $x ='local variable world'
+#     inline_epptemplate(@(END:epp), { x =>'given argument'})
+#     <%- |$x| -%>
+#     Hello <%= $x %> world!
+#     END
+#
+#     # produces 'Hello given argument world!'
+#     $x ='local variable world'
+#     inline_epptemplate(@(END:epp), { x =>'given argument'})
+#     <%- |$x| -%>
+#     Hello <%= $x %>!
+#     END
+#
+#     # results in error, missing value for y
+#     $x ='local variable world'
+#     inline_epptemplate(@(END:epp), { x =>'given argument'})
+#     <%- |$x, $y| -%>
+#     Hello <%= $x %>!
+#     END
+#
+#     # Produces 'Hello given argument planet'
+#     $x ='local variable world'
+#     inline_epptemplate(@(END:epp), { x =>'given argument'})
+#     <%- |$x, $y=planet| -%>
+#     Hello <%= $x %> <%= $y %>!
+#     END
+#
+# @since 3.5
+# @note Requires Future Parser
+#
+Puppet::Functions.create_function(:inline_epp, Puppet::Functions::InternalFunction) do
+
+  dispatch :inline_epp do
+    scope_param()
+    param 'String', :template
+    optional_param 'Hash[Pattern[/^\w+$/], Any]', :parameters
+  end
+
+  def inline_epp(scope, template, parameters = nil)
+    Puppet::Pops::Evaluator::EppEvaluator.inline_epp(scope, template, parameters)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/map.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/map.rb
new file mode 100644
index 0000000..857c1bf
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/map.rb
@@ -0,0 +1,97 @@
+# Applies a parameterized block to each element in a sequence of entries from the first
+# argument and returns an array with the result of each invocation of the parameterized block.
+#
+# This function takes two mandatory arguments: the first should be an Array, Hash, or of Enumerable type
+# (integer, Integer range, or String), and the second a parameterized block as produced by the puppet syntax:
+#
+#       $a.map |$x| { ... }
+#       map($a) |$x| { ... }
+#
+# When the first argument `$a` is an Array or of enumerable type, the block is called with each entry in turn.
+# When the first argument is a hash the entry is an array with `[key, value]`.
+#
+# @example Using map with two arguments
+#
+#      # Turns hash into array of values
+#      $a.map |$x|{ $x[1] }
+#
+#      # Turns hash into array of keys
+#      $a.map |$x| { $x[0] }
+#
+# When using a block with 2 parameters, the element's index (starting from 0) for an array, and the key for a hash
+# is given to the block's first parameter, and the value is given to the block's second parameter.args.
+#
+# @example Using map with two arguments
+#
+#      # Turns hash into array of values
+#      $a.map |$key,$val|{ $val }
+#
+#      # Turns hash into array of keys
+#      $a.map |$key,$val|{ $key }
+#
+# @since 3.4 for Array and Hash
+# @since 3.5 for other enumerables, and support for blocks with 2 parameters
+# @note requires `parser = future`
+#
+Puppet::Functions.create_function(:map) do
+  dispatch :map_Hash_2 do
+    param 'Hash[Any, Any]', :hash
+    block_param 'Callable[2,2]', :block
+  end
+
+  dispatch :map_Hash_1 do
+    param 'Hash[Any, Any]', :hash
+    block_param 'Callable[1,1]', :block
+  end
+
+  dispatch :map_Enumerable_2 do
+    param 'Any', :enumerable
+    block_param 'Callable[2,2]', :block
+  end
+
+  dispatch :map_Enumerable_1 do
+    param 'Any', :enumerable
+    block_param 'Callable[1,1]', :block
+  end
+
+  def map_Hash_1(hash)
+    hash.map {|x, y| yield([x, y]) }
+  end
+
+  def map_Hash_2(hash)
+      hash.map {|x, y| yield(x, y) }
+  end
+
+  def map_Enumerable_1(enumerable)
+    result = []
+    index = 0
+    enum = asserted_enumerable(enumerable)
+    begin
+      loop { result << yield(enum.next) }
+    rescue StopIteration
+    end
+    result
+  end
+
+  def map_Enumerable_2(enumerable)
+    result = []
+    index = 0
+    enum = asserted_enumerable(enumerable)
+    begin
+      loop do
+        result << yield(index, enum.next)
+        index = index +1
+      end
+    rescue StopIteration
+    end
+    result
+  end
+
+  def asserted_enumerable(obj)
+    unless enum = Puppet::Pops::Types::Enumeration.enumerator(obj)
+      raise ArgumentError, ("#{self.class.name}(): wrong argument type (#{obj.class}; must be something enumerable.")
+    end
+    enum
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/match.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/match.rb
new file mode 100644
index 0000000..8808a29
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/match.rb
@@ -0,0 +1,102 @@
+# Returns the match result of matching a String or Array[String] with one of:
+#
+# * Regexp
+# * String - transformed to a Regexp
+# * Pattern type
+# * Regexp type
+#
+# Returns An Array with the entire match at index 0, and each subsequent submatch at index 1-n.
+# If there was no match, nil (ie. undef) is returned. If the value to match is an Array, a array
+# with mapped match results is returned.
+#
+# @example matching
+#   "abc123".match(/([a-z]+)[1-9]+/)  # => ["abc"]
+#   "abc123".match(/([a-z]+)([1-9]+)/)  # => ["abc", "123"]
+#
+# See the documentation for "The Puppet Type System" for more information about types.
+# @since 3.7.0
+#
+Puppet::Functions.create_function(:match) do
+  dispatch :match do
+    param 'String', 'string'
+    param 'Variant[Any, Type]', 'pattern'
+  end
+
+  dispatch :enumerable_match do
+    param 'Array[String]', 'string'
+    param 'Variant[Any, Type]', 'pattern'
+  end
+
+  def initialize(closure_scope, loader)
+    super
+
+    # Make this visitor shared among all instantiations of this function since it is faster.
+    # This can be used because it is not possible to replace
+    # a puppet runtime (where this function is) without a reboot. If you model a function in a module after
+    # this class, use a regular instance variable instead to enable reloading of the module without reboot
+    #
+    @@match_visitor   ||= Puppet::Pops::Visitor.new(self, "match", 1, 1)
+  end
+
+  # Matches given string against given pattern and returns an Array with matches.
+  # @param string [String] the string to match
+  # @param pattern [String, Regexp, Puppet::Pops::Types::PPatternType, Puppet::Pops::PRegexpType, Array] the pattern
+  # @return [Array<String>] matches where first match is the entire match, and index 1-n are captures from left to right
+  #
+  def match(string, pattern)
+    @@match_visitor.visit_this_1(self, pattern, string)
+  end
+
+  # Matches given Array[String] against given pattern and returns an Array with mapped match results.
+  #
+  # @param array [Array<String>] the array of strings to match
+  # @param pattern [String, Regexp, Puppet::Pops::Types::PPatternType, Puppet::Pops::PRegexpType, Array] the pattern
+  # @return [Array<Array<String, nil>>] Array with matches (see {#match}), non matching entries produce a nil entry
+  #
+  def enumerable_match(array, pattern)
+    array.map {|s| match(s, pattern) }
+  end
+
+  protected
+
+  def match_Object(obj, s)
+    msg = "match() expects pattern of T, where T is String, Regexp, Regexp[r], Pattern[p], or Array[T]. Got #{obj.class}"
+    raise ArgumentError, msg
+  end
+
+  def match_String(pattern_string, s)
+    do_match(s, Regexp.new(pattern_string))
+  end
+
+  def match_Regexp(regexp, s)
+    do_match(s, regexp)
+  end
+
+  def match_PRegexpType(regexp_t, s)
+    raise ArgumentError, "Given Regexp Type has no regular expression" unless regexp_t.pattern
+    do_match(s, regexp_t.regexp)
+  end
+
+  def match_PPatternType(pattern_t, s)
+    # Since we want the actual match result (not just a boolean), an iteration over
+    # Pattern's regular expressions is needed. (They are of PRegexpType)
+    result = nil
+    pattern_t.patterns.find {|pattern| result = match(s, pattern) }
+    result
+  end
+
+  # Returns the first matching entry
+  def match_Array(array, s)
+    result = nil
+    array.flatten.find {|entry| result = match(s, entry) }
+    result
+  end
+
+  private
+
+  def do_match(s, regexp)
+    if result = regexp.match(s)
+      result.to_a
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/reduce.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/reduce.rb
new file mode 100644
index 0000000..48d0c3d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/reduce.rb
@@ -0,0 +1,94 @@
+# Applies a parameterized block to each element in a sequence of entries from the first
+# argument (_the enumerable_) and returns the last result of the invocation of the parameterized block.
+#
+# This function takes two mandatory arguments: the first should be an Array, Hash, or something of
+# enumerable type, and the last a parameterized block as produced by the puppet syntax:
+#
+#       $a.reduce |$memo, $x| { ... }
+#       reduce($a) |$memo, $x| { ... }
+#
+# When the first argument is an Array or someting of an enumerable type, the block is called with each entry in turn.
+# When the first argument is a hash each entry is converted to an array with `[key, value]` before being
+# fed to the block. An optional 'start memo' value may be supplied as an argument between the array/hash
+# and mandatory block.
+#
+#       $a.reduce(start) |$memo, $x| { ... }
+#       reduce($a, start) |$memo, $x| { ... }
+#
+# If no 'start memo' is given, the first invocation of the parameterized block will be given the first and second
+# elements of the enumeration, and if the enumerable has fewer than 2 elements, the first
+# element is produced as the result of the reduction without invocation of the block.
+#
+# On each subsequent invocation, the produced value of the invoked parameterized block is given as the memo in the
+# next invocation.
+#
+# @example Using reduce
+#
+#       # Reduce an array
+#       $a = [1,2,3]
+#       $a.reduce |$memo, $entry| { $memo + $entry }
+#       #=> 6
+#
+#       # Reduce hash values
+#       $a = {a => 1, b => 2, c => 3}
+#       $a.reduce |$memo, $entry| { [sum, $memo[1]+$entry[1]] }
+#       #=> [sum, 6]
+#
+#       # reverse a string
+#       "abc".reduce |$memo, $char| { "$char$memo" }
+#       #=>"cbe"
+#
+# It is possible to provide a starting 'memo' as an argument.
+#
+# @example Using reduce with given start 'memo'
+#
+#       # Reduce an array
+#       $a = [1,2,3]
+#       $a.reduce(4) |$memo, $entry| { $memo + $entry }
+#       #=> 10
+#
+#       # Reduce hash values
+#       $a = {a => 1, b => 2, c => 3}
+#       $a.reduce([na, 4]) |$memo, $entry| { [sum, $memo[1]+$entry[1]] }
+#       #=> [sum, 10]
+#
+# @example Using reduce with an Integer range
+#
+#       Integer[1,4].reduce |$memo, $x| { $memo + $x }
+#       #=> 10
+#
+# @since 3.2 for Array and Hash
+# @since 3.5 for additional enumerable types
+# @note requires `parser = future`.
+#
+Puppet::Functions.create_function(:reduce) do
+
+  dispatch :reduce_without_memo do
+    param 'Any', :enumerable
+    block_param 'Callable[2,2]', :block
+  end
+
+  dispatch :reduce_with_memo do
+    param 'Any', :enumerable
+    param 'Any', :memo
+    block_param 'Callable[2,2]', :block
+  end
+
+  def reduce_without_memo(enumerable)
+    enum = asserted_enumerable(enumerable)
+    enum.reduce {|memo, x| yield(memo, x) }
+  end
+
+  def reduce_with_memo(enumerable, given_memo)
+    enum = asserted_enumerable(enumerable)
+    enum.reduce(given_memo) {|memo, x| yield(memo, x) }
+  end
+
+  def asserted_enumerable(obj)
+    unless enum = Puppet::Pops::Types::Enumeration.enumerator(obj)
+      raise ArgumentError, ("#{self.class.name}(): wrong argument type (#{obj.class}; must be something enumerable.")
+    end
+    enum
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/scanf.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/scanf.rb
new file mode 100644
index 0000000..d2bd4ed
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/scanf.rb
@@ -0,0 +1,46 @@
+# Scans a string and returns an array of one or more converted values as directed by a given format string.args
+# See the documenation of Ruby's String::scanf method for details about the supported formats (which
+# are similar but not identical to the formats used in Puppet's `sprintf` function.
+#
+# This function takes two mandatory arguments: the first is the String to convert, and the second
+# the format String. A parameterized block may optionally be given, which is called with the result
+# that is produced by scanf if no block is present, the result of the block is then returned by
+# the function.
+#
+# The result of the scan is an Array, with each sucessfully scanned and transformed value.args The scanning
+# stops if a scan is unsuccesful and the scanned result up to that point is returned. If there was no
+# succesful scan at all, the result is an empty Array. The optional code block is typically used to
+# assert that the scan was succesful, and either produce the same input, or perform unwrapping of
+# the result
+#
+# @example scanning an integer in string form (result is an array with
+#   integer, or empty if  unsuccessful)
+#    "42".scanf("%i")
+#
+# @example scanning and processing resulting array to assert result and unwrap
+#
+#     "42".scanf("%i") |$x| {
+#       unless $x[0] =~ Integer {
+#         fail "Expected a well formed integer value, got '$x[0]'"
+#       }
+#       $x[0]
+#     }
+#
+# @since 3.7.4
+Puppet::Functions.create_function(:scanf) do
+  require 'scanf'
+
+  dispatch :scanf do
+    param 'String', 'data'
+    param 'String', 'format'
+    optional_block_param
+  end
+
+  def scanf(data, format)
+    result = data.scanf(format)
+    if block_given?
+      result = yield(result)
+    end
+    result
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/slice.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/slice.rb
new file mode 100644
index 0000000..93202e2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/slice.rb
@@ -0,0 +1,127 @@
+# Applies a parameterized block to each _slice_ of elements in a sequence of selected entries from the first
+# argument and returns the first argument, or if no block is given returns a new array with a concatenation of
+# the slices.
+#
+# This function takes two mandatory arguments: the first, `$a`, should be an Array, Hash, or something of
+# enumerable type (integer, Integer range, or String), and the second, `$n`, the number of elements to include
+# in each slice. The optional third argument should be a a parameterized block as produced by the puppet syntax:
+#
+#     $a.slice($n) |$x| { ... }
+#     slice($a) |$x| { ... }
+#
+# The parameterized block should have either one parameter (receiving an array with the slice), or the same number
+# of parameters as specified by the slice size (each parameter receiving its part of the slice).
+# In case there are fewer remaining elements than the slice size for the last slice it will contain the remaining
+# elements. When the block has multiple parameters, excess parameters are set to undef for an array or
+# enumerable type, and to empty arrays for a Hash.
+#
+#     $a.slice(2) |$first, $second| { ... }
+#
+# When the first argument is a Hash, each `key,value` entry is counted as one, e.g, a slice size of 2 will produce
+# an array of two arrays with key, and value.
+#
+# @example Using slice with Hash
+#
+#     $a.slice(2) |$entry|          { notice "first ${$entry[0]}, second ${$entry[1]}" }
+#     $a.slice(2) |$first, $second| { notice "first ${first}, second ${second}" }
+#
+# When called without a block, the function produces a concatenated result of the slices.
+#
+# @example Using slice without a block
+#
+#     slice([1,2,3,4,5,6], 2) # produces [[1,2], [3,4], [5,6]]
+#     slice(Integer[1,6], 2)  # produces [[1,2], [3,4], [5,6]]
+#     slice(4,2)              # produces [[0,1], [2,3]]
+#     slice('hello',2)        # produces [[h, e], [l, l], [o]]
+#
+# @since 3.2 for Array and Hash
+# @since 3.5 for additional enumerable types
+# @note requires `parser = future`.
+#
+Puppet::Functions.create_function(:slice) do
+  dispatch :slice_Hash do
+    param 'Hash[Any, Any]', :hash
+    param 'Integer[1, default]', :slize_size
+    optional_block_param
+  end
+
+  dispatch :slice_Enumerable do
+    param 'Any', :enumerable
+    param 'Integer[1, default]', :slize_size
+    optional_block_param
+  end
+
+  def slice_Hash(hash, slice_size, &pblock)
+    result = slice_Common(hash, slice_size, [], block_given? ? pblock : nil)
+    block_given? ? hash : result
+  end
+
+  def slice_Enumerable(enumerable, slice_size, &pblock)
+    enum = asserted_enumerable(enumerable)
+    result = slice_Common(enum, slice_size, nil, block_given? ? pblock : nil)
+    block_given? ? enumerable : result
+  end
+
+  def slice_Common(o, slice_size, filler, pblock)
+    serving_size = asserted_slice_serving_size(pblock, slice_size)
+
+    enumerator = o.each_slice(slice_size)
+    result = []
+    if serving_size == 1
+      begin
+        if pblock
+          loop do
+            pblock.call(enumerator.next)
+          end
+        else
+          loop do
+            result << enumerator.next
+          end
+        end
+      rescue StopIteration
+      end
+    else
+      begin
+        loop do
+          a = enumerator.next
+          if a.size < serving_size
+            a = a.dup.fill(filler, a.length...serving_size)
+          end
+          pblock.call(*a)
+        end
+      rescue StopIteration
+      end
+    end
+    if pblock
+      o
+    else
+      result
+    end
+  end
+
+  def asserted_slice_serving_size(pblock, slice_size)
+    if pblock
+      arity = pblock.arity
+      serving_size = arity < 0 ? slice_size : arity
+    else
+      serving_size = 1
+    end
+    if serving_size == 0
+      raise ArgumentError, "slice(): block must define at least one parameter. Block has 0."
+    end
+    unless serving_size == 1 || serving_size == slice_size
+      raise ArgumentError, "slice(): block must define one parameter, or " +
+        "the same number of parameters as the given size of the slice (#{slice_size}). Block has #{serving_size}; "+
+      pblock.parameter_names.join(', ')
+    end
+    serving_size
+  end
+
+  def asserted_enumerable(obj)
+    unless enum = Puppet::Pops::Types::Enumeration.enumerator(obj)
+      raise ArgumentError, ("#{self.class.name}(): wrong argument type (#{obj.class}; must be something enumerable.")
+    end
+    enum
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/with.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/with.rb
new file mode 100644
index 0000000..1c295f2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/functions/with.rb
@@ -0,0 +1,22 @@
+# Call a lambda with the given arguments. Since the parameters of the lambda
+# are local to the lambda's scope, this can be used to create private sections
+# of logic in a class so that the variables are not visible outside of the
+# class.
+#
+# @example Using with
+#
+#     # notices the array [1, 2, 'foo']
+#     with(1, 2, 'foo') |$x, $y, $z| { notice [$x, $y, $z] }
+#
+# @since 3.7.0
+#
+Puppet::Functions.create_function(:with) do
+  dispatch :with do
+    repeated_param 'Any', :arg
+    block_param
+  end
+
+  def with(*args)
+    yield(*args)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph.rb
new file mode 100644
index 0000000..a0aed09
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph.rb
@@ -0,0 +1,11 @@
+module Puppet::Graph
+  require 'puppet/graph/prioritizer'
+  require 'puppet/graph/sequential_prioritizer'
+  require 'puppet/graph/title_hash_prioritizer'
+  require 'puppet/graph/random_prioritizer'
+
+  require 'puppet/graph/simple_graph'
+  require 'puppet/graph/rb_tree_map'
+  require 'puppet/graph/key'
+  require 'puppet/graph/relationship_graph'
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/key.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/key.rb
new file mode 100644
index 0000000..0a06069
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/key.rb
@@ -0,0 +1,26 @@
+# Sequential, nestable keys for tracking order of insertion in "the graph"
+# @api private
+class Puppet::Graph::Key
+  include Comparable
+
+  attr_reader :value
+  protected :value
+
+  def initialize(value = [0])
+    @value = value
+  end
+
+  def next
+    next_values = @value.clone
+    next_values[-1] += 1
+    Puppet::Graph::Key.new(next_values)
+  end
+
+  def down
+    Puppet::Graph::Key.new(@value + [0])
+  end
+
+  def <=>(other)
+    @value <=> other.value
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/prioritizer.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/prioritizer.rb
new file mode 100644
index 0000000..f734a30
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/prioritizer.rb
@@ -0,0 +1,29 @@
+# Base, template method, class for Prioritizers. This provides the basic
+# tracking facilities used.
+#
+# @api private
+class Puppet::Graph::Prioritizer
+  def initialize
+    @priority = {}
+  end
+
+  def forget(key)
+    @priority.delete(key)
+  end
+
+  def record_priority_for(key, priority)
+    @priority[key] = priority
+  end
+
+  def generate_priority_for(key)
+    raise NotImplementedError
+  end
+
+  def generate_priority_contained_in(container, key)
+    raise NotImplementedError
+  end
+
+  def priority_of(key)
+    @priority[key]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/random_prioritizer.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/random_prioritizer.rb
new file mode 100644
index 0000000..c1af21d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/random_prioritizer.rb
@@ -0,0 +1,16 @@
+# Assign a random priority to items.
+#
+# @api private
+class Puppet::Graph::RandomPrioritizer < Puppet::Graph::Prioritizer
+  def generate_priority_for(key)
+    if priority_of(key).nil?
+      record_priority_for(key, SecureRandom.uuid)
+    else
+      priority_of(key)
+    end
+  end
+
+  def generate_priority_contained_in(container, key)
+    generate_priority_for(key)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/rb_tree_map.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/rb_tree_map.rb
new file mode 100644
index 0000000..bf5fe70
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/rb_tree_map.rb
@@ -0,0 +1,388 @@
+# Algorithms and Containers project is Copyright (c) 2009 Kanwei Li
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the 'Software'), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# A RbTreeMap is a map that is stored in sorted order based on the order of its keys. This ordering is
+# determined by applying the function <=> to compare the keys. No duplicate values for keys are allowed,
+# so duplicate values are overwritten.
+#
+# A major advantage of RBTreeMap over a Hash is the fact that keys are stored in order and can thus be
+# iterated over in order. This is useful for many datasets.
+#
+# The implementation is adapted from Robert Sedgewick's Left Leaning Red-Black Tree implementation,
+# which can be found at http://www.cs.princeton.edu/~rs/talks/LLRB/Java/RedBlackBST.java
+#
+# Most methods have O(log n) complexity.
+
+class Puppet::Graph::RbTreeMap
+  include Enumerable
+
+  attr_reader :size
+
+  alias_method :length, :size
+
+  # Create and initialize a new empty TreeMap.
+  def initialize
+    @root = nil
+    @size = 0
+  end
+
+  # Insert an item with an associated key into the TreeMap, and returns the item inserted
+  #
+  # Complexity: O(log n)
+  #
+  # map = Containers::TreeMap.new
+  # map.push("MA", "Massachusetts") #=> "Massachusetts"
+  # map.get("MA") #=> "Massachusetts"
+  def push(key, value)
+    @root = insert(@root, key, value)
+    @root.color = :black
+    value
+  end
+  alias_method :[]=, :push
+
+  # Return true if key is found in the TreeMap, false otherwise
+  #
+  # Complexity: O(log n)
+  #
+  #   map = Containers::TreeMap.new
+  #   map.push("MA", "Massachusetts")
+  #   map.push("GA", "Georgia")
+  #   map.has_key?("GA") #=> true
+  #   map.has_key?("DE") #=> false
+  def has_key?(key)
+    !get_recursive(@root, key).nil?
+  end
+
+  # Return the item associated with the key, or nil if none found.
+  #
+  # Complexity: O(log n)
+  #
+  #   map = Containers::TreeMap.new
+  #   map.push("MA", "Massachusetts")
+  #   map.push("GA", "Georgia")
+  #   map.get("GA") #=> "Georgia"
+  def get(key)
+    node = get_recursive(@root, key)
+    node ? node.value : nil
+    node.value if node
+  end
+  alias_method :[], :get
+
+  # Return the smallest key in the map.
+  #
+  # Complexity: O(log n)
+  #
+  #   map = Containers::TreeMap.new
+  #   map.push("MA", "Massachusetts")
+  #   map.push("GA", "Georgia")
+  #   map.min_key #=> "GA"
+  def min_key
+    @root.nil? ? nil : min_recursive(@root).key
+  end
+
+  # Return the largest key in the map.
+  #
+  # Complexity: O(log n)
+  #
+  #   map = Containers::TreeMap.new
+  #   map.push("MA", "Massachusetts")
+  #   map.push("GA", "Georgia")
+  #   map.max_key #=> "MA"
+  def max_key
+    @root.nil? ? nil : max_recursive(@root).key
+  end
+
+  # Deletes the item and key if it's found, and returns the item. Returns nil
+  # if key is not present.
+  #
+  # Complexity: O(log n)
+  #
+  #   map = Containers::TreeMap.new
+  #   map.push("MA", "Massachusetts")
+  #   map.push("GA", "Georgia")
+  #   map.delete("MA") #=> "Massachusetts"
+  def delete(key)
+    result = nil
+    if @root
+      return unless has_key? key
+      @root, result = delete_recursive(@root, key)
+      @root.color = :black if @root
+      @size -= 1
+    end
+    result
+  end
+
+  # Returns true if the tree is empty, false otherwise
+  def empty?
+    @root.nil?
+  end
+
+  # Deletes the item with the smallest key and returns the item. Returns nil
+  # if key is not present.
+  #
+  # Complexity: O(log n)
+  #
+  #   map = Containers::TreeMap.new
+  #   map.push("MA", "Massachusetts")
+  #   map.push("GA", "Georgia")
+  #   map.delete_min #=> "Massachusetts"
+  #   map.size #=> 1
+  def delete_min
+    result = nil
+    if @root
+      @root, result = delete_min_recursive(@root)
+      @root.color = :black if @root
+      @size -= 1
+    end
+    result
+  end
+
+  # Deletes the item with the largest key and returns the item. Returns nil
+  # if key is not present.
+  #
+  # Complexity: O(log n)
+  #
+  #   map = Containers::TreeMap.new
+  #   map.push("MA", "Massachusetts")
+  #   map.push("GA", "Georgia")
+  #   map.delete_max #=> "Georgia"
+  #   map.size #=> 1
+  def delete_max
+    result = nil
+    if @root
+      @root, result = delete_max_recursive(@root)
+      @root.color = :black if @root
+      @size -= 1
+    end
+    result
+  end
+
+  # Yields [key, value] pairs in order by key.
+  def each(&blk)
+    recursive_yield(@root, &blk)
+  end
+
+  def first
+    return nil unless @root
+    node = min_recursive(@root)
+    [node.key, node.value]
+  end
+
+  def last
+    return nil unless @root
+    node = max_recursive(@root)
+    [node.key, node.value]
+  end
+
+  def to_hash
+    @root ? @root.to_hash : {}
+  end
+
+  class Node # :nodoc: all
+    attr_accessor :color, :key, :value, :left, :right
+    def initialize(key, value)
+      @key = key
+      @value = value
+      @color = :red
+      @left = nil
+      @right = nil
+    end
+
+    def to_hash
+      h = {
+        :node => {
+          :key => @key,
+          :value => @value,
+          :color => @color,
+        }
+      }
+      h.merge!(:left => left.to_hash) if @left
+      h.merge!(:right => right.to_hash) if @right
+      h
+    end
+
+    def red?
+      @color == :red
+    end
+
+    def colorflip
+      @color       = @color == :red       ? :black : :red
+      @left.color  = @left.color == :red  ? :black : :red
+      @right.color = @right.color == :red ? :black : :red
+    end
+
+    def rotate_left
+      r = @right
+      r_key, r_value = r.key, r.value
+      b = r.left
+      r.left = @left
+      @left = r
+      @right = r.right
+      r.right = b
+      r.color, r.key, r.value = :red, @key, @value
+      @key, @value = r_key, r_value
+      self
+    end
+
+    def rotate_right
+      l = @left
+      l_key, l_value = l.key, l.value
+      b = l.right
+      l.right = @right
+      @right = l
+      @left = l.left
+      l.left = b
+      l.color, l.key, l.value = :red, @key, @value
+      @key, @value = l_key, l_value
+      self
+    end
+
+    def move_red_left
+      colorflip
+      if (@right.left && @right.left.red?)
+        @right.rotate_right
+        rotate_left
+        colorflip
+      end
+      self
+    end
+
+    def move_red_right
+      colorflip
+      if (@left.left && @left.left.red?)
+        rotate_right
+        colorflip
+      end
+      self
+    end
+
+    def fixup
+      rotate_left if @right && @right.red?
+      rotate_right if (@left && @left.red?) && (@left.left && @left.left.red?)
+      colorflip if (@left && @left.red?) && (@right && @right.red?)
+
+      self
+    end
+  end
+
+  private
+
+  def recursive_yield(node, &blk)
+    return unless node
+    recursive_yield(node.left, &blk)
+    yield node.key, node.value
+    recursive_yield(node.right, &blk)
+  end
+
+  def delete_recursive(node, key)
+    if (key <=> node.key) == -1
+      node.move_red_left if ( !isred(node.left) && !isred(node.left.left) )
+      node.left, result = delete_recursive(node.left, key)
+    else
+      node.rotate_right if isred(node.left)
+      if ( ( (key <=> node.key) == 0) && node.right.nil? )
+        return nil, node.value
+      end
+      if ( !isred(node.right) && !isred(node.right.left) )
+        node.move_red_right
+      end
+      if (key <=> node.key) == 0
+        result = node.value
+        min_child = min_recursive(node.right)
+        node.value = min_child.value
+        node.key = min_child.key
+        node.right = delete_min_recursive(node.right).first
+      else
+        node.right, result = delete_recursive(node.right, key)
+      end
+    end
+    return node.fixup, result
+  end
+
+  def delete_min_recursive(node)
+    if node.left.nil?
+      return nil, node.value
+    end
+    if ( !isred(node.left) && !isred(node.left.left) )
+      node.move_red_left
+    end
+    node.left, result = delete_min_recursive(node.left)
+
+    return node.fixup, result
+  end
+
+  def delete_max_recursive(node)
+    if (isred(node.left))
+      node = node.rotate_right
+    end
+    return nil, node.value if node.right.nil?
+    if ( !isred(node.right) && !isred(node.right.left) )
+      node.move_red_right
+    end
+    node.right, result = delete_max_recursive(node.right)
+
+    return node.fixup, result
+  end
+
+  def get_recursive(node, key)
+    return nil if node.nil?
+    case key <=> node.key
+    when  0 then return node
+    when -1 then return get_recursive(node.left, key)
+    when  1 then return get_recursive(node.right, key)
+    end
+  end
+
+  def min_recursive(node)
+    return node if node.left.nil?
+
+    min_recursive(node.left)
+  end
+
+  def max_recursive(node)
+    return node if node.right.nil?
+
+    max_recursive(node.right)
+  end
+
+  def insert(node, key, value)
+    unless node
+      @size += 1
+      return Node.new(key, value)
+    end
+
+    case key <=> node.key
+    when  0 then node.value = value
+    when -1 then node.left = insert(node.left, key, value)
+    when  1 then node.right = insert(node.right, key, value)
+    end
+
+    node.rotate_left if (node.right && node.right.red?)
+    node.rotate_right if (node.left && node.left.red? && node.left.left && node.left.left.red?)
+    node.colorflip if (node.left && node.left.red? && node.right && node.right.red?)
+    node
+  end
+
+  def isred(node)
+    return false if node.nil?
+
+    node.color == :red
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/relationship_graph.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/relationship_graph.rb
new file mode 100644
index 0000000..3c04faa
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/relationship_graph.rb
@@ -0,0 +1,246 @@
+# The relationship graph is the final form of a puppet catalog in
+# which all dependency edges are explicitly in the graph. This form of the
+# catalog is used to traverse the graph in the order in which resources are
+# managed.
+#
+# @api private
+class Puppet::Graph::RelationshipGraph < Puppet::Graph::SimpleGraph
+  attr_reader :blockers
+
+  def initialize(prioritizer)
+    super()
+
+    @prioritizer = prioritizer
+
+    @ready = Puppet::Graph::RbTreeMap.new
+    @generated = {}
+    @done = {}
+    @blockers = {}
+    @providerless_types = []
+  end
+
+  def populate_from(catalog)
+    add_all_resources_as_vertices(catalog)
+    build_manual_dependencies
+    build_autorequire_dependencies(catalog)
+
+    write_graph(:relationships) if catalog.host_config?
+
+    replace_containers_with_anchors(catalog)
+
+    write_graph(:expanded_relationships) if catalog.host_config?
+  end
+
+  def add_vertex(vertex, priority = nil)
+    super(vertex)
+
+    if priority
+      @prioritizer.record_priority_for(vertex, priority)
+    else
+      @prioritizer.generate_priority_for(vertex)
+    end
+  end
+
+  def add_relationship(f, t, label=nil)
+    super(f, t, label)
+    @ready.delete(@prioritizer.priority_of(t))
+  end
+
+  def remove_vertex!(vertex)
+    super
+    @prioritizer.forget(vertex)
+  end
+
+  def resource_priority(resource)
+    @prioritizer.priority_of(resource)
+  end
+
+  # Enqueue the initial set of resources, those with no dependencies.
+  def enqueue_roots
+    vertices.each do |v|
+      @blockers[v] = direct_dependencies_of(v).length
+      enqueue(v) if @blockers[v] == 0
+    end
+  end
+
+  # Decrement the blocker count for the resource by 1. If the number of
+  # blockers is unknown, count them and THEN decrement by 1.
+  def unblock(resource)
+    @blockers[resource] ||= direct_dependencies_of(resource).select { |r2| !@done[r2] }.length
+    if @blockers[resource] > 0
+      @blockers[resource] -= 1
+    else
+      resource.warning "appears to have a negative number of dependencies"
+    end
+    @blockers[resource] <= 0
+  end
+
+  def clear_blockers
+    @blockers.clear
+  end
+
+  def enqueue(*resources)
+    resources.each do |resource|
+      @ready[@prioritizer.priority_of(resource)] = resource
+    end
+  end
+
+  def finish(resource)
+    direct_dependents_of(resource).each do |v|
+      enqueue(v) if unblock(v)
+    end
+    @done[resource] = true
+  end
+
+  def next_resource
+    @ready.delete_min
+  end
+
+  def traverse(options = {}, &block)
+    continue_while = options[:while] || lambda { true }
+    pre_process = options[:pre_process] || lambda { |resource| }
+    overly_deferred_resource_handler = options[:overly_deferred_resource_handler] || lambda { |resource| }
+    canceled_resource_handler = options[:canceled_resource_handler] || lambda { |resource| }
+    teardown = options[:teardown] || lambda {}
+
+    report_cycles_in_graph
+
+    enqueue_roots
+
+    deferred_resources = []
+
+    while continue_while.call() && (resource = next_resource)
+      if resource.suitable?
+        made_progress = true
+
+        pre_process.call(resource)
+
+        yield resource
+
+        finish(resource)
+      else
+        deferred_resources << resource
+      end
+
+      if @ready.empty? and deferred_resources.any?
+        if made_progress
+          enqueue(*deferred_resources)
+        else
+          deferred_resources.each do |resource|
+            overly_deferred_resource_handler.call(resource)
+            finish(resource)
+          end
+        end
+
+        made_progress = false
+        deferred_resources = []
+      end
+    end
+
+    if !continue_while.call()
+      while (resource = next_resource)
+        canceled_resource_handler.call(resource)
+        finish(resource)
+      end
+    end
+
+    teardown.call()
+  end
+
+  private
+
+  def add_all_resources_as_vertices(catalog)
+    catalog.resources.each do |vertex|
+      add_vertex(vertex)
+    end
+  end
+
+  def build_manual_dependencies
+    vertices.each do |vertex|
+      vertex.builddepends.each do |edge|
+        add_edge(edge)
+      end
+    end
+  end
+
+  def build_autorequire_dependencies(catalog)
+    vertices.each do |vertex|
+      vertex.autorequire(catalog).each do |edge|
+        # don't let automatic relationships conflict with manual ones.
+        next if edge?(edge.source, edge.target)
+
+        if edge?(edge.target, edge.source)
+          vertex.debug "Skipping automatic relationship with #{edge.source}"
+        else
+          vertex.debug "Autorequiring #{edge.source}"
+          add_edge(edge)
+        end
+      end
+    end
+  end
+
+  # Impose our container information on another graph by using it
+  # to replace any container vertices X with a pair of vertices
+  # { admissible_X and completed_X } such that
+  #
+  #    0) completed_X depends on admissible_X
+  #    1) contents of X each depend on admissible_X
+  #    2) completed_X depends on each on the contents of X
+  #    3) everything which depended on X depends on completed_X
+  #    4) admissible_X depends on everything X depended on
+  #    5) the containers and their edges must be removed
+  #
+  # Note that this requires attention to the possible case of containers
+  # which contain or depend on other containers, but has the advantage
+  # that the number of new edges created scales linearly with the number
+  # of contained vertices regardless of how containers are related;
+  # alternatives such as replacing container-edges with content-edges
+  # scale as the product of the number of external dependencies, which is
+  # to say geometrically in the case of nested / chained containers.
+  #
+  Default_label = { :callback => :refresh, :event => :ALL_EVENTS }
+  def replace_containers_with_anchors(catalog)
+    stage_class      = Puppet::Type.type(:stage)
+    whit_class       = Puppet::Type.type(:whit)
+    component_class  = Puppet::Type.type(:component)
+    containers = catalog.resources.find_all { |v| (v.is_a?(component_class) or v.is_a?(stage_class)) and vertex?(v) }
+    #
+    # These two hashes comprise the aforementioned attention to the possible
+    #   case of containers that contain / depend on other containers; they map
+    #   containers to their sentinels but pass other vertices through.  Thus we
+    #   can "do the right thing" for references to other vertices that may or
+    #   may not be containers.
+    #
+    admissible = Hash.new { |h,k| k }
+    completed  = Hash.new { |h,k| k }
+    containers.each { |x|
+      admissible[x] = whit_class.new(:name => "admissible_#{x.ref}", :catalog => catalog)
+      completed[x]  = whit_class.new(:name => "completed_#{x.ref}",  :catalog => catalog)
+      priority = @prioritizer.priority_of(x)
+      add_vertex(admissible[x], priority)
+      add_vertex(completed[x], priority)
+    }
+    #
+    # Implement the six requirements listed above
+    #
+    containers.each { |x|
+      contents = catalog.adjacent(x, :direction => :out)
+      add_edge(admissible[x],completed[x]) if contents.empty? # (0)
+      contents.each { |v|
+        add_edge(admissible[x],admissible[v],Default_label) # (1)
+        add_edge(completed[v], completed[x], Default_label) # (2)
+      }
+      # (3) & (5)
+      adjacent(x,:direction => :in,:type => :edges).each { |e|
+        add_edge(completed[e.source],admissible[x],e.label)
+        remove_edge! e
+      }
+      # (4) & (5)
+      adjacent(x,:direction => :out,:type => :edges).each { |e|
+        add_edge(completed[x],admissible[e.target],e.label)
+        remove_edge! e
+      }
+    }
+    containers.each { |x| remove_vertex! x } # (5)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/sequential_prioritizer.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/sequential_prioritizer.rb
new file mode 100644
index 0000000..485e7ec
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/sequential_prioritizer.rb
@@ -0,0 +1,31 @@
+# This implements a priority in which keys are given values that will keep them
+# in the same priority in which they priorities are requested. Nested
+# structures (those in which a key is contained within another key) are
+# preserved in such a way that child keys are after the parent and before the
+# key after the parent.
+#
+# @api private
+class Puppet::Graph::SequentialPrioritizer < Puppet::Graph::Prioritizer
+  def initialize
+    super
+    @container = {}
+    @count = Puppet::Graph::Key.new
+  end
+
+  def generate_priority_for(key)
+    if priority_of(key).nil?
+      @count = @count.next
+      record_priority_for(key, @count)
+    else
+      priority_of(key)
+    end
+  end
+
+  def generate_priority_contained_in(container, key)
+    @container[container] ||= priority_of(container).down
+    priority = @container[container].next
+    record_priority_for(key, priority)
+    @container[container] = priority
+    priority
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/simple_graph.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/simple_graph.rb
new file mode 100644
index 0000000..29820f6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/simple_graph.rb
@@ -0,0 +1,566 @@
+require 'puppet/external/dot'
+require 'puppet/relationship'
+require 'set'
+
+# A hopefully-faster graph class to replace the use of GRATR.
+class Puppet::Graph::SimpleGraph
+  #
+  # All public methods of this class must maintain (assume ^ ensure) the following invariants, where "=~=" means
+  # equiv. up to order:
+  #
+  #   @in_to.keys =~= @out_to.keys =~= all vertices
+  #   @in_to.values.collect { |x| x.values }.flatten =~= @out_from.values.collect { |x| x.values }.flatten =~= all edges
+  #   @in_to[v1][v2] =~= @out_from[v2][v1] =~= all edges from v1 to v2
+  #   @in_to   [v].keys =~= vertices with edges leading to   v
+  #   @out_from[v].keys =~= vertices with edges leading from v
+  #   no operation may shed reference loops (for gc)
+  #   recursive operation must scale with the depth of the spanning trees, or better (e.g. no recursion over the set
+  #       of all vertices, etc.)
+  #
+  # This class is intended to be used with DAGs.  However, if the
+  # graph has a cycle, it will not cause non-termination of any of the
+  # algorithms.
+  #
+  def initialize
+    @in_to = {}
+    @out_from = {}
+    @upstream_from = {}
+    @downstream_from = {}
+  end
+
+  # Clear our graph.
+  def clear
+    @in_to.clear
+    @out_from.clear
+    @upstream_from.clear
+    @downstream_from.clear
+  end
+
+  # Which resources depend upon the given resource.
+  def dependencies(resource)
+    vertex?(resource) ? upstream_from_vertex(resource).keys : []
+  end
+
+  def dependents(resource)
+    vertex?(resource) ? downstream_from_vertex(resource).keys : []
+  end
+
+  # Whether our graph is directed.  Always true.  Used to produce dot files.
+  def directed?
+    true
+  end
+
+  # Determine all of the leaf nodes below a given vertex.
+  def leaves(vertex, direction = :out)
+    tree_from_vertex(vertex, direction).keys.find_all { |c| adjacent(c, :direction => direction).empty? }
+  end
+
+  # Collect all of the edges that the passed events match.  Returns
+  # an array of edges.
+  def matching_edges(event, base = nil)
+    source = base || event.resource
+
+    unless vertex?(source)
+      Puppet.warning "Got an event from invalid vertex #{source.ref}"
+      return []
+    end
+    # Get all of the edges that this vertex should forward events
+    # to, which is the same thing as saying all edges directly below
+    # This vertex in the graph.
+    @out_from[source].values.flatten.find_all { |edge| edge.match?(event.name) }
+  end
+
+  # Return a reversed version of this graph.
+  def reversal
+    result = self.class.new
+    vertices.each { |vertex| result.add_vertex(vertex) }
+    edges.each do |edge|
+      result.add_edge edge.class.new(edge.target, edge.source, edge.label)
+    end
+    result
+  end
+
+  # Return the size of the graph.
+  def size
+    vertices.size
+  end
+
+  def to_a
+    vertices
+  end
+
+  # This is a simple implementation of Tarjan's algorithm to find strongly
+  # connected components in the graph; this is a fairly ugly implementation,
+  # because I can't just decorate the vertices themselves.
+  #
+  # This method has an unhealthy relationship with the find_cycles_in_graph
+  # method below, which contains the knowledge of how the state object is
+  # maintained.
+  def tarjan(root, s)
+    # initialize the recursion stack we use to work around the nasty lack of a
+    # decent Ruby stack.
+    recur = [{ :node => root }]
+
+    while not recur.empty? do
+      frame = recur.last
+      vertex = frame[:node]
+
+      case frame[:step]
+      when nil then
+        s[:index][vertex]   = s[:number]
+        s[:lowlink][vertex] = s[:number]
+        s[:number]          = s[:number] + 1
+
+        s[:stack].push(vertex)
+        s[:seen][vertex] = true
+
+        frame[:children] = adjacent(vertex)
+        frame[:step]     = :children
+
+      when :children then
+        if frame[:children].length > 0 then
+          child = frame[:children].shift
+          if ! s[:index][child] then
+            # Never seen, need to recurse.
+            frame[:step] = :after_recursion
+            frame[:child] = child
+            recur.push({ :node => child })
+          elsif s[:seen][child] then
+            s[:lowlink][vertex] = [s[:lowlink][vertex], s[:index][child]].min
+          end
+        else
+          if s[:lowlink][vertex] == s[:index][vertex] then
+            this_scc = []
+            begin
+              top = s[:stack].pop
+              s[:seen][top] = false
+              this_scc << top
+            end until top == vertex
+            s[:scc] << this_scc
+          end
+          recur.pop               # done with this node, finally.
+        end
+
+      when :after_recursion then
+        s[:lowlink][vertex] = [s[:lowlink][vertex], s[:lowlink][frame[:child]]].min
+        frame[:step] = :children
+
+      else
+        fail "#{frame[:step]} is an unknown step"
+      end
+    end
+  end
+
+  # Find all cycles in the graph by detecting all the strongly connected
+  # components, then eliminating everything with a size of one as
+  # uninteresting - which it is, because it can't be a cycle. :)
+  #
+  # This has an unhealthy relationship with the 'tarjan' method above, which
+  # it uses to implement the detection of strongly connected components.
+  def find_cycles_in_graph
+    state = {
+      :number => 0, :index => {}, :lowlink => {}, :scc => [],
+      :stack => [], :seen => {}
+    }
+
+    # we usually have a disconnected graph, must walk all possible roots
+    vertices.each do |vertex|
+      if ! state[:index][vertex] then
+        tarjan vertex, state
+      end
+    end
+
+    # To provide consistent results to the user, given that a hash is never
+    # assured to return the same order, and given our graph processing is
+    # based on hash tables, we need to sort the cycles internally, as well as
+    # the set of cycles.
+    #
+    # Given we are in a failure state here, any extra cost is more or less
+    # irrelevant compared to the cost of a fix - which is on a human
+    # time-scale.
+    state[:scc].select do |component|
+      multi_vertex_component?(component) || single_vertex_referring_to_self?(component)
+    end.map do |component|
+      component.sort
+    end.sort
+  end
+
+  # Perform a BFS on the sub graph representing the cycle, with a view to
+  # generating a sufficient set of paths to report the cycle meaningfully, and
+  # ideally usefully, for the end user.
+  #
+  # BFS is preferred because it will generally report the shortest paths
+  # through the graph first, which are more likely to be interesting to the
+  # user.  I think; it would be interesting to verify that. --daniel 2011-01-23
+  def paths_in_cycle(cycle, max_paths = 1)
+    raise ArgumentError, "negative or zero max_paths" if max_paths < 1
+
+    # Calculate our filtered outbound vertex lists...
+    adj = {}
+    cycle.each do |vertex|
+      adj[vertex] = adjacent(vertex).select{|s| cycle.member? s}
+    end
+
+    found = []
+
+    # frame struct is vertex, [path]
+    stack = [[cycle.first, []]]
+    while frame = stack.shift do
+      if frame[1].member?(frame[0]) then
+        found << frame[1] + [frame[0]]
+        break if found.length >= max_paths
+      else
+        adj[frame[0]].each do |to|
+          stack.push [to, frame[1] + [frame[0]]]
+        end
+      end
+    end
+
+    return found.sort
+  end
+
+  def report_cycles_in_graph
+    cycles = find_cycles_in_graph
+    n = cycles.length           # where is "pluralize"? --daniel 2011-01-22
+    return if n == 0
+    s = n == 1 ? '' : 's'
+
+    message = "Found #{n} dependency cycle#{s}:\n"
+    cycles.each do |cycle|
+      paths = paths_in_cycle(cycle)
+      message += paths.map{ |path| '(' + path.join(" => ") + ')'}.join("\n") + "\n"
+    end
+
+    if Puppet[:graph] then
+      filename = write_cycles_to_graph(cycles)
+      message += "Cycle graph written to #{filename}."
+    else
+      message += "Try the '--graph' option and opening the "
+      message += "resulting '.dot' file in OmniGraffle or GraphViz"
+    end
+
+    raise Puppet::Error, message
+  end
+
+  def write_cycles_to_graph(cycles)
+    # This does not use the DOT graph library, just writes the content
+    # directly.  Given the complexity of this, there didn't seem much point
+    # using a heavy library to generate exactly the same content. --daniel 2011-01-27
+    Puppet.settings.use(:graphing)
+
+    graph = ["digraph Resource_Cycles {"]
+    graph << '  label = "Resource Cycles"'
+
+    cycles.each do |cycle|
+      paths_in_cycle(cycle, 10).each do |path|
+        graph << path.map { |v| '"' + v.to_s.gsub(/"/, '\\"') + '"' }.join(" -> ")
+      end
+    end
+
+    graph << '}'
+
+    filename = File.join(Puppet[:graphdir], "cycles.dot")
+    File.open(filename, "w") { |f| f.puts graph }
+    return filename
+  end
+
+  # Add a new vertex to the graph.
+  def add_vertex(vertex)
+    @in_to[vertex]    ||= {}
+    @out_from[vertex] ||= {}
+  end
+
+  # Remove a vertex from the graph.
+  def remove_vertex!(v)
+    return unless vertex?(v)
+    @upstream_from.clear
+    @downstream_from.clear
+    (@in_to[v].values+@out_from[v].values).flatten.each { |e| remove_edge!(e) }
+    @in_to.delete(v)
+    @out_from.delete(v)
+  end
+
+  # Test whether a given vertex is in the graph.
+  def vertex?(v)
+    @in_to.include?(v)
+  end
+
+  # Return a list of all vertices.
+  def vertices
+    @in_to.keys
+  end
+
+  # Add a new edge.  The graph user has to create the edge instance,
+  # since they have to specify what kind of edge it is.
+  def add_edge(e,*a)
+    return add_relationship(e,*a) unless a.empty?
+    @upstream_from.clear
+    @downstream_from.clear
+    add_vertex(e.source)
+    add_vertex(e.target)
+    @in_to[   e.target][e.source] ||= []; @in_to[   e.target][e.source] |= [e]
+    @out_from[e.source][e.target] ||= []; @out_from[e.source][e.target] |= [e]
+  end
+
+  def add_relationship(source, target, label = nil)
+    add_edge Puppet::Relationship.new(source, target, label)
+  end
+
+  # Find all matching edges.
+  def edges_between(source, target)
+    (@out_from[source] || {})[target] || []
+  end
+
+  # Is there an edge between the two vertices?
+  def edge?(source, target)
+    vertex?(source) and vertex?(target) and @out_from[source][target]
+  end
+
+  def edges
+    @in_to.values.collect { |x| x.values }.flatten
+  end
+
+  def each_edge
+    @in_to.each { |t,ns| ns.each { |s,es| es.each { |e| yield e }}}
+  end
+
+  # Remove an edge from our graph.
+  def remove_edge!(e)
+    if edge?(e.source,e.target)
+      @upstream_from.clear
+      @downstream_from.clear
+      @in_to   [e.target].delete e.source if (@in_to   [e.target][e.source] -= [e]).empty?
+      @out_from[e.source].delete e.target if (@out_from[e.source][e.target] -= [e]).empty?
+    end
+  end
+
+  # Find adjacent edges.
+  def adjacent(v, options = {})
+    return [] unless ns = (options[:direction] == :in) ? @in_to[v] : @out_from[v]
+    (options[:type] == :edges) ? ns.values.flatten : ns.keys
+  end
+
+  # Just walk the tree and pass each edge.
+  def walk(source, direction)
+    # Use an iterative, breadth-first traversal of the graph. One could do
+    # this recursively, but Ruby's slow function calls and even slower
+    # recursion make the shorter, recursive algorithm cost-prohibitive.
+    stack = [source]
+    seen = Set.new
+    until stack.empty?
+      node = stack.shift
+      next if seen.member? node
+      connected = adjacent(node, :direction => direction)
+      connected.each do |target|
+        yield node, target
+      end
+      stack.concat(connected)
+      seen << node
+    end
+  end
+
+  # A different way of walking a tree, and a much faster way than the
+  # one that comes with GRATR.
+  def tree_from_vertex(start, direction = :out)
+    predecessor={}
+    walk(start, direction) do |parent, child|
+      predecessor[child] = parent
+    end
+    predecessor
+  end
+
+  def downstream_from_vertex(v)
+    return @downstream_from[v] if @downstream_from[v]
+    result = @downstream_from[v] = {}
+    @out_from[v].keys.each do |node|
+      result[node] = 1
+      result.update(downstream_from_vertex(node))
+    end
+    result
+  end
+
+  def direct_dependents_of(v)
+    (@out_from[v] || {}).keys
+  end
+
+  def upstream_from_vertex(v)
+    return @upstream_from[v] if @upstream_from[v]
+    result = @upstream_from[v] = {}
+    @in_to[v].keys.each do |node|
+      result[node] = 1
+      result.update(upstream_from_vertex(node))
+    end
+    result
+  end
+
+  def direct_dependencies_of(v)
+    (@in_to[v] || {}).keys
+  end
+
+  # Return an array of the edge-sets between a series of n+1 vertices (f=v0,v1,v2...t=vn)
+  #   connecting the two given verticies.  The ith edge set is an array containing all the
+  #   edges between v(i) and v(i+1); these are (by definition) never empty.
+  #
+  #     * if f == t, the list is empty
+  #     * if they are adjacent the result is an array consisting of
+  #       a single array (the edges from f to t)
+  #     * and so on by induction on a vertex m between them
+  #     * if there is no path from f to t, the result is nil
+  #
+  # This implementation is not particularly efficient; it's used in testing where clarity
+  #   is more important than last-mile efficiency.
+  #
+  def path_between(f,t)
+    if f==t
+      []
+    elsif direct_dependents_of(f).include?(t)
+      [edges_between(f,t)]
+    elsif dependents(f).include?(t)
+      m = (dependents(f) & direct_dependencies_of(t)).first
+      path_between(f,m) + path_between(m,t)
+    else
+      nil
+    end
+  end
+
+  # LAK:FIXME This is just a paste of the GRATR code with slight modifications.
+
+  # Return a DOT::DOTDigraph for directed graphs or a DOT::DOTSubgraph for an
+  # undirected Graph.  _params_ can contain any graph property specified in
+  # rdot.rb. If an edge or vertex label is a kind of Hash then the keys
+  # which match +dot+ properties will be used as well.
+  def to_dot_graph (params = {})
+    params['name'] ||= self.class.name.gsub(/:/,'_')
+    fontsize   = params['fontsize'] ? params['fontsize'] : '8'
+    graph      = (directed? ? DOT::DOTDigraph : DOT::DOTSubgraph).new(params)
+    edge_klass = directed? ? DOT::DOTDirectedEdge : DOT::DOTEdge
+    vertices.each do |v|
+      name = v.ref
+      params = {'name'     => '"'+name+'"',
+        'fontsize' => fontsize,
+        'label'    => name}
+      v_label = v.ref
+      params.merge!(v_label) if v_label and v_label.kind_of? Hash
+      graph << DOT::DOTNode.new(params)
+    end
+    edges.each do |e|
+      params = {'from'     => '"'+ e.source.ref + '"',
+        'to'       => '"'+ e.target.ref + '"',
+        'fontsize' => fontsize }
+      e_label = e.ref
+      params.merge!(e_label) if e_label and e_label.kind_of? Hash
+      graph << edge_klass.new(params)
+    end
+    graph
+  end
+
+  # Output the dot format as a string
+  def to_dot (params={}) to_dot_graph(params).to_s; end
+
+  # Call +dotty+ for the graph which is written to the file 'graph.dot'
+  # in the # current directory.
+  def dotty (params = {}, dotfile = 'graph.dot')
+    File.open(dotfile, 'w') {|f| f << to_dot(params) }
+    system('dotty', dotfile)
+  end
+
+  # Produce the graph files if requested.
+  def write_graph(name)
+    return unless Puppet[:graph]
+
+    Puppet.settings.use(:graphing)
+
+    file = File.join(Puppet[:graphdir], "#{name}.dot")
+    File.open(file, "w") { |f|
+      f.puts to_dot("name" => name.to_s.capitalize)
+    }
+  end
+
+  # This flag may be set to true to use the new YAML serialzation
+  # format (where @vertices is a simple list of vertices rather than a
+  # list of VertexWrapper objects).  Deserialization supports both
+  # formats regardless of the setting of this flag.
+  class << self
+    attr_accessor :use_new_yaml_format
+  end
+  self.use_new_yaml_format = false
+
+  # Stub class to allow graphs to be represented in YAML using the old
+  # (version 2.6) format.
+  class VertexWrapper
+    attr_reader :vertex, :adjacencies
+    def initialize(vertex, adjacencies)
+      @vertex = vertex
+      @adjacencies = adjacencies
+    end
+
+    def inspect
+      { :@adjacencies => @adjacencies, :@vertex => @vertex.to_s }.inspect
+    end
+  end
+
+  # instance_variable_get is used by Object.to_zaml to get instance
+  # variables.  Override it so that we can simulate the presence of
+  # instance variables @edges and @vertices for serialization.
+  def instance_variable_get(v)
+    case v.to_s
+    when '@edges' then
+      edges
+    when '@vertices' then
+      if self.class.use_new_yaml_format
+        vertices
+      else
+        result = {}
+        vertices.each do |vertex|
+          adjacencies = {}
+          [:in, :out].each do |direction|
+            adjacencies[direction] = {}
+            adjacent(vertex, :direction => direction, :type => :edges).each do |edge|
+              other_vertex = direction == :in ? edge.source : edge.target
+              (adjacencies[direction][other_vertex] ||= Set.new).add(edge)
+            end
+          end
+          result[vertex] = Puppet::Graph::SimpleGraph::VertexWrapper.new(vertex, adjacencies)
+        end
+        result
+      end
+    else
+      super(v)
+    end
+  end
+
+  def to_yaml_properties
+    (super + [:@vertices, :@edges] -
+     [:@in_to, :@out_from, :@upstream_from, :@downstream_from]).uniq
+  end
+
+  def yaml_initialize(tag, var)
+    initialize()
+    vertices = var.delete('vertices')
+    edges = var.delete('edges')
+    if vertices.is_a?(Hash)
+      # Support old (2.6) format
+      vertices = vertices.keys
+    end
+    vertices.each { |v| add_vertex(v) }
+    edges.each { |e| add_edge(e) }
+    var.each do |varname, value|
+      instance_variable_set("@#{varname}", value)
+    end
+  end
+
+  def multi_vertex_component?(component)
+    component.length > 1
+  end
+  private :multi_vertex_component?
+
+  def single_vertex_referring_to_self?(component)
+    if component.length == 1
+      vertex = component[0]
+      adjacent(vertex).include?(vertex)
+    else
+      false
+    end
+  end
+  private :single_vertex_referring_to_self?
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/title_hash_prioritizer.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/title_hash_prioritizer.rb
new file mode 100644
index 0000000..d980b7a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/graph/title_hash_prioritizer.rb
@@ -0,0 +1,16 @@
+# Prioritize keys, which must be Puppet::Resources, based on a static hash of
+# the key's ref. This prioritizer does not take containment into account.
+#
+# @api private
+require 'digest/sha1'
+
+class Puppet::Graph::TitleHashPrioritizer < Puppet::Graph::Prioritizer
+  def generate_priority_for(resource)
+    record_priority_for(resource,
+                        Digest::SHA1.hexdigest("NaCl, MgSO4 (salts) and then #{resource.ref}"))
+  end
+
+  def generate_priority_contained_in(container, resource)
+    generate_priority_for(resource)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector.rb
new file mode 100644
index 0000000..9385a61
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector.rb
@@ -0,0 +1,61 @@
+# Manage indirections to termini.  They are organized in terms of indirections -
+# - e.g., configuration, node, file, certificate -- and each indirection has one
+# or more terminus types defined.  The indirection is configured via the
+# +indirects+ method, which will be called by the class extending itself
+# with this module.
+module Puppet::Indirector
+  # LAK:FIXME We need to figure out how to handle documentation for the
+  # different indirection types.
+
+  require 'puppet/indirector/indirection'
+  require 'puppet/indirector/terminus'
+  require 'puppet/indirector/code'
+  require 'puppet/indirector/envelope'
+  require 'puppet/network/format_support'
+
+  def self.configure_routes(application_routes)
+    application_routes.each do |indirection_name, termini|
+      indirection_name = indirection_name.to_sym
+      terminus_name = termini["terminus"]
+      cache_name    = termini["cache"]
+
+      Puppet::Indirector::Terminus.terminus_class(indirection_name, terminus_name || cache_name)
+
+      indirection = Puppet::Indirector::Indirection.instance(indirection_name)
+      raise "Indirection #{indirection_name} does not exist" unless indirection
+
+      indirection.terminus_class = terminus_name if terminus_name
+      indirection.cache_class = cache_name if cache_name
+    end
+  end
+
+  # Declare that the including class indirects its methods to
+  # this terminus.  The terminus name must be the name of a Puppet
+  # default, not the value -- if it's the value, then it gets
+  # evaluated at parse time, which is before the user has had a chance
+  # to override it.
+  def indirects(indirection, options = {})
+    raise(ArgumentError, "Already handling indirection for #{@indirection.name}; cannot also handle #{indirection}") if @indirection
+    # populate this class with the various new methods
+    extend ClassMethods
+    include Puppet::Indirector::Envelope
+    include Puppet::Network::FormatSupport
+
+    # record the indirected class name for documentation purposes
+    options[:indirected_class] = name
+
+    # instantiate the actual Terminus for that type and this name (:ldap, w/ args :node)
+    # & hook the instantiated Terminus into this class (Node: @indirection = terminus)
+    @indirection = Puppet::Indirector::Indirection.new(self, indirection, options)
+  end
+
+  module ClassMethods
+    attr_reader :indirection
+  end
+
+  # Helper definition for indirections that handle filenames.
+  BadNameRegexp = Regexp.union(/^\.\./,
+                               %r{[\\/]},
+                               "\0",
+                               /(?i)^[a-z]:/)
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/active_record.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/active_record.rb
new file mode 100644
index 0000000..32c4dd4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/active_record.rb
@@ -0,0 +1,29 @@
+require 'puppet/rails'
+require 'puppet/indirector'
+
+class Puppet::Indirector::ActiveRecord < Puppet::Indirector::Terminus
+  class << self
+    attr_accessor :ar_model
+  end
+
+  def self.use_ar_model(klass)
+    self.ar_model = klass
+  end
+
+  def ar_model
+    self.class.ar_model
+  end
+
+  def initialize
+    Puppet::Rails.init
+  end
+
+  def find(request)
+    return nil unless instance = ar_model.find_by_name(request.key)
+    instance.to_puppet
+  end
+
+  def save(request)
+    ar_model.from_puppet(request.instance).save
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/active_record.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/active_record.rb
new file mode 100644
index 0000000..8e0d96f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/active_record.rb
@@ -0,0 +1,39 @@
+require 'puppet/rails/host'
+require 'puppet/indirector/active_record'
+require 'puppet/resource/catalog'
+
+class Puppet::Resource::Catalog::ActiveRecord < Puppet::Indirector::ActiveRecord
+  use_ar_model Puppet::Rails::Host
+
+  desc "A component of ActiveRecord storeconfigs. ActiveRecord-based storeconfigs
+    and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation"
+
+  def initialize
+    Puppet.deprecation_warning "ActiveRecord-based storeconfigs and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation"
+    super
+  end
+
+  # We don't retrieve catalogs from storeconfigs
+  def find(request)
+    nil
+  end
+
+  # Save the values from a Facts instance as the facts on a Rails Host instance.
+  def save(request)
+    catalog = request.instance
+
+    host = ar_model.find_by_name(catalog.name) || ar_model.create(:name => catalog.name)
+
+    host.railsmark "Saved catalog to database" do
+      host.merge_resources(catalog.vertices)
+      host.last_compile = Time.now
+
+      if node = Puppet::Node.indirection.find(catalog.name)
+        host.ip = node.parameters["ipaddress"]
+        host.environment = node.environment.to_s
+      end
+
+      host.save
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/compiler.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/compiler.rb
new file mode 100644
index 0000000..6f4e2f3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/compiler.rb
@@ -0,0 +1,182 @@
+require 'puppet/node'
+require 'puppet/resource/catalog'
+require 'puppet/indirector/code'
+require 'puppet/util/profiler'
+require 'yaml'
+
+class Puppet::Resource::Catalog::Compiler < Puppet::Indirector::Code
+  desc "Compiles catalogs on demand using Puppet's compiler."
+
+  include Puppet::Util
+
+  attr_accessor :code
+
+  def extract_facts_from_request(request)
+    return unless text_facts = request.options[:facts]
+    unless format = request.options[:facts_format]
+      raise ArgumentError, "Facts but no fact format provided for #{request.key}"
+    end
+
+    Puppet::Util::Profiler.profile("Found facts", [:compiler, :find_facts]) do
+      # If the facts were encoded as yaml, then the param reconstitution system
+      # in Network::HTTP::Handler will automagically deserialize the value.
+      if text_facts.is_a?(Puppet::Node::Facts)
+        facts = text_facts
+      else
+        # We unescape here because the corresponding code in Puppet::Configurer::FactHandler escapes
+        facts = Puppet::Node::Facts.convert_from(format, CGI.unescape(text_facts))
+      end
+
+      unless facts.name == request.key
+        raise Puppet::Error, "Catalog for #{request.key.inspect} was requested with fact definition for the wrong node (#{facts.name.inspect})."
+      end
+
+      facts.add_timestamp
+
+      options = {
+        :environment => request.environment,
+        :transaction_uuid => request.options[:transaction_uuid],
+      }
+
+      Puppet::Node::Facts.indirection.save(facts, nil, options)
+    end
+  end
+
+  # Compile a node's catalog.
+  def find(request)
+    extract_facts_from_request(request)
+
+    node = node_from_request(request)
+    node.trusted_data = Puppet.lookup(:trusted_information) { Puppet::Context::TrustedInformation.local(node) }.to_h
+
+    if catalog = compile(node)
+      return catalog
+    else
+      # This shouldn't actually happen; we should either return
+      # a config or raise an exception.
+      return nil
+    end
+  end
+
+  # filter-out a catalog to remove exported resources
+  def filter(catalog)
+    return catalog.filter { |r| r.virtual? } if catalog.respond_to?(:filter)
+    catalog
+  end
+
+  def initialize
+    Puppet::Util::Profiler.profile("Setup server facts for compiling", [:compiler, :init_server_facts]) do
+      set_server_facts
+    end
+  end
+
+  # Is our compiler part of a network, or are we just local?
+  def networked?
+    Puppet.run_mode.master?
+  end
+
+  private
+
+  # Add any extra data necessary to the node.
+  def add_node_data(node)
+    # Merge in our server-side facts, so they can be used during compilation.
+    node.merge(@server_facts)
+  end
+
+  # Compile the actual catalog.
+  def compile(node)
+    str = "Compiled catalog for #{node.name}"
+    str += " in environment #{node.environment}" if node.environment
+    config = nil
+
+    benchmark(:notice, str) do
+      Puppet::Util::Profiler.profile(str, [:compiler, :compile, node.environment, node.name]) do
+        begin
+          config = Puppet::Parser::Compiler.compile(node)
+        rescue Puppet::Error => detail
+          Puppet.err(detail.to_s) if networked?
+          raise
+        end
+      end
+    end
+
+    config
+  end
+
+  # Turn our host name into a node object.
+  def find_node(name, environment, transaction_uuid)
+    Puppet::Util::Profiler.profile("Found node information", [:compiler, :find_node]) do
+      node = nil
+      begin
+        node = Puppet::Node.indirection.find(name, :environment => environment,
+                                             :transaction_uuid => transaction_uuid)
+      rescue => detail
+        message = "Failed when searching for node #{name}: #{detail}"
+        Puppet.log_exception(detail, message)
+        raise Puppet::Error, message, detail.backtrace
+      end
+
+
+      # Add any external data to the node.
+      if node
+        add_node_data(node)
+      end
+      node
+    end
+  end
+
+  # Extract the node from the request, or use the request
+  # to find the node.
+  def node_from_request(request)
+    if node = request.options[:use_node]
+      if request.remote?
+        raise Puppet::Error, "Invalid option use_node for a remote request"
+      else
+        return node
+      end
+    end
+
+    # We rely on our authorization system to determine whether the connected
+    # node is allowed to compile the catalog's node referenced by key.
+    # By default the REST authorization system makes sure only the connected node
+    # can compile his catalog.
+    # This allows for instance monitoring systems or puppet-load to check several
+    # node's catalog with only one certificate and a modification to auth.conf
+    # If no key is provided we can only compile the currently connected node.
+    name = request.key || request.node
+    if node = find_node(name, request.environment, request.options[:transaction_uuid])
+      return node
+    end
+
+    raise ArgumentError, "Could not find node '#{name}'; cannot compile"
+  end
+
+  # Initialize our server fact hash; we add these to each client, and they
+  # won't change while we're running, so it's safe to cache the values.
+  def set_server_facts
+    @server_facts = {}
+
+    # Add our server version to the fact list
+    @server_facts["serverversion"] = Puppet.version.to_s
+
+    # And then add the server name and IP
+    {"servername" => "fqdn",
+      "serverip" => "ipaddress"
+    }.each do |var, fact|
+      if value = Facter.value(fact)
+        @server_facts[var] = value
+      else
+        Puppet.warning "Could not retrieve fact #{fact}"
+      end
+    end
+
+    if @server_facts["servername"].nil?
+      host = Facter.value(:hostname)
+      if domain = Facter.value(:domain)
+        @server_facts["servername"] = [host, domain].join(".")
+      else
+        @server_facts["servername"] = host
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/json.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/json.rb
new file mode 100644
index 0000000..cb0ff2d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/json.rb
@@ -0,0 +1,6 @@
+require 'puppet/resource/catalog'
+require 'puppet/indirector/json'
+
+class Puppet::Resource::Catalog::Json < Puppet::Indirector::JSON
+  desc "Store catalogs as flat files, serialized using JSON."
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/msgpack.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/msgpack.rb
new file mode 100644
index 0000000..a0e5bfd
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/msgpack.rb
@@ -0,0 +1,6 @@
+require 'puppet/resource/catalog'
+require 'puppet/indirector/msgpack'
+
+class Puppet::Resource::Catalog::Msgpack < Puppet::Indirector::Msgpack
+  desc "Store catalogs as flat files, serialized using MessagePack."
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/queue.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/queue.rb
new file mode 100644
index 0000000..5135652
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/queue.rb
@@ -0,0 +1,9 @@
+require 'puppet/resource/catalog'
+require 'puppet/indirector/queue'
+
+class Puppet::Resource::Catalog::Queue < Puppet::Indirector::Queue
+
+  desc "Part of async storeconfigs, requiring the puppet queue daemon. ActiveRecord-based storeconfigs
+    and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation"
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/rest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/rest.rb
new file mode 100644
index 0000000..b7a00a3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/rest.rb
@@ -0,0 +1,6 @@
+require 'puppet/resource/catalog'
+require 'puppet/indirector/rest'
+
+class Puppet::Resource::Catalog::Rest < Puppet::Indirector::REST
+  desc "Find resource catalogs over HTTP via REST."
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/static_compiler.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/static_compiler.rb
new file mode 100644
index 0000000..a8b6bb5
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/static_compiler.rb
@@ -0,0 +1,214 @@
+require 'puppet/node'
+require 'puppet/resource/catalog'
+require 'puppet/indirector/catalog/compiler'
+
+class Puppet::Resource::Catalog::StaticCompiler < Puppet::Resource::Catalog::Compiler
+
+  desc %q{Compiles catalogs on demand using the optional static compiler. This
+    functions similarly to the normal compiler, but it replaces puppet:/// file
+    URLs with explicit metadata and file content hashes, expecting puppet agent
+    to fetch the exact specified content from the filebucket. This guarantees
+    that a given catalog will always result in the same file states. It also
+    decreases catalog application time and fileserver load, at the cost of
+    increased compilation time.
+
+    This terminus works today, but cannot be used without additional
+    configuration. Specifically:
+
+    * You must create a special filebucket resource --- with the title `puppet`
+      and the `path` attribute set to `false` --- in site.pp or somewhere else
+      where it will be added to every node's catalog. Using `puppet` as the title
+      is mandatory; the static compiler treats this title as magical.
+
+          filebucket { puppet:
+            path => false,
+          }
+
+    * You must set `catalog_terminus = static_compiler` in the puppet
+      master's puppet.conf.
+    * The puppet master's auth.conf must allow authenticated nodes to access the
+      `file_bucket_file` endpoint. This is enabled by default (see the
+      `path /file` rule), but if you have made your auth.conf more restrictive,
+      you may need to re-enable it.)
+    * If you are using multiple puppet masters, you must configure load balancer
+      affinity for agent nodes. This is because puppet masters other than the one
+      that compiled a given catalog may not have stored the required file contents
+      in their filebuckets.}
+
+  def find(request)
+    return nil unless catalog = super
+
+    raise "Did not get catalog back" unless catalog.is_a?(model)
+
+    catalog.resources.find_all { |res| res.type == "File" }.each do |resource|
+      next unless source = resource[:source]
+      next unless source =~ /^puppet:/
+
+      file = resource.to_ral
+
+      if file.recurse?
+        add_children(request.key, catalog, resource, file)
+      else
+        find_and_replace_metadata(request.key, resource, file)
+      end
+    end
+
+    catalog
+  end
+
+  # Take a resource with a fileserver based file source remove the source
+  # parameter, and insert the file metadata into the resource.
+  #
+  # This method acts to do the fileserver metadata retrieval in advance, while
+  # the file source is local and doesn't require an HTTP request. It retrieves
+  # the file metadata for a given file resource, removes the source parameter
+  # from the resource, inserts the metadata into the file resource, and uploads
+  # the file contents of the source to the file bucket.
+  #
+  # @param host [String] The host name of the node requesting this catalog
+  # @param resource [Puppet::Resource] The resource to replace the metadata in
+  # @param file [Puppet::Type::File] The file RAL associated with the resource
+  def find_and_replace_metadata(host, resource, file)
+    # We remove URL info from it, so it forces a local copy
+    # rather than routing through the network.
+    # Weird, but true.
+    newsource = file[:source][0].sub("puppet:///", "")
+    file[:source][0] = newsource
+
+    raise "Could not get metadata for #{resource[:source]}" unless metadata = file.parameter(:source).metadata
+
+    replace_metadata(host, resource, metadata)
+  end
+
+  # Rewrite a given file resource with the metadata from a fileserver based file
+  #
+  # This performs the actual metadata rewrite for the given file resource and
+  # uploads the content of the source file to the filebucket.
+  #
+  # @param host [String] The host name of the node requesting this catalog
+  # @param resource [Puppet::Resource] The resource to add the metadata to
+  # @param metadata [Puppet::FileServing::Metadata] The metadata of the given fileserver based file
+  def replace_metadata(host, resource, metadata)
+    [:mode, :owner, :group].each do |param|
+      resource[param] ||= metadata.send(param)
+    end
+
+    resource[:ensure] = metadata.ftype
+    if metadata.ftype == "file"
+      unless resource[:content]
+        resource[:content] = metadata.checksum
+        resource[:checksum] = metadata.checksum_type
+      end
+    end
+
+    store_content(resource) if resource[:ensure] == "file"
+    old_source = resource.delete(:source)
+    Puppet.info "Metadata for #{resource} in catalog for '#{host}' added from '#{old_source}'"
+  end
+
+  # Generate children resources for a recursive file and add them to the catalog.
+  #
+  # @param host [String] The host name of the node requesting this catalog
+  # @param catalog [Puppet::Resource::Catalog]
+  # @param resource [Puppet::Resource]
+  # @param file [Puppet::Type::File] The file RAL associated with the resource
+  def add_children(host, catalog, resource, file)
+    file = resource.to_ral
+
+    children = get_child_resources(host, catalog, resource, file)
+
+    remove_existing_resources(children, catalog)
+
+    children.each do |name, res|
+      catalog.add_resource res
+      catalog.add_edge(resource, res)
+    end
+  end
+
+  # Given a recursive file resource, recursively generate its children resources
+  #
+  # @param host [String] The host name of the node requesting this catalog
+  # @param catalog [Puppet::Resource::Catalog]
+  # @param resource [Puppet::Resource]
+  # @param file [Puppet::Type::File] The file RAL associated with the resource
+  #
+  # @return [Array<Puppet::Resource>] The recursively generated File resources for the given resource
+  def get_child_resources(host, catalog, resource, file)
+    sourceselect = file[:sourceselect]
+    children = {}
+
+    source = resource[:source]
+
+    # This is largely a copy of recurse_remote in File
+    total = file[:source].collect do |source|
+      next unless result = file.perform_recursion(source)
+      return if top = result.find { |r| r.relative_path == "." } and top.ftype != "directory"
+      result.each { |data| data.source = "#{source}/#{data.relative_path}" }
+      break result if result and ! result.empty? and sourceselect == :first
+      result
+    end.flatten.compact
+
+    # This only happens if we have sourceselect == :all
+    unless sourceselect == :first
+      found = []
+      total.reject! do |data|
+        result = found.include?(data.relative_path)
+        found << data.relative_path unless found.include?(data.relative_path)
+        result
+      end
+    end
+
+    total.each do |meta|
+      # This is the top-level parent directory
+      if meta.relative_path == "."
+        replace_metadata(host, resource, meta)
+        next
+      end
+      children[meta.relative_path] ||= Puppet::Resource.new(:file, File.join(file[:path], meta.relative_path))
+
+      # I think this is safe since it's a URL, not an actual file
+      children[meta.relative_path][:source] = source + "/" + meta.relative_path
+      resource.each do |param, value|
+        # These should never be passed to our children.
+        unless [:parent, :ensure, :recurse, :recurselimit, :target, :alias, :source].include? param
+          children[meta.relative_path][param] = value
+        end
+      end
+      replace_metadata(host, children[meta.relative_path], meta)
+    end
+
+    children
+  end
+
+  # Remove any file resources in the catalog that will be duplicated by the
+  # given file resources.
+  #
+  # @param children [Array<Puppet::Resource>]
+  # @param catalog [Puppet::Resource::Catalog]
+  def remove_existing_resources(children, catalog)
+    existing_names = catalog.resources.collect { |r| r.to_s }
+    both = (existing_names & children.keys).inject({}) { |hash, name| hash[name] = true; hash }
+    both.each { |name| children.delete(name) }
+  end
+
+  # Retrieve the source of a file resource using a fileserver based source and
+  # upload it to the filebucket.
+  #
+  # @param resource [Puppet::Resource]
+  def store_content(resource)
+    @summer ||= Object.new
+    @summer.extend(Puppet::Util::Checksums)
+
+    type = @summer.sumtype(resource[:content])
+    sum = @summer.sumdata(resource[:content])
+
+    if Puppet::FileBucket::File.indirection.find("#{type}/#{sum}")
+      Puppet.info "Content for '#{resource[:source]}' already exists"
+    else
+      Puppet.info "Storing content for source '#{resource[:source]}'"
+      content = Puppet::FileServing::Content.indirection.find(resource[:source])
+      file = Puppet::FileBucket::File.new(content.content)
+      Puppet::FileBucket::File.indirection.save(file)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/store_configs.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/store_configs.rb
new file mode 100644
index 0000000..e2921b2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/store_configs.rb
@@ -0,0 +1,8 @@
+require 'puppet/indirector/store_configs'
+require 'puppet/resource/catalog'
+
+class Puppet::Resource::Catalog::StoreConfigs < Puppet::Indirector::StoreConfigs
+
+  desc %q{Part of the "storeconfigs" feature. Should not be directly set by end users.}
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/yaml.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/yaml.rb
new file mode 100644
index 0000000..177b4e2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/catalog/yaml.rb
@@ -0,0 +1,22 @@
+require 'puppet/resource/catalog'
+require 'puppet/indirector/yaml'
+
+class Puppet::Resource::Catalog::Yaml < Puppet::Indirector::Yaml
+  desc "Store catalogs as flat files, serialized using YAML."
+
+  private
+
+  # Override these, because yaml doesn't want to convert our self-referential
+  # objects.  This is hackish, but eh.
+  def from_yaml(text)
+    if config = YAML.load(text)
+      return config
+    end
+  end
+
+  def to_yaml(config)
+    # We can't yaml-dump classes.
+    #config.edgelist_class = nil
+    YAML.dump(config)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate/ca.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate/ca.rb
new file mode 100644
index 0000000..563bd3c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate/ca.rb
@@ -0,0 +1,9 @@
+require 'puppet/indirector/ssl_file'
+require 'puppet/ssl/certificate'
+
+class Puppet::SSL::Certificate::Ca < Puppet::Indirector::SslFile
+  desc "Manage the CA collection of signed SSL certificates on disk."
+
+  store_in :signeddir
+  store_ca_at :cacert
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate/disabled_ca.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate/disabled_ca.rb
new file mode 100644
index 0000000..2f2da60
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate/disabled_ca.rb
@@ -0,0 +1,22 @@
+require 'puppet/indirector/code'
+require 'puppet/ssl/certificate'
+
+class Puppet::SSL::Certificate::DisabledCa < Puppet::Indirector::Code
+  desc "Manage SSL certificates on disk, but reject any remote access
+to the SSL data store.  Used when a master has an explicitly disabled
+CA to prevent clients getting confusing 'success' behaviour."
+
+  def initialize
+    @file = Puppet::SSL::Certificate.indirection.terminus(:file)
+  end
+
+  [:find, :head, :search, :save, :destroy].each do |name|
+    define_method(name) do |request|
+      if request.remote?
+        raise Puppet::Error, "this master is not a CA"
+      else
+        @file.send(name, request)
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate/file.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate/file.rb
new file mode 100644
index 0000000..4ce18f8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate/file.rb
@@ -0,0 +1,9 @@
+require 'puppet/indirector/ssl_file'
+require 'puppet/ssl/certificate'
+
+class Puppet::SSL::Certificate::File < Puppet::Indirector::SslFile
+  desc "Manage SSL certificates on disk."
+
+  store_in :certdir
+  store_ca_at :localcacert
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate/rest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate/rest.rb
new file mode 100644
index 0000000..ab18b35
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate/rest.rb
@@ -0,0 +1,16 @@
+require 'puppet/ssl/certificate'
+require 'puppet/indirector/rest'
+
+class Puppet::SSL::Certificate::Rest < Puppet::Indirector::REST
+  desc "Find certificates over HTTP via REST."
+
+  use_server_setting(:ca_server)
+  use_port_setting(:ca_port)
+  use_srv_service(:ca)
+
+  def find(request)
+    return nil unless result = super
+    result.name = request.key unless result.name == request.key
+    result
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_request/ca.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_request/ca.rb
new file mode 100644
index 0000000..5d76ee5
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_request/ca.rb
@@ -0,0 +1,22 @@
+require 'puppet/indirector/ssl_file'
+require 'puppet/ssl/certificate_request'
+
+class Puppet::SSL::CertificateRequest::Ca < Puppet::Indirector::SslFile
+  desc "Manage the CA collection of certificate requests on disk."
+
+  store_in :csrdir
+
+  def save(request)
+    if host = Puppet::SSL::Host.indirection.find(request.key)
+      if Puppet[:allow_duplicate_certs]
+        Puppet.notice "#{request.key} already has a #{host.state} certificate; new certificate will overwrite it"
+      else
+        raise "#{request.key} already has a #{host.state} certificate; ignoring certificate request"
+      end
+    end
+
+    result = super
+    Puppet.notice "#{request.key} has a waiting certificate request"
+    result
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_request/disabled_ca.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_request/disabled_ca.rb
new file mode 100644
index 0000000..43001ac
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_request/disabled_ca.rb
@@ -0,0 +1,22 @@
+require 'puppet/indirector/code'
+require 'puppet/ssl/certificate_request'
+
+class Puppet::SSL::CertificateRequest::DisabledCa < Puppet::Indirector::Code
+  desc "Manage SSL certificate requests on disk, but reject any remote access
+to the SSL data store. Used when a master has an explicitly disabled CA to
+prevent clients getting confusing 'success' behaviour."
+
+  def initialize
+    @file = Puppet::SSL::CertificateRequest.indirection.terminus(:file)
+  end
+
+  [:find, :head, :search, :save, :destroy].each do |name|
+    define_method(name) do |request|
+      if request.remote?
+        raise Puppet::Error, "this master is not a CA"
+      else
+        @file.send(name, request)
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_request/file.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_request/file.rb
new file mode 100644
index 0000000..9510e36
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_request/file.rb
@@ -0,0 +1,8 @@
+require 'puppet/indirector/ssl_file'
+require 'puppet/ssl/certificate_request'
+
+class Puppet::SSL::CertificateRequest::File < Puppet::Indirector::SslFile
+  desc "Manage the collection of certificate requests on disk."
+
+  store_in :requestdir
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_request/memory.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_request/memory.rb
new file mode 100644
index 0000000..c60a1f9
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_request/memory.rb
@@ -0,0 +1,6 @@
+require 'puppet/ssl/certificate_request'
+require 'puppet/indirector/memory'
+
+class Puppet::SSL::CertificateRequest::Memory < Puppet::Indirector::Memory
+  desc "Store certificate requests in memory. This is used for testing puppet."
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_request/rest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_request/rest.rb
new file mode 100644
index 0000000..a2004af
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_request/rest.rb
@@ -0,0 +1,10 @@
+require 'puppet/ssl/certificate_request'
+require 'puppet/indirector/rest'
+
+class Puppet::SSL::CertificateRequest::Rest < Puppet::Indirector::REST
+  desc "Find and save certificate requests over HTTP via REST."
+
+  use_server_setting(:ca_server)
+  use_port_setting(:ca_port)
+  use_srv_service(:ca)
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_revocation_list/ca.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_revocation_list/ca.rb
new file mode 100644
index 0000000..1e2be6e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_revocation_list/ca.rb
@@ -0,0 +1,8 @@
+require 'puppet/indirector/ssl_file'
+require 'puppet/ssl/certificate_revocation_list'
+
+class Puppet::SSL::CertificateRevocationList::Ca < Puppet::Indirector::SslFile
+  desc "Manage the CA collection of certificate requests on disk."
+
+  store_at :cacrl
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_revocation_list/disabled_ca.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_revocation_list/disabled_ca.rb
new file mode 100644
index 0000000..198b19f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_revocation_list/disabled_ca.rb
@@ -0,0 +1,22 @@
+require 'puppet/indirector/code'
+require 'puppet/ssl/certificate_revocation_list'
+
+class Puppet::SSL::CertificateRevocationList::DisabledCa < Puppet::Indirector::Code
+  desc "Manage SSL certificate revocation lists, but reject any remote access
+to the SSL data store. Used when a master has an explicitly disabled CA to
+prevent clients getting confusing 'success' behaviour."
+
+  def initialize
+    @file = Puppet::SSL::CertificateRevocationList.indirection.terminus(:file)
+  end
+
+  [:find, :head, :search, :save, :destroy].each do |name|
+    define_method(name) do |request|
+      if request.remote?
+        raise Puppet::Error, "this master is not a CA"
+      else
+        @file.send(name, request)
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_revocation_list/file.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_revocation_list/file.rb
new file mode 100644
index 0000000..fbc4374
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_revocation_list/file.rb
@@ -0,0 +1,8 @@
+require 'puppet/indirector/ssl_file'
+require 'puppet/ssl/certificate_revocation_list'
+
+class Puppet::SSL::CertificateRevocationList::File < Puppet::Indirector::SslFile
+  desc "Manage the global certificate revocation list."
+
+  store_at :hostcrl
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_revocation_list/rest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_revocation_list/rest.rb
new file mode 100644
index 0000000..70dc1d4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_revocation_list/rest.rb
@@ -0,0 +1,10 @@
+require 'puppet/ssl/certificate_revocation_list'
+require 'puppet/indirector/rest'
+
+class Puppet::SSL::CertificateRevocationList::Rest < Puppet::Indirector::REST
+  desc "Find and save certificate revocation lists over HTTP via REST."
+
+  use_server_setting(:ca_server)
+  use_port_setting(:ca_port)
+  use_srv_service(:ca)
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_status.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_status.rb
new file mode 100644
index 0000000..47c3adc
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_status.rb
@@ -0,0 +1,4 @@
+require 'puppet/indirector'
+
+class Puppet::Indirector::CertificateStatus
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_status/file.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_status/file.rb
new file mode 100644
index 0000000..8b7fe9a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_status/file.rb
@@ -0,0 +1,91 @@
+require 'puppet'
+require 'puppet/indirector/certificate_status'
+require 'puppet/ssl/certificate'
+require 'puppet/ssl/certificate_authority'
+require 'puppet/ssl/certificate_request'
+require 'puppet/ssl/host'
+require 'puppet/ssl/key'
+
+class Puppet::Indirector::CertificateStatus::File < Puppet::Indirector::Code
+
+  desc "Manipulate certificate status on the local filesystem. Only functional
+    on the CA."
+
+  def ca
+    raise ArgumentError, "This process is not configured as a certificate authority" unless Puppet::SSL::CertificateAuthority.ca?
+    Puppet::SSL::CertificateAuthority.new
+  end
+
+  def destroy(request)
+    deleted = []
+    [
+      Puppet::SSL::Certificate,
+      Puppet::SSL::CertificateRequest,
+      Puppet::SSL::Key,
+    ].collect do |part|
+      if part.indirection.destroy(request.key)
+        deleted << "#{part}"
+      end
+    end
+
+    return "Nothing was deleted" if deleted.empty?
+    "Deleted for #{request.key}: #{deleted.join(", ")}"
+  end
+
+  def save(request)
+    if request.instance.desired_state == "signed"
+      certificate_request = Puppet::SSL::CertificateRequest.indirection.find(request.key)
+      raise Puppet::Error, "Cannot sign for host #{request.key} without a certificate request" unless certificate_request
+      ca.sign(request.key)
+    elsif request.instance.desired_state == "revoked"
+      certificate = Puppet::SSL::Certificate.indirection.find(request.key)
+      raise Puppet::Error, "Cannot revoke host #{request.key} because has it doesn't have a signed certificate" unless certificate
+      ca.revoke(request.key)
+    else
+      raise Puppet::Error, "State #{request.instance.desired_state} invalid; Must specify desired state of 'signed' or 'revoked' for host #{request.key}"
+    end
+
+  end
+
+  def search(request)
+    # Support historic interface wherein users provide classes to filter
+    # the search.  When used via the REST API, the arguments must be
+    # a Symbol or an Array containing Symbol objects.
+    klasses = case request.options[:for]
+    when Class
+      [request.options[:for]]
+    when nil
+      [
+        Puppet::SSL::Certificate,
+        Puppet::SSL::CertificateRequest,
+        Puppet::SSL::Key,
+      ]
+    else
+      [request.options[:for]].flatten.map do |klassname|
+        indirection.class.model(klassname.to_sym)
+      end
+    end
+
+    klasses.collect do |klass|
+      klass.indirection.search(request.key, request.options)
+    end.flatten.collect do |result|
+      result.name
+    end.uniq.collect &Puppet::SSL::Host.method(:new)
+  end
+
+  def find(request)
+    ssl_host = Puppet::SSL::Host.new(request.key)
+    public_key = Puppet::SSL::Certificate.indirection.find(request.key)
+
+    if ssl_host.certificate_request || public_key
+      ssl_host
+    else
+      nil
+    end
+  end
+
+  def validate_key(request)
+    # We only use desired_state from the instance and use request.key
+    # otherwise, so the name does not need to match
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_status/rest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_status/rest.rb
new file mode 100644
index 0000000..e2a4928
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/certificate_status/rest.rb
@@ -0,0 +1,11 @@
+require 'puppet/ssl/host'
+require 'puppet/indirector/rest'
+require 'puppet/indirector/certificate_status'
+
+class Puppet::Indirector::CertificateStatus::Rest < Puppet::Indirector::REST
+  desc "Sign, revoke, search for, or clean certificates & certificate requests over HTTP."
+
+  use_server_setting(:ca_server)
+  use_port_setting(:ca_port)
+  use_srv_service(:ca)
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/code.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/code.rb
new file mode 100644
index 0000000..0c0ee14
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/code.rb
@@ -0,0 +1,6 @@
+require 'puppet/indirector/terminus'
+
+# Do nothing, requiring that the back-end terminus do all
+# of the work.
+class Puppet::Indirector::Code < Puppet::Indirector::Terminus
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/couch.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/couch.rb
new file mode 100644
index 0000000..243d33d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/couch.rb
@@ -0,0 +1,78 @@
+class Puppet::Indirector::Couch < Puppet::Indirector::Terminus
+
+  # The CouchRest database instance. One database instance per Puppet runtime
+  # should be sufficient.
+  #
+  def self.db; @db ||= CouchRest.database! Puppet[:couchdb_url] end
+  def db; self.class.db end
+
+  def find(request)
+    attributes_of get(request)
+  end
+
+  def initialize(*args)
+    raise "Couch terminus not supported without couchrest gem" unless Puppet.features.couchdb?
+    super
+  end
+
+  # Create or update the couchdb document with the request's data hash.
+  #
+  def save(request)
+    raise ArgumentError, "PUT does not accept options" unless request.options.empty?
+    update(request) || create(request)
+  end
+
+  private
+
+  # RKH:TODO: Do not depend on error handling, check if the document exists
+  # first. (Does couchrest support this?)
+  #
+  def get(request)
+    db.get(id_for(request))
+  rescue RestClient::ResourceNotFound
+    Puppet.debug "No couchdb document with id: #{id_for(request)}"
+    return nil
+  end
+
+  def update(request)
+    doc = get request
+    return unless doc
+    doc.merge!(hash_from(request))
+    doc.save
+    true
+  end
+
+  def create(request)
+    db.save_doc hash_from(request)
+  end
+
+  # The attributes hash that is serialized to CouchDB as JSON. It includes
+  # metadata that is used to help aggregate data in couchdb. Add
+  # model-specific attributes in subclasses.
+  #
+  def hash_from(request)
+    {
+      "_id"         => id_for(request),
+      "puppet_type" => document_type_for(request)
+    }
+  end
+
+  # The couchdb response stripped of metadata, used to instantiate the model
+  # instance that is returned by save.
+  #
+  def attributes_of(response)
+    response && response.reject{|k,v| k =~ /^(_rev|puppet_)/ }
+  end
+
+  def document_type_for(request)
+    request.indirection_name
+  end
+
+  # The id used to store the object in couchdb. Implemented in subclasses.
+  #
+  def id_for(request)
+    raise NotImplementedError
+  end
+
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/data_binding/hiera.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/data_binding/hiera.rb
new file mode 100644
index 0000000..e6e609d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/data_binding/hiera.rb
@@ -0,0 +1,7 @@
+require 'puppet/indirector/hiera'
+require 'hiera/scope'
+
+class Puppet::DataBinding::Hiera < Puppet::Indirector::Hiera
+  desc "Retrieve data using Hiera."
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/data_binding/none.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/data_binding/none.rb
new file mode 100644
index 0000000..f0a2fcc
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/data_binding/none.rb
@@ -0,0 +1,5 @@
+require 'puppet/indirector/none'
+
+class Puppet::DataBinding::None < Puppet::Indirector::None
+  desc "A Dummy terminus that always returns nil for data lookups."
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/direct_file_server.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/direct_file_server.rb
new file mode 100644
index 0000000..a043c42
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/direct_file_server.rb
@@ -0,0 +1,19 @@
+require 'puppet/file_serving/terminus_helper'
+require 'puppet/indirector/terminus'
+
+class Puppet::Indirector::DirectFileServer < Puppet::Indirector::Terminus
+
+  include Puppet::FileServing::TerminusHelper
+
+  def find(request)
+    return nil unless Puppet::FileSystem.exist?(request.key)
+    instance = model.new(request.key)
+    instance.links = request.options[:links] if request.options[:links]
+    instance
+  end
+
+  def search(request)
+    return nil unless Puppet::FileSystem.exist?(request.key)
+    path2instances(request, request.key)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/envelope.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/envelope.rb
new file mode 100644
index 0000000..73c33e9
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/envelope.rb
@@ -0,0 +1,11 @@
+require 'puppet/indirector'
+
+# Provide any attributes or functionality needed for indirected
+# instances.
+module Puppet::Indirector::Envelope
+  attr_accessor :expiration
+
+  def expired?
+    expiration and expiration < Time.now
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/errors.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/errors.rb
new file mode 100644
index 0000000..6b599b8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/errors.rb
@@ -0,0 +1,5 @@
+require 'puppet/error'
+
+module Puppet::Indirector
+  class ValidationError < Puppet::Error; end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/exec.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/exec.rb
new file mode 100644
index 0000000..4a65ebe
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/exec.rb
@@ -0,0 +1,38 @@
+require 'puppet/indirector/terminus'
+require 'puppet/util'
+
+class Puppet::Indirector::Exec < Puppet::Indirector::Terminus
+  # Look for external node definitions.
+  def find(request)
+    name = request.key
+    external_command = command
+
+    # Make sure it's an array
+    raise Puppet::DevError, "Exec commands must be an array" unless external_command.is_a?(Array)
+
+    # Make sure it's fully qualified.
+    raise ArgumentError, "You must set the exec parameter to a fully qualified command" unless Puppet::Util.absolute_path?(external_command[0])
+
+    # Add our name to it.
+    external_command << name
+    begin
+      output = execute(external_command, :failonfail => true, :combine => false)
+    rescue Puppet::ExecutionFailure => detail
+      raise Puppet::Error, "Failed to find #{name} via exec: #{detail}", detail.backtrace
+    end
+
+    if output =~ /\A\s*\Z/ # all whitespace
+      Puppet.debug "Empty response for #{name} from #{self.name} terminus"
+      return nil
+    else
+      return output
+    end
+  end
+
+  private
+
+  # Proxy the execution, so it's easier to test.
+  def execute(command, arguments)
+    Puppet::Util::Execution.execute(command,arguments)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/face.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/face.rb
new file mode 100644
index 0000000..10fa27e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/face.rb
@@ -0,0 +1,139 @@
+require 'puppet/face'
+
+class Puppet::Indirector::Face < Puppet::Face
+  option "--terminus TERMINUS" do
+    summary "The indirector terminus to use."
+    description <<-EOT
+      Indirector faces expose indirected subsystems of Puppet. These
+      subsystems are each able to retrieve and alter a specific type of data
+      (with the familiar actions of `find`, `search`, `save`, and `destroy`)
+      from an arbitrary number of pluggable backends. In Puppet parlance,
+      these backends are called terminuses.
+
+      Almost all indirected subsystems have a `rest` terminus that interacts
+      with the puppet master's data. Most of them have additional terminuses
+      for various local data models, which are in turn used by the indirected
+      subsystem on the puppet master whenever it receives a remote request.
+
+      The terminus for an action is often determined by context, but
+      occasionally needs to be set explicitly. See the "Notes" section of this
+      face's manpage for more details.
+    EOT
+
+    before_action do |action, args, options|
+      set_terminus(options[:terminus])
+    end
+
+    after_action do |action, args, options|
+      indirection.reset_terminus_class
+    end
+  end
+
+  def self.indirections
+    Puppet::Indirector::Indirection.instances.collect { |t| t.to_s }.sort
+  end
+
+  def self.terminus_classes(indirection)
+    Puppet::Indirector::Terminus.terminus_classes(indirection.to_sym).collect { |t| t.to_s }.sort
+  end
+
+  def call_indirection_method(method, key, options)
+    begin
+      result = indirection.__send__(method, key, options)
+    rescue => detail
+      message = "Could not call '#{method}' on '#{indirection_name}': #{detail}"
+      Puppet.log_exception(detail, message)
+      raise RuntimeError, message, detail.backtrace
+    end
+
+    return result
+  end
+
+  option "--extra HASH" do
+    summary "Extra arguments to pass to the indirection request"
+    description <<-EOT
+      A terminus can take additional arguments to refine the operation, which
+      are passed as an arbitrary hash to the back-end.  Anything passed as
+      the extra value is just send direct to the back-end.
+    EOT
+    default_to do Hash.new end
+  end
+
+  action :destroy do
+    summary "Delete an object."
+    arguments "<key>"
+    when_invoked {|key, options| call_indirection_method :destroy, key, options[:extra] }
+  end
+
+  action :find do
+    summary "Retrieve an object by name."
+    arguments "<key>"
+    when_invoked {|key, options| call_indirection_method :find, key, options[:extra] }
+  end
+
+  action :save do
+    summary "API only: create or overwrite an object."
+    arguments "<key>"
+    description <<-EOT
+      API only: create or overwrite an object. As the Faces framework does not
+      currently accept data from STDIN, save actions cannot currently be invoked
+      from the command line.
+    EOT
+    when_invoked {|key, options| call_indirection_method :save, key, options[:extra] }
+  end
+
+  action :search do
+    summary "Search for an object or retrieve multiple objects."
+    arguments "<query>"
+    when_invoked {|key, options| call_indirection_method :search, key, options[:extra] }
+  end
+
+  # Print the configuration for the current terminus class
+  action :info do
+    summary "Print the default terminus class for this face."
+    description <<-EOT
+      Prints the default terminus class for this subcommand. Note that different
+      run modes may have different default termini; when in doubt, specify the
+      run mode with the '--run_mode' option.
+    EOT
+
+    when_invoked do |options|
+      if t = indirection.terminus_class
+        "Run mode '#{Puppet.run_mode.name}': #{t}"
+      else
+        "No default terminus class for run mode '#{Puppet.run_mode.name}'"
+      end
+    end
+  end
+
+  attr_accessor :from
+
+  def indirection_name
+    @indirection_name || name.to_sym
+  end
+
+  # Here's your opportunity to override the indirection name.  By default it
+  # will be the same name as the face.
+  def set_indirection_name(name)
+    @indirection_name = name
+  end
+
+  # Return an indirection associated with a face, if one exists;
+  # One usually does.
+  def indirection
+    unless @indirection
+      @indirection = Puppet::Indirector::Indirection.instance(indirection_name)
+      @indirection or raise "Could not find terminus for #{indirection_name}"
+    end
+    @indirection
+  end
+
+  def set_terminus(from)
+    begin
+      indirection.terminus_class = from
+    rescue => detail
+      msg = "Could not set '#{indirection.name}' terminus to '#{from}' (#{detail}); valid terminus types are #{self.class.terminus_classes(indirection.name).join(", ") }"
+      raise detail, msg, detail.backtrace
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/active_record.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/active_record.rb
new file mode 100644
index 0000000..88aa4ef
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/active_record.rb
@@ -0,0 +1,44 @@
+require 'puppet/rails/fact_name'
+require 'puppet/rails/fact_value'
+require 'puppet/rails/host'
+require 'puppet/indirector/active_record'
+
+class Puppet::Node::Facts::ActiveRecord < Puppet::Indirector::ActiveRecord
+  use_ar_model Puppet::Rails::Host
+
+  desc "A component of ActiveRecord storeconfigs and inventory. ActiveRecord-based storeconfigs
+    and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation"
+
+  def initialize
+    Puppet.deprecation_warning "ActiveRecord-based storeconfigs and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation"
+    super
+  end
+
+  # Find the Rails host and pull its facts as a Facts instance.
+  def find(request)
+    return nil unless host = ar_model.find_by_name(request.key, :include => {:fact_values => :fact_name})
+
+    facts = Puppet::Node::Facts.new(host.name)
+    facts.values = host.get_facts_hash.inject({}) do |hash, ary|
+      # Convert all single-member arrays into plain values.
+      param = ary[0]
+      values = ary[1].collect { |v| v.value }
+      values = values[0] if values.length == 1
+      hash[param] = values
+      hash
+    end
+
+    facts
+  end
+
+  # Save the values from a Facts instance as the facts on a Rails Host instance.
+  def save(request)
+    facts = request.instance
+
+    host = ar_model.find_by_name(facts.name) || ar_model.create(:name => facts.name)
+
+    host.merge_facts(facts.values)
+
+    host.save
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/couch.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/couch.rb
new file mode 100644
index 0000000..9cbd0a3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/couch.rb
@@ -0,0 +1,36 @@
+require 'puppet/node/facts'
+require 'puppet/indirector/couch'
+class Puppet::Node::Facts::Couch < Puppet::Indirector::Couch
+
+  desc "DEPRECATED. This terminus will be removed in Puppet 4.0.
+
+    Store facts in CouchDB. This should not be used with the inventory service;
+    it is for more obscure custom integrations. If you are wondering whether you
+    should use it, you shouldn't; use PuppetDB instead."
+  # Return the facts object or nil if there is no document
+  def find(request)
+    doc = super
+    doc ? model.new(doc['_id'], doc['facts']) : nil
+  end
+
+  private
+
+  # Facts values are stored to the document's 'facts' attribute. Hostname is
+  # stored to 'name'
+  #
+  def hash_from(request)
+    super.merge('facts' => request.instance.values)
+  end
+
+  # Facts are stored to the 'node' document.
+  def document_type_for(request)
+    'node'
+  end
+
+  # The id used to store the object in couchdb.
+  def id_for(request)
+    request.key.to_s
+  end
+
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/facter.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/facter.rb
new file mode 100644
index 0000000..7f65e34
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/facter.rb
@@ -0,0 +1,78 @@
+require 'puppet/node/facts'
+require 'puppet/indirector/code'
+
+class Puppet::Node::Facts::Facter < Puppet::Indirector::Code
+  desc "Retrieve facts from Facter.  This provides a somewhat abstract interface
+    between Puppet and Facter.  It's only `somewhat` abstract because it always
+    returns the local host's facts, regardless of what you attempt to find."
+
+  def destroy(facts)
+    raise Puppet::DevError, 'You cannot destroy facts in the code store; it is only used for getting facts from Facter'
+  end
+
+  def save(facts)
+    raise Puppet::DevError, 'You cannot save facts to the code store; it is only used for getting facts from Facter'
+  end
+
+  # Lookup a host's facts up in Facter.
+  def find(request)
+    Facter.reset
+    self.class.setup_external_search_paths(request) if Puppet.features.external_facts?
+    self.class.setup_search_paths(request)
+
+    result = Puppet::Node::Facts.new(request.key, Facter.to_hash)
+    result.add_local_facts
+    Puppet[:stringify_facts] ? result.stringify : result.sanitize
+    result
+  end
+
+  private
+
+  def self.setup_search_paths(request)
+    # Add any per-module fact directories to facter's search path
+    dirs = request.environment.modulepath.collect do |dir|
+      ['lib', 'plugins'].map do |subdirectory|
+        Dir.glob("#{dir}/*/#{subdirectory}/facter")
+      end
+    end.flatten + Puppet[:factpath].split(File::PATH_SEPARATOR)
+
+    dirs = dirs.select do |dir|
+      next false unless FileTest.directory?(dir)
+
+      # Even through we no longer directly load facts in the terminus,
+      # print out each .rb in the facts directory as module
+      # developers may find that information useful for debugging purposes
+      if Puppet::Util::Log.sendlevel?(:info)
+        Puppet.info "Loading facts"
+        Dir.glob("#{dir}/*.rb").each do |file|
+          Puppet.debug "Loading facts from #{file}"
+        end
+      end
+
+      true
+    end
+
+    Facter.search *dirs
+  end
+
+  def self.setup_external_search_paths(request)
+    # Add any per-module external fact directories to facter's external search path
+    dirs = []
+    request.environment.modules.each do |m|
+      if m.has_external_facts?
+        dir = m.plugin_fact_directory
+        Puppet.debug "Loading external facts from #{dir}"
+        dirs << dir
+      end
+    end
+
+    # Add system external fact directory if it exists
+    if FileTest.directory?(Puppet[:pluginfactdest])
+      dir = Puppet[:pluginfactdest]
+      Puppet.debug "Loading external facts from #{dir}"
+      dirs << dir
+    end
+
+    Facter.search_external dirs
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/inventory_active_record.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/inventory_active_record.rb
new file mode 100644
index 0000000..e0e04ba
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/inventory_active_record.rb
@@ -0,0 +1,110 @@
+require 'puppet/rails'
+require 'puppet/rails/inventory_node'
+require 'puppet/rails/inventory_fact'
+require 'puppet/indirector/active_record'
+require 'puppet/util/retryaction'
+
+class Puppet::Node::Facts::InventoryActiveRecord < Puppet::Indirector::ActiveRecord
+
+  desc "Medium-performance fact storage suitable for the inventory service.
+    Most users should use PuppetDB instead. Note: ActiveRecord-based storeconfigs
+    and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation"
+
+  def initialize
+    raise Puppet::Error, "ActiveRecords-based inventory is unsupported with Ruby 2 and Rails 3.0" if RUBY_VERSION[0] == '2'
+    Puppet.deprecation_warning "ActiveRecord-based storeconfigs and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation"
+    super
+  end
+
+  def find(request)
+    node = Puppet::Rails::InventoryNode.find_by_name(request.key)
+    return nil unless node
+    facts = Puppet::Node::Facts.new(node.name, node.facts_to_hash)
+    facts.timestamp = node.timestamp
+    facts
+  end
+
+  def save(request)
+    Puppet::Util::RetryAction.retry_action :retries => 4, :retry_exceptions => {ActiveRecord::StatementInvalid => 'MySQL Error.  Retrying'} do
+      facts = request.instance
+      node = Puppet::Rails::InventoryNode.find_by_name(request.key) || Puppet::Rails::InventoryNode.create(:name => request.key, :timestamp => facts.timestamp)
+      node.timestamp = facts.timestamp
+
+      ActiveRecord::Base.transaction do
+        Puppet::Rails::InventoryFact.delete_all(:node_id => node.id)
+        # We don't want to save internal values as facts, because those are
+        # metadata that belong on the node
+        facts.values.each do |name,value|
+          next if name.to_s =~ /^_/
+          node.facts.build(:name => name, :value => value)
+        end
+        node.save
+      end
+    end
+  end
+
+  def search(request)
+    return [] unless request.options
+    matching_nodes = []
+    fact_filters = Hash.new {|h,k| h[k] = []}
+    meta_filters = Hash.new {|h,k| h[k] = []}
+    request.options.each do |key,value|
+      type, name, operator = key.to_s.split(".")
+      operator ||= "eq"
+      if type == "facts"
+        fact_filters[operator] << [name,value]
+      elsif type == "meta" and name == "timestamp"
+        meta_filters[operator] << [name,value]
+      end
+    end
+
+    matching_nodes = nodes_matching_fact_filters(fact_filters) + nodes_matching_meta_filters(meta_filters)
+
+    # to_a because [].inject == nil
+    matching_nodes.inject {|nodes,this_set| nodes & this_set}.to_a.sort
+  end
+
+  private
+
+  def nodes_matching_fact_filters(fact_filters)
+    node_sets = []
+    fact_filters['eq'].each do |name,value|
+      node_sets << Puppet::Rails::InventoryNode.has_fact_with_value(name,value).map {|node| node.name}
+    end
+    fact_filters['ne'].each do |name,value|
+      node_sets << Puppet::Rails::InventoryNode.has_fact_without_value(name,value).map {|node| node.name}
+    end
+    {
+      'gt' => '>',
+      'lt' => '<',
+      'ge' => '>=',
+      'le' => '<='
+    }.each do |operator_name,operator|
+      fact_filters[operator_name].each do |name,value|
+        facts = Puppet::Rails::InventoryFact.find_by_sql(["SELECT inventory_facts.value, inventory_nodes.name AS node_name
+                                                           FROM inventory_facts INNER JOIN inventory_nodes
+                                                           ON inventory_facts.node_id = inventory_nodes.id
+                                                           WHERE inventory_facts.name = ?", name])
+        node_sets << facts.select {|fact| fact.value.to_f.send(operator, value.to_f)}.map {|fact| fact.node_name}
+      end
+    end
+    node_sets
+  end
+
+  def nodes_matching_meta_filters(meta_filters)
+    node_sets = []
+    {
+      'eq' => '=',
+      'ne' => '!=',
+      'gt' => '>',
+      'lt' => '<',
+      'ge' => '>=',
+      'le' => '<='
+    }.each do |operator_name,operator|
+      meta_filters[operator_name].each do |name,value|
+        node_sets << Puppet::Rails::InventoryNode.find(:all, :select => "name", :conditions => ["timestamp #{operator} ?", value]).map {|node| node.name}
+      end
+    end
+    node_sets
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/inventory_service.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/inventory_service.rb
new file mode 100644
index 0000000..988e577
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/inventory_service.rb
@@ -0,0 +1,20 @@
+require 'puppet/node/facts'
+require 'puppet/indirector/rest'
+
+class Puppet::Node::Facts::InventoryService < Puppet::Indirector::REST
+  desc "Find and save facts about nodes using a remote inventory service."
+  use_server_setting(:inventory_server)
+  use_port_setting(:inventory_port)
+
+  # We don't want failing to upload to the inventory service to cause any
+  # failures, so we just suppress them and warn.
+  def save(request)
+    begin
+      super
+      true
+    rescue => e
+      Puppet.warning "Could not upload facts for #{request.key} to inventory service: #{e.to_s}"
+      false
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/memory.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/memory.rb
new file mode 100644
index 0000000..93682f4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/memory.rb
@@ -0,0 +1,9 @@
+require 'puppet/node/facts'
+require 'puppet/indirector/memory'
+
+class Puppet::Node::Facts::Memory < Puppet::Indirector::Memory
+  desc "Keep track of facts in memory but nowhere else.  This is used for
+    one-time compiles, such as what the stand-alone `puppet` does.
+    To use this terminus, you must load it with the data you want it
+    to contain."
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/network_device.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/network_device.rb
new file mode 100644
index 0000000..2c8da94
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/network_device.rb
@@ -0,0 +1,24 @@
+require 'puppet/node/facts'
+require 'puppet/indirector/code'
+
+class Puppet::Node::Facts::NetworkDevice < Puppet::Indirector::Code
+  desc "Retrieve facts from a network device."
+
+  # Look a device's facts up through the current device.
+  def find(request)
+    result = Puppet::Node::Facts.new(request.key, Puppet::Util::NetworkDevice.current.facts)
+
+    result.add_local_facts
+    Puppet[:stringify_facts] ? result.stringify : result.sanitize
+
+    result
+  end
+
+  def destroy(facts)
+    raise Puppet::DevError, "You cannot destroy facts in the code store; it is only used for getting facts from a remote device"
+  end
+
+  def save(facts)
+    raise Puppet::DevError, "You cannot save facts to the code store; it is only used for getting facts from a remote device"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/rest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/rest.rb
new file mode 100644
index 0000000..e2afa14
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/rest.rb
@@ -0,0 +1,8 @@
+require 'puppet/node/facts'
+require 'puppet/indirector/rest'
+
+class Puppet::Node::Facts::Rest < Puppet::Indirector::REST
+  desc "Find and save facts about nodes over HTTP via REST."
+  use_server_setting(:inventory_server)
+  use_port_setting(:inventory_port)
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/store_configs.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/store_configs.rb
new file mode 100644
index 0000000..247898f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/store_configs.rb
@@ -0,0 +1,8 @@
+require 'puppet/node/facts'
+require 'puppet/indirector/store_configs'
+
+class Puppet::Node::Facts::StoreConfigs < Puppet::Indirector::StoreConfigs
+
+  desc %q{Part of the "storeconfigs" feature. Should not be directly set by end users.}
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/yaml.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/yaml.rb
new file mode 100644
index 0000000..65bd783
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/facts/yaml.rb
@@ -0,0 +1,82 @@
+require 'puppet/node/facts'
+require 'puppet/indirector/yaml'
+
+class Puppet::Node::Facts::Yaml < Puppet::Indirector::Yaml
+  desc "Store client facts as flat files, serialized using YAML, or
+    return deserialized facts from disk."
+
+  def search(request)
+    node_names = []
+    Dir.glob(yaml_dir_path).each do |file|
+      facts = YAML.load_file(file)
+      node_names << facts.name if node_matches?(facts, request.options)
+    end
+    node_names
+  end
+
+  private
+
+  # Return the path to a given node's file.
+  def yaml_dir_path
+    base = Puppet.run_mode.master? ? Puppet[:yamldir] : Puppet[:clientyamldir]
+    File.join(base, 'facts', '*.yaml')
+  end
+
+  def node_matches?(facts, options)
+    options.each do |key, value|
+      type, name, operator = key.to_s.split(".")
+      operator ||= 'eq'
+
+      return false unless node_matches_option?(type, name, operator, value, facts)
+    end
+    return true
+  end
+
+  def node_matches_option?(type, name, operator, value, facts)
+    case type
+    when "meta"
+      case name
+      when "timestamp"
+        compare_timestamp(operator, facts.timestamp, Time.parse(value))
+      end
+    when "facts"
+      compare_facts(operator, facts.values[name], value)
+    end
+  end
+
+  def compare_facts(operator, value1, value2)
+    return false unless value1
+
+    case operator
+    when "eq"
+      value1.to_s == value2.to_s
+    when "le"
+      value1.to_f <= value2.to_f
+    when "ge"
+      value1.to_f >= value2.to_f
+    when "lt"
+      value1.to_f < value2.to_f
+    when "gt"
+      value1.to_f > value2.to_f
+    when "ne"
+      value1.to_s != value2.to_s
+    end
+  end
+
+  def compare_timestamp(operator, value1, value2)
+    case operator
+    when "eq"
+      value1 == value2
+    when "le"
+      value1 <= value2
+    when "ge"
+      value1 >= value2
+    when "lt"
+      value1 < value2
+    when "gt"
+      value1 > value2
+    when "ne"
+      value1 != value2
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_bucket_file/file.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_bucket_file/file.rb
new file mode 100644
index 0000000..a356033
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_bucket_file/file.rb
@@ -0,0 +1,142 @@
+require 'puppet/indirector/code'
+require 'puppet/file_bucket/file'
+require 'puppet/util/checksums'
+require 'fileutils'
+
+module Puppet::FileBucketFile
+  class File < Puppet::Indirector::Code
+    include Puppet::Util::Checksums
+
+    desc "Store files in a directory set based on their checksums."
+
+    def find(request)
+      checksum, files_original_path = request_to_checksum_and_path(request)
+      contents_file = path_for(request.options[:bucket_path], checksum, 'contents')
+      paths_file = path_for(request.options[:bucket_path], checksum, 'paths')
+
+      if Puppet::FileSystem.exist?(contents_file) && matches(paths_file, files_original_path)
+        if request.options[:diff_with]
+          other_contents_file = path_for(request.options[:bucket_path], request.options[:diff_with], 'contents')
+          raise "could not find diff_with #{request.options[:diff_with]}" unless Puppet::FileSystem.exist?(other_contents_file)
+          return `diff #{Puppet::FileSystem.path_string(contents_file).inspect} #{Puppet::FileSystem.path_string(other_contents_file).inspect}`
+        else
+          Puppet.info "FileBucket read #{checksum}"
+          model.new(Puppet::FileSystem.binread(contents_file))
+        end
+      else
+        nil
+      end
+    end
+
+    def head(request)
+      checksum, files_original_path = request_to_checksum_and_path(request)
+      contents_file = path_for(request.options[:bucket_path], checksum, 'contents')
+      paths_file = path_for(request.options[:bucket_path], checksum, 'paths')
+
+      Puppet::FileSystem.exist?(contents_file) && matches(paths_file, files_original_path)
+    end
+
+    def save(request)
+      instance = request.instance
+      _, files_original_path = request_to_checksum_and_path(request)
+      contents_file = path_for(instance.bucket_path, instance.checksum_data, 'contents')
+      paths_file = path_for(instance.bucket_path, instance.checksum_data, 'paths')
+
+      save_to_disk(instance, files_original_path, contents_file, paths_file)
+
+      # don't echo the request content back to the agent
+      model.new('')
+    end
+
+    def validate_key(request)
+      # There are no ACLs on filebucket files so validating key is not important
+    end
+
+    private
+
+    # @param paths_file [Object] Opaque file path
+    # @param files_original_path [String]
+    #
+    def matches(paths_file, files_original_path)
+      Puppet::FileSystem.open(paths_file, 0640, 'a+') do |f|
+        path_match(f, files_original_path)
+      end
+    end
+
+    def path_match(file_handle, files_original_path)
+      return true unless files_original_path # if no path was provided, it's a match
+      file_handle.rewind
+      file_handle.each_line do |line|
+        return true if line.chomp == files_original_path
+      end
+      return false
+    end
+
+    # @param contents_file [Object] Opaque file path
+    # @param paths_file [Object] Opaque file path
+    #
+    def save_to_disk(bucket_file, files_original_path, contents_file, paths_file)
+      Puppet::Util.withumask(0007) do
+        unless Puppet::FileSystem.dir_exist?(paths_file)
+          Puppet::FileSystem.dir_mkpath(paths_file)
+        end
+
+        Puppet::FileSystem.exclusive_open(paths_file, 0640, 'a+') do |f|
+          if Puppet::FileSystem.exist?(contents_file)
+            verify_identical_file!(contents_file, bucket_file)
+            Puppet::FileSystem.touch(contents_file)
+          else
+            Puppet::FileSystem.open(contents_file, 0440, 'wb') do |of|
+              # PUP-1044 writes all of the contents
+              bucket_file.stream() do |src|
+                FileUtils.copy_stream(src, of)
+              end
+            end
+          end
+
+          unless path_match(f, files_original_path)
+            f.seek(0, IO::SEEK_END)
+            f.puts(files_original_path)
+          end
+        end
+      end
+    end
+
+    def request_to_checksum_and_path(request)
+      checksum_type, checksum, path = request.key.split(/\//, 3)
+      if path == '' # Treat "md5/<checksum>/" like "md5/<checksum>"
+        path = nil
+      end
+      raise ArgumentError, "Unsupported checksum type #{checksum_type.inspect}" if checksum_type != Puppet[:digest_algorithm]
+      expected = method(checksum_type + "_hex_length").call
+      raise "Invalid checksum #{checksum.inspect}" if checksum !~ /^[0-9a-f]{#{expected}}$/
+      [checksum, path]
+    end
+
+    # @return [Object] Opaque path as constructed by the Puppet::FileSystem
+    #
+    def path_for(bucket_path, digest, subfile = nil)
+      bucket_path ||= Puppet[:bucketdir]
+
+      dir     = ::File.join(digest[0..7].split(""))
+      basedir = ::File.join(bucket_path, dir, digest)
+
+      Puppet::FileSystem.pathname(subfile ? ::File.join(basedir, subfile) : basedir)
+    end
+
+    # @param contents_file [Object] Opaque file path
+    # @param bucket_file [IO]
+    def verify_identical_file!(contents_file, bucket_file)
+      if bucket_file.size == Puppet::FileSystem.size(contents_file)
+        if bucket_file.stream() {|s| Puppet::FileSystem.compare_stream(contents_file, s) }
+          Puppet.info "FileBucket got a duplicate file #{bucket_file.checksum}"
+          return
+        end
+      end
+
+      # If the contents or sizes don't match, then we've found a conflict.
+      # Unlikely, but quite bad.
+      raise Puppet::FileBucket::BucketError, "Got passed new contents for sum #{bucket_file.checksum}"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_bucket_file/rest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_bucket_file/rest.rb
new file mode 100644
index 0000000..783d435
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_bucket_file/rest.rb
@@ -0,0 +1,8 @@
+require 'puppet/indirector/rest'
+require 'puppet/file_bucket/file'
+
+module Puppet::FileBucketFile
+  class Rest < Puppet::Indirector::REST
+    desc "This is a REST based mechanism to send/retrieve file to/from the filebucket"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_bucket_file/selector.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_bucket_file/selector.rb
new file mode 100644
index 0000000..9b32f05
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_bucket_file/selector.rb
@@ -0,0 +1,53 @@
+require 'puppet/indirector/code'
+
+module Puppet::FileBucketFile
+  class Selector < Puppet::Indirector::Code
+    desc "Select the terminus based on the request"
+
+    def select(request)
+      if request.protocol == 'https'
+        :rest
+      else
+        :file
+      end
+    end
+
+    def get_terminus(request)
+      indirection.terminus(select(request))
+    end
+
+    def head(request)
+      get_terminus(request).head(request)
+    end
+
+    def find(request)
+      get_terminus(request).find(request)
+    end
+
+    def save(request)
+      get_terminus(request).save(request)
+    end
+
+    def search(request)
+      get_terminus(request).search(request)
+    end
+
+    def destroy(request)
+      get_terminus(request).destroy(request)
+    end
+
+    def authorized?(request)
+      terminus = get_terminus(request)
+      if terminus.respond_to?(:authorized?)
+        terminus.authorized?(request)
+      else
+        true
+      end
+    end
+
+    def validate_key(request)
+      get_terminus(request).validate(request)
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_content.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_content.rb
new file mode 100644
index 0000000..5528b62
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_content.rb
@@ -0,0 +1,5 @@
+# A stub class, so our constants work.
+class Puppet::Indirector::FileContent # :nodoc:
+end
+
+require 'puppet/file_serving/content'
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_content/file.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_content/file.rb
new file mode 100644
index 0000000..0bb7106
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_content/file.rb
@@ -0,0 +1,7 @@
+require 'puppet/file_serving/content'
+require 'puppet/indirector/file_content'
+require 'puppet/indirector/direct_file_server'
+
+class Puppet::Indirector::FileContent::File < Puppet::Indirector::DirectFileServer
+  desc "Retrieve file contents from disk."
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_content/file_server.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_content/file_server.rb
new file mode 100644
index 0000000..741c704
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_content/file_server.rb
@@ -0,0 +1,7 @@
+require 'puppet/file_serving/content'
+require 'puppet/indirector/file_content'
+require 'puppet/indirector/file_server'
+
+class Puppet::Indirector::FileContent::FileServer < Puppet::Indirector::FileServer
+  desc "Retrieve file contents using Puppet's fileserver."
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_content/rest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_content/rest.rb
new file mode 100644
index 0000000..1f6bc6e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_content/rest.rb
@@ -0,0 +1,9 @@
+require 'puppet/file_serving/content'
+require 'puppet/indirector/file_content'
+require 'puppet/indirector/rest'
+
+class Puppet::Indirector::FileContent::Rest < Puppet::Indirector::REST
+  desc "Retrieve file contents via a REST HTTP interface."
+
+  use_srv_service(:fileserver)
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_content/selector.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_content/selector.rb
new file mode 100644
index 0000000..32374ed
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_content/selector.rb
@@ -0,0 +1,30 @@
+require 'puppet/file_serving/content'
+require 'puppet/indirector/file_content'
+require 'puppet/indirector/code'
+require 'puppet/file_serving/terminus_selector'
+
+class Puppet::Indirector::FileContent::Selector < Puppet::Indirector::Code
+  desc "Select the terminus based on the request"
+  include Puppet::FileServing::TerminusSelector
+
+  def get_terminus(request)
+    indirection.terminus(select(request))
+  end
+
+  def find(request)
+    get_terminus(request).find(request)
+  end
+
+  def search(request)
+    get_terminus(request).search(request)
+  end
+
+  def authorized?(request)
+    terminus = get_terminus(request)
+    if terminus.respond_to?(:authorized?)
+      terminus.authorized?(request)
+    else
+      true
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_metadata.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_metadata.rb
new file mode 100644
index 0000000..2a90955
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_metadata.rb
@@ -0,0 +1,5 @@
+# A stub class, so our constants work.
+class Puppet::Indirector::FileMetadata # :nodoc:
+end
+
+require 'puppet/file_serving/metadata'
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_metadata/file.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_metadata/file.rb
new file mode 100644
index 0000000..78dfe57
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_metadata/file.rb
@@ -0,0 +1,22 @@
+require 'puppet/file_serving/metadata'
+require 'puppet/indirector/file_metadata'
+require 'puppet/indirector/direct_file_server'
+
+class Puppet::Indirector::FileMetadata::File < Puppet::Indirector::DirectFileServer
+  desc "Retrieve file metadata directly from the local filesystem."
+
+  def find(request)
+    return unless data = super
+    data.collect(request.options[:source_permissions])
+
+    data
+  end
+
+  def search(request)
+    return unless result = super
+
+    result.each { |instance| instance.collect }
+
+    result
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_metadata/file_server.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_metadata/file_server.rb
new file mode 100644
index 0000000..d362299
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_metadata/file_server.rb
@@ -0,0 +1,7 @@
+require 'puppet/file_serving/metadata'
+require 'puppet/indirector/file_metadata'
+require 'puppet/indirector/file_server'
+
+class Puppet::Indirector::FileMetadata::FileServer < Puppet::Indirector::FileServer
+  desc "Retrieve file metadata using Puppet's fileserver."
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_metadata/rest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_metadata/rest.rb
new file mode 100644
index 0000000..b59b452
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_metadata/rest.rb
@@ -0,0 +1,9 @@
+require 'puppet/file_serving/metadata'
+require 'puppet/indirector/file_metadata'
+require 'puppet/indirector/rest'
+
+class Puppet::Indirector::FileMetadata::Rest < Puppet::Indirector::REST
+  desc "Retrieve file metadata via a REST HTTP interface."
+
+  use_srv_service(:fileserver)
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_metadata/selector.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_metadata/selector.rb
new file mode 100644
index 0000000..08e4fbb
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_metadata/selector.rb
@@ -0,0 +1,30 @@
+require 'puppet/file_serving/metadata'
+require 'puppet/indirector/file_metadata'
+require 'puppet/indirector/code'
+require 'puppet/file_serving/terminus_selector'
+
+class Puppet::Indirector::FileMetadata::Selector < Puppet::Indirector::Code
+  desc "Select the terminus based on the request"
+  include Puppet::FileServing::TerminusSelector
+
+  def get_terminus(request)
+    indirection.terminus(select(request))
+  end
+
+  def find(request)
+    get_terminus(request).find(request)
+  end
+
+  def search(request)
+    get_terminus(request).search(request)
+  end
+
+  def authorized?(request)
+    terminus = get_terminus(request)
+    if terminus.respond_to?(:authorized?)
+      terminus.authorized?(request)
+    else
+      true
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_server.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_server.rb
new file mode 100644
index 0000000..389951d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/file_server.rb
@@ -0,0 +1,65 @@
+require 'puppet/file_serving/configuration'
+require 'puppet/file_serving/fileset'
+require 'puppet/file_serving/terminus_helper'
+require 'puppet/indirector/terminus'
+
+# Look files up using the file server.
+class Puppet::Indirector::FileServer < Puppet::Indirector::Terminus
+  include Puppet::FileServing::TerminusHelper
+
+  # Is the client authorized to perform this action?
+  def authorized?(request)
+    return false unless [:find, :search].include?(request.method)
+
+    mount, file_path = configuration.split_path(request)
+
+    # If we're not serving this mount, then access is denied.
+    return false unless mount
+    mount.allowed?(request.node, request.ip)
+  end
+
+  # Find our key using the fileserver.
+  def find(request)
+    mount, relative_path = configuration.split_path(request)
+
+    return nil unless mount
+
+    # The mount checks to see if the file exists, and returns nil
+    # if not.
+    return nil unless path = mount.find(relative_path, request)
+    result = model.new(path)
+    result.links = request.options[:links] if request.options[:links]
+    result.collect(request.options[:source_permissions])
+    result
+  end
+
+  # Search for files.  This returns an array rather than a single
+  # file.
+  def search(request)
+    mount, relative_path = configuration.split_path(request)
+
+    unless mount and paths = mount.search(relative_path, request)
+      Puppet.info "Could not find filesystem info for file '#{request.key}' in environment #{request.environment}"
+      return nil
+    end
+
+    filesets = paths.collect do |path|
+      # Filesets support indirector requests as an options collection
+      Puppet::FileServing::Fileset.new(path, request)
+    end
+
+    Puppet::FileServing::Fileset.merge(*filesets).collect do |file, base_path|
+      inst = model.new(base_path, :relative_path => file)
+      inst.links = request.options[:links] if request.options[:links]
+      inst.collect
+      inst
+    end
+  end
+
+  private
+
+  # Our fileserver configuration, if needed.
+  def configuration
+    Puppet::FileServing::Configuration.configuration
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/hiera.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/hiera.rb
new file mode 100644
index 0000000..a552d56
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/hiera.rb
@@ -0,0 +1,48 @@
+require 'puppet/indirector/terminus'
+require 'hiera/scope'
+
+class Puppet::Indirector::Hiera < Puppet::Indirector::Terminus
+  def initialize(*args)
+    if ! Puppet.features.hiera?
+      raise "Hiera terminus not supported without hiera library"
+    end
+    super
+  end
+
+  if defined?(::Psych::SyntaxError)
+    DataBindingExceptions = [::StandardError, ::Psych::SyntaxError]
+  else
+    DataBindingExceptions = [::StandardError]
+  end
+
+  def find(request)
+    hiera.lookup(request.key, nil, Hiera::Scope.new(request.options[:variables]), nil, nil)
+  rescue *DataBindingExceptions => detail
+    raise Puppet::DataBinding::LookupError.new(detail.message, detail)
+  end
+
+  private
+
+  def self.hiera_config
+    hiera_config = Puppet.settings[:hiera_config]
+    config = {}
+
+    if Puppet::FileSystem.exist?(hiera_config)
+      config = Hiera::Config.load(hiera_config)
+    else
+      Puppet.warning "Config file #{hiera_config} not found, using Hiera defaults"
+    end
+
+    config[:logger] = 'puppet'
+    config
+  end
+
+  def self.hiera
+    @hiera ||= Hiera.new(:config => hiera_config)
+  end
+
+  def hiera
+    self.class.hiera
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/indirection.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/indirection.rb
new file mode 100644
index 0000000..26a3354
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/indirection.rb
@@ -0,0 +1,336 @@
+require 'puppet/util/docs'
+require 'puppet/util/profiler'
+require 'puppet/util/methodhelper'
+require 'puppet/indirector/envelope'
+require 'puppet/indirector/request'
+require 'puppet/util/instrumentation/instrumentable'
+
+# The class that connects functional classes with their different collection
+# back-ends.  Each indirection has a set of associated terminus classes,
+# each of which is a subclass of Puppet::Indirector::Terminus.
+class Puppet::Indirector::Indirection
+  include Puppet::Util::MethodHelper
+  include Puppet::Util::Docs
+  extend Puppet::Util::Instrumentation::Instrumentable
+
+  attr_accessor :name, :model
+  attr_reader :termini
+
+  probe :find, :label => Proc.new { |parent, key, *args| "find_#{parent.name}_#{parent.terminus_class}" }, :data => Proc.new { |parent, key, *args| { :key => key }}
+  probe :save, :label => Proc.new { |parent, key, *args| "save_#{parent.name}_#{parent.terminus_class}" }, :data => Proc.new { |parent, key, *args| { :key => key }}
+  probe :search, :label => Proc.new { |parent, key, *args| "search_#{parent.name}_#{parent.terminus_class}" }, :data => Proc.new { |parent, key, *args| { :key => key }}
+  probe :destroy, :label => Proc.new { |parent, key, *args| "destroy_#{parent.name}_#{parent.terminus_class}" }, :data => Proc.new { |parent, key, *args| { :key => key }}
+
+  @@indirections = []
+
+  # Find an indirection by name.  This is provided so that Terminus classes
+  # can specifically hook up with the indirections they are associated with.
+  def self.instance(name)
+    @@indirections.find { |i| i.name == name }
+  end
+
+  # Return a list of all known indirections.  Used to generate the
+  # reference.
+  def self.instances
+    @@indirections.collect { |i| i.name }
+  end
+
+  # Find an indirected model by name.  This is provided so that Terminus classes
+  # can specifically hook up with the indirections they are associated with.
+  def self.model(name)
+    return nil unless match = @@indirections.find { |i| i.name == name }
+    match.model
+  end
+
+  # Create and return our cache terminus.
+  def cache
+    raise(Puppet::DevError, "Tried to cache when no cache class was set") unless cache_class
+    terminus(cache_class)
+  end
+
+  # Should we use a cache?
+  def cache?
+    cache_class ? true : false
+  end
+
+  attr_reader :cache_class
+  # Define a terminus class to be used for caching.
+  def cache_class=(class_name)
+    validate_terminus_class(class_name) if class_name
+    @cache_class = class_name
+  end
+
+  # This is only used for testing.
+  def delete
+    @@indirections.delete(self) if @@indirections.include?(self)
+  end
+
+  # Set the time-to-live for instances created through this indirection.
+  def ttl=(value)
+    raise ArgumentError, "Indirection TTL must be an integer" unless value.is_a?(Fixnum)
+    @ttl = value
+  end
+
+  # Default to the runinterval for the ttl.
+  def ttl
+    @ttl ||= Puppet[:runinterval]
+  end
+
+  # Calculate the expiration date for a returned instance.
+  def expiration
+    Time.now + ttl
+  end
+
+  # Generate the full doc string.
+  def doc
+    text = ""
+
+    text << scrub(@doc) << "\n\n" if @doc
+
+    text << "* **Indirected Class**: `#{@indirected_class}`\n";
+    if terminus_setting
+      text << "* **Terminus Setting**: #{terminus_setting}\n"
+    end
+
+    text
+  end
+
+  def initialize(model, name, options = {})
+    @model = model
+    @name = name
+    @termini = {}
+
+    @cache_class = nil
+    @terminus_class = nil
+
+    raise(ArgumentError, "Indirection #{@name} is already defined") if @@indirections.find { |i| i.name == @name }
+    @@indirections << self
+
+    @indirected_class = options.delete(:indirected_class)
+    if mod = options[:extend]
+      extend(mod)
+      options.delete(:extend)
+    end
+
+    # This is currently only used for cache_class and terminus_class.
+    set_options(options)
+  end
+
+  # Set up our request object.
+  def request(*args)
+    Puppet::Indirector::Request.new(self.name, *args)
+  end
+
+  # Return the singleton terminus for this indirection.
+  def terminus(terminus_name = nil)
+    # Get the name of the terminus.
+    raise Puppet::DevError, "No terminus specified for #{self.name}; cannot redirect" unless terminus_name ||= terminus_class
+
+    termini[terminus_name] ||= make_terminus(terminus_name)
+  end
+
+  # This can be used to select the terminus class.
+  attr_accessor :terminus_setting
+
+  # Determine the terminus class.
+  def terminus_class
+    unless @terminus_class
+      if setting = self.terminus_setting
+        self.terminus_class = Puppet.settings[setting]
+      else
+        raise Puppet::DevError, "No terminus class nor terminus setting was provided for indirection #{self.name}"
+      end
+    end
+    @terminus_class
+  end
+
+  def reset_terminus_class
+    @terminus_class = nil
+  end
+
+  # Specify the terminus class to use.
+  def terminus_class=(klass)
+    validate_terminus_class(klass)
+    @terminus_class = klass
+  end
+
+  # This is used by terminus_class= and cache=.
+  def validate_terminus_class(terminus_class)
+    raise ArgumentError, "Invalid terminus name #{terminus_class.inspect}" unless terminus_class and terminus_class.to_s != ""
+    unless Puppet::Indirector::Terminus.terminus_class(self.name, terminus_class)
+      raise ArgumentError, "Could not find terminus #{terminus_class} for indirection #{self.name}"
+    end
+  end
+
+  # Expire a cached object, if one is cached.  Note that we don't actually
+  # remove it, we expire it and write it back out to disk.  This way people
+  # can still use the expired object if they want.
+  def expire(key, options={})
+    request = request(:expire, key, nil, options)
+
+    return nil unless cache?
+
+    return nil unless instance = cache.find(request(:find, key, nil, options))
+
+    Puppet.info "Expiring the #{self.name} cache of #{instance.name}"
+
+    # Set an expiration date in the past
+    instance.expiration = Time.now - 60
+
+    cache.save(request(:save, nil, instance, options))
+  end
+
+  def allow_remote_requests?
+    terminus.allow_remote_requests?
+  end
+
+  # Search for an instance in the appropriate terminus, caching the
+  # results if caching is configured..
+  def find(key, options={})
+    request = request(:find, key, nil, options)
+    terminus = prepare(request)
+
+    result = find_in_cache(request)
+    if not result.nil?
+      result
+    elsif request.ignore_terminus?
+      nil
+    else
+      # Otherwise, return the result from the terminus, caching if
+      # appropriate.
+      result = terminus.find(request)
+      if not result.nil?
+        result.expiration ||= self.expiration if result.respond_to?(:expiration)
+        if cache?
+          Puppet.info "Caching #{self.name} for #{request.key}"
+          cache.save request(:save, key, result, options)
+        end
+
+        filtered = result
+        if terminus.respond_to?(:filter)
+          Puppet::Util::Profiler.profile("Filtered result for #{self.name} #{request.key}", [:indirector, :filter, self.name, request.key]) do
+            filtered = terminus.filter(result)
+          end
+        end
+
+        filtered
+      end
+    end
+  end
+
+  # Search for an instance in the appropriate terminus, and return a
+  # boolean indicating whether the instance was found.
+  def head(key, options={})
+    request = request(:head, key, nil, options)
+    terminus = prepare(request)
+
+    # Look in the cache first, then in the terminus.  Force the result
+    # to be a boolean.
+    !!(find_in_cache(request) || terminus.head(request))
+  end
+
+  def find_in_cache(request)
+    # See if our instance is in the cache and up to date.
+    return nil unless cache? and ! request.ignore_cache? and cached = cache.find(request)
+    if cached.expired?
+      Puppet.info "Not using expired #{self.name} for #{request.key} from cache; expired at #{cached.expiration}"
+      return nil
+    end
+
+    Puppet.debug "Using cached #{self.name} for #{request.key}"
+    cached
+  rescue => detail
+    Puppet.log_exception(detail, "Cached #{self.name} for #{request.key} failed: #{detail}")
+    nil
+  end
+
+  # Remove something via the terminus.
+  def destroy(key, options={})
+    request = request(:destroy, key, nil, options)
+    terminus = prepare(request)
+
+    result = terminus.destroy(request)
+
+    if cache? and cache.find(request(:find, key, nil, options))
+      # Reuse the existing request, since it's equivalent.
+      cache.destroy(request)
+    end
+
+    result
+  end
+
+  # Search for more than one instance.  Should always return an array.
+  def search(key, options={})
+    request = request(:search, key, nil, options)
+    terminus = prepare(request)
+
+    if result = terminus.search(request)
+      raise Puppet::DevError, "Search results from terminus #{terminus.name} are not an array" unless result.is_a?(Array)
+      result.each do |instance|
+        next unless instance.respond_to? :expiration
+        instance.expiration ||= self.expiration
+      end
+      return result
+    end
+  end
+
+  # Save the instance in the appropriate terminus.  This method is
+  # normally an instance method on the indirected class.
+  def save(instance, key = nil, options={})
+    request = request(:save, key, instance, options)
+    terminus = prepare(request)
+
+    result = terminus.save(request)
+
+    # If caching is enabled, save our document there
+    cache.save(request) if cache?
+
+    result
+  end
+
+  private
+
+  # Check authorization if there's a hook available; fail if there is one
+  # and it returns false.
+  def check_authorization(request, terminus)
+    # At this point, we're assuming authorization makes no sense without
+    # client information.
+    return unless request.node
+
+    # This is only to authorize via a terminus-specific authorization hook.
+    return unless terminus.respond_to?(:authorized?)
+
+    unless terminus.authorized?(request)
+      msg = "Not authorized to call #{request.method} on #{request}"
+      msg += " with #{request.options.inspect}" unless request.options.empty?
+      raise ArgumentError, msg
+    end
+  end
+
+  # Setup a request, pick the appropriate terminus, check the request's authorization, and return it.
+  def prepare(request)
+    # Pick our terminus.
+    if respond_to?(:select_terminus)
+      unless terminus_name = select_terminus(request)
+        raise ArgumentError, "Could not determine appropriate terminus for #{request}"
+      end
+    else
+      terminus_name = terminus_class
+    end
+
+    dest_terminus = terminus(terminus_name)
+    check_authorization(request, dest_terminus)
+    dest_terminus.validate(request)
+
+    dest_terminus
+  end
+
+  # Create a new terminus instance.
+  def make_terminus(terminus_class)
+    # Load our terminus class.
+    unless klass = Puppet::Indirector::Terminus.terminus_class(self.name, terminus_class)
+      raise ArgumentError, "Could not find terminus #{terminus_class} for indirection #{self.name}"
+    end
+    klass.new
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_data.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_data.rb
new file mode 100644
index 0000000..f1bea33
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_data.rb
@@ -0,0 +1,3 @@
+# A stub class, so our constants work.
+class Puppet::Indirector::InstrumentationData
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_data/local.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_data/local.rb
new file mode 100644
index 0000000..7504a7d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_data/local.rb
@@ -0,0 +1,22 @@
+require 'puppet/indirector/instrumentation_data'
+
+class Puppet::Indirector::InstrumentationData::Local < Puppet::Indirector::Code
+
+  desc "Undocumented."
+
+  def find(request)
+    model.new(request.key)
+  end
+
+  def search(request)
+    raise Puppet::DevError, "You cannot search for instrumentation data"
+  end
+
+  def save(request)
+    raise Puppet::DevError, "You cannot save instrumentation data"
+  end
+
+  def destroy(request)
+    raise Puppet::DevError, "You cannot remove instrumentation data"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_data/rest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_data/rest.rb
new file mode 100644
index 0000000..f926d7d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_data/rest.rb
@@ -0,0 +1,8 @@
+require 'puppet/indirector/rest'
+require 'puppet/indirector/instrumentation_data'
+
+class Puppet::Indirector::InstrumentationData::Rest < Puppet::Indirector::REST
+
+  desc "Undocumented."
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_listener.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_listener.rb
new file mode 100644
index 0000000..6aaa71c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_listener.rb
@@ -0,0 +1,3 @@
+# A stub class, so our constants work.
+class Puppet::Indirector::InstrumentationListener
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_listener/local.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_listener/local.rb
new file mode 100644
index 0000000..947d627
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_listener/local.rb
@@ -0,0 +1,26 @@
+require 'puppet/indirector/instrumentation_listener'
+
+class Puppet::Indirector::InstrumentationListener::Local < Puppet::Indirector::Code
+
+  desc "Undocumented."
+
+  def find(request)
+    Puppet::Util::Instrumentation[request.key]
+  end
+
+  def search(request)
+    Puppet::Util::Instrumentation.listeners
+  end
+
+  def save(request)
+    res = request.instance
+    Puppet::Util::Instrumentation[res.name] = res
+    nil # don't leak the listener
+  end
+
+  def destroy(request)
+    listener = Puppet::Util::Instrumentation[request.key]
+    raise "Listener #{request.key} hasn't been subscribed" unless listener
+    Puppet::Util::Instrumentation.unsubscribe(listener)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_listener/rest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_listener/rest.rb
new file mode 100644
index 0000000..c99ec98
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_listener/rest.rb
@@ -0,0 +1,8 @@
+require 'puppet/indirector/instrumentation_listener'
+require 'puppet/indirector/rest'
+
+class Puppet::Indirector::InstrumentationListener::Rest < Puppet::Indirector::REST
+
+  desc "Undocumented."
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_probe.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_probe.rb
new file mode 100644
index 0000000..3e51444
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_probe.rb
@@ -0,0 +1,3 @@
+# A stub class, so our constants work.
+class Puppet::Indirector::InstrumentationProbe
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_probe/local.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_probe/local.rb
new file mode 100644
index 0000000..8f67115
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_probe/local.rb
@@ -0,0 +1,27 @@
+require 'puppet/indirector/instrumentation_probe'
+require 'puppet/indirector/code'
+require 'puppet/util/instrumentation/indirection_probe'
+
+class Puppet::Indirector::InstrumentationProbe::Local < Puppet::Indirector::Code
+
+  desc "Undocumented."
+
+  def find(request)
+  end
+
+  def search(request)
+    probes = []
+    Puppet::Util::Instrumentation::Instrumentable.each_probe do |probe|
+      probes << Puppet::Util::Instrumentation::IndirectionProbe.new("#{probe.klass}.#{probe.method}")
+    end
+    probes
+  end
+
+  def save(request)
+    Puppet::Util::Instrumentation::Instrumentable.enable_probes
+  end
+
+  def destroy(request)
+    Puppet::Util::Instrumentation::Instrumentable.disable_probes
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_probe/rest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_probe/rest.rb
new file mode 100644
index 0000000..ba5d5e4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/instrumentation_probe/rest.rb
@@ -0,0 +1,8 @@
+require 'puppet/indirector/rest'
+require 'puppet/indirector/instrumentation_probe'
+
+class Puppet::Indirector::InstrumentationProbe::Rest < Puppet::Indirector::REST
+
+  desc "Undocumented."
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/json.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/json.rb
new file mode 100644
index 0000000..3bfd831
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/json.rb
@@ -0,0 +1,76 @@
+require 'puppet/indirector/terminus'
+require 'puppet/util'
+
+# The base class for JSON indirection terminus implementations.
+#
+# This should generally be preferred to the YAML base for any future
+# implementations, since it is ~ three times faster despite being pure Ruby
+# rather than a C implementation.
+class Puppet::Indirector::JSON < Puppet::Indirector::Terminus
+  def find(request)
+    load_json_from_file(path(request.key), request.key)
+  end
+
+  def save(request)
+    filename = path(request.key)
+    FileUtils.mkdir_p(File.dirname(filename))
+
+    Puppet::Util.replace_file(filename, 0660) {|f| f.print to_json(request.instance) }
+  rescue TypeError => detail
+    Puppet.log_exception "Could not save #{self.name} #{request.key}: #{detail}"
+  end
+
+  def destroy(request)
+    Puppet::FileSystem.unlink(path(request.key))
+  rescue => detail
+    unless detail.is_a? Errno::ENOENT
+      raise Puppet::Error, "Could not destroy #{self.name} #{request.key}: #{detail}", detail.backtrace
+    end
+    1                           # emulate success...
+  end
+
+  def search(request)
+    Dir.glob(path(request.key)).collect do |file|
+      load_json_from_file(file, request.key)
+    end
+  end
+
+  # Return the path to a given node's file.
+  def path(name, ext = '.json')
+    if name =~ Puppet::Indirector::BadNameRegexp then
+      Puppet.crit("directory traversal detected in #{self.class}: #{name.inspect}")
+      raise ArgumentError, "invalid key"
+    end
+
+    base = Puppet.run_mode.master? ? Puppet[:server_datadir] : Puppet[:client_datadir]
+    File.join(base, self.class.indirection_name.to_s, name.to_s + ext)
+  end
+
+  private
+
+  def load_json_from_file(file, key)
+    json = nil
+
+    begin
+      json = File.read(file)
+    rescue Errno::ENOENT
+      return nil
+    rescue => detail
+      raise Puppet::Error, "Could not read JSON data for #{indirection.name} #{key}: #{detail}", detail.backtrace
+    end
+
+    begin
+      return from_json(json)
+    rescue => detail
+      raise Puppet::Error, "Could not parse JSON data for #{indirection.name} #{key}: #{detail}", detail.backtrace
+    end
+  end
+
+  def from_json(text)
+    model.convert_from('pson', text)
+  end
+
+  def to_json(object)
+    object.render('pson')
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/key/ca.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/key/ca.rb
new file mode 100644
index 0000000..d2c3482
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/key/ca.rb
@@ -0,0 +1,16 @@
+require 'puppet/indirector/ssl_file'
+require 'puppet/ssl/key'
+
+class Puppet::SSL::Key::Ca < Puppet::Indirector::SslFile
+  desc "Manage the CA's private on disk.  This terminus *only* works
+    with the CA key, because that's the only key that the CA ever interacts
+    with."
+
+  store_in :privatekeydir
+
+  store_ca_at :cakey
+
+  def allow_remote_requests?
+    false
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/key/disabled_ca.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/key/disabled_ca.rb
new file mode 100644
index 0000000..7b276b8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/key/disabled_ca.rb
@@ -0,0 +1,22 @@
+require 'puppet/indirector/code'
+require 'puppet/ssl/key'
+
+class Puppet::SSL::Key::DisabledCa < Puppet::Indirector::Code
+  desc "Manage the CA private key, but reject any remote access
+to the SSL data store. Used when a master has an explicitly disabled CA to
+prevent clients getting confusing 'success' behaviour."
+
+  def initialize
+    @file = Puppet::SSL::Key.indirection.terminus(:file)
+  end
+
+  [:find, :head, :search, :save, :destroy].each do |name|
+    define_method(name) do |request|
+      if request.remote?
+        raise Puppet::Error, "this master is not a CA"
+      else
+        @file.send(name, request)
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/key/file.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/key/file.rb
new file mode 100644
index 0000000..81c4282
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/key/file.rb
@@ -0,0 +1,49 @@
+require 'puppet/indirector/ssl_file'
+require 'puppet/ssl/key'
+
+class Puppet::SSL::Key::File < Puppet::Indirector::SslFile
+  desc "Manage SSL private and public keys on disk."
+
+  store_in :privatekeydir
+  store_ca_at :cakey
+
+  def allow_remote_requests?
+    false
+  end
+
+  # Where should we store the public key?
+  def public_key_path(name)
+    if ca?(name)
+      Puppet[:capub]
+    else
+      File.join(Puppet[:publickeydir], name.to_s + ".pem")
+    end
+  end
+
+  # Remove the public key, in addition to the private key
+  def destroy(request)
+    super
+
+    key_path = Puppet::FileSystem.pathname(public_key_path(request.key))
+    return unless Puppet::FileSystem.exist?(key_path)
+
+    begin
+      Puppet::FileSystem.unlink(key_path)
+    rescue => detail
+      raise Puppet::Error, "Could not remove #{request.key} public key: #{detail}", detail.backtrace
+    end
+  end
+
+  # Save the public key, in addition to the private key.
+  def save(request)
+    super
+
+    begin
+      Puppet.settings.setting(:publickeydir).open_file(public_key_path(request.key), 'w') do |f|
+        f.print request.instance.content.public_key.to_pem
+      end
+    rescue => detail
+      raise Puppet::Error, "Could not write #{request.key}: #{detail}", detail.backtrace
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/key/memory.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/key/memory.rb
new file mode 100644
index 0000000..527863e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/key/memory.rb
@@ -0,0 +1,6 @@
+require 'puppet/ssl/key'
+require 'puppet/indirector/memory'
+
+class Puppet::SSL::Key::Memory < Puppet::Indirector::Memory
+  desc "Store keys in memory. This is used for testing puppet."
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/ldap.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/ldap.rb
new file mode 100644
index 0000000..293c05e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/ldap.rb
@@ -0,0 +1,79 @@
+require 'puppet/indirector/terminus'
+require 'puppet/util/ldap/connection'
+
+class Puppet::Indirector::Ldap < Puppet::Indirector::Terminus
+  # Perform our ldap search and process the result.
+  def find(request)
+    ldapsearch(search_filter(request.key)) { |entry| return process(entry) } || nil
+  end
+
+  # Process the found entry.  We assume that we don't just want the
+  # ldap object.
+  def process(entry)
+    raise Puppet::DevError, "The 'process' method has not been overridden for the LDAP terminus for #{self.name}"
+  end
+
+  # Default to all attributes.
+  def search_attributes
+    nil
+  end
+
+  def search_base
+    Puppet[:ldapbase]
+  end
+
+  # The ldap search filter to use.
+  def search_filter(name)
+    raise Puppet::DevError, "No search string set for LDAP terminus for #{self.name}"
+  end
+
+  # Find the ldap node, return the class list and parent node specially,
+  # and everything else in a parameter hash.
+  def ldapsearch(filter)
+    raise ArgumentError.new("You must pass a block to ldapsearch") unless block_given?
+
+    found = false
+    count = 0
+
+    begin
+      connection.search(search_base, 2, filter, search_attributes) do |entry|
+        found = true
+        yield entry
+      end
+    rescue SystemExit,NoMemoryError
+      raise
+    rescue Exception => detail
+      if count == 0
+        # Try reconnecting to ldap if we get an exception and we haven't yet retried.
+        count += 1
+        @connection = nil
+        Puppet.warning "Retrying LDAP connection"
+        retry
+      else
+        error = Puppet::Error.new("LDAP Search failed")
+        error.set_backtrace(detail.backtrace)
+        raise error
+      end
+    end
+
+    found
+  end
+
+  # Create an ldap connection.
+  def connection
+    unless @connection
+      raise Puppet::Error, "Could not set up LDAP Connection: Missing ruby/ldap libraries" unless Puppet.features.ldap?
+      begin
+        conn = Puppet::Util::Ldap::Connection.instance
+        conn.start
+        @connection = conn.connection
+      rescue => detail
+        message = "Could not connect to LDAP: #{detail}"
+        Puppet.log_exception(detail, message)
+        raise Puppet::Error, message, detail.backtrace
+      end
+    end
+
+    @connection
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/memory.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/memory.rb
new file mode 100644
index 0000000..c16b7e9
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/memory.rb
@@ -0,0 +1,34 @@
+require 'puppet/indirector/terminus'
+
+# Manage a memory-cached list of instances.
+class Puppet::Indirector::Memory < Puppet::Indirector::Terminus
+  def initialize
+    clear
+  end
+
+  def clear
+    @instances = {}
+  end
+
+  def destroy(request)
+    raise ArgumentError.new("Could not find #{request.key} to destroy") unless @instances.include?(request.key)
+    @instances.delete(request.key)
+  end
+
+  def find(request)
+    @instances[request.key]
+  end
+
+  def search(request)
+    found_keys = @instances.keys.find_all { |key| key.include?(request.key) }
+    found_keys.collect { |key| @instances[key] }
+  end
+
+  def head(request)
+    not find(request).nil?
+  end
+
+  def save(request)
+    @instances[request.key] = request.instance
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/msgpack.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/msgpack.rb
new file mode 100644
index 0000000..bcc6286
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/msgpack.rb
@@ -0,0 +1,82 @@
+require 'puppet/indirector/terminus'
+require 'puppet/util'
+
+# The base class for MessagePack indirection terminus implementations.
+#
+# This should generally be preferred to the PSON base for any future
+# implementations, since it is ~ 30 times faster
+class Puppet::Indirector::Msgpack < Puppet::Indirector::Terminus
+  def initialize(*args)
+    if ! Puppet.features.msgpack?
+      raise "MessagePack terminus not supported without msgpack library"
+    end
+    super
+  end
+
+  def find(request)
+    load_msgpack_from_file(path(request.key), request.key)
+  end
+
+  def save(request)
+    filename = path(request.key)
+    FileUtils.mkdir_p(File.dirname(filename))
+
+    Puppet::Util.replace_file(filename, 0660) {|f| f.print to_msgpack(request.instance) }
+  rescue TypeError => detail
+    Puppet.log_exception "Could not save #{self.name} #{request.key}: #{detail}"
+  end
+
+  def destroy(request)
+    Puppet::FileSystem.unlink(path(request.key))
+  rescue => detail
+    unless detail.is_a? Errno::ENOENT
+      raise Puppet::Error, "Could not destroy #{self.name} #{request.key}: #{detail}", detail.backtrace
+    end
+    1                           # emulate success...
+  end
+
+  def search(request)
+    Dir.glob(path(request.key)).collect do |file|
+      load_msgpack_from_file(file, request.key)
+    end
+  end
+
+  # Return the path to a given node's file.
+  def path(name, ext = '.msgpack')
+    if name =~ Puppet::Indirector::BadNameRegexp then
+      Puppet.crit("directory traversal detected in #{self.class}: #{name.inspect}")
+      raise ArgumentError, "invalid key"
+    end
+
+    base = Puppet.run_mode.master? ? Puppet[:server_datadir] : Puppet[:client_datadir]
+    File.join(base, self.class.indirection_name.to_s, name.to_s + ext)
+  end
+
+  private
+
+  def load_msgpack_from_file(file, key)
+    msgpack = nil
+
+    begin
+      msgpack = File.read(file)
+    rescue Errno::ENOENT
+      return nil
+    rescue => detail
+      raise Puppet::Error, "Could not read MessagePack data for #{indirection.name} #{key}: #{detail}", detail.backtrace
+    end
+
+    begin
+      return from_msgpack(msgpack)
+    rescue => detail
+      raise Puppet::Error, "Could not parse MessagePack data for #{indirection.name} #{key}: #{detail}", detail.backtrace
+    end
+  end
+
+  def from_msgpack(text)
+    model.convert_from('msgpack', text)
+  end
+
+  def to_msgpack(object)
+    object.render('msgpack')
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/active_record.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/active_record.rb
new file mode 100644
index 0000000..0741906
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/active_record.rb
@@ -0,0 +1,22 @@
+require 'puppet/rails/host'
+require 'puppet/indirector/active_record'
+require 'puppet/node'
+
+class Puppet::Node::ActiveRecord < Puppet::Indirector::ActiveRecord
+  use_ar_model Puppet::Rails::Host
+
+  desc "A component of ActiveRecord storeconfigs. ActiveRecord-based storeconfigs
+    and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation"
+
+  def initialize
+    Puppet.deprecation_warning "ActiveRecord-based storeconfigs and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation"
+    super
+  end
+
+  def find(request)
+    node = super
+    node.environment = request.environment
+    node.fact_merge
+    node
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/exec.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/exec.rb
new file mode 100644
index 0000000..2535ffa
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/exec.rb
@@ -0,0 +1,69 @@
+require 'puppet/node'
+require 'puppet/indirector/exec'
+
+class Puppet::Node::Exec < Puppet::Indirector::Exec
+  desc "Call an external program to get node information.  See
+  the [External Nodes](http://docs.puppetlabs.com/guides/external_nodes.html) page for more information."
+  include Puppet::Util
+
+  def command
+    command = Puppet[:external_nodes]
+    raise ArgumentError, "You must set the 'external_nodes' parameter to use the external node terminus" unless command != "none"
+    command.split
+  end
+
+  # Look for external node definitions.
+  def find(request)
+    output = super or return nil
+
+    # Translate the output to ruby.
+    result = translate(request.key, output)
+
+    # Set the requested environment if it wasn't overridden
+    # If we don't do this it gets set to the local default
+    result[:environment] ||= request.environment
+
+    create_node(request.key, result)
+  end
+
+  private
+
+  # Proxy the execution, so it's easier to test.
+  def execute(command, arguments)
+    Puppet::Util::Execution.execute(command,arguments)
+  end
+
+  # Turn our outputted objects into a Puppet::Node instance.
+  def create_node(name, result)
+    node = Puppet::Node.new(name)
+    set = false
+    [:parameters, :classes, :environment].each do |param|
+      if value = result[param]
+        node.send(param.to_s + "=", value)
+        set = true
+      end
+    end
+
+    node.fact_merge
+    node
+  end
+
+  # Translate the yaml string into Ruby objects.
+  def translate(name, output)
+    YAML.load(output).inject({}) do |hash, data|
+      case data[0]
+      when String
+        hash[data[0].intern] = data[1]
+      when Symbol
+        hash[data[0]] = data[1]
+      else
+        raise Puppet::Error, "key is a #{data[0].class}, not a string or symbol"
+      end
+
+      hash
+    end
+
+  rescue => detail
+      raise Puppet::Error, "Could not load external node results for #{name}: #{detail}", detail.backtrace
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/ldap.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/ldap.rb
new file mode 100644
index 0000000..37f9c22
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/ldap.rb
@@ -0,0 +1,257 @@
+require 'puppet/node'
+require 'puppet/indirector/ldap'
+
+class Puppet::Node::Ldap < Puppet::Indirector::Ldap
+  desc "Search in LDAP for node configuration information.  See
+  the [LDAP Nodes](http://docs.puppetlabs.com/guides/ldap_nodes.html) page for more information.  This will first
+  search for whatever the certificate name is, then (if that name
+  contains a `.`) for the short name, then `default`."
+
+  # The attributes that Puppet class information is stored in.
+  def class_attributes
+    Puppet[:ldapclassattrs].split(/\s*,\s*/)
+  end
+
+  # Separate this out so it's relatively atomic.  It's tempting to call
+  # process instead of name2hash() here, but it ends up being
+  # difficult to test because all exceptions get caught by ldapsearch.
+  # LAK:NOTE Unfortunately, the ldap support is too stupid to throw anything
+  # but LDAP::ResultError, even on bad connections, so we are rough-handed
+  # with our error handling.
+  def name2hash(name)
+    info = nil
+    ldapsearch(search_filter(name)) { |entry| info = entry2hash(entry) }
+    info
+  end
+
+  # Look for our node in ldap.
+  def find(request)
+    names = [request.key]
+    names << request.key.sub(/\..+/, '') if request.key.include?(".") # we assume it's an fqdn
+    names << "default"
+
+    node = nil
+    names.each do |name|
+      next unless info = name2hash(name)
+
+      merge_parent(info) if info[:parent]
+      info[:environment] ||= request.environment
+      node = info2node(request.key, info)
+      break
+    end
+
+    node
+  end
+
+  # Find more than one node.  LAK:NOTE This is a bit of a clumsy API, because the 'search'
+  # method currently *requires* a key.  It seems appropriate in some cases but not others,
+  # and I don't really know how to get rid of it as a requirement but allow it when desired.
+  def search(request)
+    if classes = request.options[:class]
+      classes = [classes] unless classes.is_a?(Array)
+      filter = "(&(objectclass=puppetClient)(puppetclass=" + classes.join(")(puppetclass=") + "))"
+    else
+      filter = "(objectclass=puppetClient)"
+    end
+
+    infos = []
+    ldapsearch(filter) { |entry| infos << entry2hash(entry, request.options[:fqdn]) }
+
+    return infos.collect do |info|
+      merge_parent(info) if info[:parent]
+      info[:environment] ||= request.environment
+      info2node(info[:name], info)
+    end
+  end
+
+  # The parent attribute, if we have one.
+  def parent_attribute
+    if pattr = Puppet[:ldapparentattr] and ! pattr.empty?
+      pattr
+    else
+      nil
+    end
+  end
+
+  # The attributes that Puppet will stack as array over the full
+  # hierarchy.
+  def stacked_attributes(dummy_argument=:work_arround_for_ruby_GC_bug)
+    Puppet[:ldapstackedattrs].split(/\s*,\s*/)
+  end
+
+  # Convert the found entry into a simple hash.
+  def entry2hash(entry, fqdn = false)
+    result = {}
+
+    cn  = entry.dn[     /cn\s*=\s*([^,\s]+)/i,1]
+    dcs = entry.dn.scan(/dc\s*=\s*([^,\s]+)/i)
+    result[:name]    = fqdn ? ([cn]+dcs).join('.') : cn
+    result[:parent] = get_parent_from_entry(entry) if parent_attribute
+    result[:classes] = get_classes_from_entry(entry)
+    result[:stacked] = get_stacked_values_from_entry(entry)
+    result[:parameters] = get_parameters_from_entry(entry)
+
+    result[:environment] = result[:parameters]["environment"] if result[:parameters]["environment"]
+
+    result[:stacked_parameters] = {}
+
+    if result[:stacked]
+      result[:stacked].each do |value|
+        param = value.split('=', 2)
+        result[:stacked_parameters][param[0]] = param[1]
+      end
+    end
+
+    if result[:stacked_parameters]
+      result[:stacked_parameters].each do |param, value|
+        result[:parameters][param] = value unless result[:parameters].include?(param)
+      end
+    end
+
+    result[:parameters] = convert_parameters(result[:parameters])
+
+    result
+  end
+
+  # Default to all attributes.
+  def search_attributes
+    ldapattrs = Puppet[:ldapattrs]
+
+    # results in everything getting returned
+    return nil if ldapattrs == "all"
+
+    search_attrs = class_attributes + ldapattrs.split(/\s*,\s*/)
+
+    if pattr = parent_attribute
+      search_attrs << pattr
+    end
+
+    search_attrs
+  end
+
+  # The ldap search filter to use.
+  def search_filter(name)
+    filter = Puppet[:ldapstring]
+
+    if filter.include? "%s"
+      # Don't replace the string in-line, since that would hard-code our node
+      # info.
+      filter = filter.gsub('%s', name)
+    end
+    filter
+  end
+
+  private
+
+  # Add our hash of ldap information to the node instance.
+  def add_to_node(node, information)
+    node.classes = information[:classes].uniq unless information[:classes].nil? or information[:classes].empty?
+    node.parameters = information[:parameters] unless information[:parameters].nil? or information[:parameters].empty?
+    node.environment = information[:environment] if information[:environment]
+  end
+
+  def convert_parameters(parameters)
+    result = {}
+    parameters.each do |param, value|
+      if value.is_a?(Array)
+        result[param] = value.collect { |v| convert(v) }
+      else
+        result[param] = convert(value)
+      end
+    end
+    result
+  end
+
+  # Convert any values if necessary.
+  def convert(value)
+    case value
+    when Integer, Fixnum, Bignum; value
+    when "true"; true
+    when "false"; false
+    else
+      value
+    end
+  end
+
+  # Find information for our parent and merge it into the current info.
+  def find_and_merge_parent(parent, information)
+    parent_info = name2hash(parent) || raise(Puppet::Error.new("Could not find parent node '#{parent}'"))
+    information[:classes] += parent_info[:classes]
+    parent_info[:parameters].each do |param, value|
+      # Specifically test for whether it's set, so false values are handled correctly.
+      information[:parameters][param] = value unless information[:parameters].include?(param)
+    end
+    information[:environment] ||= parent_info[:environment]
+    parent_info[:parent]
+  end
+
+  # Take a name and a hash, and return a node instance.
+  def info2node(name, info)
+    node = Puppet::Node.new(name)
+
+    add_to_node(node, info)
+
+    node.fact_merge
+
+    node
+  end
+
+  def merge_parent(info)
+    parent = info[:parent]
+
+    # Preload the parent array with the node name.
+    parents = [info[:name]]
+    while parent
+      raise ArgumentError, "Found loop in LDAP node parents; #{parent} appears twice" if parents.include?(parent)
+      parents << parent
+      parent = find_and_merge_parent(parent, info)
+    end
+
+    info
+  end
+
+  def get_classes_from_entry(entry)
+    result = class_attributes.inject([]) do |array, attr|
+      if values = entry.vals(attr)
+        values.each do |v| array << v end
+      end
+      array
+    end
+    result.uniq
+  end
+
+  def get_parameters_from_entry(entry)
+    stacked_params = stacked_attributes
+    entry.to_hash.inject({}) do |hash, ary|
+      unless stacked_params.include?(ary[0]) # don't add our stacked parameters to the main param list
+        if ary[1].length == 1
+          hash[ary[0]] = ary[1].shift
+        else
+          hash[ary[0]] = ary[1]
+        end
+      end
+      hash
+    end
+  end
+
+  def get_parent_from_entry(entry)
+    pattr = parent_attribute
+
+    return nil unless values = entry.vals(pattr)
+
+    if values.length > 1
+      raise Puppet::Error,
+        "Node entry #{entry.dn} specifies more than one parent: #{values.inspect}"
+    end
+    return(values.empty? ? nil : values.shift)
+  end
+
+  def get_stacked_values_from_entry(entry)
+    stacked_attributes.inject([]) do |result, attr|
+      if values = entry.vals(attr)
+        result += values
+      end
+      result
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/memory.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/memory.rb
new file mode 100644
index 0000000..029926a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/memory.rb
@@ -0,0 +1,10 @@
+require 'puppet/node'
+require 'puppet/indirector/memory'
+
+class Puppet::Node::Memory < Puppet::Indirector::Memory
+  desc "Keep track of nodes in memory but nowhere else.  This is used for
+    one-time compiles, such as what the stand-alone `puppet` does.
+    To use this terminus, you must load it with the data you want it
+    to contain; it is only useful for developers and should generally not
+    be chosen by a normal user."
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/msgpack.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/msgpack.rb
new file mode 100644
index 0000000..bf38a70
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/msgpack.rb
@@ -0,0 +1,7 @@
+require 'puppet/node'
+require 'puppet/indirector/msgpack'
+
+class Puppet::Node::Msgpack < Puppet::Indirector::Msgpack
+  desc "Store node information as flat files, serialized using MessagePack,
+    or deserialize stored MessagePack nodes."
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/plain.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/plain.rb
new file mode 100644
index 0000000..e5d9d34
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/plain.rb
@@ -0,0 +1,20 @@
+require 'puppet/node'
+require 'puppet/indirector/plain'
+
+class Puppet::Node::Plain < Puppet::Indirector::Plain
+  desc "Always return an empty node object. Assumes you keep track of nodes
+    in flat file manifests.  You should use it when you don't have some other,
+    functional source you want to use, as the compiler will not work without a
+    valid node terminus.
+
+    Note that class is responsible for merging the node's facts into the
+    node instance before it is returned."
+
+  # Just return an empty node.
+  def find(request)
+    node = super
+    node.environment = request.environment
+    node.fact_merge
+    node
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/rest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/rest.rb
new file mode 100644
index 0000000..565c190
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/rest.rb
@@ -0,0 +1,7 @@
+require 'puppet/node'
+require 'puppet/indirector/rest'
+
+class Puppet::Node::Rest < Puppet::Indirector::REST
+  desc "Get a node via REST. Puppet agent uses this to allow the puppet master
+    to override its environment."
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/store_configs.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/store_configs.rb
new file mode 100644
index 0000000..62651db
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/store_configs.rb
@@ -0,0 +1,8 @@
+require 'puppet/indirector/store_configs'
+require 'puppet/node'
+
+class Puppet::Node::StoreConfigs < Puppet::Indirector::StoreConfigs
+
+  desc %q{Part of the "storeconfigs" feature. Should not be directly set by end users.}
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/write_only_yaml.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/write_only_yaml.rb
new file mode 100644
index 0000000..3f97e72
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/write_only_yaml.rb
@@ -0,0 +1,32 @@
+require 'puppet/node'
+require 'puppet/indirector/yaml'
+
+# This is a WriteOnlyYaml terminus that exists only for the purpose of being able to write
+# node cache data that later can be read by the YAML terminus.
+# The use case this supports is to make it possible to search among the "current nodes"
+# when Puppet DB (recommended) or other central storage of information is not available.
+#
+# @see puppet issue 16753
+# @see Puppet::Application::Master#setup_node_cache
+# @api private
+#
+class Puppet::Node::WriteOnlyYaml < Puppet::Indirector::Yaml
+  desc "Store node information as flat files, serialized using YAML,
+    does not deserialize (write only)."
+
+  # Overridden to always return nil. This is a write only terminus.
+  # @param [Object] request Ignored.
+  # @return [nil] This implementation always return nil'
+  # @api public
+  def find(request)
+    nil
+  end
+
+  # Overridden to always return nil. This is a write only terminus.
+  # @param [Object] request Ignored.
+  # @return [nil] This implementation always return nil
+  # @api public
+  def search(request)
+    nil
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/yaml.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/yaml.rb
new file mode 100644
index 0000000..b72abab
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/node/yaml.rb
@@ -0,0 +1,22 @@
+require 'puppet/node'
+require 'puppet/indirector/yaml'
+
+class Puppet::Node::Yaml < Puppet::Indirector::Yaml
+  desc "Store node information as flat files, serialized using YAML,
+    or deserialize stored YAML nodes."
+
+  protected
+
+  def fix(object)
+    # This looks very strange because when the object is read from disk the
+    # environment is a string and by assigning it back onto the object it gets
+    # converted to a Puppet::Node::Environment.
+    #
+    # The Puppet::Node class can't handle this itself because we are loading
+    # with just straight YAML, which doesn't give the object a chance to modify
+    # things as it is loaded. Instead YAML simply sets the instance variable
+    # and leaves it at that.
+    object.environment = object.environment
+    object
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/none.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/none.rb
new file mode 100644
index 0000000..69c888f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/none.rb
@@ -0,0 +1,9 @@
+require 'puppet/indirector/terminus'
+
+# A none terminus type, meant to always return nil
+class Puppet::Indirector::None < Puppet::Indirector::Terminus
+  def find(request)
+    return nil
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/plain.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/plain.rb
new file mode 100644
index 0000000..e11fc68
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/plain.rb
@@ -0,0 +1,9 @@
+require 'puppet/indirector/terminus'
+
+# An empty terminus type, meant to just return empty objects.
+class Puppet::Indirector::Plain < Puppet::Indirector::Terminus
+  # Just return nothing.
+  def find(request)
+    indirection.model.new(request.key)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/queue.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/queue.rb
new file mode 100644
index 0000000..1d5776b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/queue.rb
@@ -0,0 +1,80 @@
+require 'puppet/indirector/terminus'
+require 'puppet/util/queue'
+require 'puppet/util'
+
+# Implements the <tt>:queue</tt> abstract indirector terminus type, for storing
+# model instances to a message queue, presumably for the purpose of out-of-process
+# handling of changes related to the model.
+#
+# Relies upon Puppet::Util::Queue for registry and client object management,
+# and specifies a default queue type of <tt>:stomp</tt>, appropriate for use with a variety of message brokers.
+#
+# It's up to the queue client type to instantiate itself correctly based on Puppet configuration information.
+#
+# A single queue client is maintained for the abstract terminus, meaning that you can only use one type
+# of queue client, one message broker solution, etc., with the indirection mechanism.
+#
+# Per-indirection queues are assumed, based on the indirection name.  If the <tt>:catalog</tt> indirection makes
+# use of this <tt>:queue</tt> terminus, queue operations work against the "catalog" queue.  It is up to the queue
+# client library to handle queue creation as necessary (for a number of popular queuing solutions, queue
+# creation is automatic and not a concern).
+class Puppet::Indirector::Queue < Puppet::Indirector::Terminus
+  extend ::Puppet::Util::Queue
+  include Puppet::Util
+
+  def initialize(*args)
+    super
+  end
+
+  # Queue has no idiomatic "find"
+  def find(request)
+    nil
+  end
+
+  # Place the request on the queue
+  def save(request)
+      result = nil
+      benchmark :info, "Queued #{indirection.name} for #{request.key}" do
+        result = client.publish_message(queue, request.instance.render(:pson))
+      end
+      result
+  rescue => detail
+      msg = "Could not write #{request.key} to queue: #{detail}\nInstance::#{request.instance}\n client : #{client}"
+      raise Puppet::Error, msg, detail.backtrace
+  end
+
+  def self.queue
+    indirection_name
+  end
+
+  def queue
+    self.class.queue
+  end
+
+  # Returns the singleton queue client object.
+  def client
+    self.class.client
+  end
+
+  # converts the _message_ from deserialized format to an actual model instance.
+  def self.intern(message)
+    result = nil
+    benchmark :info, "Loaded queued #{indirection.name}" do
+      result = model.convert_from(:pson, message)
+    end
+    result
+  end
+
+  # Provides queue subscription functionality; for a given indirection, use this method on the terminus
+  # to subscribe to the indirection-specific queue.  Your _block_ will be executed per new indirection
+  # model received from the queue, with _obj_ being the model instance.
+  def self.subscribe
+    client.subscribe(queue) do |msg|
+      begin
+        yield(self.intern(msg))
+      rescue => detail
+        Puppet.log_exception(detail, "Error occurred with subscription to queue #{queue} for indirection #{indirection_name}: #{detail}")
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/report/msgpack.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/report/msgpack.rb
new file mode 100644
index 0000000..057b359
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/report/msgpack.rb
@@ -0,0 +1,11 @@
+require 'puppet/transaction/report'
+require 'puppet/indirector/msgpack'
+
+class Puppet::Transaction::Report::Msgpack < Puppet::Indirector::Msgpack
+  desc "Store last report as a flat file, serialized using MessagePack."
+
+  # Force report to be saved there
+  def path(name,ext='.msgpack')
+    Puppet[:lastrunreport]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/report/processor.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/report/processor.rb
new file mode 100644
index 0000000..ef2232e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/report/processor.rb
@@ -0,0 +1,59 @@
+require 'puppet/transaction/report'
+require 'puppet/indirector/code'
+require 'puppet/reports'
+
+class Puppet::Transaction::Report::Processor < Puppet::Indirector::Code
+  desc "Puppet's report processor.  Processes the report with each of
+    the report types listed in the 'reports' setting."
+
+  def initialize
+    Puppet.settings.use(:main, :reporting, :metrics)
+  end
+
+  def save(request)
+    process(request.instance)
+  end
+
+  def destroy(request)
+    processors do |mod|
+      mod.destroy(request.key) if mod.respond_to?(:destroy)
+    end
+  end
+
+  private
+
+  # Process the report with each of the configured report types.
+  # LAK:NOTE This isn't necessarily the best design, but it's backward
+  # compatible and that's good enough for now.
+  def process(report)
+    Puppet.debug "Received report to process from #{report.host}"
+    processors do |mod|
+      Puppet.debug "Processing report from #{report.host} with processor #{mod}"
+      # We have to use a dup because we're including a module in the
+      # report.
+      newrep = report.dup
+      begin
+        newrep.extend(mod)
+        newrep.process
+      rescue => detail
+        Puppet.log_exception(detail, "Report #{name} failed: #{detail}")
+      end
+    end
+  end
+
+  # Handle the parsing of the reports attribute.
+  def reports
+    Puppet[:reports].gsub(/(^\s+)|(\s+$)/, '').split(/\s*,\s*/)
+  end
+
+  def processors(&blk)
+    return [] if Puppet[:reports] == "none"
+    reports.each do |name|
+      if mod = Puppet::Reports.report(name)
+        yield(mod)
+      else
+        Puppet.warning "No report named '#{name}'"
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/report/rest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/report/rest.rb
new file mode 100644
index 0000000..26a80f3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/report/rest.rb
@@ -0,0 +1,15 @@
+require 'puppet/indirector/rest'
+
+class Puppet::Transaction::Report::Rest < Puppet::Indirector::REST
+  desc "Get server report over HTTP via REST."
+  use_server_setting(:report_server)
+  use_port_setting(:report_port)
+  use_srv_service(:report)
+
+  private
+
+  def deserialize_save(content_type, body)
+    format = Puppet::Network::FormatHandler.format_for(content_type)
+    format.intern(Array, body)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/report/yaml.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/report/yaml.rb
new file mode 100644
index 0000000..bf7bf4f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/report/yaml.rb
@@ -0,0 +1,11 @@
+require 'puppet/transaction/report'
+require 'puppet/indirector/yaml'
+
+class Puppet::Transaction::Report::Yaml < Puppet::Indirector::Yaml
+  desc "Store last report as a flat file, serialized using YAML."
+
+  # Force report to be saved there
+  def path(name,ext='.yaml')
+    Puppet[:lastrunreport]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/request.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/request.rb
new file mode 100644
index 0000000..a156f9d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/request.rb
@@ -0,0 +1,317 @@
+require 'cgi'
+require 'uri'
+require 'puppet/indirector'
+require 'puppet/util/pson'
+require 'puppet/network/resolver'
+
+# This class encapsulates all of the information you need to make an
+# Indirection call, and as a result also handles REST calls.  It's somewhat
+# analogous to an HTTP Request object, except tuned for our Indirector.
+class Puppet::Indirector::Request
+  attr_accessor :key, :method, :options, :instance, :node, :ip, :authenticated, :ignore_cache, :ignore_terminus
+
+  attr_accessor :server, :port, :uri, :protocol
+
+  attr_reader :indirection_name
+
+  # trusted_information is specifically left out because we can't serialize it
+  # and keep it "trusted"
+  OPTION_ATTRIBUTES = [:ip, :node, :authenticated, :ignore_terminus, :ignore_cache, :instance, :environment]
+
+  ::PSON.register_document_type('IndirectorRequest',self)
+
+  def self.from_data_hash(data)
+    raise ArgumentError, "No indirection name provided in data" unless indirection_name = data['type']
+    raise ArgumentError, "No method name provided in data" unless method = data['method']
+    raise ArgumentError, "No key provided in data" unless key = data['key']
+
+    request = new(indirection_name, method, key, nil, data['attributes'])
+
+    if instance = data['instance']
+      klass = Puppet::Indirector::Indirection.instance(request.indirection_name).model
+      if instance.is_a?(klass)
+        request.instance = instance
+      else
+        request.instance = klass.from_data_hash(instance)
+      end
+    end
+
+    request
+  end
+
+  def self.from_pson(json)
+    Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
+    self.from_data_hash(json)
+  end
+
+  def to_data_hash
+    result = {
+      'type' => indirection_name,
+      'method' => method,
+      'key' => key
+    }
+    attributes = {}
+    OPTION_ATTRIBUTES.each do |key|
+      next unless value = send(key)
+      attributes[key] = value
+    end
+
+    options.each do |opt, value|
+      attributes[opt] = value
+    end
+
+    result['attributes'] = attributes unless attributes.empty?
+    result['instance'] = instance if instance
+    result
+  end
+
+  def to_pson_data_hash
+    {
+      'document_type' => 'IndirectorRequest',
+      'data' => to_data_hash,
+    }
+  end
+
+  def to_pson(*args)
+    to_pson_data_hash.to_pson(*args)
+  end
+
+  # Is this an authenticated request?
+  def authenticated?
+    # Double negative, so we just get true or false
+    ! ! authenticated
+  end
+
+  def environment
+    # If environment has not been set directly, we should use the application's
+    # current environment
+    @environment ||= Puppet.lookup(:current_environment)
+  end
+
+  def environment=(env)
+    @environment =
+    if env.is_a?(Puppet::Node::Environment)
+      env
+    elsif (current_environment = Puppet.lookup(:current_environment)).name == env
+      current_environment
+    else
+      Puppet.lookup(:environments).get!(env)
+    end
+  end
+
+  def escaped_key
+    URI.escape(key)
+  end
+
+  # LAK:NOTE This is a messy interface to the cache, and it's only
+  # used by the Configurer class.  I decided it was better to implement
+  # it now and refactor later, when we have a better design, than
+  # to spend another month coming up with a design now that might
+  # not be any better.
+  def ignore_cache?
+    ignore_cache
+  end
+
+  def ignore_terminus?
+    ignore_terminus
+  end
+
+  def initialize(indirection_name, method, key, instance, options = {})
+    @instance = instance
+    options ||= {}
+
+    self.indirection_name = indirection_name
+    self.method = method
+
+    options = options.inject({}) { |hash, ary| hash[ary[0].to_sym] = ary[1]; hash }
+
+    set_attributes(options)
+
+    @options = options
+
+    if key
+      # If the request key is a URI, then we need to treat it specially,
+      # because it rewrites the key.  We could otherwise strip server/port/etc
+      # info out in the REST class, but it seemed bad design for the REST
+      # class to rewrite the key.
+
+      if key.to_s =~ /^\w+:\// and not Puppet::Util.absolute_path?(key.to_s) # it's a URI
+        set_uri_key(key)
+      else
+        @key = key
+      end
+    end
+
+    @key = @instance.name if ! @key and @instance
+  end
+
+  # Look up the indirection based on the name provided.
+  def indirection
+    Puppet::Indirector::Indirection.instance(indirection_name)
+  end
+
+  def indirection_name=(name)
+    @indirection_name = name.to_sym
+  end
+
+  def model
+    raise ArgumentError, "Could not find indirection '#{indirection_name}'" unless i = indirection
+    i.model
+  end
+
+  # Are we trying to interact with multiple resources, or just one?
+  def plural?
+    method == :search
+  end
+
+  # Create the query string, if options are present.
+  def query_string
+    return "" if options.nil? || options.empty?
+
+    # For backward compatibility with older (pre-3.3) masters,
+    # this puppet option allows serialization of query parameter
+    # arrays as yaml.  This can be removed when we remove yaml
+    # support entirely.
+    if Puppet.settings[:legacy_query_parameter_serialization]
+      replace_arrays_with_yaml
+    end
+
+    "?" + encode_params(expand_into_parameters(options.to_a))
+  end
+
+  def replace_arrays_with_yaml
+    options.each do |key, value|
+      case value
+        when Array
+          options[key] = YAML.dump(value)
+      end
+    end
+  end
+
+  def expand_into_parameters(data)
+    data.inject([]) do |params, key_value|
+      key, value = key_value
+
+      expanded_value = case value
+                       when Array
+                         value.collect { |val| [key, val] }
+                       else
+                         [key_value]
+                       end
+
+      params.concat(expand_primitive_types_into_parameters(expanded_value))
+    end
+  end
+
+  def expand_primitive_types_into_parameters(data)
+    data.inject([]) do |params, key_value|
+      key, value = key_value
+      case value
+      when nil
+        params
+      when true, false, String, Symbol, Fixnum, Bignum, Float
+        params << [key, value]
+      else
+        raise ArgumentError, "HTTP REST queries cannot handle values of type '#{value.class}'"
+      end
+    end
+  end
+
+  def encode_params(params)
+    params.collect do |key, value|
+      "#{key}=#{CGI.escape(value.to_s)}"
+    end.join("&")
+  end
+
+  def to_hash
+    result = options.dup
+
+    OPTION_ATTRIBUTES.each do |attribute|
+      if value = send(attribute)
+        result[attribute] = value
+      end
+    end
+    result
+  end
+
+  def to_s
+    return(uri ? uri : "/#{indirection_name}/#{key}")
+  end
+
+  def do_request(srv_service=:puppet, default_server=Puppet.settings[:server], default_port=Puppet.settings[:masterport], &block)
+    # We were given a specific server to use, so just use that one.
+    # This happens if someone does something like specifying a file
+    # source using a puppet:// URI with a specific server.
+    return yield(self) if !self.server.nil?
+
+    if Puppet.settings[:use_srv_records]
+      Puppet::Network::Resolver.each_srv_record(Puppet.settings[:srv_domain], srv_service) do |srv_server, srv_port|
+        begin
+          self.server = srv_server
+          self.port   = srv_port
+          return yield(self)
+        rescue SystemCallError => e
+          Puppet.warning "Error connecting to #{srv_server}:#{srv_port}: #{e.message}"
+        end
+      end
+    end
+
+    # ... Fall back onto the default server.
+    Puppet.debug "No more servers left, falling back to #{default_server}:#{default_port}" if Puppet.settings[:use_srv_records]
+    self.server = default_server
+    self.port   = default_port
+    return yield(self)
+  end
+
+  def remote?
+    self.node or self.ip
+  end
+
+  private
+
+  def set_attributes(options)
+    OPTION_ATTRIBUTES.each do |attribute|
+      if options.include?(attribute.to_sym)
+        send(attribute.to_s + "=", options[attribute])
+        options.delete(attribute)
+      end
+    end
+  end
+
+  # Parse the key as a URI, setting attributes appropriately.
+  def set_uri_key(key)
+    @uri = key
+    begin
+      uri = URI.parse(URI.escape(key))
+    rescue => detail
+      raise ArgumentError, "Could not understand URL #{key}: #{detail}", detail.backtrace
+    end
+
+    # Just short-circuit these to full paths
+    if uri.scheme == "file"
+      @key = Puppet::Util.uri_to_path(uri)
+      return
+    end
+
+    @server = uri.host if uri.host
+
+    # If the URI class can look up the scheme, it will provide a port,
+    # otherwise it will default to '0'.
+    if uri.port.to_i == 0 and uri.scheme == "puppet"
+      @port = Puppet.settings[:masterport].to_i
+    else
+      @port = uri.port.to_i
+    end
+
+    @protocol = uri.scheme
+
+    if uri.scheme == 'puppet'
+      @key = URI.unescape(uri.path.sub(/^\//, ''))
+      return
+    end
+
+    env, indirector, @key = URI.unescape(uri.path.sub(/^\//, '')).split('/',3)
+    @key ||= ''
+    self.environment = env unless env == ''
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource/active_record.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource/active_record.rb
new file mode 100644
index 0000000..61b6d7a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource/active_record.rb
@@ -0,0 +1,104 @@
+require 'puppet/indirector/active_record'
+require 'puppet/indirector/resource/validator'
+
+class Puppet::Resource::ActiveRecord < Puppet::Indirector::ActiveRecord
+  include Puppet::Resource::Validator
+
+  desc "A component of ActiveRecord storeconfigs. ActiveRecord-based storeconfigs
+    and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation"
+
+  def initialize
+    Puppet.deprecation_warning "ActiveRecord-based storeconfigs and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation"
+    super
+  end
+
+  def search(request)
+    type   = request_to_type_name(request)
+    host   = request.options[:host]
+    filter = request.options[:filter]
+
+    if filter and filter[1] =~ /^(and|or)$/i then
+      raise Puppet::Error, "Complex search on StoreConfigs resources is not supported"
+    end
+
+    query = build_active_record_query(type, host, filter)
+    Puppet::Rails::Resource.find(:all, query)
+  end
+
+  private
+  def request_to_type_name(request)
+    request.key.split('/', 2)[0] or
+      raise "No key found in the request, failing: #{request.inspect}"
+  end
+
+  def filter_to_active_record(filter)
+    # Don't call me if you don't have a filter, please.
+    filter.is_a?(Array) or raise ArgumentError, "active record filters must be arrays"
+    a, op, b = filter
+
+    case op
+    when /^(and|or)$/i then
+      extra = []
+      first, args = filter_to_active_record a
+      extra += args
+
+      second, args = filter_to_active_record b
+      extra += args
+
+      return "(#{first}) #{op.upcase} (#{second})", extra
+
+    when "==", "!=" then
+      op = '=' if op == '=='    # SQL, yayz!
+      case a
+      when "title" then
+        return "title #{op} ?", [b]
+
+      when "tag" then
+        return "puppet_tags.name #{op} ?", [b]
+
+      else
+        return "param_names.name = ? AND param_values.value #{op} ?", [a, b]
+      end
+
+    else
+      raise ArgumentError, "unknown operator #{op.inspect} in #{filter.inspect}"
+    end
+  end
+
+  def build_active_record_query(type, host, filter)
+    raise Puppet::DevError, "Cannot collect resources for a nil host" unless host
+
+    search = "(exported=? AND restype=?)"
+    arguments = [true, type]
+
+    if filter then
+      sql, values = filter_to_active_record(filter)
+      search    += " AND #{sql}"
+      arguments += values
+    end
+
+    # note: we're not eagerly including any relations here because it can
+    # create large numbers of objects that we will just throw out later.  We
+    # used to eagerly include param_names/values but the way the search filter
+    # is built ruined those efforts and we were eagerly loading only the
+    # searched parameter and not the other ones.
+    query = {}
+    case search
+    when /puppet_tags/
+      query = { :joins => { :resource_tags => :puppet_tag } }
+    when /param_name/
+      query = { :joins => { :param_values => :param_name } }
+    end
+
+    # We're going to collect objects from rails, but we don't want any
+    # objects from this host.
+    if host = Puppet::Rails::Host.find_by_name(host)
+      search += " AND (host_id != ?)"
+      arguments << host.id
+    end
+
+    query[:conditions] = [search, *arguments]
+
+    query
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource/ral.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource/ral.rb
new file mode 100644
index 0000000..084cbfd
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource/ral.rb
@@ -0,0 +1,64 @@
+require 'puppet/indirector/resource/validator'
+
+class Puppet::Resource::Ral < Puppet::Indirector::Code
+  include Puppet::Resource::Validator
+
+  desc "Manipulate resources with the resource abstraction layer. Only used internally."
+
+  def allow_remote_requests?
+    Puppet.deprecation_warning("Accessing resources on the network is deprecated. See http://links.puppetlabs.com/deprecate-networked-resource")
+    super
+  end
+
+  def find( request )
+    # find by name
+    res   = type(request).instances.find { |o| o.name == resource_name(request) }
+    res ||= type(request).new(:name => resource_name(request), :audit => type(request).properties.collect { |s| s.name })
+
+    res.to_resource
+  end
+
+  def search( request )
+    conditions = request.options.dup
+    conditions[:name] = resource_name(request) if resource_name(request)
+
+    type(request).instances.map do |res|
+      res.to_resource
+    end.find_all do |res|
+      conditions.all? {|property, value| res.to_resource[property].to_s == value.to_s}
+    end.sort do |a,b|
+      a.title <=> b.title
+    end
+  end
+
+  def save( request )
+    # In RAL-land, to "save" means to actually try to change machine state
+    res = request.instance
+    ral_res = res.to_ral
+
+    catalog = Puppet::Resource::Catalog.new(nil, request.environment)
+    catalog.add_resource ral_res
+    transaction = catalog.apply
+
+    [ral_res.to_resource, transaction.report]
+  end
+
+  private
+
+  # {type,resource}_name: the resource name may contain slashes:
+  # File["/etc/hosts"]. To handle, assume the type name does
+  # _not_ have any slashes in it, and split only on the first.
+
+  def type_name( request )
+    request.key.split('/', 2)[0]
+  end
+
+  def resource_name( request )
+    name = request.key.split('/', 2)[1]
+    name unless name == ""
+  end
+
+  def type( request )
+    Puppet::Type.type(type_name(request)) or raise Puppet::Error, "Could not find type #{type_name(request)}"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource/rest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource/rest.rb
new file mode 100644
index 0000000..6638479
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource/rest.rb
@@ -0,0 +1,17 @@
+require 'puppet/indirector/status'
+require 'puppet/indirector/rest'
+
+# @deprecated
+class Puppet::Resource::Rest < Puppet::Indirector::REST
+
+  desc "Maniuplate resources remotely? Undocumented."
+
+  private
+
+  def deserialize_save(content_type, body)
+    # Body is [ral_res.to_resource, transaction.report]
+    format = Puppet::Network::FormatHandler.format_for(content_type)
+    ary = format.intern(Array, body)
+    [Puppet::Resource.from_data_hash(ary[0]), Puppet::Transaction::Report.from_data_hash(ary[1])]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource/store_configs.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource/store_configs.rb
new file mode 100644
index 0000000..0c249d6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource/store_configs.rb
@@ -0,0 +1,13 @@
+require 'puppet/indirector/store_configs'
+require 'puppet/indirector/resource/validator'
+
+class Puppet::Resource::StoreConfigs < Puppet::Indirector::StoreConfigs
+  include Puppet::Resource::Validator
+
+  desc %q{Part of the "storeconfigs" feature. Should not be directly set by end users.}
+
+  def allow_remote_requests?
+    Puppet.deprecation_warning("Accessing resources on the network is deprecated. See http://links.puppetlabs.com/deprecate-networked-resource")
+    super
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource/validator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource/validator.rb
new file mode 100644
index 0000000..dff6ce5
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource/validator.rb
@@ -0,0 +1,8 @@
+module Puppet::Resource::Validator
+  def validate_key(request)
+    type, title = request.key.split('/', 2)
+    unless type.downcase == request.instance.type.downcase and title == request.instance.title
+      raise Puppet::Indirector::ValidationError, "Resource instance does not match request key"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource_type.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource_type.rb
new file mode 100644
index 0000000..0564dc2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource_type.rb
@@ -0,0 +1,5 @@
+require 'puppet/resource/type'
+
+# A stub class, so our constants work.
+class Puppet::Indirector::ResourceType # :nodoc:
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource_type/parser.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource_type/parser.rb
new file mode 100644
index 0000000..884fd2f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource_type/parser.rb
@@ -0,0 +1,101 @@
+require 'puppet/resource/type'
+require 'puppet/indirector/code'
+require 'puppet/indirector/resource_type'
+
+# The main terminus for Puppet::Resource::Type
+#
+# This exposes the known resource types from within Puppet. Only find
+# and search are supported. When a request is received, Puppet will
+# attempt to load all resource types (by parsing manifests and modules) and
+# returns a description of the resource types found. The format of these
+# objects is documented at {Puppet::Resource::Type}.
+#
+# @api public
+class Puppet::Indirector::ResourceType::Parser < Puppet::Indirector::Code
+  desc "Return the data-form of a resource type."
+
+  # Find will return the first resource_type with the given name. It is
+  # not possible to specify the kind of the resource type.
+  #
+  # @param request [Puppet::Indirector::Request] The request object.
+  #   The only parameters used from the request are `environment` and
+  #   `key`, which corresponds to the resource type's `name` field.
+  # @return [Puppet::Resource::Type, nil]
+  # @api public
+  def find(request)
+    Puppet.override(:squelch_parse_errors => true) do
+      krt = resource_types_in(request.environment)
+
+      # This is a bit ugly.
+      [:hostclass, :definition, :node].each do |type|
+        # We have to us 'find_<type>' here because it will
+        # load any missing types from disk, whereas the plain
+        # '<type>' method only returns from memory.
+        if r = krt.send("find_#{type}", [""], request.key)
+          return r
+        end
+      end
+      nil
+    end
+  end
+
+  # Search for resource types using a regular expression. Unlike `find`, this
+  # allows you to filter the results by the "kind" of the resource type
+  # ("class", "defined_type", or "node"). All three are searched if no
+  # `kind` filter is given. This also accepts the special string "`*`"
+  # to return all resource type objects.
+  #
+  # @param request [Puppet::Indirector::Request] The request object. The
+  #   `key` field holds the regular expression used to search, and
+  #   `options[:kind]` holds the kind query parameter to filter the
+  #   result as described above. The `environment` field specifies the
+  #   environment used to load resources.
+  #
+  # @return [Array<Puppet::Resource::Type>, nil]
+  #
+  # @api public
+  def search(request)
+    Puppet.override(:squelch_parse_errors => true) do
+
+      krt = resource_types_in(request.environment)
+      # Make sure we've got all of the types loaded.
+      krt.loader.import_all
+
+      result_candidates = case request.options[:kind]
+          when "class"
+            krt.hostclasses.values
+          when "defined_type"
+            krt.definitions.values
+          when "node"
+            krt.nodes.values
+          when nil
+            result_candidates = [krt.hostclasses.values, krt.definitions.values, krt.nodes.values]
+          else
+            raise ArgumentError, "Unrecognized kind filter: " +
+                      "'#{request.options[:kind]}', expected one " +
+                      " of 'class', 'defined_type', or 'node'."
+        end
+
+      result = result_candidates.flatten.reject { |t| t.name == "" }
+      return nil if result.empty?
+      return result if request.key == "*"
+
+      # Strip the regex of any wrapping slashes that might exist
+      key = request.key.sub(/^\//, '').sub(/\/$/, '')
+      begin
+        regex = Regexp.new(key)
+      rescue => detail
+        raise ArgumentError, "Invalid regex '#{request.key}': #{detail}", detail.backtrace
+      end
+
+      result.reject! { |t| t.name.to_s !~ regex }
+      return nil if result.empty?
+      result
+    end
+  end
+
+  def resource_types_in(environment)
+    environment.check_for_reparse
+    environment.known_resource_types
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource_type/rest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource_type/rest.rb
new file mode 100644
index 0000000..f372ecc
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/resource_type/rest.rb
@@ -0,0 +1,7 @@
+require 'puppet/resource/type'
+require 'puppet/indirector/rest'
+require 'puppet/indirector/resource_type'
+
+class Puppet::Indirector::ResourceType::Rest < Puppet::Indirector::REST
+  desc "Retrieve resource types via a REST HTTP interface."
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/rest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/rest.rb
new file mode 100644
index 0000000..d1f2f4d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/rest.rb
@@ -0,0 +1,267 @@
+require 'net/http'
+require 'uri'
+
+require 'puppet/network/http'
+require 'puppet/network/http_pool'
+require 'puppet/network/http/api/v1'
+require 'puppet/network/http/compression'
+
+# Access objects via REST
+class Puppet::Indirector::REST < Puppet::Indirector::Terminus
+  include Puppet::Network::HTTP::Compression.module
+
+  class << self
+    attr_reader :server_setting, :port_setting
+  end
+
+  # Specify the setting that we should use to get the server name.
+  def self.use_server_setting(setting)
+    @server_setting = setting
+  end
+
+  # Specify the setting that we should use to get the port.
+  def self.use_port_setting(setting)
+    @port_setting = setting
+  end
+
+  # Specify the service to use when doing SRV record lookup
+  def self.use_srv_service(service)
+    @srv_service = service
+  end
+
+  def self.srv_service
+    @srv_service || :puppet
+  end
+
+  def self.server
+    Puppet.settings[server_setting || :server]
+  end
+
+  def self.port
+    Puppet.settings[port_setting || :masterport].to_i
+  end
+
+  # Provide appropriate headers.
+  def headers
+    add_accept_encoding({"Accept" => model.supported_formats.join(", ")})
+  end
+
+  def add_profiling_header(headers)
+    if (Puppet[:profile])
+      headers[Puppet::Network::HTTP::HEADER_ENABLE_PROFILING] = "true"
+    end
+    headers
+  end
+
+  def network(request)
+    Puppet::Network::HttpPool.http_instance(request.server || self.class.server,
+                                            request.port || self.class.port)
+  end
+
+  def http_get(request, path, headers = nil, *args)
+    http_request(:get, request, path, add_profiling_header(headers), *args)
+  end
+
+  def http_post(request, path, data, headers = nil, *args)
+    http_request(:post, request, path, data, add_profiling_header(headers), *args)
+  end
+
+  def http_head(request, path, headers = nil, *args)
+    http_request(:head, request, path, add_profiling_header(headers), *args)
+  end
+
+  def http_delete(request, path, headers = nil, *args)
+    http_request(:delete, request, path, add_profiling_header(headers), *args)
+  end
+
+  def http_put(request, path, data, headers = nil, *args)
+    http_request(:put, request, path, data, add_profiling_header(headers), *args)
+  end
+
+  def http_request(method, request, *args)
+    conn = network(request)
+    conn.send(method, *args)
+  end
+
+  def find(request)
+    uri, body = Puppet::Network::HTTP::API::V1.request_to_uri_and_body(request)
+    uri_with_query_string = "#{uri}?#{body}"
+
+    response = do_request(request) do |request|
+      # WEBrick in Ruby 1.9.1 only supports up to 1024 character lines in an HTTP request
+      # http://redmine.ruby-lang.org/issues/show/3991
+      if "GET #{uri_with_query_string} HTTP/1.1\r\n".length > 1024
+        http_post(request, uri, body, headers)
+      else
+        http_get(request, uri_with_query_string, headers)
+      end
+    end
+
+    if is_http_200?(response)
+      check_master_version(response)
+      content_type, body = parse_response(response)
+      result = deserialize_find(content_type, body)
+      result.name = request.key if result.respond_to?(:name=)
+      result
+
+    elsif is_http_404?(response)
+      return nil unless request.options[:fail_on_404]
+
+      # 404 can get special treatment as the indirector API can not produce a meaningful
+      # reason to why something is not found - it may not be the thing the user is
+      # expecting to find that is missing, but something else (like the environment).
+      # While this way of handling the issue is not perfect, there is at least an error
+      # that makes a user aware of the reason for the failure.
+      #
+      content_type, body = parse_response(response)
+      msg = "Find #{elide(uri_with_query_string, 100)} resulted in 404 with the message: #{body}"
+      raise Puppet::Error, msg
+    else
+      nil
+    end
+  end
+
+  def head(request)
+    response = do_request(request) do |request|
+      http_head(request, Puppet::Network::HTTP::API::V1.indirection2uri(request), headers)
+    end
+
+    if is_http_200?(response)
+      check_master_version(response)
+      true
+    else
+      false
+    end
+  end
+
+  def search(request)
+    response = do_request(request) do |request|
+      http_get(request, Puppet::Network::HTTP::API::V1.indirection2uri(request), headers)
+    end
+
+    if is_http_200?(response)
+      check_master_version(response)
+      content_type, body = parse_response(response)
+      deserialize_search(content_type, body) || []
+    else
+      []
+    end
+  end
+
+  def destroy(request)
+    raise ArgumentError, "DELETE does not accept options" unless request.options.empty?
+
+    response = do_request(request) do |request|
+      http_delete(request, Puppet::Network::HTTP::API::V1.indirection2uri(request), headers)
+    end
+
+    if is_http_200?(response)
+      check_master_version(response)
+      content_type, body = parse_response(response)
+      deserialize_destroy(content_type, body)
+    else
+      nil
+    end
+  end
+
+  def save(request)
+    raise ArgumentError, "PUT does not accept options" unless request.options.empty?
+
+    response = do_request(request) do |request|
+      http_put(request, Puppet::Network::HTTP::API::V1.indirection2uri(request), request.instance.render, headers.merge({ "Content-Type" => request.instance.mime }))
+    end
+
+    if is_http_200?(response)
+      check_master_version(response)
+      content_type, body = parse_response(response)
+      deserialize_save(content_type, body)
+    else
+      nil
+    end
+  end
+
+  # Encapsulate call to request.do_request with the arguments from this class
+  # Then yield to the code block that was called in
+  # We certainly could have retained the full request.do_request(...) { |r| ... }
+  # but this makes the code much cleaner and we only then actually make the call
+  # to request.do_request from here, thus if we change what we pass or how we
+  # get it, we only need to change it here.
+  def do_request(request)
+    request.do_request(self.class.srv_service, self.class.server, self.class.port) { |request| yield(request) }
+  end
+
+  def validate_key(request)
+    # Validation happens on the remote end
+  end
+
+  private
+
+  def is_http_200?(response)
+    case response.code
+    when "404"
+      false
+    when /^2/
+      true
+    else
+      # Raise the http error if we didn't get a 'success' of some kind.
+      raise convert_to_http_error(response)
+    end
+  end
+
+  def is_http_404?(response)
+    response.code == "404"
+  end
+
+  def convert_to_http_error(response)
+    message = "Error #{response.code} on SERVER: #{(response.body||'').empty? ? response.message : uncompress_body(response)}"
+    Net::HTTPError.new(message, response)
+  end
+
+  def check_master_version response
+    if !response[Puppet::Network::HTTP::HEADER_PUPPET_VERSION] &&
+       (Puppet[:legacy_query_parameter_serialization] == false || Puppet[:report_serialization_format] != "yaml")
+      Puppet.notice "Using less secure serialization of reports and query parameters for compatibility"
+      Puppet.notice "with older puppet master. To remove this notice, please upgrade your master(s) "
+      Puppet.notice "to Puppet 3.3 or newer."
+      Puppet.notice "See http://links.puppetlabs.com/deprecate_yaml_on_network for more information."
+      Puppet[:legacy_query_parameter_serialization] = true
+      Puppet[:report_serialization_format] = "yaml"
+    end
+  end
+
+  # Returns the content_type, stripping any appended charset, and the
+  # body, decompressed if necessary (content-encoding is checked inside
+  # uncompress_body)
+  def parse_response(response)
+    if response['content-type']
+      [ response['content-type'].gsub(/\s*;.*$/,''),
+        body = uncompress_body(response) ]
+    else
+      raise "No content type in http response; cannot parse"
+    end
+  end
+
+  def deserialize_find(content_type, body)
+    model.convert_from(content_type, body)
+  end
+
+  def deserialize_search(content_type, body)
+    model.convert_from_multiple(content_type, body)
+  end
+
+  def deserialize_destroy(content_type, body)
+    model.convert_from(content_type, body)
+  end
+
+  def deserialize_save(content_type, body)
+    nil
+  end
+
+  def elide(string, length)
+    if Puppet::Util::Log.level == :debug || string.length <= length
+      string
+    else
+      string[0, length - 3] + "..."
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/run/local.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/run/local.rb
new file mode 100644
index 0000000..fd35b13
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/run/local.rb
@@ -0,0 +1,15 @@
+require 'puppet/run'
+require 'puppet/indirector/code'
+
+class Puppet::Run::Local < Puppet::Indirector::Code
+
+  desc "Trigger a Puppet run locally. Only used internally."
+
+  def save( request )
+    request.instance.run
+  end
+
+  def validate_key(request)
+    # No key is necessary for kick
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/run/rest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/run/rest.rb
new file mode 100644
index 0000000..f857d45
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/run/rest.rb
@@ -0,0 +1,12 @@
+require 'puppet/run'
+require 'puppet/indirector/rest'
+
+class Puppet::Run::Rest < Puppet::Indirector::REST
+  desc "Trigger Agent runs via REST."
+
+  private
+
+  def deserialize_save(content_type, body)
+    model.convert_from(content_type, body)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/ssl_file.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/ssl_file.rb
new file mode 100644
index 0000000..695dc42
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/ssl_file.rb
@@ -0,0 +1,180 @@
+require 'puppet/ssl'
+
+class Puppet::Indirector::SslFile < Puppet::Indirector::Terminus
+  # Specify the directory in which multiple files are stored.
+  def self.store_in(setting)
+    @directory_setting = setting
+  end
+
+  # Specify a single file location for storing just one file.
+  # This is used for things like the CRL.
+  def self.store_at(setting)
+    @file_setting = setting
+  end
+
+  # Specify where a specific ca file should be stored.
+  def self.store_ca_at(setting)
+    @ca_setting = setting
+  end
+
+  class << self
+    attr_reader :directory_setting, :file_setting, :ca_setting
+  end
+
+  # The full path to where we should store our files.
+  def self.collection_directory
+    return nil unless directory_setting
+    Puppet.settings[directory_setting]
+  end
+
+  # The full path to an individual file we would be managing.
+  def self.file_location
+    return nil unless file_setting
+    Puppet.settings[file_setting]
+  end
+
+  # The full path to a ca file we would be managing.
+  def self.ca_location
+    return nil unless ca_setting
+    Puppet.settings[ca_setting]
+  end
+
+  # We assume that all files named 'ca' are pointing to individual ca files,
+  # rather than normal host files.  It's a bit hackish, but all the other
+  # solutions seemed even more hackish.
+  def ca?(name)
+    name == Puppet::SSL::Host.ca_name
+  end
+
+  def initialize
+    Puppet.settings.use(:main, :ssl)
+
+    (collection_directory || file_location) or raise Puppet::DevError, "No file or directory setting provided; terminus #{self.class.name} cannot function"
+  end
+
+  def path(name)
+    if name =~ Puppet::Indirector::BadNameRegexp then
+      Puppet.crit("directory traversal detected in #{self.class}: #{name.inspect}")
+      raise ArgumentError, "invalid key"
+    end
+
+    if ca?(name) and ca_location
+      ca_location
+    elsif collection_directory
+      File.join(collection_directory, name.to_s + ".pem")
+    else
+      file_location
+    end
+  end
+
+  # Remove our file.
+  def destroy(request)
+    path = Puppet::FileSystem.pathname(path(request.key))
+    return false unless Puppet::FileSystem.exist?(path)
+
+    Puppet.notice "Removing file #{model} #{request.key} at '#{path}'"
+    begin
+      Puppet::FileSystem.unlink(path)
+    rescue => detail
+      raise Puppet::Error, "Could not remove #{request.key}: #{detail}", detail.backtrace
+    end
+  end
+
+  # Find the file on disk, returning an instance of the model.
+  def find(request)
+    filename = rename_files_with_uppercase(path(request.key))
+
+    filename ? create_model(request.key, filename) : nil
+  end
+
+  # Save our file to disk.
+  def save(request)
+    path = path(request.key)
+    dir = File.dirname(path)
+
+    raise Puppet::Error.new("Cannot save #{request.key}; parent directory #{dir} does not exist") unless FileTest.directory?(dir)
+    raise Puppet::Error.new("Cannot save #{request.key}; parent directory #{dir} is not writable") unless FileTest.writable?(dir)
+
+    write(request.key, path) { |f| f.print request.instance.to_s }
+  end
+
+  # Search for more than one file.  At this point, it just returns
+  # an instance for every file in the directory.
+  def search(request)
+    dir = collection_directory
+    Dir.entries(dir).
+      select  { |file| file =~ /\.pem$/ }.
+      collect { |file| create_model(file.sub(/\.pem$/, ''), File.join(dir, file)) }.
+      compact
+  end
+
+  private
+
+  def create_model(name, path)
+    result = model.new(name)
+    result.read(path)
+    result
+  end
+
+  # Demeterish pointers to class info.
+  def collection_directory
+    self.class.collection_directory
+  end
+
+  def file_location
+    self.class.file_location
+  end
+
+  def ca_location
+    self.class.ca_location
+  end
+
+  # A hack method to deal with files that exist with a different case.
+  # Just renames it; doesn't read it in or anything.
+  # LAK:NOTE This is a copy of the method in sslcertificates/support.rb,
+  # which we'll be EOL'ing at some point.  This method was added at 20080702
+  # and should be removed at some point.
+  def rename_files_with_uppercase(file)
+    return file if Puppet::FileSystem.exist?(file)
+
+    dir, short = File.split(file)
+    return nil unless Puppet::FileSystem.exist?(dir)
+
+    raise ArgumentError, "Tried to fix SSL files to a file containing uppercase" unless short.downcase == short
+    real_file = Dir.entries(dir).reject { |f| f =~ /^\./ }.find do |other|
+      other.downcase == short
+    end
+
+    return nil unless real_file
+
+    full_file = File.join(dir, real_file)
+
+    Puppet.deprecation_warning "Automatic downcasing and renaming of ssl files is deprecated; please request the file using its correct case: #{full_file}"
+    File.rename(full_file, file)
+
+    file
+  end
+
+  # Yield a filehandle set up appropriately, either with our settings doing
+  # the work or opening a filehandle manually.
+  def write(name, path)
+    if ca?(name) and ca_location
+      Puppet.settings.setting(self.class.ca_setting).open('w') { |f| yield f }
+    elsif file_location
+      Puppet.settings.setting(self.class.file_setting).open('w') { |f| yield f }
+    elsif setting = self.class.directory_setting
+      begin
+        Puppet.settings.setting(setting).open_file(path, 'w') { |f| yield f }
+      rescue => detail
+        raise Puppet::Error, "Could not write #{path} to #{setting}: #{detail}", detail.backtrace
+      end
+    else
+      raise Puppet::DevError, "You must provide a setting to determine where the files are stored"
+    end
+  end
+end
+
+# LAK:NOTE This has to be at the end, because classes like SSL::Key use this
+# class, and this require statement loads those, which results in a load loop
+# and lots of failures.
+require 'puppet/ssl/host'
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/status.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/status.rb
new file mode 100644
index 0000000..f40bbc4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/status.rb
@@ -0,0 +1,3 @@
+# A stub class, so our constants work.
+class Puppet::Indirector::Status
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/status/local.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/status/local.rb
new file mode 100644
index 0000000..fc674ee
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/status/local.rb
@@ -0,0 +1,12 @@
+require 'puppet/indirector/status'
+
+class Puppet::Indirector::Status::Local < Puppet::Indirector::Code
+
+  desc "Get status locally. Only used internally."
+
+  def find( *anything )
+    status = model.new
+    status.version= Puppet.version
+    status
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/status/rest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/status/rest.rb
new file mode 100644
index 0000000..4fd9943
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/status/rest.rb
@@ -0,0 +1,9 @@
+require 'puppet/indirector/status'
+require 'puppet/indirector/rest'
+
+class Puppet::Indirector::Status::Rest < Puppet::Indirector::REST
+
+  desc "Get puppet master's status via REST. Useful because it tests the health
+    of both the web server and the indirector."
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/store_configs.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/store_configs.rb
new file mode 100644
index 0000000..3c74474
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/store_configs.rb
@@ -0,0 +1,30 @@
+class Puppet::Indirector::StoreConfigs < Puppet::Indirector::Terminus
+  def initialize
+    super
+    # This will raise if the indirection can't be found, so we can assume it
+    # is always set to a valid instance from here on in.
+    @target = indirection.terminus Puppet[:storeconfigs_backend]
+  end
+
+  attr_reader :target
+
+  def head(request)
+    target.head request
+  end
+
+  def find(request)
+    target.find request
+  end
+
+  def search(request)
+    target.search request
+  end
+
+  def save(request)
+    target.save request
+  end
+
+  def destroy(request)
+    target.save request
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/terminus.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/terminus.rb
new file mode 100644
index 0000000..b05ac3d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/terminus.rb
@@ -0,0 +1,169 @@
+require 'puppet/indirector'
+require 'puppet/indirector/errors'
+require 'puppet/indirector/indirection'
+require 'puppet/util/instance_loader'
+
+# A simple class that can function as the base class for indirected types.
+class Puppet::Indirector::Terminus
+  require 'puppet/util/docs'
+  extend Puppet::Util::Docs
+
+  class << self
+    include Puppet::Util::InstanceLoader
+
+    attr_accessor :name, :terminus_type
+    attr_reader :abstract_terminus, :indirection
+
+    # Are we an abstract terminus type, rather than an instance with an
+    # associated indirection?
+    def abstract_terminus?
+      abstract_terminus
+    end
+
+    # Convert a constant to a short name.
+    def const2name(const)
+      const.sub(/^[A-Z]/) { |i| i.downcase }.gsub(/[A-Z]/) { |i| "_#{i.downcase}" }.intern
+    end
+
+    # Look up the indirection if we were only provided a name.
+    def indirection=(name)
+      if name.is_a?(Puppet::Indirector::Indirection)
+        @indirection = name
+      elsif ind = Puppet::Indirector::Indirection.instance(name)
+        @indirection = ind
+      else
+        raise ArgumentError, "Could not find indirection instance #{name} for #{self.name}"
+      end
+    end
+
+    def indirection_name
+      @indirection.name
+    end
+
+    # Register our subclass with the appropriate indirection.
+    # This follows the convention that our terminus is named after the
+    # indirection.
+    def inherited(subclass)
+      longname = subclass.to_s
+      if longname =~ /#<Class/
+        raise Puppet::DevError, "Terminus subclasses must have associated constants"
+      end
+      names = longname.split("::")
+
+      # Convert everything to a lower-case symbol, converting camelcase to underscore word separation.
+      name = names.pop.sub(/^[A-Z]/) { |i| i.downcase }.gsub(/[A-Z]/) { |i| "_#{i.downcase}" }.intern
+
+      subclass.name = name
+
+      # Short-circuit the abstract types, which are those that directly subclass
+      # the Terminus class.
+      if self == Puppet::Indirector::Terminus
+        subclass.mark_as_abstract_terminus
+        return
+      end
+
+      # Set the terminus type to be the name of the abstract terminus type.
+      # Yay, class/instance confusion.
+      subclass.terminus_type = self.name
+
+      # Our subclass is specifically associated with an indirection.
+      raise("Invalid name #{longname}") unless names.length > 0
+      indirection_name = names.pop.sub(/^[A-Z]/) { |i| i.downcase }.gsub(/[A-Z]/) { |i| "_#{i.downcase}" }.intern
+
+      if indirection_name == "" or indirection_name.nil?
+        raise Puppet::DevError, "Could not discern indirection model from class constant"
+      end
+
+      # This will throw an exception if the indirection instance cannot be found.
+      # Do this last, because it also registers the terminus type with the indirection,
+      # which needs the above information.
+      subclass.indirection = indirection_name
+
+      # And add this instance to the instance hash.
+      Puppet::Indirector::Terminus.register_terminus_class(subclass)
+    end
+
+    # Mark that this instance is abstract.
+    def mark_as_abstract_terminus
+      @abstract_terminus = true
+    end
+
+    def model
+      indirection.model
+    end
+
+    # Convert a short name to a constant.
+    def name2const(name)
+      name.to_s.capitalize.sub(/_(.)/) { |i| $1.upcase }
+    end
+
+    # Register a class, probably autoloaded.
+    def register_terminus_class(klass)
+      setup_instance_loading klass.indirection_name
+      instance_hash(klass.indirection_name)[klass.name] = klass
+    end
+
+    # Return a terminus by name, using the autoloader.
+    def terminus_class(indirection_name, terminus_type)
+      setup_instance_loading indirection_name
+      loaded_instance(indirection_name, terminus_type)
+    end
+
+    # Return all terminus classes for a given indirection.
+    def terminus_classes(indirection_name)
+      setup_instance_loading indirection_name
+      instance_loader(indirection_name).files_to_load.map do |file|
+        File.basename(file).chomp(".rb").intern
+      end
+    end
+
+    private
+
+    def setup_instance_loading(type)
+      instance_load type, "puppet/indirector/#{type}" unless instance_loading?(type)
+    end
+  end
+
+  def indirection
+    self.class.indirection
+  end
+
+  def initialize
+    raise Puppet::DevError, "Cannot create instances of abstract terminus types" if self.class.abstract_terminus?
+  end
+
+  def model
+    self.class.model
+  end
+
+  def name
+    self.class.name
+  end
+
+  def allow_remote_requests?
+    true
+  end
+
+  def terminus_type
+    self.class.terminus_type
+  end
+
+  def validate(request)
+    if request.instance
+      validate_model(request)
+      validate_key(request)
+    end
+  end
+
+  def validate_key(request)
+    unless request.key == request.instance.name
+      raise Puppet::Indirector::ValidationError, "Instance name #{request.instance.name.inspect} does not match requested key #{request.key.inspect}"
+    end
+  end
+
+  def validate_model(request)
+    unless model === request.instance
+      raise Puppet::Indirector::ValidationError, "Invalid instance type #{request.instance.class.inspect}, expected #{model.inspect}"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/yaml.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/yaml.rb
new file mode 100644
index 0000000..9a6be88
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/indirector/yaml.rb
@@ -0,0 +1,63 @@
+require 'puppet/indirector/terminus'
+require 'puppet/util/yaml'
+
+# The base class for YAML indirection termini.
+class Puppet::Indirector::Yaml < Puppet::Indirector::Terminus
+  # Read a given name's file in and convert it from YAML.
+  def find(request)
+    file = path(request.key)
+    return nil unless Puppet::FileSystem.exist?(file)
+
+    begin
+      return fix(Puppet::Util::Yaml.load_file(file))
+    rescue Puppet::Util::Yaml::YamlLoadError => detail
+      raise Puppet::Error, "Could not parse YAML data for #{indirection.name} #{request.key}: #{detail}", detail.backtrace
+    end
+  end
+
+  # Convert our object to YAML and store it to the disk.
+  def save(request)
+    raise ArgumentError.new("You can only save objects that respond to :name") unless request.instance.respond_to?(:name)
+
+    file = path(request.key)
+
+    basedir = File.dirname(file)
+
+    # This is quite likely a bad idea, since we're not managing ownership or modes.
+    Dir.mkdir(basedir) unless Puppet::FileSystem.exist?(basedir)
+
+    begin
+      Puppet::Util::Yaml.dump(request.instance, file)
+    rescue TypeError => detail
+      Puppet.err "Could not save #{self.name} #{request.key}: #{detail}"
+    end
+  end
+
+  # Return the path to a given node's file.
+  def path(name,ext='.yaml')
+    if name =~ Puppet::Indirector::BadNameRegexp then
+      Puppet.crit("directory traversal detected in #{self.class}: #{name.inspect}")
+      raise ArgumentError, "invalid key"
+    end
+
+    base = Puppet.run_mode.master? ? Puppet[:yamldir] : Puppet[:clientyamldir]
+    File.join(base, self.class.indirection_name.to_s, name.to_s + ext)
+  end
+
+  def destroy(request)
+    file_path = path(request.key)
+    Puppet::FileSystem.unlink(file_path) if Puppet::FileSystem.exist?(file_path)
+  end
+
+  def search(request)
+    Dir.glob(path(request.key,'')).collect do |file|
+      fix(Puppet::Util::Yaml.load_file(file))
+    end
+  end
+
+  protected
+
+  def fix(object)
+    object
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface.rb
new file mode 100644
index 0000000..d40ef8c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface.rb
@@ -0,0 +1,235 @@
+require 'puppet'
+require 'puppet/util/autoload'
+require 'prettyprint'
+require 'semver'
+
+# @api public
+class Puppet::Interface
+  require 'puppet/interface/documentation'
+  require 'puppet/interface/face_collection'
+
+  require 'puppet/interface/action'
+  require 'puppet/interface/action_builder'
+  require 'puppet/interface/action_manager'
+
+  require 'puppet/interface/option'
+  require 'puppet/interface/option_builder'
+  require 'puppet/interface/option_manager'
+
+
+  include FullDocs
+
+  include Puppet::Interface::ActionManager
+  extend Puppet::Interface::ActionManager
+
+  include Puppet::Interface::OptionManager
+  extend Puppet::Interface::OptionManager
+
+  include Puppet::Util
+
+  class << self
+    # This is just so we can search for actions.  We only use its
+    # list of directories to search.
+
+    # @api private
+    # @deprecated
+    def autoloader
+      Puppet.deprecation_warning("Puppet::Interface.autoloader is deprecated; please use Puppet::Interface#loader instead")
+      @autoloader ||= Puppet::Util::Autoload.new(:application, "puppet/face")
+    end
+
+    # Lists all loaded faces
+    # @return [Array<Symbol>] The names of the loaded faces
+    def faces
+      Puppet::Interface::FaceCollection.faces
+    end
+
+    # Register a face
+    # @param instance [Puppet::Interface] The face
+    # @return [void]
+    # @api private
+    def register(instance)
+      Puppet::Interface::FaceCollection.register(instance)
+    end
+
+    # Defines a new Face.
+    # @todo Talk about using Faces DSL inside the block
+    #
+    # @param name [Symbol] the name of the face
+    # @param version [String] the version of the face (this should
+    #   conform to {http://semver.org/ Semantic Versioning})
+    # @overload define(name, version, {|| ... })
+    # @return [Puppet::Interface] The created face
+    # @api public
+    # @dsl Faces
+    def define(name, version, &block)
+      face = Puppet::Interface::FaceCollection[name, version]
+      if face.nil? then
+        face = self.new(name, version)
+        Puppet::Interface::FaceCollection.register(face)
+        # REVISIT: Shouldn't this be delayed until *after* we evaluate the
+        # current block, not done before? --daniel 2011-04-07
+        face.load_actions
+      end
+
+      face.instance_eval(&block) if block_given?
+
+      return face
+    end
+
+    # Retrieves a face by name and version. Use `:current` for the
+    # version to get the most recent available version.
+    #
+    # @param name [Symbol] the name of the face
+    # @param version [String, :current] the version of the face
+    #
+    # @return [Puppet::Interface] the face
+    #
+    # @api public
+    def face?(name, version)
+      Puppet::Interface::FaceCollection[name, version]
+    end
+
+    # Retrieves a face by name and version
+    #
+    # @param name [Symbol] the name of the face
+    # @param version [String] the version of the face
+    #
+    # @return [Puppet::Interface] the face
+    #
+    # @api public
+    def [](name, version)
+      unless face = Puppet::Interface::FaceCollection[name, version]
+        # REVISIT (#18042) no sense in rechecking if version == :current -- josh
+        if Puppet::Interface::FaceCollection[name, :current]
+          raise Puppet::Error, "Could not find version #{version} of #{name}"
+        else
+          raise Puppet::Error, "Could not find Puppet Face #{name.to_s}"
+        end
+      end
+
+      face
+    end
+
+    # Retrieves an action for a face
+    # @param name [Symbol] The face
+    # @param action [Symbol] The action name
+    # @param version [String, :current] The version of the face
+    # @return [Puppet::Interface::Action] The action
+    def find_action(name, action, version = :current)
+      Puppet::Interface::FaceCollection.get_action_for_face(name, action, version)
+    end
+  end
+
+  ########################################################################
+  # Documentation.  We currently have to rewrite both getters because we share
+  # the same instance between build-time and the runtime instance.  When that
+  # splits out this should merge into a module that both the action and face
+  # include. --daniel 2011-04-17
+
+
+  # Returns the synopsis for the face. This shows basic usage and global
+  # options.
+  # @return [String] usage synopsis
+  # @api private
+  def synopsis
+    build_synopsis self.name, '<action>'
+  end
+
+
+  ########################################################################
+
+  # The name of the face
+  # @return [Symbol]
+  # @api private
+  attr_reader :name
+
+  # The version of the face
+  # @return [SemVer]
+  attr_reader :version
+
+  # The autoloader instance for the face
+  # @return [Puppet::Util::Autoload]
+  # @api private
+  attr_reader :loader
+  private :loader
+
+  # @api private
+  def initialize(name, version, &block)
+    unless SemVer.valid?(version)
+      raise ArgumentError, "Cannot create face #{name.inspect} with invalid version number '#{version}'!"
+    end
+
+    @name    = Puppet::Interface::FaceCollection.underscorize(name)
+    @version = SemVer.new(version)
+
+    # The few bits of documentation we actually demand.  The default license
+    # is a favour to our end users; if you happen to get that in a core face
+    # report it as a bug, please. --daniel 2011-04-26
+    @authors  = []
+    @license  = 'All Rights Reserved'
+
+    @loader = Puppet::Util::Autoload.new(@name, "puppet/face/#{@name}")
+    instance_eval(&block) if block_given?
+  end
+
+  # Loads all actions defined in other files.
+  #
+  # @return [void]
+  # @api private
+  def load_actions
+    loader.loadall
+  end
+
+  # Returns a string representation with the face's name and version
+  # @return [String]
+  def to_s
+    "Puppet::Face[#{name.inspect}, #{version.inspect}]"
+  end
+
+  ########################################################################
+  # Action decoration, whee!  You are not expected to care about this code,
+  # which exists to support face building and construction.  I marked these
+  # private because the implementation is crude and ugly, and I don't yet know
+  # enough to work out how to make it clean.
+  #
+  # Once we have established that these methods will likely change radically,
+  # to be unrecognizable in the final outcome.  At which point we will throw
+  # all this away, replace it with something nice, and work out if we should
+  # be making this visible to the outside world... --daniel 2011-04-14
+  private
+  # @return [void]
+  # @api private
+  def __invoke_decorations(type, action, passed_args = [], passed_options = {})
+    [:before, :after].member?(type) or fail "unknown decoration type #{type}"
+
+    # Collect the decoration methods matching our pass.
+    methods = action.options.select do |name|
+      passed_options.has_key? name
+    end.map do |name|
+      action.get_option(name).__decoration_name(type)
+    end
+
+    methods.reverse! if type == :after
+
+    # Exceptions here should propagate up; this implements a hook we can use
+    # reasonably for option validation.
+    methods.each do |hook|
+      respond_to? hook and self.__send__(hook, action, passed_args, passed_options)
+    end
+  end
+
+  # @return [void]
+  # @api private
+  def __add_method(name, proc)
+    meta_def(name, &proc)
+    method(name).unbind
+  end
+
+  # @return [void]
+  # @api private
+  def self.__add_method(name, proc)
+    define_method(name, proc)
+    instance_method(name)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/action.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/action.rb
new file mode 100644
index 0000000..01cd845
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/action.rb
@@ -0,0 +1,374 @@
+require 'puppet/util/methodhelper'
+require 'prettyprint'
+
+# This represents an action that is attached to a face. Actions should
+# be constructed by calling {Puppet::Interface::ActionManager#action},
+# which is available on {Puppet::Interface}, and then calling methods of
+# {Puppet::Interface::ActionBuilder} in the supplied block.
+# @api private
+class Puppet::Interface::Action
+  include Puppet::Util::MethodHelper
+  extend  Puppet::Interface::DocGen
+  include Puppet::Interface::FullDocs
+
+  # @api private
+  def initialize(face, name, attrs = {})
+    raise "#{name.inspect} is an invalid action name" unless name.to_s =~ /^[a-z]\w*$/
+    @face    = face
+    @name    = name.to_sym
+
+    # The few bits of documentation we actually demand.  The default license
+    # is a favour to our end users; if you happen to get that in a core face
+    # report it as a bug, please. --daniel 2011-04-26
+    @authors = []
+    @license  = 'All Rights Reserved'
+
+    set_options(attrs)
+
+    # @options collects the added options in the order they're declared.
+    # @options_hash collects the options keyed by alias for quick lookups.
+    @options        = []
+    @display_global_options = []
+    @options_hash   = {}
+    @when_rendering = {}
+  end
+
+  # This is not nice, but it is the easiest way to make us behave like the
+  # Ruby Method object rather than UnboundMethod.  Duplication is vaguely
+  # annoying, but at least we are a shallow clone. --daniel 2011-04-12
+
+  # @return [void]
+  # @api private
+  def __dup_and_rebind_to(to)
+    bound_version = self.dup
+    bound_version.instance_variable_set(:@face, to)
+    return bound_version
+  end
+
+  def to_s() "#{@face}##{@name}" end
+
+  # The name of this action
+  # @return [Symbol]
+  attr_reader   :name
+
+  # The face this action is attached to
+  # @return [Puppet::Interface]
+  attr_reader   :face
+
+  # Whether this is the default action for the face
+  # @return [Boolean]
+  # @api private
+  attr_accessor :default
+  def default?
+    !!@default
+  end
+
+  ########################################################################
+  # Documentation...
+  attr_doc :returns
+  attr_doc :arguments
+  def synopsis
+    build_synopsis(@face.name, default? ? nil : name, arguments)
+  end
+
+  ########################################################################
+  # Support for rendering formats and all.
+
+
+  # @api private
+  def when_rendering(type)
+    unless type.is_a? Symbol
+      raise ArgumentError, "The rendering format must be a symbol, not #{type.class.name}"
+    end
+    # Do we have a rendering hook for this name?
+    return @when_rendering[type].bind(@face) if @when_rendering.has_key? type
+
+    # How about by another name?
+    alt = type.to_s.sub(/^to_/, '').to_sym
+    return @when_rendering[alt].bind(@face) if @when_rendering.has_key? alt
+
+    # Guess not, nothing to run.
+    return nil
+  end
+
+  # @api private
+  def set_rendering_method_for(type, proc)
+    unless proc.is_a? Proc
+      msg = "The second argument to set_rendering_method_for must be a Proc"
+      msg += ", not #{proc.class.name}" unless proc.nil?
+      raise ArgumentError, msg
+    end
+
+    if proc.arity != 1 and proc.arity != (@positional_arg_count + 1)
+      msg =  "the when_rendering method for the #{@face.name} face #{name} action "
+      msg += "takes either just one argument, the result of when_invoked, "
+      msg += "or the result plus the #{@positional_arg_count} arguments passed "
+      msg += "to the when_invoked block, not "
+      if proc.arity < 0 then
+        msg += "a variable number"
+      else
+        msg += proc.arity.to_s
+      end
+      raise ArgumentError, msg
+    end
+    unless type.is_a? Symbol
+      raise ArgumentError, "The rendering format must be a symbol, not #{type.class.name}"
+    end
+    if @when_rendering.has_key? type then
+      raise ArgumentError, "You can't define a rendering method for #{type} twice"
+    end
+    # Now, the ugly bit.  We add the method to our interface object, and
+    # retrieve it, to rotate through the dance of getting a suitable method
+    # object out of the whole process. --daniel 2011-04-18
+    @when_rendering[type] =
+      @face.__send__( :__add_method, __render_method_name_for(type), proc)
+  end
+
+  # @return [void]
+  # @api private
+  def __render_method_name_for(type)
+    :"#{name}_when_rendering_#{type}"
+  end
+  private :__render_method_name_for
+
+
+  # @api private
+  # @return [Symbol]
+  attr_accessor :render_as
+  def render_as=(value)
+    @render_as = value.to_sym
+  end
+
+
+  ########################################################################
+  # Initially, this was defined to allow the @action.invoke pattern, which is
+  # a very natural way to invoke behaviour given our introspection
+  # capabilities.   Heck, our initial plan was to have the faces delegate to
+  # the action object for invocation and all.
+  #
+  # It turns out that we have a binding problem to solve: @face was bound to
+  # the parent class, not the subclass instance, and we don't pass the
+  # appropriate context or change the binding enough to make this work.
+  #
+  # We could hack around it, by either mandating that you pass the context in
+  # to invoke, or try to get the binding right, but that has probably got
+  # subtleties that we don't instantly think of – especially around threads.
+  #
+  # So, we are pulling this method for now, and will return it to life when we
+  # have the time to resolve the problem.  For now, you should replace...
+  #
+  #     @action = @face.get_action(name)
+  #     @action.invoke(arg1, arg2, arg3)
+  #
+  # ...with...
+  #
+  #     @action = @face.get_action(name)
+  #     @face.send(@action.name, arg1, arg2, arg3)
+  #
+  # I understand that is somewhat cumbersome, but it functions as desired.
+  # --daniel 2011-03-31
+  #
+  # PS: This code is left present, but commented, to support this chunk of
+  # documentation, for the benefit of the reader.
+  #
+  # def invoke(*args, &block)
+  #   @face.send(name, *args, &block)
+  # end
+
+
+  # We need to build an instance method as a wrapper, using normal code, to be
+  # able to expose argument defaulting between the caller and definer in the
+  # Ruby API.  An extra method is, sadly, required for Ruby 1.8 to work since
+  # it doesn't expose bind on a block.
+  #
+  # Hopefully we can improve this when we finally shuffle off the last of Ruby
+  # 1.8 support, but that looks to be a few "enterprise" release eras away, so
+  # we are pretty stuck with this for now.
+  #
+  # Patches to make this work more nicely with Ruby 1.9 using runtime version
+  # checking and all are welcome, provided that they don't change anything
+  # outside this little ol' bit of code and all.
+  #
+  # Incidentally, we though about vendoring evil-ruby and actually adjusting
+  # the internal C structure implementation details under the hood to make
+  # this stuff work, because it would have been cleaner.  Which gives you an
+  # idea how motivated we were to make this cleaner.  Sorry.
+  # --daniel 2011-03-31
+
+
+  # The arity of the action
+  # @return [Integer]
+  attr_reader   :positional_arg_count
+
+  # The block that is executed when the action is invoked
+  # @return [block]
+  attr_accessor :when_invoked
+  def when_invoked=(block)
+
+    internal_name = "#{@name} implementation, required on Ruby 1.8".to_sym
+
+    arity = @positional_arg_count = block.arity
+    if arity == 0 then
+      # This will never fire on 1.8.7, which treats no arguments as "*args",
+      # but will on 1.9.2, which treats it as "no arguments".  Which bites,
+      # because this just begs for us to wind up in the horrible situation
+      # where a 1.8 vs 1.9 error bites our end users. --daniel 2011-04-19
+      raise ArgumentError, "when_invoked requires at least one argument (options) for action #{@name}"
+    elsif arity > 0 then
+      range = Range.new(1, arity - 1)
+      decl = range.map { |x| "arg#{x}" } << "options = {}"
+      optn = ""
+      args = "[" + (range.map { |x| "arg#{x}" } << "options").join(", ") + "]"
+    else
+      range = Range.new(1, arity.abs - 1)
+      decl = range.map { |x| "arg#{x}" } << "*rest"
+      optn = "rest << {} unless rest.last.is_a?(Hash)"
+      if arity == -1 then
+        args = "rest"
+      else
+        args = "[" + range.map { |x| "arg#{x}" }.join(", ") + "] + rest"
+      end
+    end
+
+    file    = __FILE__ + "+eval[wrapper]"
+    line    = __LINE__ + 2 # <== points to the same line as 'def' in the wrapper.
+    wrapper = <<WRAPPER
+def #{@name}(#{decl.join(", ")})
+  #{optn}
+  args    = #{args}
+  action  = get_action(#{name.inspect})
+  args   << action.validate_and_clean(args.pop)
+  __invoke_decorations(:before, action, args, args.last)
+  rval = self.__send__(#{internal_name.inspect}, *args)
+  __invoke_decorations(:after, action, args, args.last)
+  return rval
+end
+WRAPPER
+
+    if @face.is_a?(Class)
+      @face.class_eval do eval wrapper, nil, file, line end
+      @face.send(:define_method, internal_name, &block)
+      @when_invoked = @face.instance_method(name)
+    else
+      @face.instance_eval do eval wrapper, nil, file, line end
+      @face.meta_def(internal_name, &block)
+      @when_invoked = @face.method(name).unbind
+    end
+  end
+
+  def add_option(option)
+    option.aliases.each do |name|
+      if conflict = get_option(name) then
+        raise ArgumentError, "Option #{option} conflicts with existing option #{conflict}"
+      elsif conflict = @face.get_option(name) then
+        raise ArgumentError, "Option #{option} conflicts with existing option #{conflict} on #{@face}"
+      end
+    end
+
+    @options << option.name
+
+    option.aliases.each do |name|
+      @options_hash[name] = option
+    end
+
+    option
+  end
+
+  def option?(name)
+    @options_hash.include? name.to_sym
+  end
+
+  def options
+    @face.options + @options
+  end
+
+  def add_display_global_options(*args)
+    @display_global_options ||= []
+    [args].flatten.each do |refopt|
+      raise ArgumentError, "Global option #{refopt} does not exist in Puppet.settings" unless Puppet.settings.include? refopt
+      @display_global_options << refopt
+    end
+    @display_global_options.uniq!
+    @display_global_options
+  end
+
+  def display_global_options(*args)
+    args ? add_display_global_options(args) : @display_global_options + @face.display_global_options
+  end
+  alias :display_global_option :display_global_options
+
+  def get_option(name, with_inherited_options = true)
+    option = @options_hash[name.to_sym]
+    if option.nil? and with_inherited_options
+      option = @face.get_option(name)
+    end
+    option
+  end
+
+  def validate_and_clean(original)
+    # The final set of arguments; effectively a hand-rolled shallow copy of
+    # the original, which protects the caller from the surprises they might
+    # get if they passed us a hash and we mutated it...
+    result = {}
+
+    # Check for multiple aliases for the same option, and canonicalize the
+    # name of the argument while we are about it.
+    overlap = Hash.new do |h, k| h[k] = [] end
+    unknown = []
+    original.keys.each do |name|
+      if option = get_option(name) then
+        canonical = option.name
+        if result.has_key? canonical
+          overlap[canonical] << name
+        else
+          result[canonical] = original[name]
+        end
+      elsif Puppet.settings.include? name
+        result[name] = original[name]
+      else
+        unknown << name
+      end
+    end
+
+    unless overlap.empty?
+      msg = overlap.map {|k, v| "(#{k}, #{v.sort.join(', ')})" }.join(", ")
+      raise ArgumentError, "Multiple aliases for the same option passed: #{msg}"
+    end
+
+    unless unknown.empty?
+      msg = unknown.sort.join(", ")
+      raise ArgumentError, "Unknown options passed: #{msg}"
+    end
+
+    # Inject default arguments and check for missing mandating options.
+    missing = []
+    options.map {|x| get_option(x) }.each do |option|
+      name = option.name
+      next if result.has_key? name
+
+      if option.has_default?
+        result[name] = option.default
+      elsif option.required?
+        missing << name
+      end
+    end
+
+    unless missing.empty?
+      msg = missing.sort.join(', ')
+      raise ArgumentError, "The following options are required: #{msg}"
+    end
+
+    # All done.
+    return result
+  end
+
+  ########################################################################
+  # Support code for action decoration; see puppet/interface.rb for the gory
+  # details of why this is hidden away behind private. --daniel 2011-04-15
+  private
+  # @return [void]
+  # @api private
+  def __add_method(name, proc)
+    @face.__send__ :__add_method, name, proc
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/action_builder.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/action_builder.rb
new file mode 100644
index 0000000..da1bdd0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/action_builder.rb
@@ -0,0 +1,149 @@
+# This class is used to build {Puppet::Interface::Action actions}.
+# When an action is defined with
+# {Puppet::Interface::ActionManager#action} the block is evaluated
+# within the context of a new instance of this class.
+# @api public
+class Puppet::Interface::ActionBuilder
+  # The action under construction
+  # @return [Puppet::Interface::Action]
+  # @api private
+  attr_reader :action
+
+  # Builds a new action.
+  # @return [Puppet::Interface::Action]
+  # @api private
+  def self.build(face, name, &block)
+    raise "Action #{name.inspect} must specify a block" unless block
+    new(face, name, &block).action
+  end
+
+  # Ideally the method we're defining here would be added to the action, and a
+  # method on the face would defer to it, but we can't get scope correct, so
+  # we stick with this. --daniel 2011-03-24
+
+  # Sets what the action does when it is invoked. This takes a block
+  # which will be called when the action is invoked. The action will
+  # accept arguments based on the arity of the block. It should always
+  # take at least one argument for options. Options will be the last
+  # argument.
+  #
+  # @overload when_invoked({|options| ... })
+  #   An action with no arguments
+  # @overload when_invoked({|arg1, arg2, options| ... })
+  #   An action with two arguments
+  # @return [void]
+  # @api public
+  # @dsl Faces
+  def when_invoked(&block)
+    @action.when_invoked = block
+  end
+
+  # Sets a block to be run at the rendering stage, for a specific
+  # rendering type (eg JSON, YAML, console), after the block for
+  # when_invoked gets run. This manipulates the value returned by the
+  # action. It makes it possible to work around limitations in the
+  # underlying object returned, and should be avoided in favor of
+  # returning a more capable object.
+  # @api private
+  # @todo this needs more
+  # @dsl Faces
+  def when_rendering(type = nil, &block)
+    if type.nil? then           # the default error message sucks --daniel 2011-04-18
+      raise ArgumentError, 'You must give a rendering format to when_rendering'
+    end
+    if block.nil? then
+      raise ArgumentError, 'You must give a block to when_rendering'
+    end
+    @action.set_rendering_method_for(type, block)
+  end
+
+  # Declare that this action can take a specific option, and provide the
+  # code to do so.  One or more strings are given, in the style of
+  # OptionParser (see example). These strings are parsed to derive a
+  # name for the option. Any `-` characters within the option name (ie
+  # excluding the intial `-` or `--` for an option) will be translated
+  # to `_`.The first long option will be used as the name, and the rest
+  # are retained as aliases. The original form of the option is used
+  # when invoking the face, the translated form is used internally.
+  #
+  # When the action is invoked the value of the option is available in
+  # a hash passed to the {Puppet::Interface::ActionBuilder#when_invoked
+  # when_invoked} block, using the option name in symbol form as the
+  # hash key.
+  #
+  # The block to this method is used to set attributes for the option
+  # (see {Puppet::Interface::OptionBuilder}).
+  #
+  # @param declaration [String] Option declarations, as described above
+  #   and in the example.
+  #
+  # @example Say hi
+  #   action :say_hi do
+  #     option "-u USER", "--user-name USER" do
+  #       summary "Who to say hi to"
+  #     end
+  #
+  #     when_invoked do |options|
+  #       "Hi, #{options[:user_name]}"
+  #     end
+  #   end
+  # @api public
+  # @dsl Faces
+  def option(*declaration, &block)
+    option = Puppet::Interface::OptionBuilder.build(@action, *declaration, &block)
+    @action.add_option(option)
+  end
+
+  # Set this as the default action for the face.
+  # @api public
+  # @dsl Faces
+  # @return [void]
+  def default(value = true)
+    @action.default = !!value
+  end
+
+  # @api private
+  def display_global_options(*args)
+    @action.add_display_global_options args
+  end
+  alias :display_global_option :display_global_options
+
+  # Sets the default rendering format
+  # @api private
+  def render_as(value = nil)
+    value.nil? and raise ArgumentError, "You must give a rendering format to render_as"
+
+    formats = Puppet::Network::FormatHandler.formats
+    unless formats.include? value
+      raise ArgumentError, "#{value.inspect} is not a valid rendering format: #{formats.sort.join(", ")}"
+    end
+
+    @action.render_as = value
+  end
+
+  # Metaprogram the simple DSL from the target class.
+  Puppet::Interface::Action.instance_methods.grep(/=$/).each do |setter|
+    next if setter =~ /^=/
+    property = setter.to_s.chomp('=')
+
+    unless method_defined? property
+      # Using eval because the argument handling semantics are less awful than
+      # when we use the define_method/block version.  The later warns on older
+      # Ruby versions if you pass the wrong number of arguments, but carries
+      # on, which is totally not what we want. --daniel 2011-04-18
+      eval <<-METHOD
+        def #{property}(value)
+          @action.#{property} = value
+        end
+      METHOD
+    end
+  end
+
+  private
+  def initialize(face, name, &block)
+    @face   = face
+    @action = Puppet::Interface::Action.new(face, name)
+    instance_eval(&block)
+    @action.when_invoked or raise ArgumentError, "actions need to know what to do when_invoked; please add the block"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/action_manager.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/action_manager.rb
new file mode 100644
index 0000000..87906c5
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/action_manager.rb
@@ -0,0 +1,101 @@
+# This class is not actually public API, but the method
+# {Puppet::Interface::ActionManager#action action} is public when used
+# as part of the Faces DSL (i.e. from within a
+# {Puppet::Interface.define define} block).
+# @api public
+module Puppet::Interface::ActionManager
+  # Declare that this app can take a specific action, and provide
+  # the code to do so.
+
+  # Defines a new action. This takes a block to build the action using
+  # the methods on {Puppet::Interface::ActionBuilder}.
+  # @param name [Symbol] The name that will be used to invoke the
+  #   action
+  # @overload action(name, {|| block})
+  # @return [void]
+  # @api public
+  # @dsl Faces
+  def action(name, &block)
+    @actions ||= {}
+    Puppet.warning "Redefining action #{name} for #{self}" if action?(name)
+
+    action = Puppet::Interface::ActionBuilder.build(self, name, &block)
+
+    # REVISIT: (#18042) doesn't this mean we can't redefine the default action? -- josh
+    if action.default and current = get_default_action
+      raise "Actions #{current.name} and #{name} cannot both be default"
+    end
+
+    @actions[action.name] = action
+  end
+
+  # Defines an action without using ActionBuilder. The block given is
+  # the code that will be executed when the action is invoked.
+  # @api public
+  # @deprecated
+  def script(name, &block)
+    @actions ||= {}
+    Puppet.warning "Redefining action #{name} for #{self}" if action?(name)
+
+    # REVISIT: (#18048) it's possible to create multiple default actions
+    @actions[name] = Puppet::Interface::Action.new(self, name, :when_invoked => block)
+  end
+
+  # Returns the list of available actions for this face.
+  # @return [Array<Symbol>] The names of the actions for this face
+  # @api private
+  def actions
+    @actions ||= {}
+    result = @actions.keys
+
+    if self.is_a?(Class) and superclass.respond_to?(:actions)
+      result += superclass.actions
+    elsif self.class.respond_to?(:actions)
+      result += self.class.actions
+    end
+    # We need to uniq the result, because we duplicate actions when they are
+    # fetched to ensure that they have the correct bindings; they shadow the
+    # parent, and uniq implements that. --daniel 2011-06-01
+    result.uniq.sort
+  end
+
+  # Retrieves a named action
+  # @param name [Symbol] The name of the action
+  # @return [Puppet::Interface::Action] The action object
+  # @api private
+  def get_action(name)
+    @actions ||= {}
+    result = @actions[name.to_sym]
+    if result.nil?
+      if self.is_a?(Class) and superclass.respond_to?(:get_action)
+        found = superclass.get_action(name)
+      elsif self.class.respond_to?(:get_action)
+        found = self.class.get_action(name)
+      end
+
+      if found then
+        # This is not the nicest way to make action equivalent to the Ruby
+        # Method object, rather than UnboundMethod, but it will do for now,
+        # and we only have to make this change in *one* place. --daniel 2011-04-12
+        result = @actions[name.to_sym] = found.__dup_and_rebind_to(self)
+      end
+    end
+    return result
+  end
+
+  # Retrieves the default action for the face
+  # @return [Puppet::Interface::Action]
+  # @api private
+  def get_default_action
+    default = actions.map {|x| get_action(x) }.select {|x| x.default }
+    if default.length > 1
+      raise "The actions #{default.map(&:name).join(", ")} cannot all be default"
+    end
+    default.first
+  end
+
+  # @api private
+  def action?(name)
+    actions.include?(name.to_sym)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/documentation.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/documentation.rb
new file mode 100644
index 0000000..d90a68a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/documentation.rb
@@ -0,0 +1,342 @@
+class Puppet::Interface
+  # @api private
+  module DocGen
+    require 'puppet/util/docs'
+
+    # @api private
+    def self.strip_whitespace(text)
+      # I don't want no...
+      Puppet::Util::Docs.scrub(text)
+    end
+
+    # The documentation attributes all have some common behaviours; previously
+    # we open-coded them across the set of six things, but that seemed
+    # wasteful - especially given that they were literally the same, and had
+    # the same bug hidden in them.
+    #
+    # This feels a bit like overkill, but at least the common code is common
+    # now. --daniel 2011-04-29
+
+    # @api private
+    def attr_doc(name, &validate)
+      # Now, which form of the setter do we want, validated or not?
+      get_arg = "value.to_s"
+      if validate
+        define_method(:"_validate_#{name}", validate)
+        get_arg = "_validate_#{name}(#{get_arg})"
+      end
+
+      # We use module_eval, which I don't like much, because we can't have an
+      # argument to a block with a default value in Ruby 1.8, and I don't like
+      # the side-effects (eg: no argument count validation) of using blocks
+      # without as metheds.  When we are 1.9 only (hah!) you can totally
+      # replace this with some up-and-up define_method. --daniel 2011-04-29
+      module_eval(<<-EOT, __FILE__, __LINE__ + 1)
+        def #{name}(value = nil)
+          self.#{name} = value unless value.nil?
+          @#{name}
+        end
+
+        def #{name}=(value)
+          @#{name} = Puppet::Interface::DocGen.strip_whitespace(#{get_arg})
+        end
+      EOT
+    end
+  end
+
+  # This module can be mixed in to provide a minimal set of
+  # documentation attributes.
+  # @api public
+  module TinyDocs
+    extend Puppet::Interface::DocGen
+
+    # @!method summary(summary)
+    # Sets a summary of this object.
+    # @api public
+    # @dsl Faces
+    attr_doc :summary do |value|
+      value =~ /\n/ and
+        raise ArgumentError, "Face summary should be a single line; put the long text in 'description' instead."
+      value
+    end
+
+    # @!method description(description)
+    # Sets the long description of this object.
+    # @param description [String] The description of this object.
+    # @api public
+    # @dsl Faces
+    attr_doc :description
+
+    # @api private
+    def build_synopsis(face, action = nil, arguments = nil)
+      PrettyPrint.format do |s|
+        s.text("puppet #{face}")
+        s.text(" #{action}") unless action.nil?
+        s.text(" ")
+
+        options.each do |option|
+          option = get_option(option)
+          wrap = option.required? ? %w{ < > } : %w{ [ ] }
+
+          s.group(0, *wrap) do
+            option.optparse.each do |item|
+              unless s.current_group.first?
+                s.breakable
+                s.text '|'
+                s.breakable
+              end
+              s.text item
+            end
+          end
+
+          s.breakable
+        end
+
+        display_global_options.sort.each do |option|
+          wrap = %w{ [ ] }
+          s.group(0, *wrap) do
+            type = Puppet.settings.setting(option).default
+            type ||= Puppet.settings.setting(option).type.to_s.upcase
+            s.text "--#{option} #{type}"
+            s.breakable
+          end
+          s.breakable
+        end
+
+        if arguments then
+          s.text arguments.to_s
+        end
+      end
+    end
+
+  end
+
+  # This module can be mixed in to provide a full set of documentation
+  # attributes. It is intended to be used for {Puppet::Interface}.
+  # @api public
+  module FullDocs
+    extend Puppet::Interface::DocGen
+    include TinyDocs
+
+    # @!method examples
+    # @overload examples(text)
+    #   Sets examples.
+    #   @param text [String] Example text
+    #   @api public
+    #   @return [void]
+    #   @dsl Faces
+    # @overload examples
+    #   Returns documentation of examples
+    #   @return [String] The examples
+    #   @api private
+    attr_doc :examples
+
+    # @!method notes(text)
+    # @overload notes(text)
+    #   Sets optional notes.
+    #   @param text [String] The notes
+    #   @api public
+    #   @return [void]
+    #   @dsl Faces
+    # @overload notes
+    #   Returns any optional notes
+    #   @return [String] The notes
+    #   @api private
+    attr_doc :notes
+
+    # @!method license(text)
+    # @overload license(text)
+    #   Sets the license text
+    #   @param text [String] the license text
+    #   @api public
+    #   @return [void]
+    #   @dsl Faces
+    # @overload license
+    #   Returns the license
+    #   @return [String] The license
+    #   @api private
+    attr_doc :license
+
+    attr_doc :short_description
+    # @overload short_description(value)
+    #   Sets a short description for this object.
+    #   @param value [String, nil] A short description (about a paragraph)
+    #     of this component. If `value` is `nil` the short_description
+    #     will be set to the shorter of the first paragraph or the first
+    #     five lines of {description}.
+    #   @return [void]
+    #   @api public
+    #   @dsl Faces
+    # @overload short_description
+    #   Get the short description for this object
+    #   @return [String, nil] The short description of this object. If none is
+    #     set it will be derived from {description}. Returns `nil` if
+    #     {description} is `nil`.
+    #   @api private
+    def short_description(value = nil)
+      self.short_description = value unless value.nil?
+      if @short_description.nil? then
+        return nil if @description.nil?
+        lines = @description.split("\n")
+        first_paragraph_break = lines.index('') || 5
+        grab  = [5, first_paragraph_break].min
+        @short_description = lines[0, grab].join("\n")
+        @short_description += ' [...]' if (grab < lines.length and first_paragraph_break >= 5)
+      end
+      @short_description
+    end
+
+    # @overload author(value)
+    #   Adds an author to the documentation for this object. To set
+    #   multiple authors, call this once for each author.
+    #   @param value [String] the name of the author
+    #   @api public
+    #   @dsl Faces
+    # @overload author
+    #   Returns a list of authors
+    #   @return [String, nil] The names of all authors separated by
+    #     newlines, or `nil` if no authors have been set.
+    #   @api private
+    def author(value = nil)
+      unless value.nil? then
+        unless value.is_a? String
+          raise ArgumentError, 'author must be a string; use multiple statements for multiple authors'
+        end
+
+        if value =~ /\n/ then
+          raise ArgumentError, 'author should be a single line; use multiple statements for multiple authors'
+        end
+        @authors.push(Puppet::Interface::DocGen.strip_whitespace(value))
+      end
+      @authors.empty? ? nil : @authors.join("\n")
+    end
+
+    # Returns a list of authors. See {author}.
+    # @return [String] The list of authors, separated by newlines.
+    # @api private
+    def authors
+      @authors
+    end
+
+    # @api private
+    def author=(value)
+      # I think it's a bug that this ends up being the exposed
+      # version of `author` on ActionBuilder
+      if Array(value).any? {|x| x =~ /\n/ } then
+        raise ArgumentError, 'author should be a single line; use multiple statements'
+      end
+      @authors = Array(value).map{|x| Puppet::Interface::DocGen.strip_whitespace(x) }
+    end
+    alias :authors= :author=
+
+    # Sets the copyright owner and year. This returns the copyright
+    # string, so it can be called with no arguments retrieve that string
+    # without side effects.
+    # @param owner [String, Array<String>] The copyright owner or an
+    #   array of owners
+    # @param years [Integer, Range<Integer>, Array<Integer,Range<Integer>>]
+    #   The copyright year or years. Years can be specified with integers,
+    #   a range of integers, or an array of integers and ranges of
+    #   integers.
+    # @return [String] A string describing the copyright on this object.
+    # @api public
+    # @dsl Faces
+    def copyright(owner = nil, years = nil)
+      if years.nil? and not owner.nil? then
+        raise ArgumentError, 'copyright takes the owners names, then the years covered'
+      end
+      self.copyright_owner = owner unless owner.nil?
+      self.copyright_years = years unless years.nil?
+
+      if self.copyright_years or self.copyright_owner then
+        "Copyright #{self.copyright_years} by #{self.copyright_owner}"
+      else
+        "Unknown copyright owner and years."
+      end
+    end
+
+    # Sets the copyright owner
+    # @param value [String, Array<String>] The copyright owner or
+    #   owners.
+    # @return [String] Comma-separated list of copyright owners
+    # @api private
+    attr_accessor :copyright_owner
+    def copyright_owner=(value)
+      case value
+      when String then @copyright_owner = value
+      when Array  then @copyright_owner = value.join(", ")
+      else
+        raise ArgumentError, "copyright owner must be a string or an array of strings"
+      end
+      @copyright_owner
+    end
+
+    # Sets the copyright year
+    # @param value [Integer, Range<Integer>, Array<Integer, Range>] The
+    #   copyright year or years.
+    # @return [String]
+    # @api private
+    attr_accessor :copyright_years
+    def copyright_years=(value)
+      years = munge_copyright_year value
+      years = (years.is_a?(Array) ? years : [years]).
+        sort_by do |x| x.is_a?(Range) ? x.first : x end
+
+      @copyright_years = years.map do |year|
+        if year.is_a? Range then
+          "#{year.first}-#{year.last}"
+        else
+          year
+        end
+      end.join(", ")
+    end
+
+    # @api private
+    def munge_copyright_year(input)
+      case input
+      when Range then input
+      when Integer then
+        if input < 1970 then
+          fault = "before 1970"
+        elsif input > (future = Time.now.year + 2) then
+          fault = "after #{future}"
+        end
+        if fault then
+          raise ArgumentError, "copyright with a year #{fault} is very strange; did you accidentally add or subtract two years?"
+        end
+
+        input
+
+      when String then
+        input.strip.split(/,/).map do |part|
+          part = part.strip
+          if part =~ /^\d+$/ then
+            part.to_i
+          elsif found = part.split(/-/) then
+            unless found.length == 2 and found.all? {|x| x.strip =~ /^\d+$/ }
+              raise ArgumentError, "#{part.inspect} is not a good copyright year or range"
+            end
+            Range.new(found[0].to_i, found[1].to_i)
+          else
+            raise ArgumentError, "#{part.inspect} is not a good copyright year or range"
+          end
+        end
+
+      when Array then
+        result = []
+        input.each do |item|
+          item = munge_copyright_year item
+          if item.is_a? Array
+            result.concat item
+          else
+            result << item
+          end
+        end
+        result
+
+      else
+        raise ArgumentError, "#{input.inspect} is not a good copyright year, set, or range"
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/face_collection.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/face_collection.rb
new file mode 100644
index 0000000..0c95f50
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/face_collection.rb
@@ -0,0 +1,125 @@
+module Puppet::Interface::FaceCollection
+  @faces = Hash.new { |hash, key| hash[key] = {} }
+
+  @loader = Puppet::Util::Autoload.new(:application, 'puppet/face')
+
+  def self.faces
+    unless @loaded
+      @loaded = true
+      names = @loader.files_to_load.map {|fn| ::File.basename(fn, '.rb')}.uniq
+      names.each {|name| self[name, :current]}
+    end
+    @faces.keys.select {|name| @faces[name].length > 0 }
+  end
+
+  def self.[](name, version)
+    name = underscorize(name)
+    get_face(name, version) or load_face(name, version)
+  end
+
+  def self.get_action_for_face(name, action_name, version)
+    name = underscorize(name)
+
+    # If the version they request specifically doesn't exist, don't search
+    # elsewhere.  Usually this will start from :current and all...
+    return nil unless face = self[name, version]
+    unless action = face.get_action(action_name)
+      # ...we need to search for it bound to an o{lder,ther} version.  Since
+      # we load all actions when the face is first references, this will be in
+      # memory in the known set of versions of the face.
+      (@faces[name].keys - [ :current ]).sort.reverse.each do |version|
+        break if action = @faces[name][version].get_action(action_name)
+      end
+    end
+
+    return action
+  end
+
+  # get face from memory, without loading.
+  def self.get_face(name, pattern)
+    return nil unless @faces.has_key? name
+    return @faces[name][:current] if pattern == :current
+
+    versions = @faces[name].keys - [ :current ]
+    found    = SemVer.find_matching(pattern, versions)
+    return @faces[name][found]
+  end
+
+  # try to load the face, and return it.
+  def self.load_face(name, version)
+    # We always load the current version file; the common case is that we have
+    # the expected version and any compatibility versions in the same file,
+    # the default.  Which means that this is almost always the case.
+    #
+    # We use require to avoid executing the code multiple times, like any
+    # other Ruby library that we might want to use.  --daniel 2011-04-06
+    if safely_require name then
+      # If we wanted :current, we need to index to find that; direct version
+      # requests just work as they go. --daniel 2011-04-06
+      if version == :current then
+        # We need to find current out of this.  This is the largest version
+        # number that doesn't have a dedicated on-disk file present; those
+        # represent "experimental" versions of faces, which we don't fully
+        # support yet.
+        #
+        # We walk the versions from highest to lowest and take the first version
+        # that is not defined in an explicitly versioned file on disk as the
+        # current version.
+        #
+        # This constrains us to only ship experimental versions with *one*
+        # version in the file, not multiple, but given you can't reliably load
+        # them except by side-effect when you ignore that rule this seems safe
+        # enough...
+        #
+        # Given those constraints, and that we are not going to ship a versioned
+        # interface that is not :current in this release, we are going to leave
+        # these thoughts in place, and just punt on the actual versioning.
+        #
+        # When we upgrade the core to support multiple versions we can solve the
+        # problems then; as lazy as possible.
+        #
+        # We do support multiple versions in the same file, though, so we sort
+        # versions here and return the last item in that set.
+        #
+        # --daniel 2011-04-06
+        latest_ver = @faces[name].keys.sort.last
+        @faces[name][:current] = @faces[name][latest_ver]
+      end
+    end
+
+    unless version == :current or get_face(name, version)
+      # Try an obsolete version of the face, if needed, to see if that helps?
+      safely_require name, version
+    end
+
+    return get_face(name, version)
+  end
+
+  def self.safely_require(name, version = nil)
+    path = @loader.expand(version ? ::File.join(version.to_s, name.to_s) : name)
+    require path
+    true
+
+  rescue LoadError => e
+    raise unless e.message =~ %r{-- #{path}$}
+    # ...guess we didn't find the file; return a much better problem.
+    nil
+  rescue SyntaxError => e
+    raise unless e.message =~ %r{#{path}\.rb:\d+: }
+    Puppet.err "Failed to load face #{name}:\n#{e}"
+    # ...but we just carry on after complaining.
+    nil
+  end
+
+  def self.register(face)
+    @faces[underscorize(face.name)][face.version] = face
+  end
+
+  def self.underscorize(name)
+    unless name.to_s =~ /^[-_a-z][-_a-z0-9]*$/i then
+      raise ArgumentError, "#{name.inspect} (#{name.class}) is not a valid face name"
+    end
+
+    name.to_s.downcase.split(/[-_]/).join('_').to_sym
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/option.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/option.rb
new file mode 100644
index 0000000..199039c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/option.rb
@@ -0,0 +1,150 @@
+# This represents an option on an action or face (to be globally applied
+# to its actions). Options should be constructed by calling
+# {Puppet::Interface::OptionManager#option}, which is available on
+# {Puppet::Interface}, and then calling methods of
+# {Puppet::Interface::OptionBuilder} in the supplied block.
+# @api public
+class Puppet::Interface::Option
+  include Puppet::Interface::TinyDocs
+
+  # @api private
+  def initialize(parent, *declaration, &block)
+    @parent   = parent
+    @optparse = []
+    @default  = nil
+
+    # Collect and sort the arguments in the declaration.
+    dups = {}
+    declaration.each do |item|
+      if item.is_a? String and item.to_s =~ /^-/ then
+        unless item =~ /^-[a-z]\b/ or item =~ /^--[^-]/ then
+          raise ArgumentError, "#{item.inspect}: long options need two dashes (--)"
+        end
+        @optparse << item
+
+        # Duplicate checking...
+        # for our duplicate checking purpose, we don't make a check with the
+        # translated '-' -> '_'. Right now, we do that on purpose because of
+        # a duplicated option made publicly available on certificate and ca
+        # faces for dns alt names. Puppet defines 'dns_alt_names', those
+        # faces include 'dns-alt-names'.  We can't get rid of 'dns-alt-names'
+        # yet, so we need to do our duplicate checking on the untranslated
+        # version of the option.
+        # jeffweiss 17 april 2012
+        name = optparse_to_optionname(item)
+        if Puppet.settings.include? name then
+          raise ArgumentError, "#{item.inspect}: already defined in puppet"
+        end
+        if dup = dups[name] then
+          raise ArgumentError, "#{item.inspect}: duplicates existing alias #{dup.inspect} in #{@parent}"
+        else
+          dups[name] = item
+        end
+      else
+        raise ArgumentError, "#{item.inspect} is not valid for an option argument"
+      end
+    end
+
+    if @optparse.empty? then
+      raise ArgumentError, "No option declarations found while building"
+    end
+
+    # Now, infer the name from the options; we prefer the first long option as
+    # the name, rather than just the first option.
+    @name = optparse_to_name(@optparse.find do |a| a =~ /^--/ end || @optparse.first)
+    @aliases = @optparse.map { |o| optparse_to_name(o) }
+
+    # Do we take an argument?  If so, are we consistent about it, because
+    # incoherence here makes our life super-difficult, and we can more easily
+    # relax this rule later if we find a valid use case for it. --daniel 2011-03-30
+    @argument = @optparse.any? { |o| o =~ /[ =]/ }
+    if @argument and not @optparse.all? { |o| o =~ /[ =]/ } then
+      raise ArgumentError, "Option #{@name} is inconsistent about taking an argument"
+    end
+
+    # Is our argument optional?  The rules about consistency apply here, also,
+    # just like they do to taking arguments at all. --daniel 2011-03-30
+    @optional_argument = @optparse.any? { |o| o=~/[ =]\[/ }
+    @optional_argument and raise ArgumentError, "Options with optional arguments are not supported"
+    if @optional_argument and not @optparse.all? { |o| o=~/[ =]\[/ } then
+      raise ArgumentError, "Option #{@name} is inconsistent about the argument being optional"
+    end
+  end
+
+  # to_s and optparse_to_name are roughly mirrored, because they are used to
+  # transform options to name symbols, and vice-versa.  This isn't a full
+  # bidirectional transformation though. --daniel 2011-04-07
+
+  def to_s
+    @name.to_s.tr('_', '-')
+  end
+
+  # @api private
+  def optparse_to_optionname(declaration)
+    unless found = declaration.match(/^-+(?:\[no-\])?([^ =]+)/) then
+      raise ArgumentError, "Can't find a name in the declaration #{declaration.inspect}"
+    end
+    found.captures.first
+  end
+
+  # @api private
+  def optparse_to_name(declaration)
+    name = optparse_to_optionname(declaration).tr('-', '_')
+    raise "#{name.inspect} is an invalid option name" unless name.to_s =~ /^[a-z]\w*$/
+    name.to_sym
+  end
+
+
+  def takes_argument?
+    !!@argument
+  end
+  def optional_argument?
+    !!@optional_argument
+  end
+  def required?
+    !!@required
+  end
+
+  def has_default?
+    !!@default
+  end
+
+  def default=(proc)
+    required and raise ArgumentError, "#{self} can't be optional and have a default value"
+    proc.is_a? Proc or raise ArgumentError, "default value for #{self} is a #{proc.class.name.inspect}, not a proc"
+    @default = proc
+  end
+
+  def default
+    @default and @default.call
+  end
+
+  attr_reader   :parent, :name, :aliases, :optparse
+  attr_accessor :required
+  def required=(value)
+    has_default? and raise ArgumentError, "#{self} can't be optional and have a default value"
+    @required = value
+  end
+
+  attr_accessor :before_action
+  def before_action=(proc)
+    proc.is_a? Proc or raise ArgumentError, "before action hook for #{self} is a #{proc.class.name.inspect}, not a proc"
+    @before_action =
+      @parent.__send__(:__add_method, __decoration_name(:before), proc)
+  end
+
+  attr_accessor :after_action
+  def after_action=(proc)
+    proc.is_a? Proc or raise ArgumentError, "after action hook for #{self} is a #{proc.class.name.inspect}, not a proc"
+    @after_action =
+      @parent.__send__(:__add_method, __decoration_name(:after), proc)
+  end
+
+  def __decoration_name(type)
+    if @parent.is_a? Puppet::Interface::Action then
+      :"option #{name} from #{parent.name} #{type} decoration"
+    else
+      :"option #{name} #{type} decoration"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/option_builder.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/option_builder.rb
new file mode 100644
index 0000000..72e09ca
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/option_builder.rb
@@ -0,0 +1,93 @@
+# @api public
+class Puppet::Interface::OptionBuilder
+  # The option under construction
+  # @return [Puppet::Interface::Option]
+  # @api private
+  attr_reader :option
+
+  # Build an option
+  # @return [Puppet::Interface::Option]
+  # @api private
+  def self.build(face, *declaration, &block)
+    new(face, *declaration, &block).option
+  end
+
+  def initialize(face, *declaration, &block)
+    @face   = face
+    @option = Puppet::Interface::Option.new(face, *declaration)
+    instance_eval(&block) if block_given?
+    @option
+  end
+
+  # Metaprogram the simple DSL from the option class.
+  Puppet::Interface::Option.instance_methods.grep(/=$/).each do |setter|
+    next if setter =~ /^=/
+    dsl = setter.to_s.chomp('=')
+
+    unless private_method_defined? dsl
+      define_method(dsl) do |value| @option.send(setter, value) end
+    end
+  end
+
+  # Override some methods that deal in blocks, not objects.
+
+  # Sets a block to be executed when an action is invoked before the
+  # main action code. This is most commonly used to validate an option.
+  # @yieldparam action [Puppet::Interface::Action] The action being
+  #   invoked
+  # @yieldparam args [Array] The arguments given to the action
+  # @yieldparam options [Hash<Symbol=>Object>] Any options set
+  # @api public
+  # @dsl Faces
+  def before_action(&block)
+    block or raise ArgumentError, "#{@option} before_action requires a block"
+    if @option.before_action
+      raise ArgumentError, "#{@option} already has a before_action set"
+    end
+    unless block.arity == 3 then
+      raise ArgumentError, "before_action takes three arguments, action, args, and options"
+    end
+    @option.before_action = block
+  end
+
+  # Sets a block to be executed after an action is invoked.
+  # !(see before_action)
+  # @api public
+  # @dsl Faces
+  def after_action(&block)
+    block or raise ArgumentError, "#{@option} after_action requires a block"
+    if @option.after_action
+      raise ArgumentError, "#{@option} already has an after_action set"
+    end
+    unless block.arity == 3 then
+      raise ArgumentError, "after_action takes three arguments, action, args, and options"
+    end
+    @option.after_action = block
+  end
+
+  # Sets whether the option is required. If no argument is given it
+  # defaults to setting it as a required option.
+  # @api public
+  # @dsl Faces
+  def required(value = true)
+    @option.required = value
+  end
+
+  # Sets a block that will be used to compute the default value for this
+  # option. It will be evaluated when the action is invoked. The block
+  # should take no arguments.
+  # @api public
+  # @dsl Faces
+  def default_to(&block)
+    block or raise ArgumentError, "#{@option} default_to requires a block"
+    if @option.has_default?
+      raise ArgumentError, "#{@option} already has a default value"
+    end
+    # Ruby 1.8 treats a block without arguments as accepting any number; 1.9
+    # gets this right, so we work around it for now... --daniel 2011-07-20
+    unless block.arity == 0 or (RUBY_VERSION =~ /^1\.8/ and block.arity == -1)
+      raise ArgumentError, "#{@option} default_to block should not take any arguments"
+    end
+    @option.default = block
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/option_manager.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/option_manager.rb
new file mode 100644
index 0000000..b68e38b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/interface/option_manager.rb
@@ -0,0 +1,99 @@
+# This class is not actually public API, but the method
+# {Puppet::Interface::OptionManager#option option} is public when used
+# as part of the Faces DSL (i.e. from within a
+# {Puppet::Interface.define define} block).
+# @api public
+module Puppet::Interface::OptionManager
+
+  # @api private
+  def display_global_options(*args)
+    @display_global_options ||= []
+    [args].flatten.each do |refopt|
+      raise ArgumentError, "Global option #{refopt} does not exist in Puppet.settings" unless Puppet.settings.include? refopt
+      @display_global_options << refopt if refopt
+    end
+    @display_global_options.uniq!
+    @display_global_options
+  end
+  alias :display_global_option :display_global_options
+
+  def all_display_global_options
+    walk_inheritance_tree(@display_global_options, :all_display_global_options)
+  end
+
+  # @api private
+  def walk_inheritance_tree(start, sym)
+    result = (start ||= [])
+    if self.is_a?(Class) and superclass.respond_to?(sym)
+      result = superclass.send(sym) + result
+    elsif self.class.respond_to?(sym)
+      result = self.class.send(sym) + result
+    end
+    return result
+  end
+
+  # Declare that this app can take a specific option, and provide the
+  # code to do so. See {Puppet::Interface::ActionBuilder#option} for
+  # details.
+  #
+  # @api public
+  # @dsl Faces
+  def option(*declaration, &block)
+    add_option Puppet::Interface::OptionBuilder.build(self, *declaration, &block)
+  end
+
+  # @api private
+  def add_option(option)
+    # @options collects the added options in the order they're declared.
+    # @options_hash collects the options keyed by alias for quick lookups.
+    @options      ||= []
+    @options_hash ||= {}
+
+    option.aliases.each do |name|
+      if conflict = get_option(name) then
+        raise ArgumentError, "Option #{option} conflicts with existing option #{conflict}"
+      end
+
+      actions.each do |action|
+        action = get_action(action)
+        if conflict = action.get_option(name) then
+          raise ArgumentError, "Option #{option} conflicts with existing option #{conflict} on #{action}"
+        end
+      end
+    end
+
+    @options << option.name
+
+    option.aliases.each do |name|
+      @options_hash[name] = option
+    end
+
+    return option
+  end
+
+  # @api private
+  def options
+    walk_inheritance_tree(@options, :options)
+  end
+
+  # @api private
+  def get_option(name, with_inherited_options = true)
+    @options_hash ||= {}
+
+    result = @options_hash[name.to_sym]
+    if result.nil? and with_inherited_options then
+      if self.is_a?(Class) and superclass.respond_to?(:get_option)
+        result = superclass.get_option(name)
+      elsif self.class.respond_to?(:get_option)
+        result = self.class.get_option(name)
+      end
+    end
+
+    return result
+  end
+
+  # @api private
+  def option?(name)
+    options.include? name.to_sym
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/loaders.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/loaders.rb
new file mode 100644
index 0000000..3d150bd
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/loaders.rb
@@ -0,0 +1,19 @@
+module Puppet
+  module Pops
+    require 'puppet/pops/loaders'
+
+    module Loader
+      require 'puppet/pops/loader/loader'
+      require 'puppet/pops/loader/base_loader'
+      require 'puppet/pops/loader/gem_support'
+      require 'puppet/pops/loader/module_loaders'
+      require 'puppet/pops/loader/dependency_loader'
+      require 'puppet/pops/loader/null_loader'
+      require 'puppet/pops/loader/static_loader'
+      require 'puppet/pops/loader/ruby_function_instantiator'
+      require 'puppet/pops/loader/loader_paths'
+      require 'puppet/pops/loader/simple_environment_loader'
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/metatype/manager.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/metatype/manager.rb
new file mode 100644
index 0000000..0cf1669
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/metatype/manager.rb
@@ -0,0 +1,184 @@
+require 'puppet'
+require 'puppet/util/classgen'
+require 'puppet/node/environment'
+
+# This module defines methods dealing with Type management.
+# This module gets included into the Puppet::Type class, it's just split out here for clarity.
+# @api public
+#
+module Puppet::MetaType
+module Manager
+  include Puppet::Util::ClassGen
+
+  # An implementation specific method that removes all type instances during testing.
+  # @note Only use this method for testing purposes.
+  # @api private
+  #
+  def allclear
+    @types.each { |name, type|
+      type.clear
+    }
+  end
+
+  # Iterates over all already loaded Type subclasses.
+  # @yield [t] a block receiving each type
+  # @yieldparam t [Puppet::Type] each defined type
+  # @yieldreturn [Object] the last returned object is also returned from this method
+  # @return [Object] the last returned value from the block.
+  def eachtype
+    @types.each do |name, type|
+      # Only consider types that have names
+      #if ! type.parameters.empty? or ! type.validproperties.empty?
+        yield type
+      #end
+    end
+  end
+
+  # Loads all types.
+  # @note Should only be used for purposes such as generating documentation as this is potentially a very
+  #  expensive operation.
+  # @return [void]
+  #
+  def loadall
+    typeloader.loadall
+  end
+
+  # Defines a new type or redefines an existing type with the given name.
+  # A convenience method on the form `new<name>` where name is the name of the type is also created.
+  # (If this generated method happens to clash with an existing method, a warning is issued and the original
+  # method is kept).
+  #
+  # @param name [String] the name of the type to create or redefine.
+  # @param options [Hash] options passed on to {Puppet::Util::ClassGen#genclass} as the option `:attributes`.
+  # @option options [Puppet::Type]
+  #   Puppet::Type. This option is not passed on as an attribute to genclass.
+  # @yield [ ] a block evaluated in the context of the created class, thus allowing further detailing of
+  #   that class.
+  # @return [Class<inherits Puppet::Type>] the created subclass
+  # @see Puppet::Util::ClassGen.genclass
+  #
+  # @dsl type
+  # @api public
+  def newtype(name, options = {}, &block)
+    # Handle backward compatibility
+    unless options.is_a?(Hash)
+      Puppet.warning "Puppet::Type.newtype(#{name}) now expects a hash as the second argument, not #{options.inspect}"
+    end
+
+    # First make sure we don't have a method sitting around
+    name = name.intern
+    newmethod = "new#{name}"
+
+    # Used for method manipulation.
+    selfobj = singleton_class
+
+    @types ||= {}
+
+    if @types.include?(name)
+      if self.respond_to?(newmethod)
+        # Remove the old newmethod
+        selfobj.send(:remove_method,newmethod)
+      end
+    end
+
+    options = symbolize_options(options)
+
+
+    if options.include?(:parent) 
+      Puppet.deprecation_warning "option :parent is deprecated. It has no effect"
+      options.delete(:parent)
+    end
+
+    # Then create the class.
+
+    klass = genclass(
+      name,
+      :parent => Puppet::Type,
+      :overwrite => true,
+      :hash => @types,
+      :attributes => options,
+      &block
+    )
+
+    # Now define a "new<type>" method for convenience.
+    if self.respond_to? newmethod
+      # Refuse to overwrite existing methods like 'newparam' or 'newtype'.
+      Puppet.warning "'new#{name.to_s}' method already exists; skipping"
+    else
+      selfobj.send(:define_method, newmethod) do |*args|
+        klass.new(*args)
+      end
+    end
+
+    # If they've got all the necessary methods defined and they haven't
+    # already added the property, then do so now.
+    klass.ensurable if klass.ensurable? and ! klass.validproperty?(:ensure)
+
+    # Now set up autoload any providers that might exist for this type.
+
+    klass.providerloader = Puppet::Util::Autoload.new(klass, "puppet/provider/#{klass.name.to_s}")
+
+    # We have to load everything so that we can figure out the default provider.
+    klass.providerloader.loadall Puppet.lookup(:current_environment)
+    klass.providify unless klass.providers.empty?
+
+    klass
+  end
+
+  # Removes an existing type.
+  # @note Only use this for testing.
+  # @api private
+  def rmtype(name)
+    # Then create the class.
+
+    rmclass(name, :hash => @types)
+
+    singleton_class.send(:remove_method, "new#{name}") if respond_to?("new#{name}")
+  end
+
+  # Returns a Type instance by name.
+  # This will load the type if not already defined.
+  # @param [String, Symbol] name of the wanted Type
+  # @return [Puppet::Type, nil] the type or nil if the type was not defined and could not be loaded
+  #
+  def type(name)
+    # Avoid loading if name obviously is not a type name
+    if name.to_s.include?(':')
+      return nil
+    end
+
+    @types ||= {}
+
+    # We are overwhelmingly symbols here, which usually match, so it is worth
+    # having this special-case to return quickly.  Like, 25K symbols vs. 300
+    # strings in this method. --daniel 2012-07-17
+    return @types[name] if @types[name]
+
+    # Try mangling the name, if it is a string.
+    if name.is_a? String
+      name = name.downcase.intern
+      return @types[name] if @types[name]
+    end
+    # Try loading the type.
+    if typeloader.load(name, Puppet.lookup(:current_environment))
+      Puppet.warning "Loaded puppet/type/#{name} but no class was created" unless @types.include? name
+    end
+
+    # ...and I guess that is that, eh.
+    return @types[name]
+  end
+
+  # Creates a loader for Puppet types.
+  # Defaults to an instance of {Puppet::Util::Autoload} if no other auto loader has been set.
+  # @return [Puppet::Util::Autoload] the loader to use.
+  # @api private
+  def typeloader
+    unless defined?(@typeloader)
+      @typeloader = Puppet::Util::Autoload.new(self, "puppet/type", :wrap => false)
+    end
+
+    @typeloader
+  end
+end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module.rb
new file mode 100644
index 0000000..deecfd4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module.rb
@@ -0,0 +1,339 @@
+require 'puppet/util/logging'
+require 'semver'
+require 'json'
+
+# Support for modules
+class Puppet::Module
+  class Error < Puppet::Error; end
+  class MissingModule < Error; end
+  class IncompatibleModule < Error; end
+  class UnsupportedPlatform < Error; end
+  class IncompatiblePlatform < Error; end
+  class MissingMetadata < Error; end
+  class InvalidName < Error; end
+  class InvalidFilePattern < Error; end
+
+  include Puppet::Util::Logging
+
+  FILETYPES = {
+    "manifests" => "manifests",
+    "files" => "files",
+    "templates" => "templates",
+    "plugins" => "lib",
+    "pluginfacts" => "facts.d",
+  }
+
+  # Find and return the +module+ that +path+ belongs to. If +path+ is
+  # absolute, or if there is no module whose name is the first component
+  # of +path+, return +nil+
+  def self.find(modname, environment = nil)
+    return nil unless modname
+    # Unless a specific environment is given, use the current environment
+    env = environment ? Puppet.lookup(:environments).get!(environment) : Puppet.lookup(:current_environment)
+    env.module(modname)
+  end
+
+  attr_reader :name, :environment, :path, :metadata
+  attr_writer :environment
+
+  attr_accessor :dependencies, :forge_name
+  attr_accessor :source, :author, :version, :license, :puppetversion, :summary, :description, :project_page
+
+  def initialize(name, path, environment)
+    @name = name
+    @path = path
+    @environment = environment
+
+    assert_validity
+
+    load_metadata if has_metadata?
+
+    validate_puppet_version
+
+    @absolute_path_to_manifests = Puppet::FileSystem::PathPattern.absolute(manifests)
+  end
+
+  def has_metadata?
+    return false unless metadata_file
+
+    return false unless Puppet::FileSystem.exist?(metadata_file)
+
+    begin
+      metadata =  JSON.parse(File.read(metadata_file))
+    rescue JSON::JSONError => e
+      Puppet.debug("#{name} has an invalid and unparsable metadata.json file.  The parse error: #{e.message}")
+      return false
+    end
+
+    return metadata.is_a?(Hash) && !metadata.keys.empty?
+  end
+
+  FILETYPES.each do |type, location|
+    # A boolean method to let external callers determine if
+    # we have files of a given type.
+    define_method(type +'?') do
+      type_subpath = subpath(location)
+      unless Puppet::FileSystem.exist?(type_subpath)
+        Puppet.debug("No #{type} found in subpath '#{type_subpath}' " +
+                         "(file / directory does not exist)")
+        return false
+      end
+
+      return true
+    end
+
+    # A method for returning a given file of a given type.
+    # e.g., file = mod.manifest("my/manifest.pp")
+    #
+    # If the file name is nil, then the base directory for the
+    # file type is passed; this is used for fileserving.
+    define_method(type.sub(/s$/, '')) do |file|
+      # If 'file' is nil then they're asking for the base path.
+      # This is used for things like fileserving.
+      if file
+        full_path = File.join(subpath(location), file)
+      else
+        full_path = subpath(location)
+      end
+
+      return nil unless Puppet::FileSystem.exist?(full_path)
+      return full_path
+    end
+
+    # Return the base directory for the given type
+    define_method(type) do
+      subpath(location)
+    end
+  end
+
+  def license_file
+    return @license_file if defined?(@license_file)
+
+    return @license_file = nil unless path
+    @license_file = File.join(path, "License")
+  end
+
+  def load_metadata
+    @metadata = data = JSON.parse(File.read(metadata_file))
+    @forge_name = data['name'].gsub('-', '/') if data['name']
+
+    [:source, :author, :version, :license, :puppetversion, :dependencies].each do |attr|
+      unless value = data[attr.to_s]
+        unless attr == :puppetversion
+          raise MissingMetadata, "No #{attr} module metadata provided for #{self.name}"
+        end
+      end
+
+      # NOTICE: The fallback to `versionRequirement` is something we'd like to
+      # not have to support, but we have a reasonable number of releases that
+      # don't use `version_requirement`. When we can deprecate this, we should.
+      if attr == :dependencies
+        value.tap do |dependencies|
+          dependencies.each do |dep|
+            dep['version_requirement'] ||= dep['versionRequirement'] || '>= 0.0.0'
+          end
+        end
+      end
+
+      send(attr.to_s + "=", value)
+    end
+  end
+
+  # Return the list of manifests matching the given glob pattern,
+  # defaulting to 'init.{pp,rb}' for empty modules.
+  def match_manifests(rest)
+    if rest
+      wanted_manifests = wanted_manifests_from(rest)
+      searched_manifests = wanted_manifests.glob.reject { |f| FileTest.directory?(f) }
+    else
+      searched_manifests = []
+    end
+
+    # (#4220) Always ensure init.pp in case class is defined there.
+    init_manifests = [manifest("init.pp"), manifest("init.rb")].compact
+    init_manifests + searched_manifests
+  end
+
+  def all_manifests
+    return [] unless Puppet::FileSystem.exist?(manifests)
+
+    Dir.glob(File.join(manifests, '**', '*.{rb,pp}'))
+  end
+
+  def metadata_file
+    return @metadata_file if defined?(@metadata_file)
+
+    return @metadata_file = nil unless path
+    @metadata_file = File.join(path, "metadata.json")
+  end
+
+  def modulepath
+    File.dirname(path) if path
+  end
+
+  # Find all plugin directories.  This is used by the Plugins fileserving mount.
+  def plugin_directory
+    subpath("lib")
+  end
+
+  def plugin_fact_directory
+    subpath("facts.d")
+  end
+
+  def has_external_facts?
+    File.directory?(plugin_fact_directory)
+  end
+
+  def supports(name, version = nil)
+    @supports ||= []
+    @supports << [name, version]
+  end
+
+  def to_s
+    result = "Module #{name}"
+    result += "(#{path})" if path
+    result
+  end
+
+  def dependencies_as_modules
+    dependent_modules = []
+    dependencies and dependencies.each do |dep|
+      author, dep_name = dep["name"].split('/')
+      found_module = environment.module(dep_name)
+      dependent_modules << found_module if found_module
+    end
+
+    dependent_modules
+  end
+
+  def required_by
+    environment.module_requirements[self.forge_name] || {}
+  end
+
+  def has_local_changes?
+    Puppet.deprecation_warning("This method is being removed.")
+    require 'puppet/module_tool/applications'
+    changes = Puppet::ModuleTool::Applications::Checksummer.run(path)
+    !changes.empty?
+  end
+
+  def local_changes
+    Puppet.deprecation_warning("This method is being removed.")
+    require 'puppet/module_tool/applications'
+    Puppet::ModuleTool::Applications::Checksummer.run(path)
+  end
+
+  # Identify and mark unmet dependencies.  A dependency will be marked unmet
+  # for the following reasons:
+  #
+  #   * not installed and is thus considered missing
+  #   * installed and does not meet the version requirements for this module
+  #   * installed and doesn't use semantic versioning
+  #
+  # Returns a list of hashes representing the details of an unmet dependency.
+  #
+  # Example:
+  #
+  #   [
+  #     {
+  #       :reason => :missing,
+  #       :name   => 'puppetlabs-mysql',
+  #       :version_constraint => 'v0.0.1',
+  #       :mod_details => {
+  #         :installed_version => '0.0.1'
+  #       }
+  #       :parent => {
+  #         :name    => 'puppetlabs-bacula',
+  #         :version => 'v1.0.0'
+  #       }
+  #     }
+  #   ]
+  #
+  def unmet_dependencies
+    unmet_dependencies = []
+    return unmet_dependencies unless dependencies
+
+    dependencies.each do |dependency|
+      forge_name = dependency['name']
+      version_string = dependency['version_requirement'] || '>= 0.0.0'
+
+      dep_mod = begin
+        environment.module_by_forge_name(forge_name)
+      rescue
+        nil
+      end
+
+      error_details = {
+        :name => forge_name,
+        :version_constraint => version_string.gsub(/^(?=\d)/, "v"),
+        :parent => {
+          :name => self.forge_name,
+          :version => self.version.gsub(/^(?=\d)/, "v")
+        },
+        :mod_details => {
+          :installed_version => dep_mod.nil? ? nil : dep_mod.version
+        }
+      }
+
+      unless dep_mod
+        error_details[:reason] = :missing
+        unmet_dependencies << error_details
+        next
+      end
+
+      if version_string
+        begin
+          required_version_semver_range = SemVer[version_string]
+          actual_version_semver = SemVer.new(dep_mod.version)
+        rescue ArgumentError
+          error_details[:reason] = :non_semantic_version
+          unmet_dependencies << error_details
+          next
+        end
+
+        unless required_version_semver_range.include? actual_version_semver
+          error_details[:reason] = :version_mismatch
+          unmet_dependencies << error_details
+          next
+        end
+      end
+    end
+
+    unmet_dependencies
+  end
+
+  def validate_puppet_version
+    return unless puppetversion and puppetversion != Puppet.version
+    raise IncompatibleModule, "Module #{self.name} is only compatible with Puppet version #{puppetversion}, not #{Puppet.version}"
+  end
+
+  private
+
+  def wanted_manifests_from(pattern)
+    begin
+      extended = File.extname(pattern).empty? ? "#{pattern}.{pp,rb}" : pattern
+      relative_pattern = Puppet::FileSystem::PathPattern.relative(extended)
+    rescue Puppet::FileSystem::PathPattern::InvalidPattern => error
+      raise Puppet::Module::InvalidFilePattern.new(
+        "The pattern \"#{pattern}\" to find manifests in the module \"#{name}\" " +
+        "is invalid and potentially unsafe.", error)
+    end
+
+    relative_pattern.prefix_with(@absolute_path_to_manifests)
+  end
+
+  def subpath(type)
+    File.join(path, type)
+  end
+
+  def assert_validity
+    raise InvalidName, "Invalid module name #{name}; module names must be alphanumeric (plus '-'), not '#{name}'" unless name =~ /^[-\w]+$/
+  end
+
+  def ==(other)
+    self.name == other.name &&
+    self.version == other.version &&
+    self.path == other.path &&
+    self.environment == other.environment
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool.rb
new file mode 100644
index 0000000..984947d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool.rb
@@ -0,0 +1,194 @@
+# encoding: UTF-8
+# Load standard libraries
+require 'pathname'
+require 'fileutils'
+require 'puppet/util/colors'
+
+module Puppet
+  module ModuleTool
+    require 'puppet/module_tool/tar'
+    extend Puppet::Util::Colors
+
+    # Directory and names that should not be checksummed.
+    ARTIFACTS = ['pkg', /^\./, /^~/, /^#/, 'coverage', 'checksums.json', 'REVISION']
+    FULL_MODULE_NAME_PATTERN = /\A([^-\/|.]+)[-|\/](.+)\z/
+    REPOSITORY_URL = Puppet.settings[:module_repository]
+
+    # Is this a directory that shouldn't be checksummed?
+    #
+    # TODO: Should this be part of Checksums?
+    # TODO: Rename this method to reflect its purpose?
+    # TODO: Shouldn't this be used when building packages too?
+    def self.artifact?(path)
+      case File.basename(path)
+      when *ARTIFACTS
+        true
+      else
+        false
+      end
+    end
+
+    # Return the +username+ and +modname+ for a given +full_module_name+, or raise an
+    # ArgumentError if the argument isn't parseable.
+    def self.username_and_modname_from(full_module_name)
+      if matcher = full_module_name.match(FULL_MODULE_NAME_PATTERN)
+        return matcher.captures
+      else
+        raise ArgumentError, "Not a valid full name: #{full_module_name}"
+      end
+    end
+
+    # Find the module root when given a path by checking each directory up from
+    # its current location until it finds one that contains a file called
+    # 'Modulefile'.
+    #
+    # @param path [Pathname, String] path to start from
+    # @return [Pathname, nil] the root path of the module directory or nil if
+    #   we cannot find one
+    def self.find_module_root(path)
+      path = Pathname.new(path) if path.class == String
+
+      path.expand_path.ascend do |p|
+        return p if is_module_root?(p)
+      end
+
+      nil
+    end
+
+    # Analyse path to see if it is a module root directory by detecting a
+    # file named 'metadata.json' or 'Modulefile' in the directory.
+    #
+    # @param path [Pathname, String] path to analyse
+    # @return [Boolean] true if the path is a module root, false otherwise
+    def self.is_module_root?(path)
+      path = Pathname.new(path) if path.class == String
+
+      FileTest.file?(path + 'metadata.json') || FileTest.file?(path + 'Modulefile')
+    end
+
+    # Builds a formatted tree from a list of node hashes containing +:text+
+    # and +:dependencies+ keys.
+    def self.format_tree(nodes, level = 0)
+      str = ''
+      nodes.each_with_index do |node, i|
+        last_node = nodes.length - 1 == i
+        deps = node[:dependencies] || []
+
+        str << (indent = "  " * level)
+        str << (last_node ? "└" : "├")
+        str << "─"
+        str << (deps.empty? ? "─" : "┬")
+        str << " #{node[:text]}\n"
+
+        branch = format_tree(deps, level + 1)
+        branch.gsub!(/^#{indent} /, indent + '│') unless last_node
+        str << branch
+      end
+
+      return str
+    end
+
+    def self.build_tree(mods, dir)
+      mods.each do |mod|
+        version_string = mod[:version].to_s.sub(/^(?!v)/, 'v')
+
+        if mod[:action] == :upgrade
+          previous_version = mod[:previous_version].to_s.sub(/^(?!v)/, 'v')
+          version_string = "#{previous_version} -> #{version_string}"
+        end
+
+        mod[:text] = "#{mod[:name]} (#{colorize(:cyan, version_string)})"
+        mod[:text] += " [#{mod[:path]}]" unless mod[:path].to_s == dir.to_s
+
+        deps = (mod[:dependencies] || [])
+        deps.sort! { |a, b| a[:name] <=> b[:name] }
+        build_tree(deps, dir)
+      end
+    end
+
+    # @param options [Hash<Symbol,String>] This hash will contain any
+    #   command-line arguments that are not Settings, as those will have already
+    #   been extracted by the underlying application code.
+    #
+    # @note Unfortunately the whole point of this method is the side effect of
+    # modifying the options parameter.  This same hash is referenced both
+    # when_invoked and when_rendering.  For this reason, we are not returning
+    # a duplicate.
+    # @todo Validate the above note...
+    #
+    # An :environment_instance and a :target_dir are added/updated in the
+    # options parameter.
+    #
+    # @api private
+    def self.set_option_defaults(options)
+      current_environment = environment_from_options(options)
+
+      modulepath = [options[:target_dir]] + current_environment.full_modulepath
+
+      face_environment = current_environment.override_with(:modulepath => modulepath.compact)
+
+      options[:environment_instance] = face_environment
+
+      # Note: environment will have expanded the path
+      options[:target_dir] = face_environment.full_modulepath.first
+    end
+
+    # Given a hash of options, we should discover or create a
+    # {Puppet::Node::Environment} instance that reflects the provided options.
+    #
+    # Generally speaking, the `:modulepath` parameter should supercede all
+    # others, the `:environment` parameter should follow after that, and we
+    # should default to Puppet's current environment.
+    #
+    # @param options [{Symbol => Object}] the options to derive environment from
+    # @return [Puppet::Node::Environment] the environment described by the options
+    def self.environment_from_options(options)
+      if options[:modulepath]
+        path = options[:modulepath].split(File::PATH_SEPARATOR)
+        Puppet::Node::Environment.create(:anonymous, path, '')
+      elsif options[:environment].is_a?(Puppet::Node::Environment)
+        options[:environment]
+      elsif options[:environment]
+        # This use of looking up an environment is correct since it honours
+        # a reguest to get a particular environment via environment name.
+        Puppet.lookup(:environments).get!(options[:environment])
+      else
+        Puppet.lookup(:current_environment)
+      end
+    end
+
+    # Handles parsing of module dependency expressions into proper
+    # {Semantic::VersionRange}s, including reasonable error handling.
+    #
+    # @param where [String] a description of the thing we're parsing the
+    #        dependency expression for
+    # @param dep [Hash] the dependency description to parse
+    # @return [Array(String, Semantic::VersionRange, String)] an tuple of the
+    #         dependent module's name, the version range dependency, and the
+    #         unparsed range expression.
+    def self.parse_module_dependency(where, dep)
+      dep_name = dep['name'].tr('/', '-')
+      range = dep['version_requirement'] || dep['versionRequirement'] || '>= 0.0.0'
+
+      begin
+        parsed_range = Semantic::VersionRange.parse(range)
+      rescue ArgumentError => e
+        Puppet.debug "Error in #{where} parsing dependency #{dep_name} (#{e.message}); using empty range."
+        parsed_range = Semantic::VersionRange::EMPTY_RANGE
+      end
+
+      [ dep_name, parsed_range, range ]
+    end
+  end
+end
+
+# Load remaining libraries
+require 'puppet/module_tool/errors'
+require 'puppet/module_tool/applications'
+require 'puppet/module_tool/checksums'
+require 'puppet/module_tool/contents_description'
+require 'puppet/module_tool/dependency'
+require 'puppet/module_tool/metadata'
+require 'puppet/module_tool/modulefile'
+require 'puppet/forge/cache'
+require 'puppet/forge'
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications.rb
new file mode 100644
index 0000000..50fc7aa
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications.rb
@@ -0,0 +1,14 @@
+require 'puppet/module_tool'
+
+module Puppet::ModuleTool
+  module Applications
+    require 'puppet/module_tool/applications/application'
+    require 'puppet/module_tool/applications/builder'
+    require 'puppet/module_tool/applications/checksummer'
+    require 'puppet/module_tool/applications/installer'
+    require 'puppet/module_tool/applications/searcher'
+    require 'puppet/module_tool/applications/unpacker'
+    require 'puppet/module_tool/applications/uninstaller'
+    require 'puppet/module_tool/applications/upgrader'
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/application.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/application.rb
new file mode 100644
index 0000000..c94990b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/application.rb
@@ -0,0 +1,98 @@
+require 'net/http'
+require 'semver'
+require 'json'
+require 'puppet/util/colors'
+
+module Puppet::ModuleTool
+  module Applications
+    class Application
+      include Puppet::Util::Colors
+
+      def self.run(*args)
+        new(*args).run
+      end
+
+      attr_accessor :options
+
+      def initialize(options = {})
+        @options = options
+      end
+
+      def run
+        raise NotImplementedError, "Should be implemented in child classes."
+      end
+
+      def discuss(response, success, failure)
+        case response
+        when Net::HTTPOK, Net::HTTPCreated
+          Puppet.notice success
+        else
+          errors = JSON.parse(response.body)['error'] rescue "HTTP #{response.code}, #{response.body}"
+          Puppet.warning "#{failure} (#{errors})"
+        end
+      end
+
+      def metadata(require_metadata = false)
+        return @metadata if @metadata
+        @metadata = Puppet::ModuleTool::Metadata.new
+
+        unless @path
+          raise ArgumentError, "Could not determine module path"
+        end
+
+        if require_metadata && !Puppet::ModuleTool.is_module_root?(@path)
+          raise ArgumentError, "Unable to find metadata.json or Modulefile in module root at #{@path} See http://links.puppetlabs.com/modulefile for required file format."
+        end
+
+        modulefile_path = File.join(@path, 'Modulefile')
+        metadata_path   = File.join(@path, 'metadata.json')
+
+        if File.file?(metadata_path)
+          File.open(metadata_path) do |f|
+            begin
+              @metadata.update(JSON.load(f))
+            rescue JSON::ParserError => ex
+              raise ArgumentError, "Could not parse JSON #{metadata_path}", ex.backtrace
+            end
+          end
+        end
+
+        if File.file?(modulefile_path)
+          if File.file?(metadata_path)
+            Puppet.warning "Modulefile is deprecated. Merging your Modulefile and metadata.json."
+          else
+            Puppet.warning "Modulefile is deprecated. Building metadata.json from Modulefile."
+          end
+
+          Puppet::ModuleTool::ModulefileReader.evaluate(@metadata, modulefile_path)
+        end
+
+        return @metadata
+      end
+
+      def load_metadata!
+        @metadata = nil
+        metadata(true)
+      end
+
+      def parse_filename(filename)
+        if match = /^((.*?)-(.*?))-(\d+\.\d+\.\d+.*?)$/.match(File.basename(filename,'.tar.gz'))
+          module_name, author, shortname, version = match.captures
+        else
+          raise ArgumentError, "Could not parse filename to obtain the username, module name and version.  (#{@release_name})"
+        end
+
+        unless SemVer.valid?(version)
+          raise ArgumentError, "Invalid version format: #{version} (Semantic Versions are acceptable: http://semver.org)"
+        end
+
+        return {
+          :module_name => module_name,
+          :author      => author,
+          :dir_name    => shortname,
+          :version     => version
+        }
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/builder.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/builder.rb
new file mode 100644
index 0000000..edfd2c9
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/builder.rb
@@ -0,0 +1,148 @@
+require 'fileutils'
+require 'json'
+require 'puppet/file_system'
+require 'pathspec'
+
+module Puppet::ModuleTool
+  module Applications
+    class Builder < Application
+
+      def initialize(path, options = {})
+        @path = File.expand_path(path)
+        @pkg_path = File.join(@path, 'pkg')
+        super(options)
+      end
+
+      def run
+        load_metadata!
+        create_directory
+        copy_contents
+        write_json
+        Puppet.notice "Building #{@path} for release"
+        pack
+        relative = Pathname.new(archive_file).relative_path_from(Pathname.new(File.expand_path(Dir.pwd)))
+
+        # Return the Pathname object representing the path to the release
+        # archive just created. This return value is used by the module_tool
+        # face build action, and displayed to on the console using the to_s
+        # method.
+        #
+        # Example return value:
+        #
+        #   <Pathname:puppetlabs-apache/pkg/puppetlabs-apache-0.0.1.tar.gz>
+        #
+        relative
+      end
+
+      private
+
+      def archive_file
+        File.join(@pkg_path, "#{metadata.release_name}.tar.gz")
+      end
+
+      def pack
+        FileUtils.rm archive_file rescue nil
+
+        tar = Puppet::ModuleTool::Tar.instance
+        Dir.chdir(@pkg_path) do
+          tar.pack(metadata.release_name, archive_file)
+        end
+      end
+
+      def create_directory
+        FileUtils.mkdir(@pkg_path) rescue nil
+        if File.directory?(build_path)
+          FileUtils.rm_rf(build_path, :secure => true)
+        end
+        FileUtils.mkdir(build_path)
+      end
+
+      def ignored_files
+        if @ignored_files
+          return @ignored_files
+        else
+          pmtignore = File.join(@path, '.pmtignore')
+          gitignore = File.join(@path, '.gitignore')
+
+          if File.file? pmtignore
+            @ignored_files = PathSpec.new File.read(pmtignore)
+          elsif File.file? gitignore
+            @ignored_files = PathSpec.new File.read(gitignore)
+          else
+            @ignored_files = PathSpec.new
+          end
+        end
+      end
+
+      def copy_contents
+        symlinks = []
+        Find.find(File.join(@path)) do |path|
+          # because Find.find finds the path itself
+          if path == @path
+            next
+          end
+
+          # Needed because pathspec looks for a trailing slash in the path to
+          # determine if a path is a directory
+          path = path.to_s + '/' if File.directory? path
+
+          # if it matches, then prune it with fire
+          unless ignored_files.match_paths([path], @path).empty?
+            Find.prune
+          end
+
+          # don't copy all the Puppet ARTIFACTS
+          rel = Pathname.new(path).relative_path_from(Pathname.new(@path))
+          case rel.to_s
+          when *Puppet::ModuleTool::ARTIFACTS
+            Find.prune
+          end
+
+          # make dir tree, copy files, and add symlinks to the symlinks list
+          dest = "#{build_path}/#{rel.to_s}"
+          if File.directory? path
+            FileUtils.mkdir dest, :mode => File.stat(path).mode
+          elsif Puppet::FileSystem.symlink? path
+            symlinks << path
+          else
+            FileUtils.cp path, dest, :preserve => true
+          end
+        end
+
+        # send a message about each symlink and raise an error if they exist
+        unless symlinks.empty?
+          symlinks.each do |s|
+            s = Pathname.new s
+            mpath = Pathname.new @path
+            Puppet.warning "Symlinks in modules are unsupported. Please investigate symlink #{s.relative_path_from mpath} -> #{s.realpath.relative_path_from mpath}."
+          end
+
+          raise Puppet::ModuleTool::Errors::ModuleToolError, "Found symlinks. Symlinks in modules are not allowed, please remove them."
+        end
+      end
+
+      def write_json
+        metadata_path = File.join(build_path, 'metadata.json')
+
+        if metadata.to_hash.include? 'checksums'
+          Puppet.warning "A 'checksums' field was found in metadata.json. This field will be ignored and can safely be removed."
+        end
+
+        # TODO: This may necessarily change the order in which the metadata.json
+        # file is packaged from what was written by the user.  This is a
+        # regretable, but required for now.
+        File.open(metadata_path, 'w') do |f|
+          f.write(metadata.to_json)
+        end
+
+        File.open(File.join(build_path, 'checksums.json'), 'w') do |f|
+          f.write(PSON.pretty_generate(Checksums.new(build_path)))
+        end
+      end
+
+      def build_path
+        @build_path ||= File.join(@pkg_path, metadata.release_name)
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/checksummer.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/checksummer.rb
new file mode 100644
index 0000000..0aae984
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/checksummer.rb
@@ -0,0 +1,62 @@
+require 'json'
+require 'puppet/module_tool/checksums'
+
+module Puppet::ModuleTool
+  module Applications
+    class Checksummer < Application
+
+      def initialize(path, options = {})
+        @path = Pathname.new(path)
+        super(options)
+      end
+
+      def run
+        changes = []
+        sums = Puppet::ModuleTool::Checksums.new(@path)
+        checksums.each do |child_path, canonical_checksum|
+
+          # Avoid checksumming the checksums.json file
+          next if File.basename(child_path) == "checksums.json"
+
+          path = @path + child_path
+          unless path.exist? && canonical_checksum == sums.checksum(path)
+            changes << child_path
+          end
+        end
+
+        # Return an Array of strings representing file paths of files that have
+        # been modified since this module was installed. All paths are relative
+        # to the installed module directory. This return value is used by the
+        # module_tool face changes action, and displayed on the console.
+        #
+        # Example return value:
+        #
+        #   [ "REVISION", "manifests/init.pp"]
+        #
+        changes
+      end
+
+      private
+
+      def checksums
+        if checksums_file.exist?
+          JSON.parse(checksums_file.read)
+        elsif metadata_file.exist?
+          # Check metadata.json too; legacy modules store their checksums there.
+          JSON.parse(metadata_file.read)['checksums'] or
+          raise ArgumentError, "No file containing checksums found."
+        else
+          raise ArgumentError, "No file containing checksums found."
+        end
+      end
+
+      def metadata_file
+        @path + 'metadata.json'
+      end
+
+      def checksums_file
+        @path + 'checksums.json'
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/installer.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/installer.rb
new file mode 100644
index 0000000..92aa6c0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/installer.rb
@@ -0,0 +1,353 @@
+require 'open-uri'
+require 'pathname'
+require 'fileutils'
+require 'tmpdir'
+
+require 'puppet/forge'
+require 'puppet/module_tool'
+require 'puppet/module_tool/shared_behaviors'
+require 'puppet/module_tool/install_directory'
+require 'puppet/module_tool/local_tarball'
+require 'puppet/module_tool/installed_modules'
+
+module Puppet::ModuleTool
+  module Applications
+    class Installer < Application
+
+      include Puppet::ModuleTool::Errors
+      include Puppet::Forge::Errors
+
+      def initialize(name, install_dir, options = {})
+        super(options)
+
+        @action              = :install
+        @environment         = options[:environment_instance]
+        @ignore_dependencies = forced? || options[:ignore_dependencies]
+        @name                = name
+        @install_dir         = install_dir
+
+        Puppet::Forge::Cache.clean
+
+        @local_tarball = Puppet::FileSystem.exist?(name)
+
+        if @local_tarball
+          release = local_tarball_source.release
+          @name = release.name
+          options[:version] = release.version.to_s
+          Semantic::Dependency.add_source(local_tarball_source)
+
+          # If we're operating on a local tarball and ignoring dependencies, we
+          # don't need to search any additional sources.  This will cut down on
+          # unnecessary network traffic.
+          unless @ignore_dependencies
+            Semantic::Dependency.add_source(installed_modules_source)
+            Semantic::Dependency.add_source(module_repository)
+          end
+
+        else
+          Semantic::Dependency.add_source(installed_modules_source) unless forced?
+          Semantic::Dependency.add_source(module_repository)
+        end
+      end
+
+      def run
+        name = @name.tr('/', '-')
+        version = options[:version] || '>= 0.0.0'
+
+        results = { :action => :install, :module_name => name, :module_version => version }
+
+        begin
+          if mod = installed_modules[name]
+            unless forced?
+              if Semantic::VersionRange.parse(version).include? mod.version
+                results[:result] = :noop
+                results[:version] = mod.version
+                return results
+              else
+                changes = Checksummer.run(installed_modules[name].mod.path) rescue []
+                raise AlreadyInstalledError,
+                  :module_name       => name,
+                  :installed_version => installed_modules[name].version,
+                  :requested_version => options[:version] || :latest,
+                  :local_changes     => changes
+              end
+            end
+          end
+
+          @install_dir.prepare(name, options[:version] || 'latest')
+          results[:install_dir] = @install_dir.target
+
+          unless @local_tarball && @ignore_dependencies
+            Puppet.notice "Downloading from #{module_repository.host} ..."
+          end
+
+          if @ignore_dependencies
+            graph = build_single_module_graph(name, version)
+          else
+            graph = build_dependency_graph(name, version)
+          end
+
+          unless forced?
+            add_module_name_constraints_to_graph(graph)
+          end
+
+          installed_modules.each do |mod, release|
+            mod = mod.tr('/', '-')
+            next if mod == name
+
+            version = release.version
+
+            unless forced?
+              # Since upgrading already installed modules can be troublesome,
+              # we'll place constraints on the graph for each installed module,
+              # locking it to upgrades within the same major version.
+              ">=#{version} #{version.major}.x".tap do |range|
+                graph.add_constraint('installed', mod, range) do |node|
+                  Semantic::VersionRange.parse(range).include? node.version
+                end
+              end
+
+              release.mod.dependencies.each do |dep|
+                dep_name = dep['name'].tr('/', '-')
+
+                dep['version_requirement'].tap do |range|
+                  graph.add_constraint("#{mod} constraint", dep_name, range) do |node|
+                    Semantic::VersionRange.parse(range).include? node.version
+                  end
+                end
+              end
+            end
+          end
+
+          # Ensure that there is at least one candidate release available
+          # for the target package.
+          if graph.dependencies[name].empty?
+            raise NoCandidateReleasesError, results.merge(:module_name => name, :source => module_repository.host, :requested_version => options[:version] || :latest)
+          end
+
+          begin
+            Puppet.info "Resolving dependencies ..."
+            releases = Semantic::Dependency.resolve(graph)
+          rescue Semantic::Dependency::UnsatisfiableGraph
+            raise NoVersionsSatisfyError, results.merge(:requested_name => name)
+          end
+
+          unless forced?
+            # Check for module name conflicts.
+            releases.each do |rel|
+              if mod = installed_modules_source.by_name[rel.name.split('-').last]
+                next if mod.has_metadata? && mod.forge_name.tr('/', '-') == rel.name
+
+                if rel.name != name
+                  dependency = {
+                    :name => rel.name,
+                    :version => rel.version
+                  }
+                end
+
+                raise InstallConflictError,
+                  :requested_module  => name,
+                  :requested_version => options[:version] || 'latest',
+                  :dependency        => dependency,
+                  :directory         => mod.path,
+                  :metadata          => mod.metadata
+              end
+            end
+          end
+
+          Puppet.info "Preparing to install ..."
+          releases.each { |release| release.prepare }
+
+          Puppet.notice 'Installing -- do not interrupt ...'
+          releases.each do |release|
+            installed = installed_modules[release.name]
+            if forced? || installed.nil?
+              release.install(Pathname.new(results[:install_dir]))
+            else
+              release.install(Pathname.new(installed.mod.modulepath))
+            end
+          end
+
+          results[:result] = :success
+          results[:installed_modules] = releases
+          results[:graph] = [ build_install_graph(releases.first, releases) ]
+
+        rescue ModuleToolError, ForgeError => err
+          results[:error] = {
+            :oneline   => err.message,
+            :multiline => err.multiline,
+          }
+        ensure
+          results[:result] ||= :failure
+        end
+
+        results
+      end
+
+      private
+
+      def module_repository
+        @repo ||= Puppet::Forge.new
+      end
+
+      def local_tarball_source
+        @tarball_source ||= begin
+          Puppet::ModuleTool::LocalTarball.new(@name)
+        rescue Puppet::Module::Error => e
+          raise InvalidModuleError.new(@name, :action => @action, :error  => e)
+        end
+      end
+
+      def installed_modules_source
+        @installed ||= Puppet::ModuleTool::InstalledModules.new(@environment)
+      end
+
+      def installed_modules
+        installed_modules_source.modules
+      end
+
+      def build_single_module_graph(name, version)
+        range = Semantic::VersionRange.parse(version)
+        graph = Semantic::Dependency::Graph.new(name => range)
+        releases = Semantic::Dependency.fetch_releases(name)
+        releases.each { |release| release.dependencies.clear }
+        graph << releases
+      end
+
+      def build_dependency_graph(name, version)
+        Semantic::Dependency.query(name => version)
+      end
+
+      def build_install_graph(release, installed, graphed = [])
+        graphed << release
+        dependencies = release.dependencies.values.map do |deps|
+          dep = (deps & installed).first
+          unless dep.nil? || graphed.include?(dep)
+            build_install_graph(dep, installed, graphed)
+          end
+        end
+
+        previous = installed_modules[release.name]
+        previous = previous.version if previous
+        return {
+          :release          => release,
+          :name             => release.name,
+          :path             => release.install_dir.to_s,
+          :dependencies     => dependencies.compact,
+          :version          => release.version,
+          :previous_version => previous,
+          :action           => (previous.nil? || previous == release.version || forced? ? :install : :upgrade),
+        }
+      end
+
+      include Puppet::ModuleTool::Shared
+
+      # Return a Pathname object representing the path to the module
+      # release package in the `Puppet.settings[:module_working_dir]`.
+      def get_release_packages
+        get_local_constraints
+
+        if !forced? && @installed.include?(@module_name)
+          raise AlreadyInstalledError,
+            :module_name       => @module_name,
+            :installed_version => @installed[@module_name].first.version,
+            :requested_version => @version || (@conditions[@module_name].empty? ? :latest : :best),
+            :local_changes     => Puppet::ModuleTool::Applications::Checksummer.run(@installed[@module_name].first.path)
+        end
+
+        if @ignore_dependencies && @source == :filesystem
+          @urls   = {}
+          @remote = { "#{@module_name}@#{@version}" => { } }
+          @versions = {
+            @module_name => [
+              { :vstring => @version, :semver => SemVer.new(@version) }
+            ]
+          }
+        else
+          get_remote_constraints(@forge)
+        end
+
+        @graph = resolve_constraints({ @module_name => @version })
+        @graph.first[:tarball] = @filename if @source == :filesystem
+        resolve_install_conflicts(@graph) unless forced?
+
+        # This clean call means we never "cache" the module we're installing, but this
+        # is desired since module authors can easily rerelease modules different content but the same
+        # version number, meaning someone with the old content cached will be very confused as to why
+        # they can't get new content.
+        # Long term we should just get rid of this caching behavior and cleanup downloaded modules after they install
+        # but for now this is a quick fix to disable caching
+        Puppet::Forge::Cache.clean
+        download_tarballs(@graph, @graph.last[:path], @forge)
+      end
+
+      #
+      # Resolve installation conflicts by checking if the requested module
+      # or one of its dependencies conflicts with an installed module.
+      #
+      # Conflicts occur under the following conditions:
+      #
+      # When installing 'puppetlabs-foo' and an existing directory in the
+      # target install path contains a 'foo' directory and we cannot determine
+      # the "full name" of the installed module.
+      #
+      # When installing 'puppetlabs-foo' and 'pete-foo' is already installed.
+      # This is considered a conflict because 'puppetlabs-foo' and 'pete-foo'
+      # install into the same directory 'foo'.
+      #
+      def resolve_install_conflicts(graph, is_dependency = false)
+        Puppet.debug("Resolving conflicts for #{graph.map {|n| n[:module]}.join(',')}")
+
+        graph.each do |release|
+          @environment.modules_by_path[options[:target_dir]].each do |mod|
+            if mod.has_metadata?
+              metadata = {
+                :name    => mod.forge_name.gsub('/', '-'),
+                :version => mod.version
+              }
+              next if release[:module] == metadata[:name]
+            else
+              metadata = nil
+            end
+
+            if release[:module] =~ /-#{mod.name}$/
+              dependency_info = {
+                :name    => release[:module],
+                :version => release[:version][:vstring]
+              }
+              dependency = is_dependency ? dependency_info : nil
+              all_versions = @versions["#{@module_name}"].sort_by { |h| h[:semver] }
+              versions = all_versions.select { |x| x[:semver].special == '' }
+              versions = all_versions if versions.empty?
+              latest_version = versions.last[:vstring]
+
+              raise InstallConflictError,
+                :requested_module  => @module_name,
+                :requested_version => @version || "latest: v#{latest_version}",
+                :dependency        => dependency,
+                :directory         => mod.path,
+                :metadata          => metadata
+            end
+          end
+
+          deps = release[:dependencies]
+          if deps && !deps.empty?
+            resolve_install_conflicts(deps, true)
+          end
+        end
+      end
+
+      #
+      # Check if a file is a vaild module package.
+      # ---
+      # FIXME: Checking for a valid module package should be more robust and
+      # use the actual metadata contained in the package. 03132012 - Hightower
+      # +++
+      #
+      def is_module_package?(name)
+        filename = File.expand_path(name)
+        filename =~ /.tar.gz$/
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/searcher.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/searcher.rb
new file mode 100644
index 0000000..88fb6fd
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/searcher.rb
@@ -0,0 +1,29 @@
+module Puppet::ModuleTool
+  module Applications
+    class Searcher < Application
+      include Puppet::Forge::Errors
+
+      def initialize(term, forge, options = {})
+        @term = term
+        @forge = forge
+        super(options)
+      end
+
+      def run
+        results = {}
+        begin
+          Puppet.notice "Searching #{@forge.host} ..."
+          results[:answers] = @forge.search(@term)
+          results[:result] = :success
+        rescue ForgeError => e
+          results[:result] = :failure
+          results[:error] = {
+            :oneline   => e.message,
+            :multiline => e.multiline,
+          }
+        end
+        results
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/uninstaller.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/uninstaller.rb
new file mode 100644
index 0000000..46e5391
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/uninstaller.rb
@@ -0,0 +1,117 @@
+module Puppet::ModuleTool
+  module Applications
+    class Uninstaller < Application
+      include Puppet::ModuleTool::Errors
+
+      def initialize(name, options)
+        @name        = name
+        @options     = options
+        @errors      = Hash.new {|h, k| h[k] = {}}
+        @unfiltered  = []
+        @installed   = []
+        @suggestions = []
+        @environment = options[:environment_instance]
+        @ignore_changes = options[:force] || options[:ignore_changes]
+      end
+
+      def run
+        results = {
+          :module_name       => @name,
+          :requested_version => @version,
+        }
+
+        begin
+          find_installed_module
+          validate_module
+
+          FileUtils.rm_rf(@installed.first.path, :secure => true)
+
+          results[:affected_modules] = @installed
+          results[:result] = :success
+        rescue ModuleToolError => err
+          results[:error] = {
+            :oneline   => err.message,
+            :multiline => err.multiline,
+          }
+        rescue => e
+          results[:error] = {
+            :oneline => e.message,
+            :multiline => e.respond_to?(:multiline) ? e.multiline : [e.to_s, e.backtrace].join("\n")
+          }
+        ensure
+          results[:result] ||= :failure
+        end
+
+        results
+      end
+
+      private
+
+      def find_installed_module
+        @environment.modules_by_path.values.flatten.each do |mod|
+          mod_name = (mod.forge_name || mod.name).gsub('/', '-')
+          if mod_name == @name
+            @unfiltered << {
+              :name    => mod_name,
+              :version => mod.version,
+              :path    => mod.modulepath,
+            }
+            if @options[:version] && mod.version
+              next unless SemVer[@options[:version]].include?(SemVer.new(mod.version))
+            end
+            @installed << mod
+          elsif mod_name =~ /#{@name}/
+            @suggestions << mod_name
+          end
+        end
+
+        if @installed.length > 1
+          raise MultipleInstalledError,
+            :action            => :uninstall,
+            :module_name       => @name,
+            :installed_modules => @installed.sort_by { |mod| @environment.modulepath.index(mod.modulepath) }
+        elsif @installed.empty?
+          if @unfiltered.empty?
+            raise NotInstalledError,
+              :action      => :uninstall,
+              :suggestions => @suggestions,
+              :module_name => @name
+          else
+            raise NoVersionMatchesError,
+              :installed_modules => @unfiltered.sort_by { |mod| @environment.modulepath.index(mod[:path]) },
+              :version_range     => @options[:version],
+              :module_name       => @name
+          end
+        end
+      end
+
+      def validate_module
+        mod = @installed.first
+
+        unless @ignore_changes
+          changes = begin
+            Puppet::ModuleTool::Applications::Checksummer.run(mod.path)
+          rescue ArgumentError
+            []
+          end
+
+          if mod.has_metadata? && !changes.empty?
+            raise LocalChangesError,
+              :action            => :uninstall,
+              :module_name       => (mod.forge_name || mod.name).gsub('/', '-'),
+              :requested_version => @options[:version],
+              :installed_version => mod.version
+          end
+        end
+
+        if !@options[:force] && !mod.required_by.empty?
+          raise ModuleIsRequiredError,
+            :module_name       => (mod.forge_name || mod.name).gsub('/', '-'),
+            :required_by       => mod.required_by,
+            :requested_version => @options[:version],
+            :installed_version => mod.version
+        end
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/unpacker.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/unpacker.rb
new file mode 100644
index 0000000..1b00e4c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/unpacker.rb
@@ -0,0 +1,100 @@
+require 'pathname'
+require 'tmpdir'
+require 'json'
+require 'puppet/file_system'
+
+module Puppet::ModuleTool
+  module Applications
+    class Unpacker < Application
+      def self.unpack(filename, target)
+        app = self.new(filename, :target_dir => target)
+        app.unpack
+        app.sanity_check
+        app.move_into(target)
+      end
+
+      def self.harmonize_ownership(source, target)
+        unless Puppet.features.microsoft_windows?
+          source = Pathname.new(source) unless source.respond_to?(:stat)
+          target = Pathname.new(target) unless target.respond_to?(:stat)
+
+          FileUtils.chown_R(source.stat.uid, source.stat.gid, target)
+        end
+      end
+
+      def initialize(filename, options = {})
+        @filename = Pathname.new(filename)
+        super(options)
+        @module_path = Pathname(options[:target_dir])
+      end
+
+      def run
+        unpack
+        sanity_check
+        module_dir = @module_path + module_name
+        move_into(module_dir)
+
+        # Return the Pathname object representing the directory where the
+        # module release archive was unpacked the to.
+        return module_dir
+      end
+
+      # @api private
+      # Error on symlinks and other junk
+      def sanity_check
+        symlinks = Dir.glob("#{tmpdir}/**/*", File::FNM_DOTMATCH).map { |f| Pathname.new(f) }.select {|p| Puppet::FileSystem.symlink? p}
+        tmpdirpath = Pathname.new tmpdir
+
+        symlinks.each do |s|
+          Puppet.warning "Symlinks in modules are unsupported. Please investigate symlink #{s.relative_path_from tmpdirpath}->#{Puppet::FileSystem.readlink(s)}."
+        end
+      end
+
+      # @api private
+      def unpack
+        begin
+          Puppet::ModuleTool::Tar.instance.unpack(@filename.to_s, tmpdir, [@module_path.stat.uid, @module_path.stat.gid].join(':'))
+        rescue Puppet::ExecutionFailure => e
+          raise RuntimeError, "Could not extract contents of module archive: #{e.message}"
+        end
+      end
+
+      # @api private
+      def root_dir
+        return @root_dir if @root_dir
+
+        # Grab the first directory containing a metadata.json file
+        metadata_file = Dir["#{tmpdir}/**/metadata.json"].sort_by(&:length)[0]
+
+        if metadata_file
+          @root_dir = Pathname.new(metadata_file).dirname
+        else
+          raise "No valid metadata.json found!"
+        end
+      end
+
+      # @api private
+      def module_name
+        metadata = JSON.parse((root_dir + 'metadata.json').read)
+        name = metadata['name'][/-(.*)/, 1]
+      end
+
+      # @api private
+      def move_into(dir)
+        dir = Pathname.new(dir)
+        dir.rmtree if dir.exist?
+        FileUtils.mv(root_dir, dir)
+      ensure
+        FileUtils.rmtree(tmpdir)
+      end
+
+      # Obtain a suitable temporary path for unpacking tarballs
+      #
+      # @api private
+      # @return [String] path to temporary unpacking location
+      def tmpdir
+        @dir ||= Dir.mktmpdir('tmp', Puppet::Forge::Cache.base_path)
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/upgrader.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/upgrader.rb
new file mode 100644
index 0000000..d901f86
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/applications/upgrader.rb
@@ -0,0 +1,279 @@
+require 'pathname'
+
+require 'puppet/forge'
+require 'puppet/module_tool'
+require 'puppet/module_tool/shared_behaviors'
+require 'puppet/module_tool/install_directory'
+require 'puppet/module_tool/installed_modules'
+
+module Puppet::ModuleTool
+  module Applications
+    class Upgrader < Application
+
+      include Puppet::ModuleTool::Errors
+
+      def initialize(name, options)
+        super(options)
+
+        @action              = :upgrade
+        @environment         = options[:environment_instance]
+        @name                = name
+        @ignore_changes      = forced? || options[:ignore_changes]
+        @ignore_dependencies = forced? || options[:ignore_dependencies]
+
+        Semantic::Dependency.add_source(installed_modules_source)
+        Semantic::Dependency.add_source(module_repository)
+      end
+
+      def run
+        name = @name.tr('/', '-')
+        version = options[:version] || '>= 0.0.0'
+
+        results = {
+          :action => :upgrade,
+          :requested_version => options[:version] || :latest,
+        }
+
+        begin
+          all_modules = @environment.modules_by_path.values.flatten
+          matching_modules = all_modules.select do |x|
+            x.forge_name && x.forge_name.tr('/', '-') == name
+          end
+
+          if matching_modules.empty?
+            raise NotInstalledError, results.merge(:module_name => name)
+          elsif matching_modules.length > 1
+            raise MultipleInstalledError, results.merge(:module_name => name, :installed_modules => matching_modules)
+          end
+
+          installed_release = installed_modules[name]
+
+          # `priority` is an attribute of a `Semantic::Dependency::Source`,
+          # which is delegated through `ModuleRelease` instances for the sake of
+          # comparison (sorting). By default, the `InstalledModules` source has
+          # a priority of 10 (making it the most preferable source, so that
+          # already installed versions of modules are selected in preference to
+          # modules from e.g. the Forge). Since we are specifically looking to
+          # upgrade this module, we don't want the installed version of this
+          # module to be chosen in preference to those with higher versions.
+          #
+          # This implementation is suboptimal, and since we can expect this sort
+          # of behavior to be reasonably common in Semantic, we should probably
+          # see about implementing a `ModuleRelease#override_priority` method
+          # (or something similar).
+          def installed_release.priority
+            0
+          end
+
+          mod = installed_release.mod
+          results[:installed_version] = Semantic::Version.parse(mod.version)
+          dir = Pathname.new(mod.modulepath)
+
+          vstring = mod.version ? "v#{mod.version}" : '???'
+          Puppet.notice "Found '#{name}' (#{colorize(:cyan, vstring)}) in #{dir} ..."
+          unless @ignore_changes
+            changes = Checksummer.run(mod.path) rescue []
+            if mod.has_metadata? && !changes.empty?
+              raise LocalChangesError,
+                :action            => :upgrade,
+                :module_name       => name,
+                :requested_version => results[:requested_version],
+                :installed_version => mod.version
+            end
+          end
+
+          Puppet::Forge::Cache.clean
+
+          # Ensure that there is at least one candidate release available
+          # for the target package.
+          available_versions = module_repository.fetch(name)
+          if available_versions.empty?
+            raise NoCandidateReleasesError, results.merge(:module_name => name, :source => module_repository.host)
+          elsif results[:requested_version] != :latest
+            requested = Semantic::VersionRange.parse(results[:requested_version])
+            unless available_versions.any? {|m| requested.include? m.version}
+              raise NoCandidateReleasesError, results.merge(:module_name => name, :source => module_repository.host)
+            end
+          end
+
+          Puppet.notice "Downloading from #{module_repository.host} ..."
+          if @ignore_dependencies
+            graph = build_single_module_graph(name, version)
+          else
+            graph = build_dependency_graph(name, version)
+          end
+
+          unless forced?
+            add_module_name_constraints_to_graph(graph)
+          end
+
+          installed_modules.each do |mod, release|
+            mod = mod.tr('/', '-')
+            next if mod == name
+
+            version = release.version
+
+            unless forced?
+              # Since upgrading already installed modules can be troublesome,
+              # we'll place constraints on the graph for each installed
+              # module, locking it to upgrades within the same major version.
+              ">=#{version} #{version.major}.x".tap do |range|
+                graph.add_constraint('installed', mod, range) do |node|
+                  Semantic::VersionRange.parse(range).include? node.version
+                end
+              end
+
+              release.mod.dependencies.each do |dep|
+                dep_name = dep['name'].tr('/', '-')
+
+                dep['version_requirement'].tap do |range|
+                  graph.add_constraint("#{mod} constraint", dep_name, range) do |node|
+                    Semantic::VersionRange.parse(range).include? node.version
+                  end
+                end
+              end
+            end
+          end
+
+          begin
+            Puppet.info "Resolving dependencies ..."
+            releases = Semantic::Dependency.resolve(graph)
+          rescue Semantic::Dependency::UnsatisfiableGraph
+            raise NoVersionsSatisfyError, results.merge(:requested_name => name)
+          end
+
+          releases.each do |rel|
+            if mod = installed_modules_source.by_name[rel.name.split('-').last]
+              next if mod.has_metadata? && mod.forge_name.tr('/', '-') == rel.name
+
+              if rel.name != name
+                dependency = {
+                  :name => rel.name,
+                  :version => rel.version
+                }
+              end
+
+              raise InstallConflictError,
+                :requested_module  => name,
+                :requested_version => options[:version] || 'latest',
+                :dependency        => dependency,
+                :directory         => mod.path,
+                :metadata          => mod.metadata
+            end
+          end
+
+          child = releases.find { |x| x.name == name }
+
+          unless forced?
+            if child.version == results[:installed_version]
+              versions = graph.dependencies[name].map { |r| r.version }
+              newer_versions = versions.select { |v| v > results[:installed_version] }
+
+              raise VersionAlreadyInstalledError,
+                :module_name       => name,
+                :requested_version => results[:requested_version],
+                :installed_version => results[:installed_version],
+                :newer_versions    => newer_versions,
+                :possible_culprits => installed_modules_source.fetched.reject { |x| x == name }
+            elsif child.version < results[:installed_version]
+              raise DowngradingUnsupportedError,
+                :module_name       => name,
+                :requested_version => results[:requested_version],
+                :installed_version => results[:installed_version]
+            end
+          end
+
+          Puppet.info "Preparing to upgrade ..."
+          releases.each { |release| release.prepare }
+
+          Puppet.notice 'Upgrading -- do not interrupt ...'
+          releases.each do |release|
+            if installed = installed_modules[release.name]
+              release.install(Pathname.new(installed.mod.modulepath))
+            else
+              release.install(dir)
+            end
+          end
+
+          results[:result] = :success
+          results[:base_dir] = releases.first.install_dir
+          results[:affected_modules] = releases
+          results[:graph] = [ build_install_graph(releases.first, releases) ]
+
+        rescue VersionAlreadyInstalledError => e
+          results[:result] = (e.newer_versions.empty? ? :noop : :failure)
+          results[:error] = { :oneline => e.message, :multiline => e.multiline }
+        rescue => e
+          results[:error] = {
+            :oneline   => e.message,
+            :multiline => e.respond_to?(:multiline) ? e.multiline : [e.to_s, e.backtrace].join("\n")
+          }
+        ensure
+          results[:result] ||= :failure
+        end
+
+        results
+      end
+
+      private
+      def module_repository
+        @repo ||= Puppet::Forge.new
+      end
+
+      def installed_modules_source
+        @installed ||= Puppet::ModuleTool::InstalledModules.new(@environment)
+      end
+
+      def installed_modules
+        installed_modules_source.modules
+      end
+
+      def build_single_module_graph(name, version)
+        range = Semantic::VersionRange.parse(version)
+        graph = Semantic::Dependency::Graph.new(name => range)
+        releases = Semantic::Dependency.fetch_releases(name)
+        releases.each { |release| release.dependencies.clear }
+        graph << releases
+      end
+
+      def build_dependency_graph(name, version)
+        Semantic::Dependency.query(name => version)
+      end
+
+      def build_install_graph(release, installed, graphed = [])
+        previous = installed_modules[release.name]
+        previous = previous.version if previous
+
+        action = :upgrade
+        unless previous && previous != release.version
+          action = :install
+        end
+
+        graphed << release
+
+        dependencies = release.dependencies.values.map do |deps|
+          dep = (deps & installed).first
+          if dep == installed_modules[dep.name]
+            next
+          end
+
+          if dep && !graphed.include?(dep)
+            build_install_graph(dep, installed, graphed)
+          end
+        end.compact
+
+        return {
+          :release          => release,
+          :name             => release.name,
+          :path             => release.install_dir,
+          :dependencies     => dependencies.compact,
+          :version          => release.version,
+          :previous_version => previous,
+          :action           => action,
+        }
+      end
+
+      include Puppet::ModuleTool::Shared
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/checksums.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/checksums.rb
new file mode 100644
index 0000000..8931455
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/checksums.rb
@@ -0,0 +1,49 @@
+require 'digest/md5'
+require 'puppet/network/format_support'
+
+module Puppet::ModuleTool
+
+  # = Checksums
+  #
+  # This class proides methods for generating checksums for data and adding
+  # them to +Metadata+.
+  class Checksums
+    include Puppet::Network::FormatSupport
+    include Enumerable
+
+    # Instantiate object with string +path+ to create checksums from.
+    def initialize(path)
+      @path = Pathname.new(path)
+    end
+
+    # Return checksum for the +Pathname+.
+    def checksum(pathname)
+      return Digest::MD5.hexdigest(Puppet::FileSystem.binread(pathname))
+    end
+
+    # Return checksums for object's +Pathname+, generate if it's needed.
+    # Result is a hash of path strings to checksum strings.
+    def data
+      unless @data
+        @data = {}
+        @path.find do |descendant|
+          if Puppet::ModuleTool.artifact?(descendant)
+            Find.prune
+          elsif descendant.file?
+            path = descendant.relative_path_from(@path)
+            @data[path.to_s] = checksum(descendant)
+          end
+        end
+      end
+      return @data
+    end
+
+    alias :to_data_hash :data
+    alias :to_hash :data
+
+    # TODO: Why?
+    def each(&block)
+      data.each(&block)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/contents_description.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/contents_description.rb
new file mode 100644
index 0000000..7fd6505
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/contents_description.rb
@@ -0,0 +1,84 @@
+require 'puppet/module_tool'
+
+module Puppet::ModuleTool
+
+  # = ContentsDescription
+  #
+  # This class populates +Metadata+'s Puppet type information.
+  class ContentsDescription
+
+    # Instantiate object for string +module_path+.
+    def initialize(module_path)
+      @module_path = module_path
+    end
+
+    # Update +Metadata+'s Puppet type information.
+    def annotate(metadata)
+      metadata.types.replace data.clone
+    end
+
+    # Return types for this module. Result is an array of hashes, each of which
+    # describes a Puppet type. The type description hash structure is:
+    # * :name => Name of this Puppet type.
+    # * :doc => Documentation for this type.
+    # * :properties => Array of hashes representing the type's properties, each
+    #   containing :name and :doc.
+    # * :parameters => Array of hashes representing the type's parameters, each
+    #   containing :name and :doc.
+    # * :providers => Array of hashes representing the types providers, each
+    #   containing :name and :doc.
+    # TODO Write a TypeDescription to encapsulate these structures and logic?
+    def data
+      unless @data
+        @data = []
+        type_names = []
+        for module_filename in Dir[File.join(@module_path, "lib/puppet/type/*.rb")]
+          require module_filename
+          type_name = File.basename(module_filename, ".rb")
+          type_names << type_name
+
+          for provider_filename in Dir[File.join(@module_path, "lib/puppet/provider/#{type_name}/*.rb")]
+            require provider_filename
+          end
+        end
+
+        type_names.each do |type_name|
+          if type = Puppet::Type.type(type_name.to_sym)
+            type_hash = {:name => type_name, :doc => type.doc}
+            type_hash[:properties] = attr_doc(type, :property)
+            type_hash[:parameters] = attr_doc(type, :param)
+            if type.providers.size > 0
+              type_hash[:providers] = provider_doc(type)
+            end
+            @data << type_hash
+          else
+            Puppet.warning "Could not find/load type: #{type_name}"
+          end
+        end
+      end
+      @data
+    end
+
+    # Return an array of hashes representing this +type+'s attrs of +kind+
+    # (e.g. :param or :property), each containing :name and :doc.
+    def attr_doc(type, kind)
+      [].tap do |attrs|
+        type.allattrs.each do |name|
+          if type.attrtype(name) == kind && name != :provider
+            attrs.push(:name => name, :doc => type.attrclass(name).doc)
+          end
+        end
+      end
+    end
+
+    # Return an array of hashes representing this +type+'s providers, each
+    # containing :name and :doc.
+    def provider_doc(type)
+      [].tap do |providers|
+        type.providers.sort.each do |prov|
+          providers.push(:name => prov, :doc => type.provider(prov).doc)
+        end
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/dependency.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/dependency.rb
new file mode 100644
index 0000000..2f0995e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/dependency.rb
@@ -0,0 +1,42 @@
+require 'puppet/module_tool'
+require 'puppet/network/format_support'
+
+module Puppet::ModuleTool
+
+  class Dependency
+    include Puppet::Network::FormatSupport
+    alias :to_json :to_pson
+
+    attr_reader :full_module_name, :username, :name, :version_requirement, :repository
+
+    # Instantiates a new module dependency with a +full_module_name+ (e.g.
+    # "myuser-mymodule"), and optional +version_requirement+ (e.g. "0.0.1") and
+    # optional repository (a URL string).
+    def initialize(full_module_name, version_requirement = nil, repository = nil)
+      @full_module_name = full_module_name
+      # TODO: add error checking, the next line raises ArgumentError when +full_module_name+ is invalid
+      @username, @name = Puppet::ModuleTool.username_and_modname_from(full_module_name)
+      @version_requirement = version_requirement
+      @repository = repository ? Puppet::Forge::Repository.new(repository) : nil
+    end
+
+    # We override Object's ==, eql, and hash so we can more easily find identical
+    # dependencies.
+    def ==(o)
+      self.hash == o.hash
+    end
+
+    alias :eql? :==
+
+    def hash
+      [@full_module_name, @version_requirement, @repository].hash
+    end
+
+    def to_data_hash
+      result = { :name => @full_module_name }
+      result[:version_requirement] = @version_requirement if @version_requirement && ! @version_requirement.nil?
+      result[:repository] = @repository.to_s if @repository && ! @repository.nil?
+      result
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/errors.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/errors.rb
new file mode 100644
index 0000000..3f917bd
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/errors.rb
@@ -0,0 +1,11 @@
+require 'puppet/module_tool'
+
+module Puppet::ModuleTool
+  module Errors
+    require 'puppet/module_tool/errors/base'
+    require 'puppet/module_tool/errors/installer'
+    require 'puppet/module_tool/errors/uninstaller'
+    require 'puppet/module_tool/errors/upgrader'
+    require 'puppet/module_tool/errors/shared'
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/errors/base.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/errors/base.rb
new file mode 100644
index 0000000..c8f153a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/errors/base.rb
@@ -0,0 +1,15 @@
+module Puppet::ModuleTool::Errors
+  class ModuleToolError < Puppet::Error
+    def v(version)
+      (version || '???').to_s.sub(/^(?=\d)/, 'v')
+    end
+
+    def vstring
+      if @action == :upgrade
+        "#{v(@installed_version)} -> #{v(@requested_version)}"
+      else
+        "#{v(@installed_version || @requested_version)}"
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/errors/installer.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/errors/installer.rb
new file mode 100644
index 0000000..79963a6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/errors/installer.rb
@@ -0,0 +1,95 @@
+module Puppet::ModuleTool::Errors
+
+  class InstallError < ModuleToolError; end
+
+  class AlreadyInstalledError < InstallError
+    def initialize(options)
+      @module_name       = options[:module_name]
+      @installed_version = v(options[:installed_version])
+      @requested_version = v(options[:requested_version])
+      @local_changes     = options[:local_changes]
+      super "'#{@module_name}' (#{@requested_version}) requested; '#{@module_name}' (#{@installed_version}) already installed"
+    end
+
+    def multiline
+      message = []
+      message << "Could not install module '#{@module_name}' (#{@requested_version})"
+      message << "  Module '#{@module_name}' (#{@installed_version}) is already installed"
+      message << "    Installed module has had changes made locally" unless @local_changes.empty?
+      message << "    Use `puppet module upgrade` to install a different version"
+      message << "    Use `puppet module install --force` to re-install only this module"
+      message.join("\n")
+    end
+  end
+
+  class MissingPackageError < InstallError
+    def initialize(options)
+      @requested_package = options[:requested_package]
+      @source = options[:source]
+
+      super "Could not install '#{@requested_package}'; no releases are available from #{@source}"
+    end
+
+    def multiline
+      message = []
+      message << "Could not install '#{@requested_package}'"
+
+      message << "  No releases are available from #{@source}"
+      message << "    Does '#{@requested_package}' have at least one published release?"
+
+      message.join("\n")
+    end
+  end
+
+  class InstallPathExistsNotDirectoryError < InstallError
+    def initialize(original, options)
+      @requested_module  = options[:requested_module]
+      @requested_version = options[:requested_version]
+      @directory         = options[:directory]
+      super("'#{@requested_module}' (#{@requested_version}) requested; Path #{@directory} is not a directory.", original)
+    end
+
+    def multiline
+      <<-MSG.strip
+Could not install module '#{@requested_module}' (#{@requested_version})
+  Path '#{@directory}' exists but is not a directory.
+  A potential solution is to rename the path and then
+  mkdir -p '#{@directory}'
+      MSG
+    end
+  end
+
+  class PermissionDeniedCreateInstallDirectoryError < InstallError
+    def initialize(original, options)
+      @requested_module  = options[:requested_module]
+      @requested_version = options[:requested_version]
+      @directory         = options[:directory]
+      super("'#{@requested_module}' (#{@requested_version}) requested; Permission is denied to create #{@directory}.", original)
+    end
+
+    def multiline
+      <<-MSG.strip
+Could not install module '#{@requested_module}' (#{@requested_version})
+  Permission is denied when trying to create directory '#{@directory}'.
+  A potential solution is to check the ownership and permissions of
+  parent directories.
+      MSG
+    end
+  end
+
+  class InvalidPathInPackageError < InstallError
+    def initialize(options)
+      @entry_path = options[:entry_path]
+      @directory  = options[:directory]
+      super "Attempt to install file into #{@entry_path.inspect} under #{@directory.inspect}"
+    end
+
+    def multiline
+      <<-MSG.strip
+Could not install package
+  Package attempted to install file into
+  #{@entry_path.inspect} under #{@directory.inspect}.
+      MSG
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/errors/shared.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/errors/shared.rb
new file mode 100644
index 0000000..a1e0282
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/errors/shared.rb
@@ -0,0 +1,188 @@
+module Puppet::ModuleTool::Errors
+
+  class NoVersionsSatisfyError < ModuleToolError
+    def initialize(options)
+      @requested_name    = options[:requested_name]
+      @requested_version = options[:requested_version]
+      @installed_version = options[:installed_version]
+      @conditions        = options[:conditions]
+      @action            = options[:action]
+
+      super "Could not #{@action} '#{@requested_name}' (#{vstring}); no version satisfies all dependencies"
+    end
+
+    def multiline
+      message = []
+      message << "Could not #{@action} module '#{@requested_name}' (#{vstring})"
+      message << "  No version of '#{@requested_name}' can satisfy all dependencies"
+      message << "    Use `puppet module #{@action} --ignore-dependencies` to #{@action} only this module"
+
+      message.join("\n")
+    end
+  end
+
+  class NoCandidateReleasesError < ModuleToolError
+    def initialize(options)
+      @module_name       = options[:module_name]
+      @requested_version = options[:requested_version]
+      @installed_version = options[:installed_version]
+      @source            = options[:source]
+      @action            = options[:action]
+
+      if @requested_version == :latest
+        super "Could not #{@action} '#{@module_name}'; no releases are available from #{@source}"
+      else
+        super "Could not #{@action} '#{@module_name}'; no releases matching '#{@requested_version}' are available from #{@source}"
+      end
+    end
+
+    def multiline
+      message = []
+      message << "Could not #{@action} '#{@module_name}' (#{vstring})"
+
+      if @requested_version == :latest
+        message << "  No releases are available from #{@source}"
+        message << "    Does '#{@module_name}' have at least one published release?"
+      else
+        message << "  No releases matching '#{@requested_version}' are available from #{@source}"
+      end
+
+      message.join("\n")
+    end
+  end
+
+  class InstallConflictError < ModuleToolError
+    def initialize(options)
+      @requested_module  = options[:requested_module]
+      @requested_version = v(options[:requested_version])
+      @dependency        = options[:dependency]
+      @directory         = options[:directory]
+      @metadata          = options[:metadata]
+      super "'#{@requested_module}' (#{@requested_version}) requested; installation conflict"
+    end
+
+    def multiline
+      message = []
+      message << "Could not install module '#{@requested_module}' (#{@requested_version})"
+
+      if @dependency
+        message << "  Dependency '#{@dependency[:name]}' (#{v(@dependency[:version])}) would overwrite #{@directory}"
+      else
+        message << "  Installation would overwrite #{@directory}"
+      end
+
+      if @metadata
+        message << "    Currently, '#{@metadata["name"]}' (#{v(@metadata["version"])}) is installed to that directory"
+      end
+
+      if @dependency
+        message << "    Use `puppet module install --ignore-dependencies` to install only this module"
+      else
+        message << "    Use `puppet module install --force` to install this module anyway"
+      end
+
+      message.join("\n")
+    end
+  end
+
+  class InvalidDependencyCycleError < ModuleToolError
+    def initialize(options)
+      @module_name       = options[:module_name]
+      @requested_module  = options[:requested_module]
+      @requested_version = options[:requested_version]
+      @conditions        = options[:conditions]
+      @source            = options[:source][1..-1]
+
+      super "'#{@requested_module}' (#{v(@requested_version)}) requested; Invalid dependency cycle"
+    end
+
+    def multiline
+      trace = []
+      trace << "You specified '#{@source.first[:name]}' (#{v(@requested_version)})"
+      trace += @source[1..-1].map { |m| "which depends on '#{m[:name]}' (#{v(m[:version])})" }
+
+      message = []
+      message << "Could not install module '#{@requested_module}' (#{v(@requested_version)})"
+      message << "  No version of '#{@module_name}' will satisfy dependencies"
+      message << trace.map { |s| "    #{s}" }.join(",\n")
+      message << "    Use `puppet module install --force` to install this module anyway"
+
+      message.join("\n")
+    end
+  end
+
+  class NotInstalledError < ModuleToolError
+    def initialize(options)
+      @module_name = options[:module_name]
+      @suggestions = options[:suggestions] || []
+      @action      = options[:action]
+      super "Could not #{@action} '#{@module_name}'; module is not installed"
+    end
+
+    def multiline
+      message = []
+      message << "Could not #{@action} module '#{@module_name}'"
+      message << "  Module '#{@module_name}' is not installed"
+      message += @suggestions.map do |suggestion|
+        "    You may have meant `puppet module #{@action} #{suggestion}`"
+      end
+      message << "    Use `puppet module install` to install this module" if @action == :upgrade
+      message.join("\n")
+    end
+  end
+
+  class MultipleInstalledError < ModuleToolError
+    def initialize(options)
+      @module_name = options[:module_name]
+      @modules     = options[:installed_modules]
+      @action      = options[:action]
+      super "Could not #{@action} '#{@module_name}'; module appears in multiple places in the module path"
+    end
+
+    def multiline
+      message = []
+      message << "Could not #{@action} module '#{@module_name}'"
+      message << "  Module '#{@module_name}' appears multiple places in the module path"
+      message += @modules.map do |mod|
+        "    '#{@module_name}' (#{v(mod.version)}) was found in #{mod.modulepath}"
+      end
+      message << "    Use the `--modulepath` option to limit the search to specific directories"
+      message.join("\n")
+    end
+  end
+
+  class LocalChangesError < ModuleToolError
+    def initialize(options)
+      @module_name       = options[:module_name]
+      @requested_version = options[:requested_version]
+      @installed_version = options[:installed_version]
+      @action            = options[:action]
+      super "Could not #{@action} '#{@module_name}'; module has had changes made locally"
+    end
+
+    def multiline
+      message = []
+      message << "Could not #{@action} module '#{@module_name}' (#{vstring})"
+      message << "  Installed module has had changes made locally"
+      message << "    Use `puppet module #{@action} --ignore-changes` to #{@action} this module anyway"
+      message.join("\n")
+    end
+  end
+
+  class InvalidModuleError < ModuleToolError
+    def initialize(name, options)
+      @name   = name
+      @action = options[:action]
+      @error  = options[:error]
+      super "Could not #{@action} '#{@name}'; #{@error.message}"
+    end
+
+    def multiline
+      message = []
+      message << "Could not #{@action} module '#{@name}'"
+      message << "  Failure trying to parse metadata"
+      message << "    Original message was: #{@error.message}"
+      message.join("\n")
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/errors/uninstaller.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/errors/uninstaller.rb
new file mode 100644
index 0000000..18809cb
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/errors/uninstaller.rb
@@ -0,0 +1,45 @@
+module Puppet::ModuleTool::Errors
+
+  class UninstallError < ModuleToolError; end
+
+  class NoVersionMatchesError < UninstallError
+    def initialize(options)
+      @module_name = options[:module_name]
+      @modules     = options[:installed_modules]
+      @version     = options[:version_range]
+      super "Could not uninstall '#{@module_name}'; no installed version matches"
+    end
+
+    def multiline
+      message = []
+      message << "Could not uninstall module '#{@module_name}' (#{v(@version)})"
+      message << "  No installed version of '#{@module_name}' matches (#{v(@version)})"
+      message += @modules.map do |mod|
+        "    '#{mod[:name]}' (#{v(mod[:version])}) is installed in #{mod[:path]}"
+      end
+      message.join("\n")
+    end
+  end
+
+  class ModuleIsRequiredError < UninstallError
+    def initialize(options)
+      @module_name       = options[:module_name]
+      @required_by       = options[:required_by]
+      @requested_version = options[:requested_version]
+      @installed_version = options[:installed_version]
+
+      super "Could not uninstall '#{@module_name}'; installed modules still depend upon it"
+    end
+
+    def multiline
+      message = []
+      message << ("Could not uninstall module '#{@module_name}'" << (@requested_version ? " (#{v(@requested_version)})" : ''))
+      message << "  Other installed modules have dependencies on '#{@module_name}' (#{v(@installed_version)})"
+      message += @required_by.map do |mod|
+        "    '#{mod['name']}' (#{v(mod['version'])}) requires '#{@module_name}' (#{v(mod['version_requirement'])})"
+      end
+      message << "    Use `puppet module uninstall --force` to uninstall this module anyway"
+      message.join("\n")
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/errors/upgrader.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/errors/upgrader.rb
new file mode 100644
index 0000000..0247f79
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/errors/upgrader.rb
@@ -0,0 +1,63 @@
+module Puppet::ModuleTool::Errors
+
+  class UpgradeError < ModuleToolError
+    def initialize(msg)
+      @action = :upgrade
+      super
+    end
+  end
+
+  class VersionAlreadyInstalledError < UpgradeError
+    attr_reader :newer_versions
+
+    def initialize(options)
+      @module_name       = options[:module_name]
+      @requested_version = options[:requested_version]
+      @installed_version = options[:installed_version]
+      @dependency_name   = options[:dependency_name]
+      @newer_versions    = options[:newer_versions]
+      @possible_culprits = options[:possible_culprits]
+      super "Could not upgrade '#{@module_name}'; more recent versions not found"
+    end
+
+    def multiline
+      message = []
+      message << "Could not upgrade module '#{@module_name}' (#{vstring})"
+      if @newer_versions.empty?
+        message << "  The installed version is already the latest version matching #{vstring}"
+      else
+        message << "  There are #{@newer_versions.length} newer versions"
+        message << "    No combination of dependency upgrades would satisfy all dependencies"
+        unless @possible_culprits.empty?
+          message << "    Dependencies will not be automatically upgraded across major versions"
+          message << "    Upgrading one or more of these modules may permit the upgrade to succeed:"
+          @possible_culprits.each do |name|
+            message << "    - #{name}"
+          end
+        end
+      end
+      message << "    Use `puppet module upgrade --force` to upgrade only this module"
+      message.join("\n")
+    end
+  end
+
+  class DowngradingUnsupportedError < UpgradeError
+    def initialize(options)
+      @module_name    = options[:module_name]
+      @requested_version = options[:requested_version]
+      @installed_version = options[:installed_version]
+      @conditions        = options[:conditions]
+      @action            = options[:action]
+
+      super "Could not #{@action} '#{@module_name}' (#{vstring}); downgrades are not allowed"
+    end
+
+    def multiline
+      message = []
+      message << "Could not #{@action} module '#{@module_name}' (#{vstring})"
+      message << "  Downgrading is not allowed."
+
+      message.join("\n")
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/install_directory.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/install_directory.rb
new file mode 100644
index 0000000..0054897
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/install_directory.rb
@@ -0,0 +1,45 @@
+require 'puppet/module_tool'
+require 'puppet/module_tool/errors'
+
+module Puppet
+  module ModuleTool
+    # Control the install location for modules.
+    class InstallDirectory
+      include Puppet::ModuleTool::Errors
+
+      attr_reader :target
+      def initialize(target)
+        @target = target
+      end
+
+      # prepare the module install location. This will create the location if
+      # needed.
+      def prepare(module_name, version)
+        return if @target.directory?
+
+        begin
+          @target.mkpath
+          Puppet.notice "Created target directory #{@target}"
+        rescue SystemCallError => orig_error
+          raise converted_to_friendly_error(module_name, version, orig_error)
+        end
+      end
+
+    private
+
+      ERROR_MAPPINGS = {
+        Errno::EACCES => PermissionDeniedCreateInstallDirectoryError,
+        Errno::EEXIST => InstallPathExistsNotDirectoryError,
+      }
+
+      def converted_to_friendly_error(module_name, version, orig_error)
+        return orig_error if not ERROR_MAPPINGS.include?(orig_error.class)
+
+        ERROR_MAPPINGS[orig_error.class].new(orig_error,
+          :requested_module  => module_name,
+          :requested_version => version,
+          :directory         => @target.to_s)
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/installed_modules.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/installed_modules.rb
new file mode 100644
index 0000000..de94211
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/installed_modules.rb
@@ -0,0 +1,98 @@
+require 'pathname'
+
+require 'puppet/forge'
+require 'puppet/module_tool'
+
+module Puppet::ModuleTool
+  class InstalledModules < Semantic::Dependency::Source
+    attr_reader :modules, :by_name
+
+    def priority
+      10
+    end
+
+    def initialize(env)
+      @env = env
+      modules = env.modules_by_path
+
+      @fetched = []
+      @modules = {}
+      @by_name = {}
+      env.modulepath.each do |path|
+        modules[path].each do |mod|
+          @by_name[mod.name] = mod
+          next unless mod.has_metadata?
+          release = ModuleRelease.new(self, mod)
+          @modules[release.name] ||= release
+        end
+      end
+
+      @modules.freeze
+    end
+
+    # Fetches {ModuleRelease} entries for each release of the named module.
+    #
+    # @param name [String] the module name to look up
+    # @return [Array<Semantic::Dependency::ModuleRelease>] a list of releases for
+    #         the given name
+    # @see Semantic::Dependency::Source#fetch
+    def fetch(name)
+      name = name.tr('/', '-')
+
+      if @modules.key? name
+        @fetched << name
+        [ @modules[name] ]
+      else
+        [ ]
+      end
+    end
+
+    def fetched
+      @fetched
+    end
+
+    class ModuleRelease < Semantic::Dependency::ModuleRelease
+      attr_reader :mod, :metadata
+
+      def initialize(source, mod)
+        @mod = mod
+        @metadata = mod.metadata
+        name = mod.forge_name.tr('/', '-')
+        begin
+          version = Semantic::Version.parse(mod.version)
+        rescue Semantic::Version::ValidationFailure => e
+          Puppet.warning "#{mod.name} (#{mod.path}) has an invalid version number (#{mod.version}). The version has been set to 0.0.0. If you are the maintainer for this module, please update the metadata.json with a valid Semantic Version (http://semver.org)."
+          version = Semantic::Version.parse("0.0.0")
+        end
+        release = "#{name}@#{version}"
+
+        super(source, name, version, {})
+
+        if mod.dependencies
+          mod.dependencies.each do |dep|
+            results = Puppet::ModuleTool.parse_module_dependency(release, dep)
+            dep_name, parsed_range, range = results
+
+            dep.tap do |dep|
+              add_constraint('initialize', dep_name, range.to_s) do |node|
+                parsed_range === node.version
+              end
+            end
+          end
+        end
+      end
+
+      def install_dir
+        Pathname.new(@mod.path).dirname
+      end
+
+      def install(dir)
+        # If we're already installed, there's no need for us to faff about.
+      end
+
+      def prepare
+        # We're already installed; what preparation remains?
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/local_tarball.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/local_tarball.rb
new file mode 100644
index 0000000..d85c4c0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/local_tarball.rb
@@ -0,0 +1,90 @@
+require 'pathname'
+require 'tmpdir'
+
+require 'puppet/forge'
+require 'puppet/module_tool'
+
+module Puppet::ModuleTool
+  class LocalTarball < Semantic::Dependency::Source
+    attr_accessor :release
+
+    def initialize(filename)
+      unpack(filename, tmpdir)
+      Puppet.debug "Unpacked local tarball to #{tmpdir}"
+
+      mod = Puppet::Module.new('tarball', tmpdir, nil)
+      @release = ModuleRelease.new(self, mod)
+    end
+
+    def fetch(name)
+      if @release.name == name
+        [ @release ]
+      else
+        [ ]
+      end
+    end
+
+    def prepare(release)
+      release.mod.path
+    end
+
+    def install(release, dir)
+      staging_dir = release.prepare
+
+      module_dir = dir + release.name[/-(.*)/, 1]
+      module_dir.rmtree if module_dir.exist?
+
+      # Make sure unpacked module has the same ownership as the folder we are moving it into.
+      Puppet::ModuleTool::Applications::Unpacker.harmonize_ownership(dir, staging_dir)
+
+      FileUtils.mv(staging_dir, module_dir)
+    end
+
+    class ModuleRelease < Semantic::Dependency::ModuleRelease
+      attr_reader :mod, :install_dir, :metadata
+
+      def initialize(source, mod)
+        @mod = mod
+        @metadata = mod.metadata
+        name = mod.forge_name.tr('/', '-')
+        version = Semantic::Version.parse(mod.version)
+        release = "#{name}@#{version}"
+
+        if mod.dependencies
+          dependencies = mod.dependencies.map do |dep|
+            Puppet::ModuleTool.parse_module_dependency(release, dep)[0..1]
+          end
+          dependencies = Hash[dependencies]
+        end
+
+        super(source, name, version, dependencies || {})
+      end
+
+      def install(dir)
+        @source.install(self, dir)
+        @install_dir = dir
+      end
+
+      def prepare
+        @source.prepare(self)
+      end
+    end
+
+    private
+
+    # Obtain a suitable temporary path for unpacking tarballs
+    #
+    # @return [String] path to temporary unpacking location
+    def tmpdir
+      @dir ||= Dir.mktmpdir('local-tarball', Puppet::Forge::Cache.base_path)
+    end
+
+    def unpack(file, destination)
+      begin
+        Puppet::ModuleTool::Applications::Unpacker.unpack(file, destination)
+      rescue Puppet::ExecutionFailure => e
+        raise RuntimeError, "Could not extract contents of module archive: #{e.message}"
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/metadata.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/metadata.rb
new file mode 100644
index 0000000..0237555
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/metadata.rb
@@ -0,0 +1,209 @@
+require 'puppet/util/methodhelper'
+require 'puppet/module_tool'
+require 'puppet/network/format_support'
+require 'uri'
+require 'json'
+require 'set'
+
+module Puppet::ModuleTool
+
+  # This class provides a data structure representing a module's metadata.
+  # @api private
+  class Metadata
+    include Puppet::Network::FormatSupport
+
+    attr_accessor :module_name
+
+    DEFAULTS = {
+      'name'         => nil,
+      'version'      => nil,
+      'author'       => nil,
+      'summary'      => nil,
+      'license'      => 'Apache 2.0',
+      'source'       => '',
+      'project_page' => nil,
+      'issues_url'   => nil,
+      'dependencies' => Set.new.freeze,
+    }
+
+    def initialize
+      @data = DEFAULTS.dup
+      @data['dependencies'] = @data['dependencies'].dup
+    end
+
+    # Returns a filesystem-friendly version of this module name.
+    def dashed_name
+      @data['name'].tr('/', '-') if @data['name']
+    end
+
+    # Returns a string that uniquely represents this version of this module.
+    def release_name
+      return nil unless @data['name'] && @data['version']
+      [ dashed_name, @data['version'] ].join('-')
+    end
+
+    alias :name :module_name
+    alias :full_module_name :dashed_name
+
+    # Merges the current set of metadata with another metadata hash.  This
+    # method also handles the validation of module names and versions, in an
+    # effort to be proactive about module publishing constraints.
+    def update(data)
+      process_name(data) if data['name']
+      process_version(data) if data['version']
+      process_source(data) if data['source']
+      merge_dependencies(data) if data['dependencies']
+
+      @data.merge!(data)
+      return self
+    end
+
+    # Validates the name and version_requirement for a dependency, then creates
+    # the Dependency and adds it.
+    # Returns the Dependency that was added.
+    def add_dependency(name, version_requirement=nil, repository=nil)
+      validate_name(name)
+      validate_version_range(version_requirement) if version_requirement
+
+      if dup = @data['dependencies'].find { |d| d.full_module_name == name && d.version_requirement != version_requirement }
+        raise ArgumentError, "Dependency conflict for #{full_module_name}: Dependency #{name} was given conflicting version requirements #{version_requirement} and #{dup.version_requirement}. Verify that there are no duplicates in the metadata.json or the Modulefile."
+      end
+
+      dep = Dependency.new(name, version_requirement, repository)
+      @data['dependencies'].add(dep)
+
+      dep
+    end
+
+    # Provides an accessor for the now defunct 'description' property.  This
+    # addresses a regression in Puppet 3.6.x where previously valid templates
+    # refering to the 'description' property were broken.
+    # @deprecated
+    def description
+      @data['description']
+    end
+
+    def dependencies
+      @data['dependencies'].to_a
+    end
+
+    # Returns a hash of the module's metadata.  Used by Puppet's automated
+    # serialization routines.
+    #
+    # @see Puppet::Network::FormatSupport#to_data_hash
+    def to_hash
+      @data
+    end
+    alias :to_data_hash :to_hash
+
+    def to_json
+      data = @data.dup.merge('dependencies' => dependencies)
+
+      # This is used to simulate an ordered hash.  In particular, some keys
+      # are promoted to the top of the serialized hash (while others are
+      # demoted) for human-friendliness.
+      #
+      # This particularly works around the lack of ordered hashes in 1.8.7.
+      promoted_keys = %w[ name version author summary license source ]
+      demoted_keys = %w[ dependencies ]
+      keys = data.keys
+      keys -= promoted_keys
+      keys -= demoted_keys
+
+      contents = (promoted_keys + keys + demoted_keys).map do |k|
+        value = (JSON.pretty_generate(data[k]) rescue data[k].to_json)
+        "#{k.to_json}: #{value}"
+      end
+
+      "{\n" + contents.join(",\n").gsub(/^/, '  ') + "\n}\n"
+    end
+
+    # Expose any metadata keys as callable reader methods.
+    def method_missing(name, *args)
+      return @data[name.to_s] if @data.key? name.to_s
+      super
+    end
+
+    private
+
+    # Do basic validation and parsing of the name parameter.
+    def process_name(data)
+      validate_name(data['name'])
+      author, @module_name = data['name'].split(/[-\/]/, 2)
+
+      data['author'] ||= author if @data['author'] == DEFAULTS['author']
+    end
+
+    # Do basic validation on the version parameter.
+    def process_version(data)
+      validate_version(data['version'])
+    end
+
+    # Do basic parsing of the source parameter.  If the source is hosted on
+    # GitHub, we can predict sensible defaults for both project_page and
+    # issues_url.
+    def process_source(data)
+      if data['source'] =~ %r[://]
+        source_uri = URI.parse(data['source'])
+      else
+        source_uri = URI.parse("http://#{data['source']}")
+      end
+
+      if source_uri.host =~ /^(www\.)?github\.com$/
+        source_uri.scheme = 'https'
+        source_uri.path.sub!(/\.git$/, '')
+        data['project_page'] ||= @data['project_page'] || source_uri.to_s
+        data['issues_url'] ||= @data['issues_url'] || source_uri.to_s.sub(/\/*$/, '') + '/issues'
+      end
+
+    rescue URI::Error
+      return
+    end
+
+    # Validates and parses the dependencies.
+    def merge_dependencies(data)
+      data['dependencies'].each do |dep|
+        add_dependency(dep['name'], dep['version_requirement'], dep['repository'])
+      end
+
+      # Clear dependencies so @data dependencies are not overwritten
+      data.delete 'dependencies'
+    end
+
+    # Validates that the given module name is both namespaced and well-formed.
+    def validate_name(name)
+      return if name =~ /\A[a-z0-9]+[-\/][a-z][a-z0-9_]*\Z/i
+
+      namespace, modname = name.split(/[-\/]/, 2)
+      modname = :namespace_missing if namespace == ''
+
+      err = case modname
+      when nil, '', :namespace_missing
+        "the field must be a namespaced module name"
+      when /[^a-z0-9_]/i
+        "the module name contains non-alphanumeric (or underscore) characters"
+      when /^[^a-z]/i
+        "the module name must begin with a letter"
+      else
+        "the namespace contains non-alphanumeric characters"
+      end
+
+      raise ArgumentError, "Invalid 'name' field in metadata.json: #{err}"
+    end
+
+    # Validates that the version string can be parsed as per SemVer.
+    def validate_version(version)
+      return if SemVer.valid?(version)
+
+      err = "version string cannot be parsed as a valid Semantic Version"
+      raise ArgumentError, "Invalid 'version' field in metadata.json: #{err}"
+    end
+
+    # Validates that the version range can be parsed by Semantic.
+    def validate_version_range(version_range)
+      Semantic::VersionRange.parse(version_range)
+    rescue ArgumentError => e
+      raise ArgumentError, "Invalid 'version_range' field in metadata.json: #{e}"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/modulefile.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/modulefile.rb
new file mode 100644
index 0000000..31eb9c1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/modulefile.rb
@@ -0,0 +1,78 @@
+require 'puppet/module_tool'
+require 'puppet/module_tool/dependency'
+
+module Puppet::ModuleTool
+
+  # = Modulefile
+  #
+  # This class provides the DSL used for evaluating the module's 'Modulefile'.
+  # These methods are used to concisely define this module's attributes, which
+  # are later rendered as PSON into a 'metadata.json' file.
+  class ModulefileReader
+
+    # Read the +filename+ and eval its Ruby code to set values in the Metadata
+    # +metadata+ instance.
+    def self.evaluate(metadata, filename)
+      builder = new(metadata)
+      if File.file?(filename)
+        builder.instance_eval(File.read(filename.to_s), filename.to_s, 1)
+      else
+        Puppet.warning "No Modulefile: #{filename}"
+      end
+      return builder
+    end
+
+    # Instantiate with the Metadata +metadata+ instance.
+    def initialize(metadata)
+      @metadata = metadata
+    end
+
+    # Set the +full_module_name+ (e.g. "myuser-mymodule"), which will also set the
+    # +username+ and module +name+. Required.
+    def name(name)
+      @metadata.update('name' => name)
+    end
+
+    # Set the module +version+ (e.g., "0.1.0"). Required.
+    def version(version)
+      @metadata.update('version' => version)
+    end
+
+    # Add a dependency with the full_module_name +name+ (e.g. "myuser-mymodule"), an
+    # optional +version_requirement+ (e.g. "0.1.0") and +repository+ (a URL
+    # string). Optional. Can be called multiple times to add many dependencies.
+    def dependency(name, version_requirement = nil, repository = nil)
+      @metadata.add_dependency(name, version_requirement, repository)
+    end
+
+    # Set the source
+    def source(source)
+      @metadata.update('source' => source)
+    end
+
+    # Set the author or default to +username+
+    def author(author)
+      @metadata.update('author' => author)
+    end
+
+    # Set the license
+    def license(license)
+      @metadata.update('license' => license)
+    end
+
+    # Set the summary
+    def summary(summary)
+      @metadata.update('summary' => summary)
+    end
+
+    # Set the description
+    def description(description)
+      @metadata.update('description' => description)
+    end
+
+    # Set the project page
+    def project_page(project_page)
+      @metadata.update('project_page' => project_page)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/shared_behaviors.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/shared_behaviors.rb
new file mode 100644
index 0000000..0475089
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/shared_behaviors.rb
@@ -0,0 +1,180 @@
+module Puppet::ModuleTool::Shared
+
+  include Puppet::ModuleTool::Errors
+
+  def get_local_constraints
+    @local      = Hash.new { |h,k| h[k] = { } }
+    @conditions = Hash.new { |h,k| h[k] = [] }
+    @installed  = Hash.new { |h,k| h[k] = [] }
+
+    @environment.modules_by_path.values.flatten.each do |mod|
+      mod_name = (mod.forge_name || mod.name).gsub('/', '-')
+      @installed[mod_name] << mod
+      d = @local["#{mod_name}@#{mod.version}"]
+      (mod.dependencies || []).each do |hash|
+        name, conditions = hash['name'], hash['version_requirement']
+        name = name.gsub('/', '-')
+        d[name] = conditions
+        @conditions[name] << {
+          :module => mod_name,
+          :version => mod.version,
+          :dependency => conditions
+        }
+      end
+    end
+  end
+
+  def get_remote_constraints(forge)
+    @remote   = Hash.new { |h,k| h[k] = { } }
+    @urls     = {}
+    @versions = Hash.new { |h,k| h[k] = [] }
+
+    Puppet.notice "Downloading from #{forge.uri} ..."
+    author, modname = Puppet::ModuleTool.username_and_modname_from(@module_name)
+    info = forge.remote_dependency_info(author, modname, @options[:version])
+    info.each do |pair|
+      mod_name, releases = pair
+      mod_name = mod_name.gsub('/', '-')
+      releases.each do |rel|
+        semver = SemVer.new(rel['version'] || '0.0.0') rescue SemVer::MIN
+        @versions[mod_name] << { :vstring => rel['version'], :semver => semver }
+        @versions[mod_name].sort! { |a, b| a[:semver] <=> b[:semver] }
+        @urls["#{mod_name}@#{rel['version']}"] = rel['file']
+        d = @remote["#{mod_name}@#{rel['version']}"]
+        (rel['dependencies'] || []).each do |name, conditions|
+          d[name.gsub('/', '-')] = conditions
+        end
+      end
+    end
+  end
+
+  def implicit_version(mod)
+    return :latest if @conditions[mod].empty?
+    if @conditions[mod].all? { |c| c[:queued] || c[:module] == :you }
+      return :latest
+    end
+    return :best
+  end
+
+  def annotated_version(mod, versions)
+    if versions.empty?
+      return implicit_version(mod)
+    else
+      return "#{implicit_version(mod)}: #{versions.last}"
+    end
+  end
+
+  def resolve_constraints(dependencies, source = [{:name => :you}], seen = {}, action = @action)
+    dependencies = dependencies.map do |mod, range|
+      source.last[:dependency] = range
+
+      @conditions[mod] << {
+        :module     => source.last[:name],
+        :version    => source.last[:version],
+        :dependency => range,
+        :queued     => true
+      }
+
+      if forced?
+        range = SemVer[@version] rescue SemVer['>= 0.0.0']
+      else
+        range = (@conditions[mod]).map do |r|
+          SemVer[r[:dependency]] rescue SemVer['>= 0.0.0']
+        end.inject(&:&)
+      end
+
+      if @action == :install && seen.include?(mod)
+        next if range === seen[mod][:semver]
+
+        req_module   = @module_name
+        req_versions = @versions["#{@module_name}"].map { |v| v[:semver] }
+        raise InvalidDependencyCycleError,
+          :module_name       => mod,
+          :source            => (source + [{ :name => mod, :version => source.last[:dependency] }]),
+          :requested_module  => req_module,
+          :requested_version => @version || annotated_version(req_module, req_versions),
+          :conditions        => @conditions
+      end
+
+      if !(forced? || @installed[mod].empty? || source.last[:name] == :you)
+        next if range === SemVer.new(@installed[mod].first.version)
+        action = :upgrade
+      elsif @installed[mod].empty?
+        action = :install
+      end
+
+      if action == :upgrade
+        @conditions.each { |_, conds| conds.delete_if { |c| c[:module] == mod } }
+      end
+
+      versions = @versions["#{mod}"].select { |h| range === h[:semver] }
+      valid_versions = versions.select { |x| x[:semver].special == '' }
+      valid_versions = versions if valid_versions.empty?
+
+      unless version = valid_versions.last
+        req_module   = @module_name
+        req_versions = @versions["#{@module_name}"].map { |v| v[:semver] }
+        raise NoVersionsSatisfyError,
+          :requested_name    => req_module,
+          :requested_version => @version || annotated_version(req_module, req_versions),
+          :installed_version => @installed[@module_name].empty? ? nil : @installed[@module_name].first.version,
+          :dependency_name   => mod,
+          :conditions        => @conditions[mod],
+          :action            => @action
+      end
+
+      seen[mod] = version
+
+      {
+        :module           => mod,
+        :version          => version,
+        :action           => action,
+        :previous_version => @installed[mod].empty? ? nil : @installed[mod].first.version,
+        :file             => @urls["#{mod}@#{version[:vstring]}"],
+        :path             => action == :install ? @options[:target_dir] : (@installed[mod].empty? ? @options[:target_dir] : @installed[mod].first.modulepath),
+        :dependencies     => []
+      }
+    end.compact
+    dependencies.each do |mod|
+      deps = @remote["#{mod[:module]}@#{mod[:version][:vstring]}"].sort_by(&:first)
+      mod[:dependencies] = resolve_constraints(deps, source + [{ :name => mod[:module], :version => mod[:version][:vstring] }], seen, :install)
+    end unless @ignore_dependencies
+    return dependencies
+  end
+
+  def download_tarballs(graph, default_path, forge)
+    graph.map do |release|
+      begin
+        if release[:tarball]
+          cache_path = Pathname(release[:tarball])
+        else
+          cache_path = forge.retrieve(release[:file])
+        end
+      rescue OpenURI::HTTPError => e
+        raise RuntimeError, "Could not download module: #{e.message}", e.backtrace
+      end
+
+      [
+        { (release[:path] ||= default_path) => cache_path},
+        *download_tarballs(release[:dependencies], default_path, forge)
+      ]
+    end.flatten
+  end
+
+  def forced?
+    options[:force]
+  end
+
+  def add_module_name_constraints_to_graph(graph)
+    # Puppet modules are installed by "module name", but resolved by
+    # "full name" (including namespace).  So that we don't run into
+    # problems at install time, we should reject any solution that
+    # depends on multiple nodes with the same "module name".
+    graph.add_graph_constraint('PMT') do |nodes|
+      names = nodes.map { |x| x.dependency_names + [ x.name ] }.flatten
+      names = names.map { |x| x.tr('/', '-') }.uniq
+      names = names.map { |x| x[/-(.*)/, 1] }
+      names.length == names.uniq.length
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/Gemfile b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/Gemfile
new file mode 100644
index 0000000..7bd34cd
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/Gemfile
@@ -0,0 +1,7 @@
+source 'https://rubygems.org'
+
+puppetversion = ENV.key?('PUPPET_VERSION') ? "= #{ENV['PUPPET_VERSION']}" : ['>= 3.3']
+gem 'puppet', puppetversion
+gem 'puppetlabs_spec_helper', '>= 0.1.0'
+gem 'puppet-lint', '>= 0.3.2'
+gem 'facter', '>= 1.7.0'
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/README.md.erb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/README.md.erb
new file mode 100644
index 0000000..40d2966
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/README.md.erb
@@ -0,0 +1,79 @@
+# <%= metadata.name %>
+
+#### Table of Contents
+
+1. [Overview](#overview)
+2. [Module Description - What the module does and why it is useful](#module-description)
+3. [Setup - The basics of getting started with <%= metadata.name %>](#setup)
+    * [What <%= metadata.name %> affects](#what-<%= metadata.name %>-affects)
+    * [Setup requirements](#setup-requirements)
+    * [Beginning with <%= metadata.name %>](#beginning-with-<%= metadata.name %>)
+4. [Usage - Configuration options and additional functionality](#usage)
+5. [Reference - An under-the-hood peek at what the module is doing and how](#reference)
+5. [Limitations - OS compatibility, etc.](#limitations)
+6. [Development - Guide for contributing to the module](#development)
+
+## Overview
+
+A one-maybe-two sentence summary of what the module does/what problem it solves.
+This is your 30 second elevator pitch for your module. Consider including
+OS/Puppet version it works with.
+
+## Module Description
+
+If applicable, this section should have a brief description of the technology
+the module integrates with and what that integration enables. This section
+should answer the questions: "What does this module *do*?" and "Why would I use
+it?"
+
+If your module has a range of functionality (installation, configuration,
+management, etc.) this is the time to mention it.
+
+## Setup
+
+### What <%= metadata.name %> affects
+
+* A list of files, packages, services, or operations that the module will alter,
+  impact, or execute on the system it's installed on.
+* This is a great place to stick any warnings.
+* Can be in list or paragraph form.
+
+### Setup Requirements **OPTIONAL**
+
+If your module requires anything extra before setting up (pluginsync enabled,
+etc.), mention it here.
+
+### Beginning with <%= metadata.name %>
+
+The very basic steps needed for a user to get the module up and running.
+
+If your most recent release breaks compatibility or requires particular steps
+for upgrading, you may wish to include an additional section here: Upgrading
+(For an example, see http://forge.puppetlabs.com/puppetlabs/firewall).
+
+## Usage
+
+Put the classes, types, and resources for customizing, configuring, and doing
+the fancy stuff with your module here.
+
+## Reference
+
+Here, list the classes, types, providers, facts, etc contained in your module.
+This section should include all of the under-the-hood workings of your module so
+people know what the module is touching on their system but don't need to mess
+with things. (We are working on automating this section!)
+
+## Limitations
+
+This is where you list OS compatibility, version compatibility, etc.
+
+## Development
+
+Since your module is awesome, other users will want to play with it. Let them
+know what the ground rules for contributing are.
+
+## Release Notes/Contributors/Etc **Optional**
+
+If you aren't using changelog, put your release notes here (though you should
+consider using changelog). You may also add any additional sections you feel are
+necessary or important to include here. Please use the `## ` header.
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/Rakefile b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/Rakefile
new file mode 100644
index 0000000..d1e11f7
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/Rakefile
@@ -0,0 +1,18 @@
+require 'rubygems'
+require 'puppetlabs_spec_helper/rake_tasks'
+require 'puppet-lint/tasks/puppet-lint'
+PuppetLint.configuration.send('disable_80chars')
+PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"]
+
+desc "Validate manifests, templates, and ruby files"
+task :validate do
+  Dir['manifests/**/*.pp'].each do |manifest|
+    sh "puppet parser validate --noop #{manifest}"
+  end
+  Dir['spec/**/*.rb','lib/**/*.rb'].each do |ruby_file|
+    sh "ruby -c #{ruby_file}" unless ruby_file =~ /spec\/fixtures/
+  end
+  Dir['templates/**/*.erb'].each do |template|
+    sh "erb -P -x -T '-' #{template} | ruby -c"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/manifests/init.pp.erb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/manifests/init.pp.erb
new file mode 100644
index 0000000..d7c5f4a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/manifests/init.pp.erb
@@ -0,0 +1,41 @@
+# == Class: <%= metadata.name %>
+#
+# Full description of class <%= metadata.name %> here.
+#
+# === Parameters
+#
+# Document parameters here.
+#
+# [*sample_parameter*]
+#   Explanation of what this parameter affects and what it defaults to.
+#   e.g. "Specify one or more upstream ntp servers as an array."
+#
+# === Variables
+#
+# Here you should define a list of variables that this module would require.
+#
+# [*sample_variable*]
+#   Explanation of how this variable affects the funtion of this class and if
+#   it has a default. e.g. "The parameter enc_ntp_servers must be set by the
+#   External Node Classifier as a comma separated list of hostnames." (Note,
+#   global variables should be avoided in favor of class parameters as
+#   of Puppet 2.6.)
+#
+# === Examples
+#
+#  class { '<%= metadata.name %>':
+#    servers => [ 'pool.ntp.org', 'ntp.local.company.com' ],
+#  }
+#
+# === Authors
+#
+# Author Name <author@domain.com>
+#
+# === Copyright
+#
+# Copyright <%= Time.now.year %> Your name here, unless otherwise noted.
+#
+class <%= metadata.name %> {
+
+
+}
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/metadata.json.erb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/metadata.json.erb
new file mode 100644
index 0000000..95e35ae
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/metadata.json.erb
@@ -0,0 +1 @@
+<%= metadata.to_json %>
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/spec/classes/init_spec.rb.erb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/spec/classes/init_spec.rb.erb
new file mode 100644
index 0000000..5e0f4b9
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/spec/classes/init_spec.rb.erb
@@ -0,0 +1,7 @@
+require 'spec_helper'
+describe '<%= metadata.name %>' do
+
+  context 'with defaults for all parameters' do
+    it { should contain_class('<%= metadata.name %>') }
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/spec/spec_helper.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/spec/spec_helper.rb
new file mode 100644
index 0000000..2c6f566
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/spec/spec_helper.rb
@@ -0,0 +1 @@
+require 'puppetlabs_spec_helper/module_spec_helper'
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/tests/init.pp.erb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/tests/init.pp.erb
new file mode 100644
index 0000000..740a095
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/skeleton/templates/generator/tests/init.pp.erb
@@ -0,0 +1,12 @@
+# The baseline for module testing used by Puppet Labs is that each manifest
+# should have a corresponding test manifest that declares that class or defined
+# type.
+#
+# Tests are then run by using puppet apply --noop (to check for compilation
+# errors and view a log of events) or by fully applying the test in a virtual
+# environment (to compare the resulting system state to the desired state).
+#
+# Learn more about module testing here:
+# http://docs.puppetlabs.com/guides/tests_smoke.html
+#
+include <%= metadata.name %>
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/tar.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/tar.rb
new file mode 100644
index 0000000..baef5ef
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/tar.rb
@@ -0,0 +1,17 @@
+require 'puppet/module_tool'
+require 'puppet/util'
+
+module Puppet::ModuleTool::Tar
+  require 'puppet/module_tool/tar/gnu'
+  require 'puppet/module_tool/tar/mini'
+
+  def self.instance
+    if Puppet::Util.which('tar') && ! Puppet::Util::Platform.windows?
+      Gnu.new
+    elsif Puppet.features.minitar? && Puppet.features.zlib?
+      Mini.new
+    else
+      raise RuntimeError, 'No suitable tar implementation found'
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/tar/gnu.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/tar/gnu.rb
new file mode 100644
index 0000000..f0fd2af
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/tar/gnu.rb
@@ -0,0 +1,19 @@
+require 'shellwords'
+
+class Puppet::ModuleTool::Tar::Gnu
+  def unpack(sourcefile, destdir, owner)
+    sourcefile = File.expand_path(sourcefile)
+    destdir = File.expand_path(destdir)
+
+    Dir.chdir(destdir) do
+      Puppet::Util::Execution.execute("gzip -dc #{Shellwords.shellescape(sourcefile)} | tar xof -")
+      Puppet::Util::Execution.execute("find . -type d -exec chmod 755 {} +")
+      Puppet::Util::Execution.execute("find . -type f -exec chmod a-wst {} +")
+      Puppet::Util::Execution.execute("chown -R #{owner} .")
+    end
+  end
+
+  def pack(sourcedir, destfile)
+    Puppet::Util::Execution.execute("tar cf - #{sourcedir} | gzip -c > #{File.basename(destfile)}")
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/tar/mini.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/tar/mini.rb
new file mode 100644
index 0000000..4f15182
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/module_tool/tar/mini.rb
@@ -0,0 +1,53 @@
+class Puppet::ModuleTool::Tar::Mini
+  def unpack(sourcefile, destdir, _)
+    Zlib::GzipReader.open(sourcefile) do |reader|
+      Archive::Tar::Minitar.unpack(reader, destdir, find_valid_files(reader)) do |action, name, stats|
+        case action
+        when :file_done
+          File.chmod(0444, "#{destdir}/#{name}")
+        when :dir, :file_start
+          validate_entry(destdir, name)
+          Puppet.debug("Extracting: #{destdir}/#{name}")
+        end
+      end
+    end
+  end
+
+  def pack(sourcedir, destfile)
+    Zlib::GzipWriter.open(destfile) do |writer|
+      Archive::Tar::Minitar.pack(sourcedir, writer)
+    end
+  end
+
+  private
+
+  # Find all the valid files in tarfile.
+  #
+  # This check was mainly added to ignore 'x' and 'g' flags from the PAX
+  # standard but will also ignore any other non-standard tar flags.
+  # tar format info: http://pic.dhe.ibm.com/infocenter/zos/v1r13/index.jsp?topic=%2Fcom.ibm.zos.r13.bpxa500%2Ftaf.htm
+  # pax format info: http://pic.dhe.ibm.com/infocenter/zos/v1r13/index.jsp?topic=%2Fcom.ibm.zos.r13.bpxa500%2Fpxarchfm.htm
+  def find_valid_files(tarfile)
+    Archive::Tar::Minitar.open(tarfile).collect do |entry|
+      flag = entry.typeflag
+      if flag.nil? || flag =~ /[[:digit:]]/ && (0..7).include?(flag.to_i)
+        entry.name
+      else
+        Puppet.debug "Invalid tar flag '#{flag}' will not be extracted: #{entry.name}"
+        next
+      end
+    end
+  end
+
+  def validate_entry(destdir, path)
+    if Pathname.new(path).absolute?
+      raise Puppet::ModuleTool::Errors::InvalidPathInPackageError, :entry_path => path, :directory => destdir
+    end
+
+    path = File.expand_path File.join(destdir, path)
+
+    if path !~ /\A#{Regexp.escape destdir}/
+      raise Puppet::ModuleTool::Errors::InvalidPathInPackageError, :entry_path => path, :directory => destdir
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network.rb
new file mode 100644
index 0000000..8993b88
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network.rb
@@ -0,0 +1,3 @@
+# Just a stub, so we can correctly scope other classes.
+module Puppet::Network # :nodoc:
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/auth_config_parser.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/auth_config_parser.rb
new file mode 100644
index 0000000..cb7199e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/auth_config_parser.rb
@@ -0,0 +1,84 @@
+require 'puppet/network/rights'
+
+module Puppet::Network
+class AuthConfigParser
+
+  def self.new_from_file(file)
+    self.new(File.read(file))
+  end
+
+  def initialize(string)
+    @string = string
+  end
+
+  def parse
+    Puppet::Network::AuthConfig.new(parse_rights)
+  end
+
+  def parse_rights
+    rights = Puppet::Network::Rights.new
+    right = nil
+    count = 1
+    @string.each_line { |line|
+      case line.chomp
+      when /^\s*#/, /^\s*$/
+        # skip comments and blank lines
+      when /^path\s+((?:~\s+)?[^ ]+)\s*$/ # "path /path" or "path ~ regex"
+        name = $1.chomp
+        right = rights.newright(name, count, @file)
+      when /^\s*(allow(?:_ip)?|deny(?:_ip)?|method|environment|auth(?:enticated)?)\s+(.+?)(\s*#.*)?$/
+        if right.nil?
+          raise Puppet::ConfigurationError, "Missing or invalid 'path' before right directive at line #{count} of #{@file}"
+        end
+        parse_right_directive(right, $1, $2, count)
+      else
+        raise Puppet::ConfigurationError, "Invalid line #{count}: #{line}"
+      end
+      count += 1
+    }
+
+    # Verify each of the rights are valid.
+    # We let the check raise an error, so that it can raise an error
+    # pointing to the specific problem.
+    rights.each { |name, right|
+      right.valid?
+    }
+    rights
+  end
+
+  def parse_right_directive(right, var, value, count)
+    value.strip!
+    case var
+    when "allow"
+      modify_right(right, :allow, value, "allowing %s access", count)
+    when "deny"
+      modify_right(right, :deny, value, "denying %s access", count)
+    when "allow_ip"
+      modify_right(right, :allow_ip, value, "allowing IP %s access", count)
+    when "deny_ip"
+      modify_right(right, :deny_ip, value, "denying IP %s access", count)
+    when "method"
+      modify_right(right, :restrict_method, value, "allowing 'method' %s", count)
+    when "environment"
+      modify_right(right, :restrict_environment, value, "adding environment %s", count)
+    when /auth(?:enticated)?/
+      modify_right(right, :restrict_authenticated, value, "adding authentication %s", count)
+    else
+      raise Puppet::ConfigurationError,
+        "Invalid argument '#{var}' at line #{count}"
+    end
+  end
+
+  def modify_right(right, method, value, msg, count)
+    value.split(/\s*,\s*/).each do |val|
+      begin
+        val.strip!
+        right.info msg % val
+        right.send(method, val)
+      rescue Puppet::AuthStoreError => detail
+        raise Puppet::ConfigurationError, "#{detail} at line #{count} of #{@file}", detail.backtrace
+      end
+    end
+  end
+end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/authconfig.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/authconfig.rb
new file mode 100644
index 0000000..f99c129
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/authconfig.rb
@@ -0,0 +1,76 @@
+require 'puppet/network/rights'
+
+module Puppet
+  class ConfigurationError < Puppet::Error; end
+  class Network::AuthConfig
+    attr_accessor :rights
+
+    DEFAULT_ACL = [
+      { :acl => "~ ^\/catalog\/([^\/]+)$", :method => :find, :allow => '$1', :authenticated => true },
+      { :acl => "~ ^\/node\/([^\/]+)$", :method => :find, :allow => '$1', :authenticated => true },
+      # this one will allow all file access, and thus delegate
+      # to fileserver.conf
+      { :acl => "/file" },
+      { :acl => "/certificate_revocation_list/ca", :method => :find, :authenticated => true },
+      { :acl => "~ ^\/report\/([^\/]+)$", :method => :save, :allow => '$1', :authenticated => true },
+      # These allow `auth any`, because if you can do them anonymously you
+      # should probably also be able to do them when trusted.
+      { :acl => "/certificate/ca", :method => :find, :authenticated => :any },
+      { :acl => "/certificate/", :method => :find, :authenticated => :any },
+      { :acl => "/certificate_request", :method => [:find, :save], :authenticated => :any },
+      { :acl => "/status", :method => [:find], :authenticated => true },
+
+      # API V2.0
+      { :acl => "/v2.0/environments", :method => :find, :allow => '*', :authenticated => true },
+    ]
+
+    # Just proxy the setting methods to our rights stuff
+    [:allow, :deny].each do |method|
+      define_method(method) do |*args|
+        @rights.send(method, *args)
+      end
+    end
+
+    # force regular ACLs to be present
+    def insert_default_acl
+      DEFAULT_ACL.each do |acl|
+        unless rights[acl[:acl]]
+          Puppet.info "Inserting default '#{acl[:acl]}' (auth #{acl[:authenticated]}) ACL"
+          mk_acl(acl)
+        end
+      end
+      # queue an empty (ie deny all) right for every other path
+      # actually this is not strictly necessary as the rights system
+      # denies not explicitely allowed paths
+      unless rights["/"]
+        rights.newright("/").restrict_authenticated(:any)
+      end
+    end
+
+    def mk_acl(acl)
+      right = @rights.newright(acl[:acl])
+      right.allow(acl[:allow] || "*")
+
+      if method = acl[:method]
+        method = [method] unless method.is_a?(Array)
+        method.each { |m| right.restrict_method(m) }
+      end
+      right.restrict_authenticated(acl[:authenticated]) unless acl[:authenticated].nil?
+    end
+
+    # check whether this request is allowed in our ACL
+    # raise an Puppet::Network::AuthorizedError if the request
+    # is denied.
+    def check_authorization(method, path, params)
+      if authorization_failure_exception = @rights.is_request_forbidden_and_why?(method, path, params)
+        Puppet.warning("Denying access: #{authorization_failure_exception}")
+        raise authorization_failure_exception
+      end
+    end
+
+    def initialize(rights=nil)
+      @rights = rights || Puppet::Network::Rights.new
+      insert_default_acl
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/authentication.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/authentication.rb
new file mode 100644
index 0000000..c7f9ace
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/authentication.rb
@@ -0,0 +1,35 @@
+require 'puppet/ssl/certificate_authority'
+require 'puppet/util/log/rate_limited_logger'
+
+# Place for any authentication related bits
+module Puppet::Network::Authentication
+  # Create a rate-limited logger for the expiration warning that uses the run interval
+  # as the minimum amount of time before a warning about the same cert can be logged again.
+  # This is a class variable so that all classes that include the module share the same logger.
+  @@logger = Puppet::Util::Log::RateLimitedLogger.new(Puppet[:runinterval])
+
+  # Check the expiration of known certificates and optionally any that are specified as part of a request
+  def warn_if_near_expiration(*certs)
+    # Check CA cert if we're functioning as a CA
+    certs << Puppet::SSL::CertificateAuthority.instance.host.certificate if Puppet::SSL::CertificateAuthority.ca?
+
+    # Depending on the run mode, the localhost certificate will be for the
+    # master or the agent. Don't load the certificate if the CA cert is not
+    # present: infinite recursion will occur as another authenticated request
+    # will be spawned to download the CA cert.
+    if [Puppet[:hostcert], Puppet[:localcacert]].all? {|path| Puppet::FileSystem.exist?(path) }
+      certs << Puppet::SSL::Host.localhost.certificate
+    end
+
+    # Remove nil values for caller convenience
+    certs.compact.each do |cert|
+      # Allow raw OpenSSL certificate instances or Puppet certificate wrappers to be specified
+      cert = Puppet::SSL::Certificate.from_instance(cert) if cert.is_a?(OpenSSL::X509::Certificate)
+      raise ArgumentError, "Invalid certificate '#{cert.inspect}'" unless cert.is_a?(Puppet::SSL::Certificate)
+
+      if cert.near_expiration?
+        @@logger.warning("Certificate '#{cert.unmunged_name}' will expire on #{cert.expiration.strftime('%Y-%m-%dT%H:%M:%S%Z')}")
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/authorization.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/authorization.rb
new file mode 100644
index 0000000..82e4bc3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/authorization.rb
@@ -0,0 +1,34 @@
+require 'puppet/network/client_request'
+require 'puppet/network/authconfig'
+require 'puppet/network/auth_config_parser'
+
+module Puppet::Network
+  class AuthConfigLoader
+    # Create our config object if necessary. If there's no configuration file
+    # we install our defaults
+    def self.authconfig
+      @auth_config_file ||= Puppet::Util::WatchedFile.new(Puppet[:rest_authconfig])
+      if (not @auth_config) or @auth_config_file.changed?
+        begin
+          @auth_config = Puppet::Network::AuthConfigParser.new_from_file(Puppet[:rest_authconfig]).parse
+        rescue Errno::ENOENT, Errno::ENOTDIR
+          @auth_config = Puppet::Network::AuthConfig.new
+        end
+      end
+
+      @auth_config
+    end
+  end
+
+  module Authorization
+    def authconfig
+      AuthConfigLoader.authconfig
+    end
+
+    # Verify that our client has access.
+    def check_authorization(method, path, params)
+      authconfig.check_authorization(method, path, params)
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/authstore.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/authstore.rb
new file mode 100644
index 0000000..ba86ed9
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/authstore.rb
@@ -0,0 +1,282 @@
+# standard module for determining whether a given hostname or IP has access to
+# the requested resource
+
+require 'ipaddr'
+require 'puppet/util/logging'
+
+module Puppet
+  class AuthStoreError < Puppet::Error; end
+  class AuthorizationError < Puppet::Error; end
+
+  class Network::AuthStore
+    include Puppet::Util::Logging
+
+    # Is a given combination of name and ip address allowed?  If either input
+    # is non-nil, then both inputs must be provided.  If neither input
+    # is provided, then the authstore is considered local and defaults to "true".
+    def allowed?(name, ip)
+      if name or ip
+        # This is probably unnecessary, and can cause some weirdnesses in
+        # cases where we're operating over localhost but don't have a real
+        # IP defined.
+        raise Puppet::DevError, "Name and IP must be passed to 'allowed?'" unless name and ip
+        # else, we're networked and such
+      else
+        # we're local
+        return true
+      end
+
+      # yay insecure overrides
+      return true if globalallow?
+
+      if decl = declarations.find { |d| d.match?(name, ip) }
+        return decl.result
+      end
+
+      info "defaulting to no access for #{name}"
+      false
+    end
+
+    # Mark a given pattern as allowed.
+    def allow(pattern)
+      # a simple way to allow anyone at all to connect
+      if pattern == "*"
+        @globalallow = true
+      else
+        store(:allow, pattern)
+      end
+
+      nil
+    end
+
+    def allow_ip(pattern)
+      store(:allow_ip, pattern)
+    end
+
+    # Deny a given pattern.
+    def deny(pattern)
+      store(:deny, pattern)
+    end
+
+    def deny_ip(pattern)
+      store(:deny_ip, pattern)
+    end
+
+    # Is global allow enabled?
+    def globalallow?
+      @globalallow
+    end
+
+    # does this auth store has any rules?
+    def empty?
+      @globalallow.nil? && @declarations.size == 0
+    end
+
+    def initialize
+      @globalallow = nil
+      @declarations = []
+    end
+
+    def to_s
+      "authstore"
+    end
+
+    def interpolate(match)
+      @modified_declarations = @declarations.collect { |ace| ace.interpolate(match) }.sort
+    end
+
+    def reset_interpolation
+      @modified_declarations = nil
+    end
+
+    private
+
+    # Returns our ACEs list, but if we have a modification of it, let's return
+    # it. This is used if we want to override the this purely immutable list
+    # by a modified version.
+    def declarations
+      @modified_declarations || @declarations
+    end
+
+    # Store the results of a pattern into our hash.  Basically just
+    # converts the pattern and sticks it into the hash.
+    def store(type, pattern)
+      @declarations << Declaration.new(type, pattern)
+      @declarations.sort!
+
+      nil
+    end
+
+    # A single declaration.  Stores the info for a given declaration,
+    # provides the methods for determining whether a declaration matches,
+    # and handles sorting the declarations appropriately.
+    class Declaration
+      include Puppet::Util
+      include Comparable
+
+      # The type of declaration: either :allow or :deny
+      attr_reader :type
+      VALID_TYPES = [ :allow, :deny, :allow_ip, :deny_ip ]
+
+      attr_accessor :name
+
+      # The pattern we're matching against.  Can be an IPAddr instance,
+      # or an array of strings, resulting from reversing a hostname
+      # or domain name.
+      attr_reader :pattern
+
+      # The length.  Only used for iprange and domain.
+      attr_accessor :length
+
+      # Sort the declarations most specific first.
+      def <=>(other)
+        compare(exact?, other.exact?) ||
+        compare(ip?, other.ip?)  ||
+        ((length != other.length) &&  (other.length <=> length)) ||
+        compare(deny?, other.deny?) ||
+        ( ip? ? pattern.to_s <=> other.pattern.to_s : pattern <=> other.pattern)
+      end
+
+      def deny?
+        type == :deny
+      end
+
+      def exact?
+        @exact == :exact
+      end
+
+      def initialize(type, pattern)
+        self.type = type
+        self.pattern = pattern
+      end
+
+      # Are we an IP type?
+      def ip?
+        name == :ip
+      end
+
+      # Does this declaration match the name/ip combo?
+      def match?(name, ip)
+        if ip?
+          pattern.include?(IPAddr.new(ip))
+        else
+          matchname?(name)
+        end
+      end
+
+      # Set the pattern appropriately.  Also sets the name and length.
+      def pattern=(pattern)
+        if [:allow_ip, :deny_ip].include?(self.type)
+          parse_ip(pattern)
+        else
+          parse(pattern)
+        end
+        @orig = pattern
+      end
+
+      # Mapping a type of statement into a return value.
+      def result
+        [:allow, :allow_ip].include?(type)
+      end
+
+      def to_s
+        "#{type}: #{pattern}"
+      end
+
+      # Set the declaration type.  Either :allow or :deny.
+      def type=(type)
+        type = type.intern
+        raise ArgumentError, "Invalid declaration type #{type}" unless VALID_TYPES.include?(type)
+        @type = type
+      end
+
+      # interpolate a pattern to replace any
+      # backreferences by the given match
+      # for instance if our pattern is $1.reductivelabs.com
+      # and we're called with a MatchData whose capture 1 is puppet
+      # we'll return a pattern of puppet.reductivelabs.com
+      def interpolate(match)
+        clone = dup
+        if @name == :dynamic
+          clone.pattern = clone.pattern.reverse.collect do |p|
+            p.gsub(/\$(\d)/) { |m| match[$1.to_i] }
+          end.join(".")
+        end
+        clone
+      end
+
+      private
+
+      # Returns nil if both values are true or both are false, returns
+      # -1 if the first is true, and 1 if the second is true.  Used
+      # in the <=> operator.
+      def compare(me, them)
+        (me and them) ? nil : me ? -1 : them ? 1 : nil
+      end
+
+      # Does the name match our pattern?
+      def matchname?(name)
+        case @name
+          when :domain, :dynamic, :opaque
+            name = munge_name(name)
+            (pattern == name) or (not exact? and pattern.zip(name).all? { |p,n| p == n })
+          when :regex
+            Regexp.new(pattern.slice(1..-2)).match(name)
+        end
+      end
+
+      # Convert the name to a common pattern.
+      def munge_name(name)
+        # Change to name.downcase.split(".",-1).reverse for FQDN support
+        name.downcase.split(".").reverse
+      end
+
+      # Parse our input pattern and figure out what kind of allowable
+      # statement it is.  The output of this is used for later matching.
+      Octet = '(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])'
+      IPv4 = "#{Octet}\.#{Octet}\.#{Octet}\.#{Octet}"
+      IPv6_full    = "_:_:_:_:_:_:_:_|_:_:_:_:_:_::_?|_:_:_:_:_::((_:)?_)?|_:_:_:_::((_:){0,2}_)?|_:_:_::((_:){0,3}_)?|_:_::((_:){0,4}_)?|_::((_:){0,5}_)?|::((_:){0,6}_)?"
+      IPv6_partial = "_:_:_:_:_:_:|_:_:_:_::(_:)?|_:_::(_:){0,2}|_::(_:){0,3}"
+      # It should be:
+      #     IP = "#{IPv4}|#{IPv6_full}|(#{IPv6_partial}#{IPv4})".gsub(/_/,'([0-9a-fA-F]{1,4})').gsub(/\(/,'(?:')
+      # but ruby's ipaddr lib doesn't support the hybrid format
+      IP = "#{IPv4}|#{IPv6_full}".gsub(/_/,'([0-9a-fA-F]{1,4})').gsub(/\(/,'(?:')
+
+      def parse_ip(value)
+        @name = :ip
+        @exact, @length, @pattern = *case value
+        when /^(?:#{IP})\/(\d+)$/                                 # 12.34.56.78/24, a001:b002::efff/120, c444:1000:2000::9:192.168.0.1/112
+          [:inexact, $1.to_i, IPAddr.new(value)]
+        when /^(#{IP})$/                                          # 10.20.30.40,
+          [:exact, nil, IPAddr.new(value)]
+        when /^(#{Octet}\.){1,3}\*$/                              # an ip address with a '*' at the end
+          segments = value.split(".")[0..-2]
+          bits = 8*segments.length
+          [:inexact, bits, IPAddr.new((segments+[0,0,0])[0,4].join(".") + "/#{bits}")]
+        else
+          raise AuthStoreError, "Invalid IP pattern #{value}"
+        end
+      end
+
+      def parse(value)
+        @name,@exact,@length,@pattern = *case value
+        when /^(\w[-\w]*\.)+[-\w]+$/                              # a full hostname
+          # Change to /^(\w[-\w]*\.)+[-\w]+\.?$/ for FQDN support
+          [:domain,:exact,nil,munge_name(value)]
+        when /^\*(\.(\w[-\w]*)){1,}$/                             # *.domain.com
+          host_sans_star = munge_name(value)[0..-2]
+          [:domain,:inexact,host_sans_star.length,host_sans_star]
+        when /\$\d+/                                              # a backreference pattern ala $1.reductivelabs.com or 192.168.0.$1 or $1.$2
+          [:dynamic,:exact,nil,munge_name(value)]
+        when /^\w[-.@\w]*$/                                       # ? Just like a host name but allow '@'s and ending '.'s
+          [:opaque,:exact,nil,[value]]
+        when /^\/.*\/$/                                           # a regular expression
+          [:regex,:inexact,nil,value]
+        else
+          raise AuthStoreError, "Invalid pattern #{value}"
+        end
+      end
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/client_request.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/client_request.rb
new file mode 100644
index 0000000..e3df471
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/client_request.rb
@@ -0,0 +1,29 @@
+module Puppet::Network # :nodoc:
+  # A struct-like class for passing around a client request.  It's mostly
+  # just used for validation and authorization.
+  class ClientRequest
+    attr_accessor :name, :ip, :authenticated, :handler, :method
+
+    def authenticated?
+      self.authenticated
+    end
+
+    # A common way of talking about the full call.  Individual servers
+    # are responsible for setting the values correctly, but this common
+    # format makes it possible to check rights.
+    def call
+      raise ArgumentError, "Request is not set up; cannot build call" unless handler and method
+
+      [handler, method].join(".")
+    end
+
+    def initialize(name, ip, authenticated)
+      @name, @ip, @authenticated = name, ip, authenticated
+    end
+
+    def to_s
+      "#{self.name}(#{self.ip})"
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/format.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/format.rb
new file mode 100644
index 0000000..e50dfd3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/format.rb
@@ -0,0 +1,110 @@
+require 'puppet/confiner'
+
+# A simple class for modeling encoding formats for moving
+# instances around the network.
+class Puppet::Network::Format
+  include Puppet::Confiner
+
+  attr_reader :name, :mime
+  attr_accessor :intern_method, :render_method, :intern_multiple_method, :render_multiple_method, :weight, :required_methods, :extension
+
+  def init_attribute(name, default)
+    if value = @options[name]
+      @options.delete(name)
+    else
+      value = default
+    end
+    self.send(name.to_s + "=", value)
+  end
+
+  def initialize(name, options = {}, &block)
+    @name = name.to_s.downcase.intern
+
+    @options = options
+
+    # This must be done early the values can be used to set required_methods
+    define_method_names
+
+    method_list = {
+      :intern_method => "from_#{name}",
+      :intern_multiple_method => "from_multiple_#{name}",
+      :render_multiple_method => "to_multiple_#{name}",
+      :render_method => "to_#{name}"
+    }
+
+    init_attribute(:mime, "text/#{name}")
+    init_attribute(:weight, 5)
+    init_attribute(:required_methods, method_list.keys)
+    init_attribute(:extension, name.to_s)
+
+    method_list.each do |method, value|
+      init_attribute(method, value)
+    end
+
+    raise ArgumentError, "Unsupported option(s) #{@options.keys}" unless @options.empty?
+
+    @options = nil
+
+    instance_eval(&block) if block_given?
+  end
+
+  def intern(klass, text)
+    return klass.send(intern_method, text) if klass.respond_to?(intern_method)
+    raise NotImplementedError, "#{klass} does not respond to #{intern_method}; can not intern instances from #{mime}"
+  end
+
+  def intern_multiple(klass, text)
+    return klass.send(intern_multiple_method, text) if klass.respond_to?(intern_multiple_method)
+    raise NotImplementedError, "#{klass} does not respond to #{intern_multiple_method}; can not intern multiple instances from #{mime}"
+  end
+
+  def mime=(mime)
+    @mime = mime.to_s.downcase
+  end
+
+  def render(instance)
+    return instance.send(render_method) if instance.respond_to?(render_method)
+    raise NotImplementedError, "#{instance.class} does not respond to #{render_method}; can not render instances to #{mime}"
+  end
+
+  def render_multiple(instances)
+    # This method implicitly assumes that all instances are of the same type.
+    return instances[0].class.send(render_multiple_method, instances) if instances[0].class.respond_to?(render_multiple_method)
+    raise NotImplementedError, "#{instances[0].class} does not respond to #{render_multiple_method}; can not intern multiple instances to #{mime}"
+  end
+
+  def required_methods_present?(klass)
+    [:intern_method, :intern_multiple_method, :render_multiple_method].each do |name|
+      return false unless required_method_present?(name, klass, :class)
+    end
+
+    return false unless required_method_present?(:render_method, klass, :instance)
+
+    true
+  end
+
+  def supported?(klass)
+    suitable? and required_methods_present?(klass)
+  end
+
+  def to_s
+    "Puppet::Network::Format[#{name}]"
+  end
+
+  private
+
+  def define_method_names
+    @intern_method = "from_#{name}"
+    @render_method = "to_#{name}"
+    @intern_multiple_method = "from_multiple_#{name}"
+    @render_multiple_method = "to_multiple_#{name}"
+  end
+
+  def required_method_present?(name, klass, type)
+    return true unless required_methods.include?(name)
+
+    method = send(name)
+
+    return(type == :class ? klass.respond_to?(method) : klass.method_defined?(method))
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/format_handler.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/format_handler.rb
new file mode 100644
index 0000000..d341b43
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/format_handler.rb
@@ -0,0 +1,105 @@
+require 'yaml'
+require 'puppet/network'
+require 'puppet/network/format'
+
+module Puppet::Network::FormatHandler
+  class FormatError < Puppet::Error; end
+
+  ALL_MEDIA_TYPES = '*/*'.freeze
+
+  @formats = {}
+
+  def self.create(*args, &block)
+    instance = Puppet::Network::Format.new(*args, &block)
+
+    @formats[instance.name] = instance
+    instance
+  end
+
+  def self.create_serialized_formats(name,options = {},&block)
+    ["application/x-#{name}", "application/#{name}", "text/x-#{name}", "text/#{name}"].each { |mime_type|
+      create name, {:mime => mime_type}.update(options), &block
+    }
+  end
+
+  def self.format(name)
+    @formats[name.to_s.downcase.intern]
+  end
+
+  def self.format_for(name)
+    name = format_to_canonical_name(name)
+    format(name)
+  end
+
+  def self.format_by_extension(ext)
+    @formats.each do |name, format|
+      return format if format.extension == ext
+    end
+    nil
+  end
+
+  # Provide a list of all formats.
+  def self.formats
+    @formats.keys
+  end
+
+  # Return a format capable of handling the provided mime type.
+  def self.mime(mimetype)
+    mimetype = mimetype.to_s.downcase
+    @formats.values.find { |format| format.mime == mimetype }
+  end
+
+  # Return a format name given:
+  #  * a format name
+  #  * a mime-type
+  #  * a format instance
+  def self.format_to_canonical_name(format)
+    case format
+    when Puppet::Network::Format
+      out = format
+    when %r{\w+/\w+}
+      out = mime(format)
+    else
+      out = format(format)
+    end
+    raise ArgumentError, "No format match the given format name or mime-type (#{format})" if out.nil?
+    out.name
+  end
+
+  # Determine which of the accepted formats should be used given what is supported.
+  #
+  # @param accepted [Array<String, Symbol>] the accepted formats in a form a
+  #   that generally conforms to an HTTP Accept header. Any quality specifiers
+  #   are ignored and instead the formats are simply in strict preference order
+  #   (most preferred is first)
+  # @param supported [Array<Symbol>] the names of the supported formats (the
+  #   most preferred format is first)
+  # @return [Puppet::Network::Format, nil] the most suitable format
+  # @api private
+  def self.most_suitable_format_for(accepted, supported)
+    format_name = accepted.collect do |accepted|
+      accepted.to_s.sub(/;q=.*$/, '')
+    end.collect do |accepted|
+      if accepted == ALL_MEDIA_TYPES
+        supported.first
+      else
+        format_to_canonical_name_or_nil(accepted)
+      end
+    end.find do |accepted|
+      supported.include?(accepted)
+    end
+
+    if format_name
+      format_for(format_name)
+    end
+  end
+
+  # @api private
+  def self.format_to_canonical_name_or_nil(format)
+    format_to_canonical_name(format)
+  rescue ArgumentError
+    nil
+  end
+end
+
+require 'puppet/network/formats'
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/format_support.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/format_support.rb
new file mode 100644
index 0000000..6a42fd4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/format_support.rb
@@ -0,0 +1,124 @@
+require 'puppet/network/format_handler'
+
+# Provides network serialization support when included
+# @api public
+module Puppet::Network::FormatSupport
+  def self.included(klass)
+    klass.extend(ClassMethods)
+  end
+
+  module ClassMethods
+    def convert_from(format, data)
+      get_format(format).intern(self, data)
+    rescue => err
+      raise Puppet::Network::FormatHandler::FormatError, "Could not intern from #{format}: #{err}", err.backtrace
+    end
+
+    def convert_from_multiple(format, data)
+      get_format(format).intern_multiple(self, data)
+    rescue => err
+      raise Puppet::Network::FormatHandler::FormatError, "Could not intern_multiple from #{format}: #{err}", err.backtrace
+    end
+
+    def render_multiple(format, instances)
+      get_format(format).render_multiple(instances)
+    rescue => err
+      raise Puppet::Network::FormatHandler::FormatError, "Could not render_multiple to #{format}: #{err}", err.backtrace
+    end
+
+    def default_format
+      supported_formats[0]
+    end
+
+    def support_format?(name)
+      Puppet::Network::FormatHandler.format(name).supported?(self)
+    end
+
+    def supported_formats
+      result = format_handler.formats.collect do |f|
+        format_handler.format(f)
+      end.find_all do |f|
+        f.supported?(self)
+      end.sort do |a, b|
+        # It's an inverse sort -- higher weight formats go first.
+        b.weight <=> a.weight
+      end.collect do |f|
+        f.name
+      end
+
+      result = put_preferred_format_first(result)
+
+      Puppet.debug "#{friendly_name} supports formats: #{result.join(' ')}"
+
+      result
+    end
+
+    # @api private
+    def get_format(format_name)
+      format_handler.format_for(format_name)
+    end
+
+    private
+
+    def format_handler
+      Puppet::Network::FormatHandler
+    end
+
+    def friendly_name
+      if self.respond_to? :indirection
+        indirection.name
+      else
+        self
+      end
+    end
+
+    def put_preferred_format_first(list)
+      preferred_format = Puppet.settings[:preferred_serialization_format].to_sym
+      if list.include?(preferred_format)
+        list.delete(preferred_format)
+        list.unshift(preferred_format)
+      else
+        Puppet.debug "Value of 'preferred_serialization_format' (#{preferred_format}) is invalid for #{friendly_name}, using default (#{list.first})"
+      end
+      list
+    end
+  end
+
+  def to_msgpack(*args)
+    to_data_hash.to_msgpack(*args)
+  end
+
+  def to_pson(*args)
+    to_data_hash.to_pson(*args)
+  end
+
+  def render(format = nil)
+    format ||= self.class.default_format
+
+    self.class.get_format(format).render(self)
+  rescue => err
+    raise Puppet::Network::FormatHandler::FormatError, "Could not render to #{format}: #{err}", err.backtrace
+  end
+
+  def mime(format = nil)
+    format ||= self.class.default_format
+
+    self.class.get_format(format).mime
+  rescue => err
+    raise Puppet::Network::FormatHandler::FormatError, "Could not mime to #{format}: #{err}", err.backtrace
+  end
+
+  def support_format?(name)
+    self.class.support_format?(name)
+  end
+
+  # @comment Document to_data_hash here as it is called as a hook from to_msgpack if it exists
+  # @!method to_data_hash(*args)
+  # @api public
+  # @abstract
+  # This method may be implemented to return a hash object that is used for serializing.
+  # The object returned by this method should contain all the info needed to instantiate it again.
+  # If the method exists it will be called from to_msgpack and other serialization methods.
+  # @return [Hash]
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/formats.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/formats.rb
new file mode 100644
index 0000000..e636b30
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/formats.rb
@@ -0,0 +1,216 @@
+require 'puppet/network/format_handler'
+
+Puppet::Network::FormatHandler.create_serialized_formats(:msgpack, :weight => 20, :mime => "application/x-msgpack", :required_methods => [:render_method, :intern_method], :intern_method => :from_data_hash) do
+
+  confine :feature => :msgpack
+
+  def intern(klass, text)
+    data = MessagePack.unpack(text)
+    return data if data.is_a?(klass)
+    klass.from_data_hash(data)
+  end
+
+  def intern_multiple(klass, text)
+    MessagePack.unpack(text).collect do |data|
+      klass.from_data_hash(data)
+    end
+  end
+
+  def render_multiple(instances)
+    instances.to_msgpack
+  end
+end
+
+Puppet::Network::FormatHandler.create_serialized_formats(:yaml) do
+  def intern(klass, text)
+    data = YAML.load(text, :safe => true, :deserialize_symbols => true)
+    data_to_instance(klass, data)
+  end
+
+  def intern_multiple(klass, text)
+    data = YAML.load(text, :safe => true, :deserialize_symbols => true)
+    unless data.respond_to?(:collect)
+      raise Puppet::Network::FormatHandler::FormatError, "Serialized YAML did not contain a collection of instances when calling intern_multiple"
+    end
+
+    data.collect do |datum|
+      data_to_instance(klass, datum)
+    end
+  end
+
+  def data_to_instance(klass, data)
+    return data if data.is_a?(klass)
+
+    unless data.is_a? Hash
+      raise Puppet::Network::FormatHandler::FormatError, "Serialized YAML did not contain a valid instance of #{klass}"
+    end
+
+    klass.from_data_hash(data)
+  end
+
+  def render(instance)
+    instance.to_yaml
+  end
+
+  # Yaml monkey-patches Array, so this works.
+  def render_multiple(instances)
+    instances.to_yaml
+  end
+
+  def supported?(klass)
+    true
+  end
+end
+
+# This is a "special" format which is used for the moment only when sending facts
+# as REST GET parameters (see Puppet::Configurer::FactHandler).
+# This format combines a yaml serialization, then zlib compression and base64 encoding.
+Puppet::Network::FormatHandler.create_serialized_formats(:b64_zlib_yaml) do
+  require 'base64'
+
+  def use_zlib?
+    Puppet.features.zlib? && Puppet[:zlib]
+  end
+
+  def requiring_zlib
+    if use_zlib?
+      yield
+    else
+      raise Puppet::Error, "the zlib library is not installed or is disabled."
+    end
+  end
+
+  def intern(klass, text)
+    requiring_zlib do
+      Puppet::Network::FormatHandler.format(:yaml).intern(klass, decode(text))
+    end
+  end
+
+  def intern_multiple(klass, text)
+    requiring_zlib do
+      Puppet::Network::FormatHandler.format(:yaml).intern_multiple(klass, decode(text))
+    end
+  end
+
+  def render(instance)
+    encode(instance.to_yaml)
+  end
+
+  def render_multiple(instances)
+    encode(instances.to_yaml)
+  end
+
+  def supported?(klass)
+    true
+  end
+
+  def decode(data)
+    Zlib::Inflate.inflate(Base64.decode64(data))
+  end
+
+  def encode(text)
+    requiring_zlib do
+      Base64.encode64(Zlib::Deflate.deflate(text, Zlib::BEST_COMPRESSION))
+    end
+  end
+end
+
+Puppet::Network::FormatHandler.create(:s, :mime => "text/plain", :extension => "txt")
+
+# A very low-weight format so it'll never get chosen automatically.
+Puppet::Network::FormatHandler.create(:raw, :mime => "application/x-raw", :weight => 1) do
+  def intern_multiple(klass, text)
+    raise NotImplementedError
+  end
+
+  def render_multiple(instances)
+    raise NotImplementedError
+  end
+
+  # LAK:NOTE The format system isn't currently flexible enough to handle
+  # what I need to support raw formats just for individual instances (rather
+  # than both individual and collections), but we don't yet have enough data
+  # to make a "correct" design.
+  #   So, we hack it so it works for singular but fail if someone tries it
+  # on plurals.
+  def supported?(klass)
+    true
+  end
+end
+
+Puppet::Network::FormatHandler.create_serialized_formats(:pson, :weight => 10, :required_methods => [:render_method, :intern_method], :intern_method => :from_data_hash) do
+  def intern(klass, text)
+    data_to_instance(klass, PSON.parse(text))
+  end
+
+  def intern_multiple(klass, text)
+    PSON.parse(text).collect do |data|
+      data_to_instance(klass, data)
+    end
+  end
+
+  # PSON monkey-patches Array, so this works.
+  def render_multiple(instances)
+    instances.to_pson
+  end
+
+  # If they pass class information, we want to ignore it.  By default,
+  # we'll include class information but we won't rely on it - we don't
+  # want class names to be required because we then can't change our
+  # internal class names, which is bad.
+  def data_to_instance(klass, data)
+    if data.is_a?(Hash) and d = data['data']
+      data = d
+    end
+    return data if data.is_a?(klass)
+    klass.from_data_hash(data)
+  end
+end
+
+# This is really only ever going to be used for Catalogs.
+Puppet::Network::FormatHandler.create_serialized_formats(:dot, :required_methods => [:render_method])
+
+
+Puppet::Network::FormatHandler.create(:console,
+                                      :mime   => 'text/x-console-text',
+                                      :weight => 0) do
+  def json
+    @json ||= Puppet::Network::FormatHandler.format(:pson)
+  end
+
+  def render(datum)
+    # String to String
+    return datum if datum.is_a? String
+    return datum if datum.is_a? Numeric
+
+    # Simple hash to table
+    if datum.is_a? Hash and datum.keys.all? { |x| x.is_a? String or x.is_a? Numeric }
+      output = ''
+      column_a = datum.empty? ? 2 : datum.map{ |k,v| k.to_s.length }.max + 2
+      datum.sort_by { |k,v| k.to_s } .each do |key, value|
+        output << key.to_s.ljust(column_a)
+        output << json.render(value).
+          chomp.gsub(/\n */) { |x| x + (' ' * column_a) }
+        output << "\n"
+      end
+      return output
+    end
+
+    # Print one item per line for arrays
+    if datum.is_a? Array
+      output = ''
+      datum.each do |item|
+        output << item.to_s
+        output << "\n"
+      end
+      return output
+    end
+
+    # ...or pretty-print the inspect outcome.
+    return json.render(datum)
+  end
+
+  def render_multiple(data)
+    data.collect(&:render).join("\n")
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http.rb
new file mode 100644
index 0000000..68a345e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http.rb
@@ -0,0 +1,20 @@
+module Puppet::Network::HTTP
+  HEADER_ENABLE_PROFILING = "X-Puppet-Profiling"
+  HEADER_PUPPET_VERSION = "X-Puppet-Version"
+
+  require 'puppet/network/http/issues'
+  require 'puppet/network/http/error'
+  require 'puppet/network/http/route'
+  require 'puppet/network/http/api'
+  require 'puppet/network/http/api/v1'
+  require 'puppet/network/http/api/v2'
+  require 'puppet/network/http/handler'
+  require 'puppet/network/http/response'
+  require 'puppet/network/http/request'
+  require 'puppet/network/http/site'
+  require 'puppet/network/http/session'
+  require 'puppet/network/http/factory'
+  require 'puppet/network/http/nocache_pool'
+  require 'puppet/network/http/pool'
+  require 'puppet/network/http/memory_response'
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/api.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/api.rb
new file mode 100644
index 0000000..ba0b0b7
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/api.rb
@@ -0,0 +1,2 @@
+class Puppet::Network::HTTP::API
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/api/v1.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/api/v1.rb
new file mode 100644
index 0000000..24b7d91
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/api/v1.rb
@@ -0,0 +1,222 @@
+require 'puppet/network/authorization'
+
+class Puppet::Network::HTTP::API::V1
+  include Puppet::Network::Authorization
+
+  # How we map http methods and the indirection name in the URI
+  # to an indirection method.
+  METHOD_MAP = {
+    "GET" => {
+      :plural => :search,
+      :singular => :find
+    },
+    "POST" => {
+      :singular => :find,
+    },
+    "PUT" => {
+      :singular => :save
+    },
+    "DELETE" => {
+      :singular => :destroy
+    },
+    "HEAD" => {
+      :singular => :head
+    }
+  }
+
+  def self.routes
+    Puppet::Network::HTTP::Route.path(/.*/).any(new)
+  end
+
+  # handle an HTTP request
+  def call(request, response)
+    indirection_name, method, key, params = uri2indirection(request.method, request.path, request.params)
+    certificate = request.client_cert
+
+    check_authorization(method, "/#{indirection_name}/#{key}", params)
+
+    indirection = Puppet::Indirector::Indirection.instance(indirection_name.to_sym)
+    raise ArgumentError, "Could not find indirection '#{indirection_name}'" unless indirection
+
+    if !indirection.allow_remote_requests?
+      # TODO: should we tell the user we found an indirection but it doesn't
+      # allow remote requests, or just pretend there's no handler at all? what
+      # are the security implications for the former?
+      raise Puppet::Network::HTTP::Error::HTTPNotFoundError.new("No handler for #{indirection.name}", :NO_INDIRECTION_REMOTE_REQUESTS)
+    end
+
+    trusted = Puppet::Context::TrustedInformation.remote(params[:authenticated], params[:node], certificate)
+    Puppet.override(:trusted_information => trusted) do
+      send("do_#{method}", indirection, key, params, request, response)
+    end
+  rescue Puppet::Network::HTTP::Error::HTTPError => e
+    return do_http_control_exception(response, e)
+  rescue Exception => e
+    return do_exception(response, e)
+  end
+
+  def uri2indirection(http_method, uri, params)
+    environment, indirection, key = uri.split("/", 4)[1..-1] # the first field is always nil because of the leading slash
+
+    raise ArgumentError, "The environment must be purely alphanumeric, not '#{environment}'" unless Puppet::Node::Environment.valid_name?(environment)
+    raise ArgumentError, "The indirection name must be purely alphanumeric, not '#{indirection}'" unless indirection =~ /^\w+$/
+
+    method = indirection_method(http_method, indirection)
+
+    configured_environment = Puppet.lookup(:environments).get(environment)
+    if configured_environment.nil?
+      raise Puppet::Network::HTTP::Error::HTTPNotFoundError.new("Could not find environment '#{environment}'", Puppet::Network::HTTP::Issues::ENVIRONMENT_NOT_FOUND)
+    else
+      configured_environment = configured_environment.override_from_commandline(Puppet.settings)
+      params[:environment] = configured_environment
+    end
+
+    params.delete(:bucket_path)
+
+    raise ArgumentError, "No request key specified in #{uri}" if key == "" or key.nil?
+
+    key = URI.unescape(key)
+
+    [indirection, method, key, params]
+  end
+
+  private
+
+  def do_http_control_exception(response, exception)
+    msg = exception.message
+    Puppet.info(msg)
+    response.respond_with(exception.status, "text/plain", msg)
+  end
+
+  def do_exception(response, exception, status=400)
+    if exception.is_a?(Puppet::Network::AuthorizationError)
+      # make sure we return the correct status code
+      # for authorization issues
+      status = 403 if status == 400
+    end
+
+    Puppet.log_exception(exception)
+
+    response.respond_with(status, "text/plain", exception.to_s)
+  end
+
+  # Execute our find.
+  def do_find(indirection, key, params, request, response)
+    unless result = indirection.find(key, params)
+      raise Puppet::Network::HTTP::Error::HTTPNotFoundError.new("Could not find #{indirection.name} #{key}", Puppet::Network::HTTP::Issues::RESOURCE_NOT_FOUND)
+    end
+
+    format = accepted_response_formatter_for(indirection.model, request)
+
+    rendered_result = result
+    if result.respond_to?(:render)
+      Puppet::Util::Profiler.profile("Rendered result in #{format}", [:http, :v1_render, format]) do
+        rendered_result = result.render(format)
+      end
+    end
+
+    Puppet::Util::Profiler.profile("Sent response", [:http, :v1_response]) do
+      response.respond_with(200, format, rendered_result)
+    end
+  end
+
+  # Execute our head.
+  def do_head(indirection, key, params, request, response)
+    unless indirection.head(key, params)
+      raise Puppet::Network::HTTP::Error::HTTPNotFoundError.new("Could not find #{indirection.name} #{key}", Puppet::Network::HTTP::Issues::RESOURCE_NOT_FOUND)
+    end
+
+    # No need to set a response because no response is expected from a
+    # HEAD request.  All we need to do is not die.
+  end
+
+  # Execute our search.
+  def do_search(indirection, key, params, request, response)
+    result = indirection.search(key, params)
+
+    if result.nil?
+      raise Puppet::Network::HTTP::Error::HTTPNotFoundError.new("Could not find instances in #{indirection.name} with '#{key}'", Puppet::Network::HTTP::Issues::RESOURCE_NOT_FOUND)
+    end
+
+    format = accepted_response_formatter_for(indirection.model, request)
+
+    response.respond_with(200, format, indirection.model.render_multiple(format, result))
+  end
+
+  # Execute our destroy.
+  def do_destroy(indirection, key, params, request, response)
+    formatter = accepted_response_formatter_or_yaml_for(indirection.model, request)
+
+    result = indirection.destroy(key, params)
+
+    response.respond_with(200, formatter, formatter.render(result))
+  end
+
+  # Execute our save.
+  def do_save(indirection, key, params, request, response)
+    formatter = accepted_response_formatter_or_yaml_for(indirection.model, request)
+    sent_object = read_body_into_model(indirection.model, request)
+
+    result = indirection.save(sent_object, key)
+
+    response.respond_with(200, formatter, formatter.render(result))
+  end
+
+  def accepted_response_formatter_for(model_class, request)
+    accepted_formats = request.headers['accept'] or raise Puppet::Network::HTTP::Error::HTTPNotAcceptableError.new("Missing required Accept header", Puppet::Network::HTTP::Issues::MISSING_HEADER_FIELD)
+    request.response_formatter_for(model_class.supported_formats, accepted_formats)
+  end
+
+  def accepted_response_formatter_or_yaml_for(model_class, request)
+    accepted_formats = request.headers['accept'] || "yaml"
+    request.response_formatter_for(model_class.supported_formats, accepted_formats)
+  end
+
+  def read_body_into_model(model_class, request)
+    data = request.body.to_s
+
+    format = request.format
+    model_class.convert_from(format, data)
+  end
+
+  def indirection_method(http_method, indirection)
+    raise ArgumentError, "No support for http method #{http_method}" unless METHOD_MAP[http_method]
+
+    unless method = METHOD_MAP[http_method][plurality(indirection)]
+      raise ArgumentError, "No support for plurality #{plurality(indirection)} for #{http_method} operations"
+    end
+
+    method
+  end
+
+  def self.indirection2uri(request)
+    indirection = request.method == :search ? pluralize(request.indirection_name.to_s) : request.indirection_name.to_s
+    "/#{request.environment.to_s}/#{indirection}/#{request.escaped_key}#{request.query_string}"
+  end
+
+  def self.request_to_uri_and_body(request)
+    indirection = request.method == :search ? pluralize(request.indirection_name.to_s) : request.indirection_name.to_s
+    ["/#{request.environment.to_s}/#{indirection}/#{request.escaped_key}", request.query_string.sub(/^\?/,'')]
+  end
+
+  def self.pluralize(indirection)
+    return(indirection == "status" ? "statuses" : indirection + "s")
+  end
+
+  def plurality(indirection)
+    # NOTE This specific hook for facts is ridiculous, but it's a *many*-line
+    # fix to not need this, and our goal is to move away from the complication
+    # that leads to the fix being too long.
+    return :singular if indirection == "facts"
+    return :singular if indirection == "status"
+    return :singular if indirection == "certificate_status"
+    return :plural if indirection == "inventory"
+
+    result = (indirection =~ /s$|_search$/) ? :plural : :singular
+
+    indirection.sub!(/s$|_search$/, '')
+    indirection.sub!(/statuse$/, 'status')
+
+    result
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/api/v2.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/api/v2.rb
new file mode 100644
index 0000000..ef9672d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/api/v2.rb
@@ -0,0 +1,32 @@
+module Puppet::Network::HTTP::API::V2
+  require 'puppet/network/http/api/v2/environments'
+  require 'puppet/network/http/api/v2/authorization'
+
+  def self.routes
+    path(%r{^/v2\.0}).
+      get(Authorization.new).
+      chain(ENVIRONMENTS, NOT_FOUND)
+  end
+
+  private
+
+  def self.path(path)
+    Puppet::Network::HTTP::Route.path(path)
+  end
+
+  def self.provide(&block)
+    lambda do |request, response|
+      block.call.call(request, response)
+    end
+  end
+
+  NOT_FOUND = Puppet::Network::HTTP::Route.
+    path(/.*/).
+    any(lambda do |req, res|
+      raise Puppet::Network::HTTP::Error::HTTPNotFoundError.new(req.path, Puppet::Network::HTTP::Issues::HANDLER_NOT_FOUND)
+    end)
+
+  ENVIRONMENTS = path(%r{^/environments$}).get(provide do
+    Environments.new(Puppet.lookup(:environments))
+  end)
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/api/v2/authorization.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/api/v2/authorization.rb
new file mode 100644
index 0000000..fff0da0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/api/v2/authorization.rb
@@ -0,0 +1,15 @@
+class Puppet::Network::HTTP::API::V2::Authorization
+  include Puppet::Network::Authorization
+
+  def call(request, response)
+    if request.method != "GET"
+      raise Puppet::Network::HTTP::Error::HTTPNotAuthorizedError.new("Only GET requests are authorized for V2 endpoints", Puppet::Network::HTTP::Issues::UNSUPPORTED_METHOD)
+    end
+
+    begin
+      check_authorization(:find, request.path, request.params)
+    rescue Puppet::Network::AuthorizationError => e
+      raise Puppet::Network::HTTP::Error::HTTPNotAuthorizedError.new(e.message, Puppet::Network::HTTP::Issues::FAILED_AUTHORIZATION)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/api/v2/environments.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/api/v2/environments.rb
new file mode 100644
index 0000000..51a4e04
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/api/v2/environments.rb
@@ -0,0 +1,35 @@
+require 'json'
+
+class Puppet::Network::HTTP::API::V2::Environments
+  def initialize(env_loader)
+    @env_loader = env_loader
+  end
+
+  def call(request, response)
+    response.respond_with(200, "application/json", JSON.dump({
+      "search_paths" => @env_loader.search_paths,
+      "environments" => Hash[@env_loader.list.collect do |env|
+        [env.name, {
+          "settings" => {
+            "modulepath" => env.full_modulepath,
+            "manifest" => env.manifest,
+            "environment_timeout" => timeout(env),
+            "config_version" => env.config_version || '',
+          }
+        }]
+      end]
+    }))
+  end
+
+  private
+
+  def timeout(env)
+    ttl = @env_loader.get_conf(env.name).environment_timeout
+    if ttl == 1.0 / 0.0 # INFINITY
+      "unlimited"
+    else
+      ttl
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/compression.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/compression.rb
new file mode 100644
index 0000000..839fe40
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/compression.rb
@@ -0,0 +1,118 @@
+require 'puppet/network/http'
+
+module Puppet::Network::HTTP::Compression
+
+  # this module function allows to use the right underlying
+  # methods depending on zlib presence
+  def module
+    return(Puppet.features.zlib? ? Active : None)
+  end
+  module_function :module
+
+  module Active
+    require 'zlib'
+    require 'stringio'
+
+    # return an uncompressed body if the response has been
+    # compressed
+    def uncompress_body(response)
+      case response['content-encoding']
+      when 'gzip'
+        return Zlib::GzipReader.new(StringIO.new(response.body)).read
+      when 'deflate'
+        return Zlib::Inflate.new.inflate(response.body)
+      when nil, 'identity'
+        return response.body
+      else
+        raise Net::HTTPError.new("Unknown content encoding - #{response['content-encoding']}", response)
+      end
+    end
+
+    def uncompress(response)
+      raise Net::HTTPError.new("No block passed") unless block_given?
+
+      case response['content-encoding']
+      when 'gzip','deflate'
+        uncompressor = ZlibAdapter.new
+      when nil, 'identity'
+        uncompressor = IdentityAdapter.new
+      else
+        raise Net::HTTPError.new("Unknown content encoding - #{response['content-encoding']}", response)
+      end
+
+      yield uncompressor
+
+      uncompressor.close
+    end
+
+    def add_accept_encoding(headers={})
+      if Puppet.settings[:http_compression]
+        headers['accept-encoding'] = 'gzip; q=1.0, deflate; q=1.0; identity'
+      else
+        headers['accept-encoding'] = 'identity'
+      end
+      headers
+    end
+
+    # This adapters knows how to uncompress both 'zlib' stream (the deflate algorithm from Content-Encoding)
+    # and GZip streams.
+    class ZlibAdapter
+      def initialize
+        # Create an inflater that knows to parse GZip streams and zlib streams.
+        # This uses a property of the C Zlib library, documented as follow:
+        #   windowBits can also be greater than 15 for optional gzip decoding. Add
+        #   32 to windowBits to enable zlib and gzip decoding with automatic header
+        #   detection, or add 16 to decode only the gzip format (the zlib format will
+        #   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is
+        #   a crc32 instead of an adler32.
+        @uncompressor = Zlib::Inflate.new(15 + 32)
+        @first = true
+      end
+
+      def uncompress(chunk)
+        out = @uncompressor.inflate(chunk)
+        @first = false
+        return out
+      rescue Zlib::DataError
+        # it can happen that we receive a raw deflate stream
+        # which might make our inflate throw a data error.
+        # in this case, we try with a verbatim (no header)
+        # deflater.
+        @uncompressor = Zlib::Inflate.new
+        if @first then
+          @first = false
+          retry
+        end
+        raise
+      end
+
+      def close
+        @uncompressor.finish
+        @uncompressor.close
+      end
+    end
+  end
+
+  module None
+    def uncompress_body(response)
+      response.body
+    end
+
+    def add_accept_encoding(headers)
+      headers
+    end
+
+    def uncompress(response)
+      yield IdentityAdapter.new
+    end
+  end
+
+  class IdentityAdapter
+    def uncompress(chunk)
+      chunk
+    end
+
+    def close
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/connection.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/connection.rb
new file mode 100644
index 0000000..8ffb1dd
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/connection.rb
@@ -0,0 +1,240 @@
+require 'net/https'
+require 'puppet/ssl/host'
+require 'puppet/ssl/configuration'
+require 'puppet/ssl/validator'
+require 'puppet/network/authentication'
+require 'puppet/network/http'
+require 'uri'
+
+module Puppet::Network::HTTP
+
+  # This will be raised if too many redirects happen for a given HTTP request
+  class RedirectionLimitExceededException < Puppet::Error ; end
+
+  # This class provides simple methods for issuing various types of HTTP
+  # requests.  It's interface is intended to mirror Ruby's Net::HTTP
+  # object, but it provides a few important bits of additional
+  # functionality.  Notably:
+  #
+  # * Any HTTPS requests made using this class will use Puppet's SSL
+  #   certificate configuration for their authentication, and
+  # * Provides some useful error handling for any SSL errors that occur
+  #   during a request.
+  # @api public
+  class Connection
+    include Puppet::Network::Authentication
+
+    OPTION_DEFAULTS = {
+      :use_ssl => true,
+      :verify => nil,
+      :redirect_limit => 10,
+    }
+
+    # Creates a new HTTP client connection to `host`:`port`.
+    # @param host [String] the host to which this client will connect to
+    # @param port [Fixnum] the port to which this client will connect to
+    # @param options [Hash] options influencing the properties of the created
+    #   connection,
+    # @option options [Boolean] :use_ssl true to connect with SSL, false
+    #   otherwise, defaults to true
+    # @option options [#setup_connection] :verify An object that will configure
+    #   any verification to do on the connection
+    # @option options [Fixnum] :redirect_limit the number of allowed
+    #   redirections, defaults to 10 passing any other option in the options
+    #   hash results in a Puppet::Error exception
+    #
+    # @note the HTTP connection itself happens lazily only when {#request}, or
+    #   one of the {#get}, {#post}, {#delete}, {#head} or {#put} is called
+    # @note The correct way to obtain a connection is to use one of the factory
+    #   methods on {Puppet::Network::HttpPool}
+    # @api private
+    def initialize(host, port, options = {})
+      @host = host
+      @port = port
+
+      unknown_options = options.keys - OPTION_DEFAULTS.keys
+      raise Puppet::Error, "Unrecognized option(s): #{unknown_options.map(&:inspect).sort.join(', ')}" unless unknown_options.empty?
+
+      options = OPTION_DEFAULTS.merge(options)
+      @use_ssl = options[:use_ssl]
+      @verify = options[:verify]
+      @redirect_limit = options[:redirect_limit]
+      @site = Puppet::Network::HTTP::Site.new(@use_ssl ? 'https' : 'http', host, port)
+      @pool = Puppet.lookup(:http_pool)
+    end
+
+    # @!macro [new] common_options
+    #   @param options [Hash] options influencing the request made
+    #   @option options [Hash{Symbol => String}] :basic_auth The basic auth
+    #     :username and :password to use for the request
+
+    # @param path [String]
+    # @param headers [Hash{String => String}]
+    # @!macro common_options
+    # @api public
+    def get(path, headers = {}, options = {})
+      request_with_redirects(Net::HTTP::Get.new(path, headers), options)
+    end
+
+    # @param path [String]
+    # @param data [String]
+    # @param headers [Hash{String => String}]
+    # @!macro common_options
+    # @api public
+    def post(path, data, headers = nil, options = {})
+      request = Net::HTTP::Post.new(path, headers)
+      request.body = data
+      request_with_redirects(request, options)
+    end
+
+    # @param path [String]
+    # @param headers [Hash{String => String}]
+    # @!macro common_options
+    # @api public
+    def head(path, headers = {}, options = {})
+      request_with_redirects(Net::HTTP::Head.new(path, headers), options)
+    end
+
+    # @param path [String]
+    # @param headers [Hash{String => String}]
+    # @!macro common_options
+    # @api public
+    def delete(path, headers = {'Depth' => 'Infinity'}, options = {})
+      request_with_redirects(Net::HTTP::Delete.new(path, headers), options)
+    end
+
+    # @param path [String]
+    # @param data [String]
+    # @param headers [Hash{String => String}]
+    # @!macro common_options
+    # @api public
+    def put(path, data, headers = nil, options = {})
+      request = Net::HTTP::Put.new(path, headers)
+      request.body = data
+      request_with_redirects(request, options)
+    end
+
+    def request(method, *args)
+      self.send(method, *args)
+    end
+
+    # TODO: These are proxies for the Net::HTTP#request_* methods, which are
+    # almost the same as the "get", "post", etc. methods that we've ported above,
+    # but they are able to accept a code block and will yield to it, which is
+    # necessary to stream responses, e.g. file content.  For now
+    # we're not funneling these proxy implementations through our #request
+    # method above, so they will not inherit the same error handling.  In the
+    # future we may want to refactor these so that they are funneled through
+    # that method and do inherit the error handling.
+    def request_get(*args, &block)
+      with_connection(@site) do |connection|
+        connection.request_get(*args, &block)
+      end
+    end
+
+    def request_head(*args, &block)
+      with_connection(@site) do |connection|
+        connection.request_head(*args, &block)
+      end
+    end
+
+    def request_post(*args, &block)
+      with_connection(@site) do |connection|
+        connection.request_post(*args, &block)
+      end
+    end
+    # end of Net::HTTP#request_* proxies
+
+    # The address to connect to.
+    def address
+      @site.host
+    end
+
+    # The port to connect to.
+    def port
+      @site.port
+    end
+
+    # Whether to use ssl
+    def use_ssl?
+      @site.use_ssl?
+    end
+
+    private
+
+    def request_with_redirects(request, options)
+      current_request = request
+      current_site = @site
+      response = nil
+
+      0.upto(@redirect_limit) do |redirection|
+        return response if response
+
+        with_connection(current_site) do |connection|
+          apply_options_to(current_request, options)
+
+          current_response = execute_request(connection, current_request)
+
+          if [301, 302, 307].include?(current_response.code.to_i)
+
+            # handle the redirection
+            location = URI.parse(current_response['location'])
+            current_site = current_site.move_to(location)
+
+            # update to the current request path
+            current_request = current_request.class.new(location.path)
+            current_request.body = request.body
+            request.each do |header, value|
+              current_request[header] = value
+            end
+          else
+            response = current_response
+          end
+        end
+
+        # and try again...
+      end
+
+      raise RedirectionLimitExceededException, "Too many HTTP redirections for #{@host}:#{@port}"
+    end
+
+    def apply_options_to(request, options)
+      if options[:basic_auth]
+        request.basic_auth(options[:basic_auth][:user], options[:basic_auth][:password])
+      end
+    end
+
+    def execute_request(connection, request)
+      response = connection.request(request)
+
+      # Check the peer certs and warn if they're nearing expiration.
+      warn_if_near_expiration(*@verify.peer_certs)
+
+      response
+    end
+
+    def with_connection(site, &block)
+      response = nil
+      @pool.with_connection(site, @verify) do |conn|
+        response = yield conn
+      end
+      response
+    rescue OpenSSL::SSL::SSLError => error
+      if error.message.include? "certificate verify failed"
+        msg = error.message
+        msg << ": [" + @verify.verify_errors.join('; ') + "]"
+        raise Puppet::Error, msg, error.backtrace
+      elsif error.message =~ /hostname.*not match.*server certificate/
+        leaf_ssl_cert = @verify.peer_certs.last
+
+        valid_certnames = [leaf_ssl_cert.name, *leaf_ssl_cert.subject_alt_names].uniq
+        msg = valid_certnames.length > 1 ? "one of #{valid_certnames.join(', ')}" : valid_certnames.first
+        msg = "Server hostname '#{site.host}' did not match server certificate; expected #{msg}"
+
+        raise Puppet::Error, msg, error.backtrace
+      else
+        raise
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/error.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/error.rb
new file mode 100644
index 0000000..4e521d1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/error.rb
@@ -0,0 +1,69 @@
+require 'json'
+
+module Puppet::Network::HTTP::Error
+  Issues = Puppet::Network::HTTP::Issues
+
+  class HTTPError < Exception
+    attr_reader :status, :issue_kind
+
+    def initialize(message, status, issue_kind)
+      super(message)
+      @status = status
+      @issue_kind = issue_kind
+    end
+
+    def to_json
+      JSON({:message => message, :issue_kind => @issue_kind})
+    end
+  end
+
+  class HTTPNotAcceptableError < HTTPError
+    CODE = 406
+    def initialize(message, issue_kind = Issues::RUNTIME_ERROR)
+      super("Not Acceptable: " + message, CODE, issue_kind)
+    end
+  end
+
+  class HTTPNotFoundError < HTTPError
+    CODE = 404
+    def initialize(message, issue_kind = Issues::RUNTIME_ERROR)
+      super("Not Found: " + message, CODE, issue_kind)
+    end
+  end
+
+  class HTTPNotAuthorizedError < HTTPError
+    CODE = 403
+    def initialize(message, issue_kind = Issues::RUNTIME_ERROR)
+      super("Not Authorized: " + message, CODE, issue_kind)
+    end
+  end
+
+  class HTTPBadRequestError < HTTPError
+    CODE = 400
+    def initialize(message, issue_kind = Issues::RUNTIME_ERROR)
+      super("Bad Request: " + message, CODE, issue_kind)
+    end
+  end
+
+  class HTTPMethodNotAllowedError < HTTPError
+    CODE = 405
+    def initialize(message, issue_kind = Issues::RUNTIME_ERROR)
+      super("Method Not Allowed: " + message, CODE, issue_kind)
+    end
+  end
+
+  class HTTPServerError < HTTPError
+    CODE = 500
+
+    attr_reader :backtrace
+
+    def initialize(original_error, issue_kind = Issues::RUNTIME_ERROR)
+      super("Server Error: " + original_error.message, CODE, issue_kind)
+      @backtrace = original_error.backtrace
+    end
+
+    def to_json
+      JSON({:message => message, :issue_kind => @issue_kind, :stacktrace => self.backtrace})
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/factory.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/factory.rb
new file mode 100644
index 0000000..8e60ad2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/factory.rb
@@ -0,0 +1,44 @@
+require 'openssl'
+require 'net/http'
+
+# Factory for <tt>Net::HTTP</tt> objects.
+#
+# Encapsulates the logic for creating a <tt>Net::HTTP</tt> object based on the
+# specified {Puppet::Network::HTTP::Site Site} and puppet settings.
+#
+# @api private
+#
+class Puppet::Network::HTTP::Factory
+  @@openssl_initialized = false
+
+  def initialize
+    # PUP-1411, make sure that openssl is initialized before we try to connect
+    if ! @@openssl_initialized
+      OpenSSL::SSL::SSLContext.new
+      @@openssl_initialized = true
+    end
+  end
+
+  def create_connection(site)
+    Puppet.debug("Creating new connection for #{site}")
+
+    args = [site.host, site.port]
+    if Puppet[:http_proxy_host] == "none"
+      args << nil << nil
+    else
+      args << Puppet[:http_proxy_host] << Puppet[:http_proxy_port]
+    end
+
+    http = Net::HTTP.new(*args)
+    http.use_ssl = site.use_ssl?
+    # Use configured timeout (#1176)
+    http.read_timeout = Puppet[:configtimeout]
+    http.open_timeout = Puppet[:configtimeout]
+
+    if Puppet[:http_debug]
+      http.set_debug_output($stderr)
+    end
+
+    http
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/handler.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/handler.rb
new file mode 100644
index 0000000..a8aa1aa
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/handler.rb
@@ -0,0 +1,186 @@
+module Puppet::Network::HTTP
+end
+
+require 'puppet/network/http'
+require 'puppet/network/http/api/v1'
+require 'puppet/network/authentication'
+require 'puppet/network/rights'
+require 'puppet/util/profiler'
+require 'puppet/util/profiler/aggregate'
+require 'resolv'
+
+module Puppet::Network::HTTP::Handler
+  include Puppet::Network::Authentication
+  include Puppet::Network::HTTP::Issues
+
+  # These shouldn't be allowed to be set by clients
+  # in the query string, for security reasons.
+  DISALLOWED_KEYS = ["node", "ip"]
+
+  def register(routes)
+    # There's got to be a simpler way to do this, right?
+    dupes = {}
+    routes.each { |r| dupes[r.path_matcher] = (dupes[r.path_matcher] || 0) + 1 }
+    dupes = dupes.collect { |pm, count| pm if count > 1 }.compact
+    if dupes.count > 0
+      raise ArgumentError, "Given multiple routes with identical path regexes: #{dupes.map{ |rgx| rgx.inspect }.join(', ')}"
+    end
+
+    @routes = routes
+    Puppet.debug("Routes Registered:")
+    @routes.each do |route|
+      Puppet.debug(route.inspect)
+    end
+  end
+
+  # Retrieve all headers from the http request, as a hash with the header names
+  # (lower-cased) as the keys
+  def headers(request)
+    raise NotImplementedError
+  end
+
+  def format_to_mime(format)
+    format.is_a?(Puppet::Network::Format) ? format.mime : format
+  end
+
+  # handle an HTTP request
+  def process(request, response)
+    new_response = Puppet::Network::HTTP::Response.new(self, response)
+
+    request_headers = headers(request)
+    request_params = params(request)
+    request_method = http_method(request)
+    request_path = path(request)
+
+    new_request = Puppet::Network::HTTP::Request.new(request_headers, request_params, request_method, request_path, request_path, client_cert(request), body(request))
+
+    response[Puppet::Network::HTTP::HEADER_PUPPET_VERSION] = Puppet.version
+
+    profiler = configure_profiler(request_headers, request_params)
+
+    Puppet::Util::Profiler.profile("Processed request #{request_method} #{request_path}", [:http, request_method, request_path]) do
+      if route = @routes.find { |route| route.matches?(new_request) }
+        route.process(new_request, new_response)
+      else
+        raise Puppet::Network::HTTP::Error::HTTPNotFoundError.new("No route for #{new_request.method} #{new_request.path}", HANDLER_NOT_FOUND)
+      end
+    end
+
+  rescue Puppet::Network::HTTP::Error::HTTPError => e
+    Puppet.info(e.message)
+    new_response.respond_with(e.status, "application/json", e.to_json)
+  rescue Exception => e
+    http_e = Puppet::Network::HTTP::Error::HTTPServerError.new(e)
+    Puppet.err(http_e.message)
+    new_response.respond_with(http_e.status, "application/json", http_e.to_json)
+  ensure
+    if profiler
+      remove_profiler(profiler)
+    end
+    cleanup(request)
+  end
+
+  # Set the response up, with the body and status.
+  def set_response(response, body, status = 200)
+    raise NotImplementedError
+  end
+
+  # Set the specified format as the content type of the response.
+  def set_content_type(response, format)
+    raise NotImplementedError
+  end
+
+  # resolve node name from peer's ip address
+  # this is used when the request is unauthenticated
+  def resolve_node(result)
+    begin
+      return Resolv.getname(result[:ip])
+    rescue => detail
+      Puppet.err "Could not resolve #{result[:ip]}: #{detail}"
+    end
+    result[:ip]
+  end
+
+  private
+
+  # methods to be overridden by the including web server class
+
+  def http_method(request)
+    raise NotImplementedError
+  end
+
+  def path(request)
+    raise NotImplementedError
+  end
+
+  def request_key(request)
+    raise NotImplementedError
+  end
+
+  def body(request)
+    raise NotImplementedError
+  end
+
+  def params(request)
+    raise NotImplementedError
+  end
+
+  def client_cert(request)
+    raise NotImplementedError
+  end
+
+  def cleanup(request)
+    # By default, there is nothing to cleanup.
+  end
+
+  def decode_params(params)
+    params.select { |key, _| allowed_parameter?(key) }.inject({}) do |result, ary|
+      param, value = ary
+      result[param.to_sym] = parse_parameter_value(param, value)
+      result
+    end
+  end
+
+  def allowed_parameter?(name)
+    not (name.nil? || name.empty? || DISALLOWED_KEYS.include?(name))
+  end
+
+  def parse_parameter_value(param, value)
+    case value
+    when /^---/
+      Puppet.debug("Found YAML while processing request parameter #{param} (value: <#{value}>)")
+      Puppet.deprecation_warning("YAML in network requests is deprecated and will be removed in a future version. See http://links.puppetlabs.com/deprecate_yaml_on_network")
+      YAML.load(value, :safe => true, :deserialize_symbols => true)
+    when Array
+      value.collect { |v| parse_primitive_parameter_value(v) }
+    else
+      parse_primitive_parameter_value(value)
+    end
+  end
+
+  def parse_primitive_parameter_value(value)
+    case value
+    when "true"
+      true
+    when "false"
+      false
+    when /^\d+$/
+      Integer(value)
+    when /^\d+\.\d+$/
+      value.to_f
+    else
+      value
+    end
+  end
+
+  def configure_profiler(request_headers, request_params)
+    if (request_headers.has_key?(Puppet::Network::HTTP::HEADER_ENABLE_PROFILING.downcase) or Puppet[:profile])
+      Puppet::Util::Profiler.add_profiler(Puppet::Util::Profiler::Aggregate.new(Puppet.method(:debug), request_params.object_id))
+    end
+  end
+
+  def remove_profiler(profiler)
+    profiler.shutdown
+    Puppet::Util::Profiler.remove_profiler(profiler)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/issues.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/issues.rb
new file mode 100644
index 0000000..324d832
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/issues.rb
@@ -0,0 +1,11 @@
+module Puppet::Network::HTTP::Issues
+  NO_INDIRECTION_REMOTE_REQUESTS = :NO_INDIRECTION_REMOTE_REQUESTS
+  HANDLER_NOT_FOUND = :HANDLER_NOT_FOUND
+  RESOURCE_NOT_FOUND = :RESOURCE_NOT_FOUND
+  ENVIRONMENT_NOT_FOUND = :ENVIRONMENT_NOT_FOUND
+  RUNTIME_ERROR = :RUNTIME_ERROR
+  MISSING_HEADER_FIELD = :MISSING_HEADER_FIELD
+  UNSUPPORTED_FORMAT = :UNSUPPORTED_FORMAT
+  UNSUPPORTED_METHOD = :UNSUPPORTED_METHOD
+  FAILED_AUTHORIZATION = :FAILED_AUTHORIZATION
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/memory_response.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/memory_response.rb
new file mode 100644
index 0000000..8171cfb
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/memory_response.rb
@@ -0,0 +1,13 @@
+class Puppet::Network::HTTP::MemoryResponse
+  attr_reader :code, :type, :body
+
+  def initialize
+    @body = ""
+  end
+
+  def respond_with(code, type, body)
+    @code = code
+    @type = type
+    @body += body
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/nocache_pool.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/nocache_pool.rb
new file mode 100644
index 0000000..d80e040
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/nocache_pool.rb
@@ -0,0 +1,21 @@
+# A pool that does not cache HTTP connections.
+#
+# @api private
+class Puppet::Network::HTTP::NoCachePool
+  def initialize(factory = Puppet::Network::HTTP::Factory.new)
+    @factory = factory
+  end
+
+  # Yields a <tt>Net::HTTP</tt> connection.
+  #
+  # @yieldparam http [Net::HTTP] An HTTP connection
+  def with_connection(site, verify, &block)
+    http = @factory.create_connection(site)
+    verify.setup_connection(http)
+    yield http
+  end
+
+  def close
+    # do nothing
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/pool.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/pool.rb
new file mode 100644
index 0000000..b817b47
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/pool.rb
@@ -0,0 +1,120 @@
+# A pool for persistent <tt>Net::HTTP</tt> connections. Connections are
+# stored in the pool indexed by their {Puppet::Network::HTTP::Site Site}.
+# Connections are borrowed from the pool, yielded to the caller, and
+# released back into the pool. If a connection is expired, it will be
+# closed either when a connection to that site is requested, or when
+# the pool is closed. The pool can store multiple connections to the
+# same site, and will be reused in MRU order.
+#
+# @api private
+#
+class Puppet::Network::HTTP::Pool
+  FIFTEEN_SECONDS = 15
+
+  attr_reader :factory
+
+  def initialize(keepalive_timeout = FIFTEEN_SECONDS)
+    @pool = {}
+    @factory = Puppet::Network::HTTP::Factory.new
+    @keepalive_timeout = keepalive_timeout
+  end
+
+  def with_connection(site, verify, &block)
+    reuse = true
+
+    http = borrow(site, verify)
+    begin
+      if http.use_ssl? && http.verify_mode != OpenSSL::SSL::VERIFY_PEER
+        reuse = false
+      end
+
+      yield http
+    rescue => detail
+      reuse = false
+      raise detail
+    ensure
+      if reuse
+        release(site, http)
+      else
+        close_connection(site, http)
+      end
+    end
+  end
+
+  def close
+    @pool.each_pair do |site, sessions|
+      sessions.each do |session|
+        close_connection(site, session.connection)
+      end
+    end
+    @pool.clear
+  end
+
+  # @api private
+  def pool
+    @pool
+  end
+
+  # Safely close a persistent connection.
+  #
+  # @api private
+  def close_connection(site, http)
+    Puppet.debug("Closing connection for #{site}")
+    http.finish
+  rescue => detail
+    Puppet.log_exception(detail, "Failed to close connection for #{site}: #{detail}")
+  end
+
+  # Borrow and take ownership of a persistent connection. If a new
+  # connection is created, it will be started prior to being returned.
+  #
+  # @api private
+  def borrow(site, verify)
+    @pool[site] = active_sessions(site)
+    session = @pool[site].shift
+    if session
+      Puppet.debug("Using cached connection for #{site}")
+      session.connection
+    else
+      http = @factory.create_connection(site)
+      verify.setup_connection(http)
+
+      Puppet.debug("Starting connection for #{site}")
+      http.start
+      http
+    end
+  end
+
+  # Release a connection back into the pool.
+  #
+  # @api private
+  def release(site, http)
+    expiration = Time.now + @keepalive_timeout
+    session = Puppet::Network::HTTP::Session.new(http, expiration)
+    Puppet.debug("Caching connection for #{site}")
+
+    sessions = @pool[site]
+    if sessions
+      sessions.unshift(session)
+    else
+      @pool[site] = [session]
+    end
+  end
+
+  # Returns an Array of sessions whose connections are not expired.
+  #
+  # @api private
+  def active_sessions(site)
+    now = Time.now
+
+    sessions = @pool[site] || []
+    sessions.select do |session|
+      if session.expired?(now)
+        close_connection(site, session.connection)
+        false
+      else
+        true
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/rack.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/rack.rb
new file mode 100644
index 0000000..908b200
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/rack.rb
@@ -0,0 +1,33 @@
+require 'rack'
+require 'rack/request'
+require 'rack/response'
+
+require 'puppet/network/http'
+require 'puppet/network/http/rack/rest'
+
+# An rack application, for running the Puppet HTTP Server.
+class Puppet::Network::HTTP::Rack
+  # The real rack application (which needs to respond to call).
+  # The work we need to do, roughly is:
+  # * Read request (from env) and prepare a response
+  # * Route the request to the correct handler
+  # * Return the response (in rack-format) to our caller.
+  def call(env)
+    request = Rack::Request.new(env)
+    response = Rack::Response.new
+    Puppet.debug 'Handling request: %s %s' % [request.request_method, request.fullpath]
+
+    begin
+      Puppet::Network::HTTP::RackREST.new.process(request, response)
+    rescue => detail
+      # Send a Status 500 Error on unhandled exceptions.
+      response.status = 500
+      response['Content-Type'] = 'text/plain'
+      response.write 'Internal Server Error: "%s"' % detail.message
+      # log what happened
+      Puppet.log_exception(detail, "Puppet Server (Rack): Internal Server Error: Unhandled Exception: \"%s\"" % detail.message)
+    end
+    response.finish
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/rack/rest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/rack/rest.rb
new file mode 100644
index 0000000..3ca79c8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/rack/rest.rb
@@ -0,0 +1,138 @@
+require 'openssl'
+require 'cgi'
+require 'puppet/network/http/handler'
+require 'puppet/util/ssl'
+
+class Puppet::Network::HTTP::RackREST
+  include Puppet::Network::HTTP::Handler
+
+  ContentType = 'Content-Type'.freeze
+
+  CHUNK_SIZE = 8192
+
+  class RackFile
+    def initialize(file)
+      @file = file
+    end
+
+    def each
+      while chunk = @file.read(CHUNK_SIZE)
+        yield chunk
+      end
+    end
+
+    def close
+      @file.close
+    end
+  end
+
+  def initialize(args={})
+    super()
+    register([Puppet::Network::HTTP::API::V2.routes, Puppet::Network::HTTP::API::V1.routes])
+  end
+
+  def set_content_type(response, format)
+    response[ContentType] = format_to_mime(format)
+  end
+
+  # produce the body of the response
+  def set_response(response, result, status = 200)
+    response.status = status
+    unless result.is_a?(File)
+      response.write result
+    else
+      response["Content-Length"] = result.stat.size.to_s
+      response.body = RackFile.new(result)
+    end
+  end
+
+  # Retrieve all headers from the http request, as a map.
+  def headers(request)
+    headers = request.env.select {|k,v| k.start_with? 'HTTP_'}.inject({}) do |m, (k,v)|
+      m[k.sub(/^HTTP_/, '').gsub('_','-').downcase] = v
+      m
+    end
+    headers['content-type'] = request.content_type
+    headers
+  end
+
+  # Return which HTTP verb was used in this request.
+  def http_method(request)
+    request.request_method
+  end
+
+  # Return the query params for this request.
+  def params(request)
+    if request.post?
+      params = request.params
+    else
+      # rack doesn't support multi-valued query parameters,
+      # e.g. ignore, so parse them ourselves
+      params = CGI.parse(request.query_string)
+      convert_singular_arrays_to_value(params)
+    end
+    result = decode_params(params)
+    result.merge(extract_client_info(request))
+  end
+
+  # what path was requested? (this is, without any query parameters)
+  def path(request)
+    request.path
+  end
+
+  # return the request body
+  def body(request)
+    request.body.read
+  end
+
+  def client_cert(request)
+    # This environment variable is set by mod_ssl, note that it
+    # requires the `+ExportCertData` option in the `SSLOptions` directive
+    cert = request.env['SSL_CLIENT_CERT']
+    # NOTE: The SSL_CLIENT_CERT environment variable will be the empty string
+    # when Puppet agent nodes have not yet obtained a signed certificate.
+    if cert.nil? || cert.empty?
+      nil
+    else
+      cert = Puppet::SSL::Certificate.from_instance(OpenSSL::X509::Certificate.new(cert))
+      warn_if_near_expiration(cert)
+      cert
+    end
+  end
+
+  # Passenger freaks out if we finish handling the request without reading any
+  # part of the body, so make sure we have.
+  def cleanup(request)
+    request.body.read(1)
+    nil
+  end
+
+  def extract_client_info(request)
+    result = {}
+    result[:ip] = request.ip
+
+    # if we find SSL info in the headers, use them to get a hostname from the CN.
+    # try this with :ssl_client_header, which defaults should work for
+    # Apache with StdEnvVars.
+    subj_str = request.env[Puppet[:ssl_client_header]]
+    subject = Puppet::Util::SSL.subject_from_dn(subj_str || "")
+
+    if cn = Puppet::Util::SSL.cn_from_subject(subject)
+      result[:node] = cn
+      result[:authenticated] = (request.env[Puppet[:ssl_client_verify_header]] == 'SUCCESS')
+    else
+      result[:node] = resolve_node(result)
+      result[:authenticated] = false
+    end
+
+    result
+  end
+
+  def convert_singular_arrays_to_value(hash)
+    hash.each do |key, value|
+      if value.size == 1
+        hash[key] = value.first
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/request.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/request.rb
new file mode 100644
index 0000000..c17673b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/request.rb
@@ -0,0 +1,56 @@
+Puppet::Network::HTTP::Request = Struct.new(:headers, :params, :method, :path, :routing_path, :client_cert, :body) do
+  def self.from_hash(hash)
+    symbol_members = members.collect(&:intern)
+    unknown = hash.keys - symbol_members
+    if unknown.empty?
+      new(hash[:headers] || {},
+          hash[:params] || {},
+          hash[:method] || "GET",
+          hash[:path],
+          hash[:routing_path] || hash[:path],
+          hash[:client_cert],
+          hash[:body])
+    else
+      raise ArgumentError, "Unknown arguments: #{unknown.collect(&:inspect).join(', ')}"
+    end
+  end
+
+  def route_into(prefix)
+    self.class.new(headers, params, method, path, routing_path.sub(prefix, ''), client_cert, body)
+  end
+
+  def format
+    if header = headers['content-type']
+      header.gsub!(/\s*;.*$/,'') # strip any charset
+      format = Puppet::Network::FormatHandler.mime(header)
+      if format.nil?
+        raise "Client sent a mime-type (#{header}) that doesn't correspond to a format we support"
+      else
+        report_if_deprecated(format)
+        return format.name.to_s if format.suitable?
+      end
+    end
+
+    raise "No Content-Type header was received, it isn't possible to unserialize the request"
+  end
+
+  def response_formatter_for(supported_formats, accepted_formats = headers['accept'])
+    formatter = Puppet::Network::FormatHandler.most_suitable_format_for(
+      accepted_formats.split(/\s*,\s*/),
+      supported_formats)
+
+      if formatter.nil?
+        raise Puppet::Network::HTTP::Error::HTTPNotAcceptableError.new("No supported formats are acceptable (Accept: #{accepted_formats})", Puppet::Network::HTTP::Issues::UNSUPPORTED_FORMAT)
+      end
+
+      report_if_deprecated(formatter)
+
+      formatter
+  end
+
+  def report_if_deprecated(format)
+    if format.name == :yaml || format.name == :b64_zlib_yaml
+      Puppet.deprecation_warning("YAML in network requests is deprecated and will be removed in a future version. See http://links.puppetlabs.com/deprecate_yaml_on_network")
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/response.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/response.rb
new file mode 100644
index 0000000..f73399d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/response.rb
@@ -0,0 +1,11 @@
+class Puppet::Network::HTTP::Response
+  def initialize(handler, response)
+    @handler = handler
+    @response = response
+  end
+
+  def respond_with(code, type, body)
+    @handler.set_content_type(@response, type)
+    @handler.set_response(@response, body, code)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/route.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/route.rb
new file mode 100644
index 0000000..81f3116
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/route.rb
@@ -0,0 +1,100 @@
+class Puppet::Network::HTTP::Route
+  MethodNotAllowedHandler = lambda do |req, res|
+    raise Puppet::Network::HTTP::Error::HTTPMethodNotAllowedError.new("method #{req.method} not allowed for route #{req.path}", Puppet::Network::HTTP::Issues::UNSUPPORTED_METHOD)
+  end
+
+  NO_HANDLERS = [MethodNotAllowedHandler]
+
+  attr_reader :path_matcher
+
+  def self.path(path_matcher)
+    new(path_matcher)
+  end
+
+  def initialize(path_matcher)
+    @path_matcher = path_matcher
+    @method_handlers = {
+      :GET => NO_HANDLERS,
+      :HEAD => NO_HANDLERS,
+      :OPTIONS => NO_HANDLERS,
+      :POST => NO_HANDLERS,
+      :PUT => NO_HANDLERS,
+      :DELETE => NO_HANDLERS
+    }
+    @chained = []
+  end
+
+  def get(*handlers)
+    @method_handlers[:GET] = handlers
+    return self
+  end
+
+  def head(*handlers)
+    @method_handlers[:HEAD] = handlers
+    return self
+  end
+
+  def options(*handlers)
+    @method_handlers[:OPTIONS] = handlers
+    return self
+  end
+
+  def post(*handlers)
+    @method_handlers[:POST] = handlers
+    return self
+  end
+
+  def put(*handlers)
+    @method_handlers[:PUT] = handlers
+    return self
+  end
+
+  def delete(*handlers)
+    @method_handlers[:DELETE] = handlers
+    return self
+  end
+
+  def any(*handlers)
+    @method_handlers.each do |method, registered_handlers|
+      @method_handlers[method] = handlers
+    end
+    return self
+  end
+
+  def chain(*routes)
+    @chained = routes
+    self
+  end
+
+  def matches?(request)
+    Puppet.debug("Evaluating match for #{self.inspect}")
+    if match(request.routing_path)
+      return true
+    else
+      Puppet.debug("Did not match path (#{request.routing_path.inspect})")
+    end
+    return false
+  end
+
+  def process(request, response)
+    handlers = @method_handlers[request.method.upcase.intern] || NO_HANDLERS
+    handlers.each do |handler|
+      handler.call(request, response)
+    end
+
+    subrequest = request.route_into(match(request.routing_path).to_s)
+    if chained_route = @chained.find { |route| route.matches?(subrequest) }
+      chained_route.process(subrequest, response)
+    end
+  end
+
+  def inspect
+    "Route #{@path_matcher.inspect}"
+  end
+
+  private
+
+  def match(path)
+    @path_matcher.match(path)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/session.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/session.rb
new file mode 100644
index 0000000..21136a1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/session.rb
@@ -0,0 +1,17 @@
+# An HTTP session that references a persistent HTTP connection and
+# an expiration time for the connection.
+#
+# @api private
+#
+class Puppet::Network::HTTP::Session
+  attr_reader :connection
+
+  def initialize(connection, expiration_time)
+    @connection = connection
+    @expiration_time = expiration_time
+  end
+
+  def expired?(now)
+    @expiration_time <= now
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/site.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/site.rb
new file mode 100644
index 0000000..c219e60
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/site.rb
@@ -0,0 +1,39 @@
+# Represents a site to which HTTP connections are made. It is a value
+# object, and is suitable for use in a hash. If two sites are equal,
+# then a persistent connection made to the first site, can be re-used
+# for the second.
+#
+# @api private
+#
+class Puppet::Network::HTTP::Site
+  attr_reader :scheme, :host, :port
+
+  def initialize(scheme, host, port)
+    @scheme = scheme
+    @host = host
+    @port = port.to_i
+  end
+
+  def addr
+    "#{@scheme}://#{@host}:#{@port.to_s}"
+  end
+  alias to_s addr
+
+  def ==(rhs)
+    (@scheme == rhs.scheme) && (@host == rhs.host) && (@port == rhs.port)
+  end
+
+  alias eql? ==
+
+  def hash
+    [@scheme, @host, @port].hash
+  end
+
+  def use_ssl?
+    @scheme == 'https'
+  end
+
+  def move_to(uri)
+    self.class.new(uri.scheme, uri.host, uri.port)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/webrick.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/webrick.rb
new file mode 100644
index 0000000..aa4f383
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/webrick.rb
@@ -0,0 +1,129 @@
+require 'webrick'
+require 'webrick/https'
+require 'puppet/network/http/webrick/rest'
+require 'thread'
+
+require 'puppet/ssl/certificate'
+require 'puppet/ssl/certificate_revocation_list'
+require 'puppet/ssl/configuration'
+
+class Puppet::Network::HTTP::WEBrick
+  CIPHERS = "EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:+CAMELLIA256:+AES256:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA256-SHA:AES256-SHA:CAMELLIA128-SHA:AES128-SHA"
+
+  def initialize
+    @listening = false
+  end
+
+  def listen(address, port)
+    @server = create_server(address, port)
+
+    @server.listeners.each { |l| l.start_immediately = false }
+
+    @server.mount('/', Puppet::Network::HTTP::WEBrickREST)
+
+    raise "WEBrick server is already listening" if @listening
+    @listening = true
+    @thread = Thread.new do
+      @server.start do |sock|
+        timeout = 10.0
+        if ! IO.select([sock],nil,nil,timeout)
+          raise "Client did not send data within %.1f seconds of connecting" % timeout
+        end
+        sock.accept
+        @server.run(sock)
+      end
+    end
+    sleep 0.1 until @server.status == :Running
+  end
+
+  def unlisten
+    raise "WEBrick server is not listening" unless @listening
+    @server.shutdown
+    wait_for_shutdown
+    @server = nil
+    @listening = false
+  end
+
+  def listening?
+    @listening
+  end
+
+  def wait_for_shutdown
+    @thread.join
+  end
+
+  # @api private
+  def create_server(address, port)
+    arguments = {:BindAddress => address, :Port => port, :DoNotReverseLookup => true}
+    arguments.merge!(setup_logger)
+    arguments.merge!(setup_ssl)
+
+    BasicSocket.do_not_reverse_lookup = true
+
+    server = WEBrick::HTTPServer.new(arguments)
+    server.ssl_context.ciphers = CIPHERS
+    server
+  end
+
+  # Configure our http log file.
+  def setup_logger
+    # Make sure the settings are all ready for us.
+    Puppet.settings.use(:main, :ssl, :application)
+
+    if Puppet.run_mode.master?
+      file = Puppet[:masterhttplog]
+    else
+      file = Puppet[:httplog]
+    end
+
+    # open the log manually to prevent file descriptor leak
+    file_io = ::File.open(file, "a+")
+    file_io.sync = true
+    if defined?(Fcntl::FD_CLOEXEC)
+      file_io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
+    end
+
+    args = [file_io]
+    args << WEBrick::Log::DEBUG if Puppet::Util::Log.level == :debug
+
+    logger = WEBrick::Log.new(*args)
+    return :Logger => logger, :AccessLog => [
+      [logger, WEBrick::AccessLog::COMMON_LOG_FORMAT ],
+      [logger, WEBrick::AccessLog::REFERER_LOG_FORMAT ]
+    ]
+  end
+
+  # Add all of the ssl cert information.
+  def setup_ssl
+    results = {}
+
+    # Get the cached copy.  We know it's been generated, too.
+    host = Puppet::SSL::Host.localhost
+
+    raise Puppet::Error, "Could not retrieve certificate for #{host.name} and not running on a valid certificate authority" unless host.certificate
+
+    results[:SSLPrivateKey] = host.key.content
+    results[:SSLCertificate] = host.certificate.content
+    results[:SSLStartImmediately] = true
+    results[:SSLEnable] = true
+    results[:SSLOptions] = OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3
+
+    raise Puppet::Error, "Could not find CA certificate" unless Puppet::SSL::Certificate.indirection.find(Puppet::SSL::CA_NAME)
+
+    results[:SSLCACertificateFile] = ssl_configuration.ca_auth_file
+    results[:SSLVerifyClient] = OpenSSL::SSL::VERIFY_PEER
+
+    results[:SSLCertificateStore] = host.ssl_store
+
+    results
+  end
+
+  private
+
+  def ssl_configuration
+    @ssl_configuration ||= Puppet::SSL::Configuration.new(
+      Puppet[:localcacert],
+      :ca_chain_file => Puppet[:ssl_server_ca_chain],
+      :ca_auth_file  => Puppet[:ssl_server_ca_auth])
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/webrick/rest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/webrick/rest.rb
new file mode 100644
index 0000000..1cad768
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http/webrick/rest.rb
@@ -0,0 +1,107 @@
+require 'puppet/network/http/handler'
+require 'resolv'
+require 'webrick'
+require 'puppet/util/ssl'
+
+class Puppet::Network::HTTP::WEBrickREST < WEBrick::HTTPServlet::AbstractServlet
+
+  include Puppet::Network::HTTP::Handler
+
+  def self.mutex
+    @mutex ||= Mutex.new
+  end
+
+  def initialize(server)
+    raise ArgumentError, "server is required" unless server
+    register([Puppet::Network::HTTP::API::V2.routes, Puppet::Network::HTTP::API::V1.routes])
+    super(server)
+  end
+
+  # Retrieve the request parameters, including authentication information.
+  def params(request)
+    params = request.query || {}
+
+    params = Hash[params.collect do |key, value|
+      all_values = value.list
+      [key, all_values.length == 1 ? value : all_values]
+    end]
+
+    params = decode_params(params)
+    params.merge(client_information(request))
+  end
+
+  # WEBrick uses a service method to respond to requests.  Simply delegate to
+  # the handler response method.
+  def service(request, response)
+    self.class.mutex.synchronize do
+      process(request, response)
+    end
+  end
+
+  def headers(request)
+    result = {}
+    request.each do |k, v|
+      result[k.downcase] = v
+    end
+    result
+  end
+
+  def http_method(request)
+    request.request_method
+  end
+
+  def path(request)
+    request.path
+  end
+
+  def body(request)
+    request.body
+  end
+
+  def client_cert(request)
+    if cert = request.client_cert
+      cert = Puppet::SSL::Certificate.from_instance(cert)
+      warn_if_near_expiration(cert)
+      cert
+    else
+      nil
+    end
+  end
+
+  # Set the specified format as the content type of the response.
+  def set_content_type(response, format)
+    response["content-type"] = format_to_mime(format)
+  end
+
+  def set_response(response, result, status = 200)
+    response.status = status
+    if status >= 200 and status != 304
+      response.body = result
+      response["content-length"] = result.stat.size if result.is_a?(File)
+    end
+    if RUBY_VERSION[0,3] == "1.8"
+      response["connection"] = 'close'
+    end
+  end
+
+  # Retrieve node/cert/ip information from the request object.
+  def client_information(request)
+    result = {}
+    if peer = request.peeraddr and ip = peer[3]
+      result[:ip] = ip
+    end
+
+    # If they have a certificate (which will almost always be true)
+    # then we get the hostname from the cert, instead of via IP
+    # info
+    result[:authenticated] = false
+    if cert = request.client_cert and cn = Puppet::Util::SSL.cn_from_subject(cert.subject)
+      result[:node] = cn
+      result[:authenticated] = true
+    else
+      result[:node] = resolve_node(result)
+    end
+
+    result
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http_pool.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http_pool.rb
new file mode 100644
index 0000000..5bab380
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/http_pool.rb
@@ -0,0 +1,61 @@
+require 'puppet/network/http/connection'
+
+module Puppet::Network; end
+
+# This module contains the factory methods that should be used for getting a
+# {Puppet::Network::HTTP::Connection} instance. The pool may return a new
+# connection or a persistent cached connection, depending on the underlying
+# pool implementation in use.
+#
+# @api public
+#
+module Puppet::Network::HttpPool
+
+  @http_client_class = Puppet::Network::HTTP::Connection
+
+  def self.http_client_class
+    @http_client_class
+  end
+  def self.http_client_class=(klass)
+    @http_client_class = klass
+  end
+
+  # Retrieve a connection for the given host and port.
+  #
+  # @param host [String] The hostname to connect to
+  # @param port [Integer] The port on the host to connect to
+  # @param use_ssl [Boolean] Whether to use an SSL connection
+  # @param verify_peer [Boolean] Whether to verify the peer credentials, if possible. Verification will not take place if the CA certificate is missing.
+  # @return [Puppet::Network::HTTP::Connection]
+  #
+  # @api public
+  #
+  def self.http_instance(host, port, use_ssl = true, verify_peer = true)
+    verifier = if verify_peer
+                 Puppet::SSL::Validator.default_validator()
+               else
+                 Puppet::SSL::Validator.no_validator()
+               end
+
+    http_client_class.new(host, port,
+                            :use_ssl => use_ssl,
+                            :verify => verifier)
+  end
+
+  # Get an http connection that will be secured with SSL and have the
+  # connection verified with the given verifier
+  #
+  # @param host [String] the DNS name to connect to
+  # @param port [Integer] the port to connect to
+  # @param verifier [#setup_connection, #peer_certs, #verify_errors] An object that will setup the appropriate
+  #   verification on a Net::HTTP instance and report any errors and the certificates used.
+  # @return [Puppet::Network::HTTP::Connection]
+  #
+  # @api public
+  #
+  def self.http_ssl_instance(host, port, verifier = Puppet::SSL::Validator.default_validator())
+    http_client_class.new(host, port,
+                            :use_ssl => true,
+                            :verify => verifier)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/resolver.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/resolver.rb
new file mode 100644
index 0000000..98554eb
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/resolver.rb
@@ -0,0 +1,86 @@
+require 'resolv'
+module Puppet::Network; end
+
+module Puppet::Network::Resolver
+  # Iterate through the list of servers that service this hostname
+  # and yield each server/port since SRV records have ports in them
+  # It will override whatever masterport setting is already set.
+  def self.each_srv_record(domain, service_name = :puppet, &block)
+    if (domain.nil? or domain.empty?)
+      Puppet.debug "Domain not known; skipping SRV lookup"
+      return
+    end
+
+    Puppet.debug "Searching for SRV records for domain: #{domain}"
+
+    case service_name
+      when :puppet then service = '_x-puppet'
+      when :ca     then service = '_x-puppet-ca'
+      when :report then service = '_x-puppet-report'
+      when :file   then service = '_x-puppet-fileserver'
+      else              service = "_x-puppet-#{service_name.to_s}"
+    end
+    srv_record = "#{service}._tcp.#{domain}"
+
+    resolver = Resolv::DNS.new
+    records = resolver.getresources(srv_record, Resolv::DNS::Resource::IN::SRV)
+    Puppet.debug "Found #{records.size} SRV records for: #{srv_record}"
+
+    if records.size == 0 && service_name != :puppet
+      # Try the generic :puppet service if no SRV records were found
+      # for the specific service.
+      each_srv_record(domain, :puppet, &block)
+    else
+      each_priority(records) do |priority, records|
+        while next_rr = records.delete(find_weighted_server(records))
+          Puppet.debug "Yielding next server of #{next_rr.target.to_s}:#{next_rr.port}"
+          yield next_rr.target.to_s, next_rr.port
+        end
+      end
+    end
+  end
+
+  private
+
+  def self.each_priority(records)
+    pri_hash = records.inject({}) do |groups, element|
+      groups[element.priority] ||= []
+      groups[element.priority] << element
+      groups
+    end
+
+    pri_hash.keys.sort.each do |key|
+      yield key, pri_hash[key]
+    end
+  end
+
+  def self.find_weighted_server(records)
+    return nil if records.nil? || records.empty?
+    return records.first if records.size == 1
+
+    # Calculate the sum of all weights in the list of resource records,
+    # This is used to then select hosts until the weight exceeds what
+    # random number we selected.  For example, if we have weights of 1 8 and 3:
+    #
+    # |-|---|--------|
+    #        ^
+    # We generate a random number 5, and iterate through the records, adding
+    # the current record's weight to the accumulator until the weight of the
+    # current record plus previous records is greater than the random number.
+
+    total_weight = records.inject(0) { |sum,record|
+      sum + weight(record)
+    }
+    current_weight = 0
+    chosen_weight  = 1 + Kernel.rand(total_weight)
+
+    records.each do |record|
+      current_weight += weight(record)
+      return record if current_weight >= chosen_weight
+    end
+  end
+
+  def self.weight(record)
+    record.weight == 0 ? 1 : record.weight * 10
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/rest_controller.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/rest_controller.rb
new file mode 100644
index 0000000..76a9830
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/rest_controller.rb
@@ -0,0 +1,2 @@
+class Puppet::Network::RESTController # :nodoc:
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/rights.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/rights.rb
new file mode 100644
index 0000000..d7275ba
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/rights.rb
@@ -0,0 +1,219 @@
+require 'puppet/network/authstore'
+require 'puppet/error'
+
+module Puppet::Network
+
+# this exception is thrown when a request is not authenticated
+class AuthorizationError < Puppet::Error; end
+
+# Rights class manages a list of ACLs for paths.
+class Rights
+  # Check that name is allowed or not
+  def allowed?(name, *args)
+    !is_forbidden_and_why?(name, :node => args[0], :ip => args[1])
+  end
+
+  def is_request_forbidden_and_why?(method, path, params)
+    methods_to_check = if method == :head
+                         # :head is ok if either :find or :save is ok.
+                         [:find, :save]
+                       else
+                         [method]
+                       end
+    authorization_failure_exceptions = methods_to_check.map do |method|
+      is_forbidden_and_why?(path, params.merge({:method => method}))
+    end
+    if authorization_failure_exceptions.include? nil
+      # One of the methods we checked is ok, therefore this request is ok.
+      nil
+    else
+      # Just need to return any of the failure exceptions.
+      authorization_failure_exceptions.first
+    end
+  end
+
+  def is_forbidden_and_why?(name, args = {})
+    res = :nomatch
+    right = @rights.find do |acl|
+      found = false
+      # an acl can return :dunno, which means "I'm not qualified to answer your question,
+      # please ask someone else". This is used when for instance an acl matches, but not for the
+      # current rest method, where we might think some other acl might be more specific.
+      if match = acl.match?(name)
+        args[:match] = match
+        if (res = acl.allowed?(args[:node], args[:ip], args)) != :dunno
+          # return early if we're allowed
+          return nil if res
+          # we matched, select this acl
+          found = true
+        end
+      end
+      found
+    end
+
+    # if we end up here, then that means we either didn't match or failed, in any
+    # case will return an error to the outside world
+    host_description = args[:node] ? "#{args[:node]}(#{args[:ip]})" : args[:ip]
+
+    msg = "#{host_description} access to #{name} [#{args[:method]}]"
+
+    if args[:authenticated]
+      msg += " authenticated "
+    end
+
+    if right
+      msg += " at #{right.file}:#{right.line}"
+    end
+
+    AuthorizationError.new("Forbidden request: #{msg}")
+  end
+
+  def initialize
+    @rights = []
+  end
+
+  def [](name)
+    @rights.find { |acl| acl == name }
+  end
+
+  def empty?
+    @rights.empty?
+  end
+
+  def include?(name)
+    @rights.include?(name)
+  end
+
+  def each
+    @rights.each { |r| yield r.name,r }
+  end
+
+  # Define a new right to which access can be provided.
+  def newright(name, line=nil, file=nil)
+    add_right( Right.new(name, line, file) )
+  end
+
+  private
+
+  def add_right(right)
+    @rights << right
+    right
+  end
+
+  # Retrieve a right by name.
+  def right(name)
+    self[name]
+  end
+
+  # A right.
+  class Right < Puppet::Network::AuthStore
+    attr_accessor :name, :key
+    # Overriding Object#methods sucks for debugging. If we're in here in the
+    # future, it would be nice to rename Right#methods
+    attr_accessor :methods, :environment, :authentication
+    attr_accessor :line, :file
+
+    ALL = [:save, :destroy, :find, :search]
+
+    Puppet::Util.logmethods(self, true)
+
+    def initialize(name, line, file)
+      @methods = []
+      @environment = []
+      @authentication = true # defaults to authenticated
+      @name = name
+      @line = line || 0
+      @file = file
+      @methods = ALL
+
+      case name
+      when /^\//
+        @key = Regexp.new("^" + Regexp.escape(name))
+      when /^~/ # this is a regex
+        @name = name.gsub(/^~\s+/,'')
+        @key = Regexp.new(@name)
+      else
+        raise ArgumentError, "Unknown right type '#{name}'"
+      end
+
+      super()
+    end
+
+    def to_s
+      "access[#{@name}]"
+    end
+
+    # There's no real check to do at this point
+    def valid?
+      true
+    end
+
+    # does this right is allowed for this triplet?
+    # if this right is too restrictive (ie we don't match this access method)
+    # then return :dunno so that upper layers have a chance to try another right
+    # tailored to the given method
+    def allowed?(name, ip, args = {})
+      if not @methods.include?(args[:method])
+        return :dunno
+      elsif @environment.size > 0 and not @environment.include?(args[:environment])
+        return :dunno
+      elsif (@authentication and not args[:authenticated])
+        return :dunno
+      end
+
+      begin
+        # make sure any capture are replaced if needed
+        interpolate(args[:match]) if args[:match]
+        res = super(name,ip)
+      ensure
+        reset_interpolation
+      end
+      res
+    end
+
+    # restrict this right to some method only
+    def restrict_method(m)
+      m = m.intern if m.is_a?(String)
+
+      raise ArgumentError, "'#{m}' is not an allowed value for method directive" unless ALL.include?(m)
+
+      # if we were allowing all methods, then starts from scratch
+      if @methods === ALL
+        @methods = []
+      end
+
+      raise ArgumentError, "'#{m}' is already in the '#{name}' ACL" if @methods.include?(m)
+
+      @methods << m
+    end
+
+    def restrict_environment(environment)
+      env = Puppet.lookup(:environments).get(environment)
+      raise ArgumentError, "'#{env}' is already in the '#{name}' ACL" if @environment.include?(env)
+
+      @environment << env
+    end
+
+    def restrict_authenticated(authentication)
+      case authentication
+      when "yes", "on", "true", true
+        authentication = true
+      when "no", "off", "false", false, "all" ,"any", :all, :any
+        authentication = false
+      else
+        raise ArgumentError, "'#{name}' incorrect authenticated value: #{authentication}"
+      end
+      @authentication = authentication
+    end
+
+    def match?(key)
+      # otherwise match with the regex
+      self.key.match(key)
+    end
+
+    def ==(name)
+      self.name == name.gsub(/^~\s+/,'')
+    end
+  end
+end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/server.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/server.rb
new file mode 100644
index 0000000..a5cd1c7
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/network/server.rb
@@ -0,0 +1,39 @@
+require 'puppet/network/http'
+require 'puppet/network/http/webrick'
+
+#
+# @api private
+class Puppet::Network::Server
+  attr_reader :address, :port
+
+  def initialize(address, port)
+    @port = port
+    @address = address
+    @http_server = Puppet::Network::HTTP::WEBrick.new
+
+    @listening = false
+
+    # Make sure we have all of the directories we need to function.
+    Puppet.settings.use(:main, :ssl, :application)
+  end
+
+  def listening?
+    @listening
+  end
+
+  def start
+    raise "Cannot listen -- already listening." if listening?
+    @listening = true
+    @http_server.listen(address, port)
+  end
+
+  def stop
+    raise "Cannot unlisten -- not currently listening." unless listening?
+    @http_server.unlisten
+    @listening = false
+  end
+
+  def wait_for_shutdown
+    @http_server.wait_for_shutdown
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/node.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/node.rb
new file mode 100644
index 0000000..8e849b1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/node.rb
@@ -0,0 +1,193 @@
+require 'puppet/indirector'
+
+# A class for managing nodes, including their facts and environment.
+class Puppet::Node
+  require 'puppet/node/facts'
+  require 'puppet/node/environment'
+
+  # Set up indirection, so that nodes can be looked for in
+  # the node sources.
+  extend Puppet::Indirector
+
+  # Use the node source as the indirection terminus.
+  indirects :node, :terminus_setting => :node_terminus, :doc => "Where to find node information.
+    A node is composed of its name, its facts, and its environment."
+
+  attr_accessor :name, :classes, :source, :ipaddress, :parameters, :trusted_data, :environment_name
+  attr_reader :time, :facts
+
+  ::PSON.register_document_type('Node',self)
+
+  ENVIRONMENT = 'environment'.freeze
+
+  def self.from_data_hash(data)
+    raise ArgumentError, "No name provided in serialized data" unless name = data['name']
+
+    node = new(name)
+    node.classes = data['classes']
+    node.parameters = data['parameters']
+    node.environment_name = data['environment']
+    node
+  end
+
+  def self.from_pson(pson)
+    Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
+    self.from_data_hash(pson)
+  end
+
+  def to_data_hash
+    result = {
+      'name' => name,
+      'environment' => environment.name,
+    }
+    result['classes'] = classes unless classes.empty?
+    result['parameters'] = parameters unless parameters.empty?
+    result
+  end
+
+  def to_pson_data_hash(*args)
+    {
+      'document_type' => "Node",
+      'data' =>  to_data_hash,
+    }
+  end
+
+  def to_pson(*args)
+    to_pson_data_hash.to_pson(*args)
+  end
+
+  def environment
+    if @environment
+      @environment
+    else
+      if env = parameters[ENVIRONMENT]
+        self.environment = env
+      elsif environment_name
+        self.environment = environment_name
+      else
+        # This should not be :current_environment, this is the default
+        # for a node when it has not specified its environment
+        # Tt will be used to establish what the current environment is.
+        #
+        self.environment = Puppet.lookup(:environments).get!(Puppet[:environment])
+      end
+
+      @environment
+    end
+  end
+
+  def environment=(env)
+    if env.is_a?(String) or env.is_a?(Symbol)
+      @environment = Puppet.lookup(:environments).get!(env)
+    else
+      @environment = env
+    end
+
+    # Keep environment_name attribute and parameter in sync if they have been set
+    unless @environment.nil?
+      @parameters[ENVIRONMENT] = @environment.name if @parameters.include?(ENVIRONMENT)
+      self.environment_name = @environment.name if instance_variable_defined?(:@environment_name)
+    end
+    @environment
+  end
+
+  def has_environment_instance?
+    !@environment.nil?
+  end
+
+  def initialize(name, options = {})
+    raise ArgumentError, "Node names cannot be nil" unless name
+    @name = name
+
+    if classes = options[:classes]
+      if classes.is_a?(String)
+        @classes = [classes]
+      else
+        @classes = classes
+      end
+    else
+      @classes = []
+    end
+
+    @parameters = options[:parameters] || {}
+
+    @facts = options[:facts]
+
+    if env = options[:environment]
+      self.environment = env
+    end
+
+    @time = Time.now
+  end
+
+  # Merge the node facts with parameters from the node source.
+  def fact_merge
+    if @facts = Puppet::Node::Facts.indirection.find(name, :environment => environment)
+      @facts.sanitize
+      merge(@facts.values)
+    end
+  rescue => detail
+    error = Puppet::Error.new("Could not retrieve facts for #{name}: #{detail}")
+    error.set_backtrace(detail.backtrace)
+    raise error
+  end
+
+  # Merge any random parameters into our parameter list.
+  def merge(params)
+    params.each do |name, value|
+      @parameters[name] = value unless @parameters.include?(name)
+    end
+
+    @parameters[ENVIRONMENT] ||= self.environment.name.to_s
+  end
+
+  # Calculate the list of names we might use for looking
+  # up our node.  This is only used for AST nodes.
+  def names
+    return [name] if Puppet.settings[:strict_hostname_checking]
+
+    names = []
+
+    names += split_name(name) if name.include?(".")
+
+    # First, get the fqdn
+    unless fqdn = parameters["fqdn"]
+      if parameters["hostname"] and parameters["domain"]
+        fqdn = parameters["hostname"] + "." + parameters["domain"]
+      else
+        Puppet.warning "Host is missing hostname and/or domain: #{name}"
+      end
+    end
+
+    # Now that we (might) have the fqdn, add each piece to the name
+    # list to search, in order of longest to shortest.
+    names += split_name(fqdn) if fqdn
+
+    # And make sure the node name is first, since that's the most
+    # likely usage.
+    #   The name is usually the Certificate CN, but it can be
+    # set to the 'facter' hostname instead.
+    if Puppet[:node_name] == 'cert'
+      names.unshift name
+    else
+      names.unshift parameters["hostname"]
+    end
+    names.uniq
+  end
+
+  def split_name(name)
+    list = name.split(".")
+    tmp = []
+    list.each_with_index do |short, i|
+      tmp << list[0..i].join(".")
+    end
+    tmp.reverse
+  end
+
+  # Ensures the data is frozen
+  #
+  def trusted_data=(data)
+    Puppet.warning("Trusted node data modified for node #{name}") unless @trusted_data.nil?
+    @trusted_data = data.freeze
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/node/environment.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/node/environment.rb
new file mode 100644
index 0000000..41be6c8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/node/environment.rb
@@ -0,0 +1,608 @@
+require 'puppet/util'
+require 'puppet/util/cacher'
+require 'monitor'
+require 'puppet/parser/parser_factory'
+
+# Just define it, so this class has fewer load dependencies.
+class Puppet::Node
+end
+
+# Puppet::Node::Environment acts as a container for all configuration
+# that is expected to vary between environments.
+#
+# ## The root environment
+#
+# In addition to normal environments that are defined by the user,there is a
+# special 'root' environment. It is defined as an instance variable on the
+# Puppet::Node::Environment metaclass. The environment name is `*root*` and can
+# be accessed by looking up the `:root_environment` using {Puppet.lookup}.
+#
+# The primary purpose of the root environment is to contain parser functions
+# that are not bound to a specific environment. The main case for this is for
+# logging functions. Logging functions are attached to the 'root' environment
+# when {Puppet::Parser::Functions.reset} is called.
+class Puppet::Node::Environment
+  include Puppet::Util::Cacher
+
+  NO_MANIFEST = :no_manifest
+
+  # @api private
+  def self.seen
+    @seen ||= {}
+  end
+
+  # Create a new environment with the given name, or return an existing one
+  #
+  # The environment class memoizes instances so that attempts to instantiate an
+  # environment with the same name with an existing environment will return the
+  # existing environment.
+  #
+  # @overload self.new(environment)
+  #   @param environment [Puppet::Node::Environment]
+  #   @return [Puppet::Node::Environment] the environment passed as the param,
+  #     this is implemented so that a calling class can use strings or
+  #     environments interchangeably.
+  #
+  # @overload self.new(string)
+  #   @param string [String, Symbol]
+  #   @return [Puppet::Node::Environment] An existing environment if it exists,
+  #     else a new environment with that name
+  #
+  # @overload self.new()
+  #   @return [Puppet::Node::Environment] The environment as set by
+  #     Puppet.settings[:environment]
+  #
+  # @api public
+  def self.new(name = nil)
+    return name if name.is_a?(self)
+    name ||= Puppet.settings.value(:environment)
+
+    raise ArgumentError, "Environment name must be specified" unless name
+
+    symbol = name.to_sym
+
+    return seen[symbol] if seen[symbol]
+
+    obj = self.create(symbol,
+             split_path(Puppet.settings.value(:modulepath, symbol)),
+             Puppet.settings.value(:manifest, symbol),
+             Puppet.settings.value(:config_version, symbol))
+    seen[symbol] = obj
+  end
+
+  # Create a new environment with the given name
+  #
+  # @param name [Symbol] the name of the
+  # @param modulepath [Array<String>] the list of paths from which to load modules
+  # @param manifest [String] the path to the manifest for the environment or
+  # the constant Puppet::Node::Environment::NO_MANIFEST if there is none.
+  # @param config_version [String] path to a script whose output will be added
+  #   to report logs (optional)
+  # @return [Puppet::Node::Environment]
+  #
+  # @api public
+  def self.create(name, modulepath, manifest = NO_MANIFEST, config_version = nil)
+    obj = self.allocate
+    obj.send(:initialize,
+             name,
+             expand_dirs(extralibs() + modulepath),
+             manifest == NO_MANIFEST ? manifest : File.expand_path(manifest),
+             config_version)
+    obj
+  end
+
+  # A "reference" to a remote environment. The created environment instance
+  # isn't expected to exist on the local system, but is instead a reference to
+  # environment information on a remote system. For instance when a catalog is
+  # being applied, this will be used on the agent.
+  #
+  # @note This does not provide access to the information of the remote
+  # environment's modules, manifest, or anything else. It is simply a value
+  # object to pass around and use as an environment.
+  #
+  # @param name [Symbol] The name of the remote environment
+  #
+  def self.remote(name)
+    create(name, [], NO_MANIFEST)
+  end
+
+  # Instantiate a new environment
+  #
+  # @note {Puppet::Node::Environment.new} is overridden to return memoized
+  #   objects, so this will not be invoked with the normal Ruby initialization
+  #   semantics.
+  #
+  # @param name [Symbol] The environment name
+  def initialize(name, modulepath, manifest, config_version)
+    @name = name
+    @modulepath = modulepath
+    @manifest = manifest
+    @config_version = config_version
+    # set watching to true for legacy environments - the directory based environment loaders will set this to
+    # false for directory based environments after the environment has been created.
+    @watching = true
+  end
+
+  # Returns if files are being watched or not.
+  # @api private
+  #
+  def watching?
+    @watching
+  end
+
+  # Turns watching of files on or off
+  # @param flag [TrueClass, FalseClass] if files should be watched or not
+  # @ api private
+  def watching=(flag)
+    @watching = flag
+  end
+
+  # Creates a new Puppet::Node::Environment instance, overriding any of the passed
+  # parameters.
+  #
+  # @param env_params [Hash<{Symbol => String,Array<String>}>] new environment
+  #   parameters (:modulepath, :manifest, :config_version)
+  # @return [Puppet::Node::Environment]
+  def override_with(env_params)
+    return self.class.create(name,
+                      env_params[:modulepath] || modulepath,
+                      env_params[:manifest] || manifest,
+                      env_params[:config_version] || config_version)
+  end
+
+  # Creates a new Puppet::Node::Environment instance, overriding manfiest
+  # modulepath, or :config_version from the passed settings if they were
+  # originally set from the commandline, or returns self if there is nothing to
+  # override.
+  #
+  # @param settings [Puppet::Settings] an initialized puppet settings instance
+  # @return [Puppet::Node::Environment] new overridden environment or self if
+  #   there are no commandline changes from settings.
+  def override_from_commandline(settings)
+    overrides = {}
+
+    if settings.set_by_cli?(:modulepath)
+      overrides[:modulepath] = self.class.split_path(settings.value(:modulepath))
+    end
+
+    if settings.set_by_cli?(:config_version)
+      overrides[:config_version] = settings.value(:config_version)
+    end
+
+    if settings.set_by_cli?(:manifest) ||
+      (settings.set_by_cli?(:manifestdir) && settings.value(:manifest).start_with?(settings.value(:manifestdir)))
+      overrides[:manifest] = settings.value(:manifest)
+    end
+
+    overrides.empty? ?
+      self :
+      self.override_with(overrides)
+  end
+
+  # Retrieve the environment for the current process.
+  #
+  # @note This should only used when a catalog is being compiled.
+  #
+  # @api private
+  #
+  # @return [Puppet::Node::Environment] the currently set environment if one
+  #   has been explicitly set, else it will return the '*root*' environment
+  def self.current
+    Puppet.deprecation_warning("Puppet::Node::Environment.current has been replaced by Puppet.lookup(:current_environment), see http://links.puppetlabs.com/current-env-deprecation")
+    Puppet.lookup(:current_environment)
+  end
+
+  # @param [String] name Environment name to check for valid syntax.
+  # @return [Boolean] true if name is valid
+  # @api public
+  def self.valid_name?(name)
+    !!name.match(/\A\w+\Z/)
+  end
+
+  # Clear all memoized environments and the 'current' environment
+  #
+  # @api private
+  def self.clear
+    seen.clear
+  end
+
+  # @!attribute [r] name
+  #   @api public
+  #   @return [Symbol] the human readable environment name that serves as the
+  #     environment identifier
+  attr_reader :name
+
+  # @api public
+  # @return [Array<String>] All directories present on disk in the modulepath
+  def modulepath
+    @modulepath.find_all do |p|
+      Puppet::FileSystem.directory?(p)
+    end
+  end
+
+  # @api public
+  # @return [Array<String>] All directories in the modulepath (even if they are not present on disk)
+  def full_modulepath
+    @modulepath
+  end
+
+  # @!attribute [r] manifest
+  #   @api public
+  #   @return [String] path to the manifest file or directory.
+  attr_reader :manifest
+
+  # @!attribute [r] config_version
+  #   @api public
+  #   @return [String] path to a script whose output will be added to report logs
+  #     (optional)
+  attr_reader :config_version
+
+  # Checks to make sure that this environment did not have a manifest set in
+  # its original environment.conf if Puppet is configured with
+  # +disable_per_environment_manifest+ set true.  If it did, the environment's
+  # modules may not function as intended by the original authors, and we may
+  # seek to halt a puppet compilation for a node in this environment.
+  #
+  # The only exception to this would be if the environment.conf manifest is an exact,
+  # uninterpolated match for the current +default_manifest+ setting.
+  #
+  # @return [Boolean] true if using directory environments, and
+  #   Puppet[:disable_per_environment_manifest] is true, and this environment's
+  #   original environment.conf had a manifest setting that is not the
+  #   Puppet[:default_manifest].
+  # @api public
+  def conflicting_manifest_settings?
+    return false if Puppet[:environmentpath].empty? || !Puppet[:disable_per_environment_manifest]
+    environment_conf = Puppet.lookup(:environments).get_conf(name)
+    original_manifest = environment_conf.raw_setting(:manifest)
+    !original_manifest.nil? && !original_manifest.empty? && original_manifest != Puppet[:default_manifest]
+  end
+
+  # @api private
+  def future_parser?
+    if @future_parser.nil?
+      environment_conf = Puppet.lookup(:environments).get_conf(name)
+      @future_parser = 'future' == (environment_conf.nil? ? Puppet[:parser] : environment_conf.parser)
+    end
+    @future_parser
+  end
+
+  # Return an environment-specific Puppet setting.
+  #
+  # @api public
+  #
+  # @param param [String, Symbol] The environment setting to look up
+  # @return [Object] The resolved setting value
+  def [](param)
+    Puppet.settings.value(param, self.name)
+  end
+
+  # @api public
+  # @return [Puppet::Resource::TypeCollection] The current global TypeCollection
+  def known_resource_types
+    if @known_resource_types.nil?
+      @known_resource_types = Puppet::Resource::TypeCollection.new(self)
+      @known_resource_types.import_ast(perform_initial_import(), '')
+    end
+    @known_resource_types
+  end
+
+  # Yields each modules' plugin directory if the plugin directory (modulename/lib)
+  # is present on the filesystem.
+  #
+  # @yield [String] Yields the plugin directory from each module to the block.
+  # @api public
+  def each_plugin_directory(&block)
+    modules.map(&:plugin_directory).each do |lib|
+      lib = Puppet::Util::Autoload.cleanpath(lib)
+      yield lib if File.directory?(lib)
+    end
+  end
+
+  # Locate a module instance by the module name alone.
+  #
+  # @api public
+  #
+  # @param name [String] The module name
+  # @return [Puppet::Module, nil] The module if found, else nil
+  def module(name)
+    modules.find {|mod| mod.name == name}
+  end
+
+  # Locate a module instance by the full forge name (EG authorname/module)
+  #
+  # @api public
+  #
+  # @param forge_name [String] The module name
+  # @return [Puppet::Module, nil] The module if found, else nil
+  def module_by_forge_name(forge_name)
+    author, modname = forge_name.split('/')
+    found_mod = self.module(modname)
+    found_mod and found_mod.forge_name == forge_name ?
+      found_mod :
+      nil
+  end
+
+  # @!attribute [r] modules
+  #   Return all modules for this environment in the order they appear in the
+  #   modulepath.
+  #   @note If multiple modules with the same name are present they will
+  #     both be added, but methods like {#module} and {#module_by_forge_name}
+  #     will return the first matching entry in this list.
+  #   @note This value is cached so that the filesystem doesn't have to be
+  #     re-enumerated every time this method is invoked, since that
+  #     enumeration could be a costly operation and this method is called
+  #     frequently. The cache expiry is determined by `Puppet[:filetimeout]`.
+  #   @see Puppet::Util::Cacher.cached_attr
+  #   @api public
+  #   @return [Array<Puppet::Module>] All modules for this environment
+  cached_attr(:modules, Puppet[:filetimeout]) do
+    module_references = []
+    seen_modules = {}
+    modulepath.each do |path|
+      Dir.entries(path).each do |name|
+        warn_about_mistaken_path(path, name)
+        next if module_references.include?(name)
+        if not seen_modules[name]
+          module_references << {:name => name, :path => File.join(path, name)}
+          seen_modules[name] = true
+        end
+      end
+    end
+
+    module_references.collect do |reference|
+      begin
+        Puppet::Module.new(reference[:name], reference[:path], self)
+      rescue Puppet::Module::Error
+        nil
+      end
+    end.compact
+  end
+
+  # Generate a warning if the given directory in a module path entry is named `lib`.
+  #
+  # @api private
+  #
+  # @param path [String] The module directory containing the given directory
+  # @param name [String] The directory name
+  def warn_about_mistaken_path(path, name)
+    if name == "lib"
+      Puppet.debug("Warning: Found directory named 'lib' in module path ('#{path}/lib'); unless " +
+          "you are expecting to load a module named 'lib', your module path may be set " +
+          "incorrectly.")
+    end
+  end
+
+  # Modules broken out by directory in the modulepath
+  #
+  # @note This method _changes_ the current working directory while enumerating
+  #   the modules. This seems rather dangerous.
+  #
+  # @api public
+  #
+  # @return [Hash<String, Array<Puppet::Module>>] A hash whose keys are file
+  #   paths, and whose values is an array of Puppet Modules for that path
+  def modules_by_path
+    modules_by_path = {}
+    modulepath.each do |path|
+      Dir.chdir(path) do
+        module_names = Dir.glob('*').select do |d|
+          FileTest.directory?(d) && (File.basename(d) =~ /\A\w+(-\w+)*\Z/)
+        end
+        modules_by_path[path] = module_names.sort.map do |name|
+          Puppet::Module.new(name, File.join(path, name), self)
+        end
+      end
+    end
+    modules_by_path
+  end
+
+  # All module requirements for all modules in the environment modulepath
+  #
+  # @api public
+  #
+  # @comment This has nothing to do with an environment. It seems like it was
+  #   stuffed into the first convenient class that vaguely involved modules.
+  #
+  # @example
+  #   environment.module_requirements
+  #   # => {
+  #   #   'username/amodule' => [
+  #   #     {
+  #   #       'name'    => 'username/moduledep',
+  #   #       'version' => '1.2.3',
+  #   #       'version_requirement' => '>= 1.0.0',
+  #   #     },
+  #   #     {
+  #   #       'name'    => 'username/anotherdep',
+  #   #       'version' => '4.5.6',
+  #   #       'version_requirement' => '>= 3.0.0',
+  #   #     }
+  #   #   ]
+  #   # }
+  #   #
+  #
+  # @return [Hash<String, Array<Hash<String, String>>>] See the method example
+  #   for an explanation of the return value.
+  def module_requirements
+    deps = {}
+
+    modules.each do |mod|
+      next unless mod.forge_name
+      deps[mod.forge_name] ||= []
+
+      mod.dependencies and mod.dependencies.each do |mod_dep|
+        dep_name = mod_dep['name'].tr('-', '/')
+        (deps[dep_name] ||= []) << {
+          'name'                => mod.forge_name,
+          'version'             => mod.version,
+          'version_requirement' => mod_dep['version_requirement']
+        }
+      end
+    end
+
+    deps.each do |mod, mod_deps|
+      deps[mod] = mod_deps.sort_by { |d| d['name'] }
+    end
+
+    deps
+  end
+
+  # Set a periodic watcher on the file, so we can tell if it has changed.
+  # If watching has been turned off, this call has no effect.
+  # @param file[File,String] File instance or filename
+  # @api private
+  def watch_file(file)
+    if watching?
+      known_resource_types.watch_file(file.to_s)
+    end
+  end
+
+  # Checks if a reparse is required (cache of files is stale).
+  # This call does nothing unless files are being watched.
+  #
+  def check_for_reparse
+    if (Puppet[:code] != @parsed_code) || (watching? && @known_resource_types && @known_resource_types.require_reparse?)
+      @parsed_code = nil
+      @known_resource_types = nil
+    end
+  end
+
+  # @return [String] The stringified value of the `name` instance variable
+  # @api public
+  def to_s
+    name.to_s
+  end
+
+  # @return [Symbol] The `name` value, cast to a string, then cast to a symbol.
+  #
+  # @api public
+  #
+  # @note the `name` instance variable is a Symbol, but this casts the value
+  #   to a String and then converts it back into a Symbol which will needlessly
+  #   create an object that needs to be garbage collected
+  def to_sym
+    to_s.to_sym
+  end
+
+  # Return only the environment name when serializing.
+  #
+  # The only thing we care about when serializing an environment is its
+  # identity; everything else is ephemeral and should not be stored or
+  # transmitted.
+  #
+  # @api public
+  def to_zaml(z)
+    self.to_s.to_zaml(z)
+  end
+
+  def self.split_path(path_string)
+    path_string.split(File::PATH_SEPARATOR)
+  end
+
+  def ==(other)
+    return true if other.kind_of?(Puppet::Node::Environment) &&
+      self.name == other.name &&
+      self.full_modulepath == other.full_modulepath &&
+      self.manifest == other.manifest
+  end
+
+  alias eql? ==
+
+  def hash
+    [self.class, name, full_modulepath, manifest].hash
+  end
+
+  private
+
+  def self.extralibs()
+    if ENV["PUPPETLIB"]
+      split_path(ENV["PUPPETLIB"])
+    else
+      []
+    end
+  end
+
+  def self.expand_dirs(dirs)
+    dirs.collect do |dir|
+      File.expand_path(dir)
+    end
+  end
+
+  # Reparse the manifests for the given environment
+  #
+  # There are two sources that can be used for the initial parse:
+  #
+  #   1. The value of `Puppet.settings[:code]`: Puppet can take a string from
+  #     its settings and parse that as a manifest. This is used by various
+  #     Puppet applications to read in a manifest and pass it to the
+  #     environment as a side effect. This is attempted first.
+  #   2. The contents of `Puppet.settings[:manifest]`: Puppet will try to load
+  #     the environment manifest. By default this is `$manifestdir/site.pp`
+  #
+  # @note This method will return an empty hostclass if
+  #   `Puppet.settings[:ignoreimport]` is set to true.
+  #
+  # @return [Puppet::Parser::AST::Hostclass] The AST hostclass object
+  #   representing the 'main' hostclass
+  def perform_initial_import
+    return empty_parse_result if Puppet[:ignoreimport]
+    parser = Puppet::Parser::ParserFactory.parser(self)
+    @parsed_code = Puppet[:code]
+    if @parsed_code != ""
+      parser.string = @parsed_code
+      parser.parse
+    else
+      file = self.manifest
+      # if the manifest file is a reference to a directory, parse and combine all .pp files in that
+      # directory
+      if file == NO_MANIFEST
+        Puppet::Parser::AST::Hostclass.new('')
+      elsif File.directory?(file)
+        if Puppet.future_parser?
+          parse_results = Puppet::FileSystem::PathPattern.absolute(File.join(file, '**/*.pp')).glob.sort.map do | file_to_parse |
+            parser.file = file_to_parse
+            parser.parse
+          end
+        else
+          parse_results = Dir.entries(file).find_all { |f| f =~ /\.pp$/ }.sort.map do |file_to_parse|
+            parser.file = File.join(file, file_to_parse)
+            parser.parse
+          end
+        end
+        # Use a parser type specific merger to concatenate the results
+        Puppet::Parser::AST::Hostclass.new('', :code => Puppet::Parser::ParserFactory.code_merger.concatenate(parse_results))
+      else
+        parser.file = file
+        parser.parse
+      end
+    end
+  rescue Puppet::ParseErrorWithIssue => detail
+    @known_resource_types.parse_failed = true
+    detail.environment = self.name
+    raise
+  rescue => detail
+    @known_resource_types.parse_failed = true
+
+    msg = "Could not parse for environment #{self}: #{detail}"
+    error = Puppet::Error.new(msg)
+    error.set_backtrace(detail.backtrace)
+    raise error
+  end
+
+  # Return an empty toplevel hostclass to indicate that no file was loaded
+  #
+  # This is used as the return value of {#perform_initial_import} when
+  # `Puppet.settings[:ignoreimport]` is true.
+  #
+  # @return [Puppet::Parser::AST::Hostclass]
+  def empty_parse_result
+    return Puppet::Parser::AST::Hostclass.new('')
+  end
+
+  # A special "null" environment
+  #
+  # This environment should be used when there is no specific environment in
+  # effect.
+  NONE = create(:none, [])
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/node/facts.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/node/facts.rb
new file mode 100644
index 0000000..be98713
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/node/facts.rb
@@ -0,0 +1,155 @@
+require 'time'
+
+require 'puppet/node'
+require 'puppet/indirector'
+
+require 'puppet/util/pson'
+
+# Manage a given node's facts.  This either accepts facts and stores them, or
+# returns facts for a given node.
+class Puppet::Node::Facts
+  # Set up indirection, so that nodes can be looked for in
+  # the node sources.
+  extend Puppet::Indirector
+  extend Puppet::Util::Pson
+
+  # We want to expire any cached nodes if the facts are saved.
+  module NodeExpirer
+    def save(instance, key = nil, options={})
+      Puppet::Node.indirection.expire(instance.name, options)
+      super
+    end
+  end
+
+  indirects :facts, :terminus_setting => :facts_terminus, :extend => NodeExpirer
+
+  attr_accessor :name, :values
+
+  def add_local_facts
+    values["clientcert"] = Puppet.settings[:certname]
+    values["clientversion"] = Puppet.version.to_s
+    values["clientnoop"] = Puppet.settings[:noop]
+  end
+
+  def initialize(name, values = {})
+    @name = name
+    @values = values
+
+    add_timestamp
+  end
+
+  def initialize_from_hash(data)
+    @name = data['name']
+    @values = data['values']
+    # Timestamp will be here in YAML
+    timestamp = data['values']['_timestamp']
+    @values.delete_if do |key, val|
+      key =~ /^_/
+    end
+
+    #Timestamp will be here in pson
+    timestamp ||= data['timestamp']
+    timestamp = Time.parse(timestamp) if timestamp.is_a? String
+    self.timestamp = timestamp
+
+    self.expiration = data['expiration']
+    if expiration.is_a? String
+      self.expiration = Time.parse(expiration)
+    end
+  end
+
+  # Convert all fact values into strings.
+  def stringify
+    values.each do |fact, value|
+      values[fact] = value.to_s
+    end
+  end
+
+  # Sanitize fact values by converting everything not a string, boolean
+  # numeric, array or hash into strings.
+  def sanitize
+    values.each do |fact, value|
+      values[fact] = sanitize_fact value
+    end
+  end
+
+  def ==(other)
+    return false unless self.name == other.name
+    strip_internal == other.send(:strip_internal)
+  end
+
+  def self.from_data_hash(data)
+    new_facts = allocate
+    new_facts.initialize_from_hash(data)
+    new_facts
+  end
+
+  def self.from_pson(data)
+    Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
+    self.from_data_hash(data)
+  end
+
+  def to_data_hash
+    result = {
+      'name' => name,
+      'values' => strip_internal,
+    }
+
+    if timestamp
+      if timestamp.is_a? Time
+        result['timestamp'] = timestamp.iso8601(9)
+      else
+        result['timestamp'] = timestamp
+      end
+    end
+
+    if expiration
+      if expiration.is_a? Time
+        result['expiration'] = expiration.iso8601(9)
+      else
+        result['expiration'] = expiration
+      end
+    end
+
+    result
+  end
+
+  # Add internal data to the facts for storage.
+  def add_timestamp
+    self.timestamp = Time.now
+  end
+
+  def timestamp=(time)
+    self.values['_timestamp'] = time
+  end
+
+  def timestamp
+    self.values['_timestamp']
+  end
+
+  # Strip out that internal data.
+  def strip_internal
+    newvals = values.dup
+    newvals.find_all { |name, value| name.to_s =~ /^_/ }.each { |name, value| newvals.delete(name) }
+    newvals
+  end
+
+  private
+
+  def sanitize_fact(fact)
+    if fact.is_a? Hash then
+      ret = {}
+      fact.each_pair { |k,v| ret[sanitize_fact k]=sanitize_fact v }
+      ret
+    elsif fact.is_a? Array then
+      fact.collect { |i| sanitize_fact i }
+    elsif fact.is_a? Numeric \
+      or fact.is_a? TrueClass \
+      or fact.is_a? FalseClass \
+      or fact.is_a? String
+      fact
+    else
+      fact.to_s
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parameter.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parameter.rb
new file mode 100644
index 0000000..59e18de
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parameter.rb
@@ -0,0 +1,585 @@
+require 'puppet/util/methodhelper'
+require 'puppet/util/logging'
+require 'puppet/util/docs'
+
+# The Parameter class is the implementation of a resource's attributes of _parameter_ kind.
+# The Parameter class is also the base class for {Puppet::Property}, and is used to describe meta-parameters
+# (parameters that apply to all resource types).
+# A Parameter (in contrast to a Property) has a single value where a property has both a current and a wanted value.
+# The Parameter class methods are used to configure and create an instance of Parameter that represents
+# one particular attribute data type; its valid value(s), and conversion to/from internal form.
+#
+# The intention is that a new parameter is created by using the DSL method {Puppet::Type.newparam}, or
+# {Puppet::Type.newmetaparam} if the parameter should be applicable to all resource types.
+#
+# A Parameter that does not specify and valid values (via {newvalues}) accepts any value.
+#
+# @see Puppet::Type
+# @see Puppet::Property
+# @api public
+#
+class Puppet::Parameter
+  include Puppet::Util
+  include Puppet::Util::Errors
+  include Puppet::Util::Logging
+  include Puppet::Util::MethodHelper
+
+  require 'puppet/parameter/value_collection'
+
+  class << self
+    include Puppet::Util
+    include Puppet::Util::Docs
+    # Unused?
+    # @todo The term "validater" only appears in this location in the Puppet code base. There is `validate`
+    #   which seems to works fine without this attribute declaration.
+    # @api private
+    #
+    attr_reader :validater
+
+    # Unused?
+    # @todo The term "munger" only appears in this location in the Puppet code base. There is munge and unmunge
+    #  and they seem to work perfectly fine without this attribute declaration.
+    # @api private
+    #
+    attr_reader :munger
+
+    # @return [Symbol] The parameter name as given when it was created.
+    attr_reader :name
+
+    # @return [Object] The default value of the parameter as determined by the {defaultto} method, or nil if no
+    #  default has been set.
+    attr_reader :default
+
+    # @comment This somewhat odd documentation construct is because the getter and setter are not
+    #  orthogonal; the setter uses varargs and this confuses yard. To overcome the problem both the
+    #  getter and the setter are documented here. If this issues is fixed, a todo will be displayed
+    #  for the setter method, and the setter documentation can be moved there.
+    #  Since the attribute is actually RW it should  perhaps instead just be implemented as a setter
+    #  and a getter method (and no attr_xxx declaration).
+    #
+    # @!attribute [rw] required_features
+    # @return [Array<Symbol>] The names of the _provider features_ required for this parameter to work.
+    #   the returned names are always all lower case symbols.
+    # @overload required_features
+    #   Returns the required _provider features_ as an array of lower case symbols
+    # @overload required_features=(*args)
+    #   @param *args [Symbol] one or more names of required provider features
+    #   Sets the required_provider_features_ from one or more values, or array. The given arguments
+    #   are flattened, and internalized.
+    # @api public
+    # @dsl type
+    #
+    attr_reader :required_features
+
+    # @return [Puppet::Parameter::ValueCollection] The set of valid values (or an empty set that accepts any value).
+    # @api private
+    #
+    attr_reader :value_collection
+
+    # @return [Boolean] Flag indicating whether this parameter is a meta-parameter or not.
+    attr_accessor :metaparam
+
+    # Defines how the `default` value of a parameter is computed.
+    # The computation of the parameter's default value is defined by providing a value or a block.
+    # A default of `nil` can not be used.
+    # @overload defaultto(value)
+    #   Defines the default value with a literal value
+    #   @param value [Object] the literal value to use as the default value
+    # @overload defaultto({|| ... })
+    #   Defines that the default value is produced by the given block. The given block
+    #   should produce the default value.
+    # @raise [Puppet::DevError] if value is nil, and no block is given.
+    # @return [void]
+    # @see Parameter.default
+    # @dsl type
+    # @api public
+    #
+    def defaultto(value = nil, &block)
+      if block
+        define_method(:default, &block)
+      else
+        if value.nil?
+          raise Puppet::DevError,
+            "Either a default value or block must be provided"
+        end
+        define_method(:default) do value end
+      end
+    end
+
+    # Produces a documentation string.
+    # If an enumeration of _valid values_ has been defined, it is appended to the documentation
+    # for this parameter specified with the {desc} method.
+    # @return [String] Returns a documentation string.
+    # @api public
+    #
+    def doc
+      @doc ||= ""
+
+      unless defined?(@addeddocvals)
+        @doc = Puppet::Util::Docs.scrub(@doc)
+        if vals = value_collection.doc
+          @doc << "\n\n#{vals}"
+        end
+
+        if f = self.required_features
+          @doc << "\n\nRequires features #{f.flatten.collect { |f| f.to_s }.join(" ")}."
+        end
+        @addeddocvals = true
+      end
+
+      @doc
+    end
+
+    # Removes the `default` method if defined.
+    # Has no effect if the default method is not defined.
+    # This method is intended to be used in a DSL scenario where a parameter inherits from a parameter
+    # with a default value that is not wanted in the derived parameter (otherwise, simply do not define
+    # a default value method).
+    #
+    # @return [void]
+    # @see desc
+    # @api public
+    # @dsl type
+    #
+    def nodefault
+      undef_method :default if public_method_defined? :default
+    end
+
+    # Sets the documentation for this parameter.
+    # @param str [String] The documentation string to set
+    # @return [String] the given `str` parameter
+    # @see doc
+    # @dsl type
+    # @api public
+    #
+    def desc(str)
+      @doc = str
+    end
+
+    # Initializes the instance variables.
+    # Clears the internal value collection (set of allowed values).
+    # @return [void]
+    # @api private
+    #
+    def initvars
+      @value_collection = ValueCollection.new
+    end
+
+    # @overload munge {|| ... }
+    # Defines an optional method used to convert the parameter value from DSL/string form to an internal form.
+    # If a munge method is not defined, the DSL/string value is used as is.
+    # @note This adds a method with the name `unsafe_munge` in the created parameter class. Later this method is
+    #   called in a context where exceptions will be rescued and handled.
+    # @dsl type
+    # @api public
+    #
+    def munge(&block)
+      # I need to wrap the unsafe version in begin/rescue parameterments,
+      # but if I directly call the block then it gets bound to the
+      # class's context, not the instance's, thus the two methods,
+      # instead of just one.
+      define_method(:unsafe_munge, &block)
+    end
+
+    # @overload unmunge {|| ... }
+    # Defines an optional method used to convert the parameter value to DSL/string form from an internal form.
+    # If an `unmunge` method is not defined, the internal form is used.
+    # @see munge
+    # @note This adds a method with the name `unmunge` in the created parameter class.
+    # @dsl type
+    # @api public
+    #
+    def unmunge(&block)
+      define_method(:unmunge, &block)
+    end
+
+    # Sets a marker indicating that this parameter is the _namevar_ (unique identifier) of the type
+    # where the parameter is contained.
+    # This also makes the parameter a required value. The marker can not be unset once it has been set.
+    # @return [void]
+    # @dsl type
+    # @api public
+    #
+    def isnamevar
+      @isnamevar = true
+      @required = true
+    end
+
+    # @return [Boolean] Returns whether this parameter is the _namevar_ or not.
+    # @api public
+    #
+    def isnamevar?
+      @isnamevar
+    end
+
+    # Sets a marker indicating that this parameter is required.
+    # Once set, it is not possible to make a parameter optional.
+    # @return [void]
+    # @dsl type
+    # @api public
+    #
+    def isrequired
+      @required = true
+    end
+
+    # @comment This method is not picked up by yard as it has a different signature than
+    #   expected for an attribute (varargs). Instead, this method is documented as an overload
+    #   of the attribute required_features. (Not ideal, but better than nothing).
+    # @todo If this text appears in documentation - see comment in source and makes corrections - it means
+    #   that an issue in yardoc has been fixed.
+    #
+    def required_features=(*args)
+      @required_features = args.flatten.collect { |a| a.to_s.downcase.intern }
+    end
+
+    # Returns whether this parameter is required or not.
+    # A parameter is required if a call has been made to the DSL method {isrequired}.
+    # @return [Boolean] Returns whether this parameter is required or not.
+    # @api public
+    #
+    def required?
+      @required
+    end
+
+    # @overload validate {|| ... }
+    # Defines an optional method that is used to validate the parameter's DSL/string value.
+    # Validation should raise appropriate exceptions, the return value of the given block is ignored.
+    # The easiest way to raise an appropriate exception is to call the method {Puppet::Util::Errors.fail} with
+    # the message as an argument.
+    # To validate the munged value instead, just munge the value (`munge(value)`).
+    #
+    # @return [void]
+    # @dsl type
+    # @api public
+    #
+    def validate(&block)
+      define_method(:unsafe_validate, &block)
+    end
+
+    # Defines valid values for the parameter (enumeration or regular expressions).
+    # The set of valid values for the parameter can be limited to a (mix of) literal values and
+    # regular expression patterns.
+    # @note Each call to this method adds to the set of valid values
+    # @param names [Symbol, Regexp] The set of valid literal values and/or patterns for the parameter.
+    # @return [void]
+    # @dsl type
+    # @api public
+    #
+    def newvalues(*names)
+      @value_collection.newvalues(*names)
+    end
+
+    # Makes the given `name` an alias for the given `other` name.
+    # Or said differently, the valid value `other` can now also be referred to via the given `name`.
+    # Aliasing may affect how the parameter's value is serialized/stored (it may store the `other` value
+    # instead of the alias).
+    # @api public
+    # @dsl type
+    #
+    def aliasvalue(name, other)
+      @value_collection.aliasvalue(name, other)
+    end
+  end
+
+  # Creates instance (proxy) methods that delegates to a class method with the same name.
+  # @api private
+  #
+  def self.proxymethods(*values)
+    values.each { |val|
+      define_method(val) do
+        self.class.send(val)
+      end
+    }
+  end
+
+  # @!method required?
+  #   (see required?)
+  # @!method isnamevar?
+  #   (see isnamevar?)
+  #
+  proxymethods("required?", "isnamevar?")
+
+  # @return [Puppet::Resource] A reference to the resource this parameter is an attribute of (the _associated resource_).
+  attr_accessor :resource
+
+  # @comment LAK 2007-05-09: Keep the @parent around for backward compatibility.
+  # @return [Puppet::Parameter] A reference to the parameter's parent kept for backwards compatibility.
+  # @api private
+  #
+  attr_accessor :parent
+
+  # Returns a string representation of the resource's containment path in
+  # the catalog.
+  # @return [String]
+  def path
+    @path ||= '/' + pathbuilder.join('/')
+  end
+
+  # @return [Integer] Returns the result of calling the same method on the associated resource.
+  def line
+    resource.line
+  end
+
+  # @return [Integer] Returns the result of calling the same method on the associated resource.
+  def file
+    resource.file
+  end
+
+  # @return [Integer] Returns the result of calling the same method on the associated resource.
+  def version
+    resource.version
+  end
+
+
+  # Initializes the parameter with a required resource reference and optional attribute settings.
+  # The option `:resource` must be specified or an exception is raised. Any additional options passed
+  # are used to initialize the attributes of this parameter by treating each key in the `options` hash as
+  # the name of the attribute to set, and the value as the value to set.
+  # @param options [Hash{Symbol => Object]] Options, where `resource` is required
+  # @option options [Puppet::Resource] :resource The resource this parameter holds a value for. Required.
+  # @raise [Puppet::DevError] If resource is not specified in the options hash.
+  # @api public
+  # @note A parameter should be created via the DSL method {Puppet::Type::newparam}
+  #
+  def initialize(options = {})
+    options = symbolize_options(options)
+    if resource = options[:resource]
+      self.resource = resource
+      options.delete(:resource)
+    else
+      raise Puppet::DevError, "No resource set for #{self.class.name}"
+    end
+
+    set_options(options)
+  end
+
+  # Writes the given `msg` to the log with the loglevel indicated by the associated resource's
+  # `loglevel` parameter.
+  # @todo is loglevel a metaparameter? it is looked up with `resource[:loglevel]`
+  # @return [void]
+  # @api public
+  def log(msg)
+    send_log(resource[:loglevel], msg)
+  end
+
+  # @return [Boolean] Returns whether this parameter is a meta-parameter or not.
+  def metaparam?
+    self.class.metaparam
+  end
+
+  # @!attribute [r] name
+  # @return [Symbol] The parameter's name as given when it was created.
+  # @note Since a Parameter defines the name at the class level, each Parameter class must be
+  #  unique within a type's inheritance chain.
+  # @comment each parameter class must define the name method, and parameter
+  #   instances do not change that name this implicitly means that a given
+  #   object can only have one parameter instance of a given parameter
+  #   class
+  def name
+    self.class.name
+  end
+
+  # @return [Boolean] Returns true if this parameter, the associated resource, or overall puppet mode is `noop`.
+  # @todo How is noop mode set for a parameter? Is this of value in DSL to inhibit a parameter?
+  #
+  def noop
+    @noop ||= false
+    tmp = @noop || self.resource.noop || Puppet[:noop] || false
+    #debug "noop is #{tmp}"
+    tmp
+  end
+
+  # Returns an array of strings representing the containment heirarchy
+  # (types/classes) that make up the path to the resource from the root
+  # of the catalog.  This is mostly used for logging purposes.
+  #
+  # @api private
+  def pathbuilder
+    if @resource
+      return [@resource.pathbuilder, self.name]
+    else
+      return [self.name]
+    end
+  end
+
+  # This is the default implementation of `munge` that simply produces the value (if it is valid).
+  # The DSL method {munge} should be used to define an overriding method if munging is required.
+  #
+  # @api private
+  #
+  def unsafe_munge(value)
+    self.class.value_collection.munge(value)
+  end
+
+  # Unmunges the value by transforming it from internal form to DSL form.
+  # This is the default implementation of `unmunge` that simply returns the value without processing.
+  # The DSL method {unmunge} should be used to define an overriding method if required.
+  # @return [Object] the unmunged value
+  #
+  def unmunge(value)
+    value
+  end
+
+  # Munges the value to internal form.
+  # This implementation of `munge` provides exception handling around the specified munging of this parameter.
+  # @note This method should not be overridden. Use the DSL method {munge} to define a munging method
+  #   if required.
+  # @param value [Object] the DSL value to munge
+  # @return [Object] the munged (internal) value
+  #
+  def munge(value)
+    begin
+      ret = unsafe_munge(value)
+    rescue Puppet::Error => detail
+      Puppet.debug "Reraising #{detail}"
+      raise
+    rescue => detail
+      raise Puppet::DevError, "Munging failed for value #{value.inspect} in class #{self.name}: #{detail}", detail.backtrace
+    end
+    ret
+  end
+
+  # This is the default implementation of `validate` that may be overridden by the DSL method {validate}.
+  # If no valid values have been defined, the given value is accepted, else it is validated against
+  # the literal values (enumerator) and/or patterns defined by calling {newvalues}.
+  #
+  # @param value [Object] the value to check for validity
+  # @raise [ArgumentError] if the value is not valid
+  # @return [void]
+  # @api private
+  #
+  def unsafe_validate(value)
+    self.class.value_collection.validate(value)
+  end
+
+  # Performs validation of the given value against the rules defined by this parameter.
+  # @return [void]
+  # @todo Better description of when the various exceptions are raised.ArgumentError is rescued and
+  #   changed into Puppet::Error.
+  # @raise [ArgumentError, TypeError, Puppet::DevError, Puppet::Error] under various conditions
+  # A protected validation method that only ever raises useful exceptions.
+  # @api public
+  #
+  def validate(value)
+    begin
+      unsafe_validate(value)
+    rescue ArgumentError => detail
+      self.fail Puppet::Error, detail.to_s, detail
+    rescue Puppet::Error, TypeError
+      raise
+    rescue => detail
+      raise Puppet::DevError, "Validate method failed for class #{self.name}: #{detail}", detail.backtrace
+    end
+  end
+
+  # Sets the associated resource to nil.
+  # @todo Why - what is the intent/purpose of this?
+  # @return [nil]
+  #
+  def remove
+    @resource = nil
+  end
+
+  # @return [Object] Gets the value of this parameter after performing any specified unmunging.
+  def value
+    unmunge(@value) unless @value.nil?
+  end
+
+  # Sets the given value as the value of this parameter.
+  # @todo This original comment _"All of the checking should possibly be
+  #   late-binding (e.g., users might not exist when the value is assigned
+  #   but might when it is asked for)."_ does not seem to be correct, the implementation
+  #   calls both validate and munge on the given value, so no late binding.
+  #
+  # The given value is validated and then munged (if munging has been specified). The result is store
+  # as the value of this arameter.
+  # @return [Object] The given `value` after munging.
+  # @raise (see #validate)
+  #
+  def value=(value)
+    validate(value)
+
+    @value = munge(value)
+  end
+
+  # @return [Puppet::Provider] Returns the provider of the associated resource.
+  # @todo The original comment says = _"Retrieve the resource's provider.
+  #   Some types don't have providers, in which case we return the resource object itself."_
+  #   This does not seem to be true, the default implementation that sets this value may be
+  #   {Puppet::Type.provider=} which always gets either the name of a provider or an instance of one.
+  #
+  def provider
+    @resource.provider
+  end
+
+  # @return [Array<Symbol>] Returns an array of the associated resource's symbolic tags (including the parameter itself).
+  # Returns an array of the associated resource's symbolic tags (including the parameter itself).
+  # At a minimun, the array contains the name of the parameter. If the associated resource
+  # has tags, these tags are also included in the array.
+  # @todo The original comment says = _"The properties need to return tags so that logs correctly
+  #   collect them."_ what if anything of that is of interest to document. Should tags and their relationship
+  #   to logs be described. This is a more general concept.
+  #
+  def tags
+    unless defined?(@tags)
+      @tags = []
+      # This might not be true in testing
+      @tags = @resource.tags if @resource.respond_to? :tags
+      @tags << self.name.to_s
+    end
+    @tags
+  end
+
+  # @return [String] The name of the parameter in string form.
+  def to_s
+    name.to_s
+  end
+
+  # Produces a String with the value formatted for display to a human.
+  # When the parameter value is a:
+  #
+  # * **single valued parameter value** the result is produced on the
+  #   form `'value'` where _value_ is the string form of the parameter's value.
+  #
+  # * **Array** the list of values is enclosed in `[]`, and
+  #   each produced value is separated by a comma.
+  #
+  # * **Hash** value is output with keys in sorted order enclosed in `{}` with each entry formatted
+  #   on the form `'k' => v` where
+  #   `k` is the key in string form and _v_ is the value of the key. Entries are comma separated.
+  #
+  # For both Array and Hash this method is called recursively to format contained values.
+  # @note this method does not protect against infinite structures.
+  #
+  # @return [String] The formatted value in string form.
+  #
+  def self.format_value_for_display(value)
+    if value.is_a? Array
+      formatted_values = value.collect {|value| format_value_for_display(value)}.join(', ')
+      "[#{formatted_values}]"
+    elsif value.is_a? Hash
+      # Sorting the hash keys for display is largely for having stable
+      # output to test against, but also helps when scanning for hash
+      # keys, since they will be in ASCIIbetical order.
+      hash = value.keys.sort {|a,b| a.to_s <=> b.to_s}.collect do |k|
+        "'#{k}' => #{format_value_for_display(value[k])}"
+      end.join(', ')
+
+      "{#{hash}}"
+    else
+      "'#{value}'"
+    end
+  end
+
+  # @comment Document post_compile_hook here as it does not exist anywhere (called from type if implemented)
+  # @!method post_compile()
+  # @since 3.4.0
+  # @api public
+  #   @abstract A subclass may implement this - it is not implemented in the Parameter class
+  #   This method may be implemented by a parameter in order to perform actions during compilation
+  #   after all resources have been added to the catalog.
+  #   @see Puppet::Type#finish
+  #   @see Puppet::Parser::Compiler#finish
+end
+
+require 'puppet/parameter/path'
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parameter/boolean.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parameter/boolean.rb
new file mode 100644
index 0000000..11ad807
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parameter/boolean.rb
@@ -0,0 +1,15 @@
+require 'puppet/coercion'
+
+# This specialized {Puppet::Parameter} handles boolean options, accepting lots
+# of strings and symbols for both truthiness and falsehood.
+#
+class Puppet::Parameter::Boolean < Puppet::Parameter
+  def unsafe_munge(value)
+    Puppet::Coercion.boolean(value)
+  end
+
+  def self.initvars
+    super
+    @value_collection.newvalues(*Puppet::Coercion.boolean_values)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parameter/package_options.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parameter/package_options.rb
new file mode 100644
index 0000000..b063ae4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parameter/package_options.rb
@@ -0,0 +1,31 @@
+require 'puppet/parameter'
+
+# This specialized {Puppet::Parameter} handles munging of package options.
+# Package options are passed as an array of key value pairs. Special munging is
+# required as the keys and values needs to be quoted in a safe way.
+#
+class Puppet::Parameter::PackageOptions < Puppet::Parameter
+  def unsafe_munge(values)
+    values = [values] unless values.is_a? Array
+
+    values.collect do |val|
+      case val
+      when Hash
+        safe_hash = {}
+        val.each_pair do |k, v|
+          safe_hash[quote(k)] = quote(v)
+        end
+        safe_hash
+      when String
+        quote(val)
+      else
+        fail("Expected either a string or hash of options")
+      end
+    end
+  end
+
+  # @api private
+  def quote(value)
+    value.include?(' ') ? %Q["#{value.gsub(/"/, '\"')}"] : value
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parameter/path.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parameter/path.rb
new file mode 100644
index 0000000..d5fb29e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parameter/path.rb
@@ -0,0 +1,57 @@
+require 'puppet/parameter'
+
+# This specialized {Puppet::Parameter} handles validation and munging of paths.
+# By default, a single path is accepted, and by calling {accept_arrays} it is possible to
+# allow an array of paths.
+#
+class Puppet::Parameter::Path < Puppet::Parameter
+  # Specifies whether multiple paths are accepted or not.
+  # @dsl type
+  #
+  def self.accept_arrays(bool = true)
+    @accept_arrays = !!bool
+  end
+  def self.arrays?
+    @accept_arrays
+  end
+
+  # Performs validation of the given paths.
+  # If the concrete parameter defines a validation method, it may call this method to perform
+  # path validation.
+  # @raise [Puppet::Error] if this property is configured for single paths and an array is given
+  # @raise [Puppet::Error] if a path is not an absolute path
+  # @return [Array<String>] the given paths
+  #
+  def validate_path(paths)
+    if paths.is_a?(Array) and ! self.class.arrays? then
+      fail "#{name} only accepts a single path, not an array of paths"
+    end
+
+    fail("#{name} must be a fully qualified path") unless Array(paths).all? {|path| absolute_path?(path)}
+
+    paths
+  end
+
+  # This is the default implementation of the `validate` method.
+  # It will be overridden if the validate option is used when defining the parameter.
+  # @return [void]
+  #
+  def unsafe_validate(paths)
+    validate_path(paths)
+  end
+
+  # This is the default implementation  of `munge`.
+  # If the concrete parameter defines a `munge` method, this default implementation will be overridden.
+  # This default implementation does not perform any munging, it just checks the one/many paths
+  # constraints. A derived implementation can perform this check as:
+  # `paths.is_a?(Array) and ! self.class.arrays?` and raise a {Puppet::Error}.
+  # @param paths [String, Array<String>] one of multiple paths
+  # @return [String, Array<String>] the given paths
+  # @raise [Puppet::Error] if the given paths does not comply with the on/many paths rule.
+  def unsafe_munge(paths)
+    if paths.is_a?(Array) and ! self.class.arrays? then
+      fail "#{name} only accepts a single path, not an array of paths"
+    end
+    paths
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parameter/value.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parameter/value.rb
new file mode 100644
index 0000000..dc4de2a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parameter/value.rb
@@ -0,0 +1,93 @@
+require 'puppet/parameter/value_collection'
+
+# Describes an acceptable value for a parameter or property.
+# An acceptable value is either specified as a literal value or a regular expression.
+# @note this class should be used via the api methods in {Puppet::Parameter} and {Puppet::Property}
+# @api private
+#
+class Puppet::Parameter::Value
+  attr_reader :name, :options, :event
+  attr_accessor :block, :call, :method, :required_features, :invalidate_refreshes
+
+  # Adds an alias for this value.
+  # Makes the given _name_ be an alias for this acceptable value.
+  # @param name [Symbol] the additonal alias this value should be known as
+  # @api private
+  #
+  def alias(name)
+    @aliases << convert(name)
+  end
+
+  # @return [Array<Symbol>] Returns all aliases (or an empty array).
+  # @api private
+  #
+  def aliases
+    @aliases.dup
+  end
+
+  # Stores the event that our value generates, if it does so.
+  # @api private
+  #
+  def event=(value)
+    @event = convert(value)
+  end
+
+  # Initializes the instance with a literal accepted value, or a regular expression.
+  # If anything else is passed, it is turned into a String, and then made into a Symbol.
+  # @param name [Symbol, Regexp, Object] the value to accept, Symbol, a regular expression, or object to convert.
+  # @api private
+  #
+  def initialize(name)
+    if name.is_a?(Regexp)
+      @name = name
+    else
+      # Convert to a string and then a symbol, so things like true/false
+      # still show up as symbols.
+      @name = convert(name)
+    end
+
+    @aliases = []
+
+    @call = :instead
+  end
+
+  # Checks if the given value matches the acceptance rules (literal value, regular expression, or one
+  # of the aliases.
+  # @api private
+  #
+  def match?(value)
+    if regex?
+      return true if name =~ value.to_s
+    else
+      return(name == convert(value) ? true : @aliases.include?(convert(value)))
+    end
+  end
+
+  # @return [Boolean] whether the accepted value is a regular expression or not.
+  # @api private
+  #
+  def regex?
+    @name.is_a?(Regexp)
+  end
+
+  private
+
+  # A standard way of converting all of our values, so we're always
+  # comparing apples to apples.
+  # @api private
+  #
+  def convert(value)
+    case value
+    when Symbol, ''             # can't intern an empty string
+      value
+    when String
+      value.intern
+    when true
+      :true
+    when false
+      :false
+    else
+      value.to_s.intern
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parameter/value_collection.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parameter/value_collection.rb
new file mode 100644
index 0000000..4cbd95d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parameter/value_collection.rb
@@ -0,0 +1,211 @@
+require 'puppet/parameter/value'
+
+# A collection of values and regular expressions, used for specifying allowed values
+# in a given parameter.
+# @note This class is considered part of the internal implementation of {Puppet::Parameter}, and
+#   {Puppet::Property} and the functionality provided by this class should be used via their interfaces.
+# @comment This class probably have several problems when trying to use it with a combination of
+#   regular expressions and aliases as it finds an acceptable value holder vi "name" which may be
+#   a regular expression...
+#
+# @api private
+#
+class Puppet::Parameter::ValueCollection
+
+  # Aliases the given existing _other_ value with the additional given _name_.
+  # @return [void]
+  # @api private
+  #
+  def aliasvalue(name, other)
+    other = other.to_sym
+    unless value = match?(other)
+      raise Puppet::DevError, "Cannot alias nonexistent value #{other}"
+    end
+
+    value.alias(name)
+  end
+
+  # Returns a doc string (enumerating the acceptable values) for all of the values in this parameter/property.
+  # @return [String] a documentation string.
+  # @api private
+  #
+  def doc
+    unless defined?(@doc)
+      @doc = ""
+      unless values.empty?
+        @doc << "Valid values are "
+        @doc << @strings.collect do |value|
+          if aliases = value.aliases and ! aliases.empty?
+            "`#{value.name}` (also called `#{aliases.join(", ")}`)"
+          else
+            "`#{value.name}`"
+          end
+        end.join(", ") << ". "
+      end
+
+      unless regexes.empty?
+        @doc << "Values can match `#{regexes.join("`, `")}`."
+      end
+    end
+
+    @doc
+  end
+
+  # @return [Boolean] Returns whether the set of allowed values is empty or not.
+  # @api private
+  #
+  def empty?
+    @values.empty?
+  end
+
+  # @api private
+  #
+  def initialize
+    # We often look values up by name, so a hash makes more sense.
+    @values = {}
+
+    # However, we want to retain the ability to match values in order,
+    # but we always prefer directly equality (i.e., strings) over regex matches.
+    @regexes = []
+    @strings = []
+  end
+
+  # Checks if the given value is acceptable (matches one of the literal values or patterns) and returns
+  # the "matcher" that matched.
+  # Literal string matchers are tested first, if both a literal and a regexp match would match, the literal
+  # match wins.
+  #
+  # @param test_value [Object] the value to test if it complies with the configured rules
+  # @return [Puppet::Parameter::Value, nil] The instance of Puppet::Parameter::Value that matched the given value, or nil if there was no match.
+  # @api private
+  #
+  def match?(test_value)
+    # First look for normal values
+    if value = @strings.find { |v| v.match?(test_value) }
+      return value
+    end
+
+    # Then look for a regex match
+    @regexes.find { |v| v.match?(test_value) }
+  end
+
+  # Munges the value if it is valid, else produces the same value.
+  # @param value [Object] the value to munge
+  # @return [Object] the munged value, or the given value
+  # @todo This method does not seem to do any munging. It just returns the value if it matches the
+  #   regexp, or the (most likely Symbolic) allowed value if it matches (which is more of a replacement
+  #   of one instance with an equal one. Is the intent that this method should be specialized?
+  # @api private
+  #
+  def munge(value)
+    return value if empty?
+
+    if instance = match?(value)
+      if instance.regex?
+        return value
+      else
+        return instance.name
+      end
+    else
+      return value
+    end
+  end
+
+  # Defines a new valid value for a {Puppet::Property}.
+  # A valid value is specified as a literal (typically a Symbol), but can also be
+  # specified with a regexp.
+  #
+  # @param name [Symbol, Regexp] a valid literal value, or a regexp that matches a value
+  # @param options [Hash] a hash with options
+  # @option options [Symbol] :event The event that should be emitted when this value is set.
+  # @todo Option :event original comment says "event should be returned...", is "returned" the correct word
+  #   to use?
+  # @option options [Symbol] :call When to call any associated block. The default value is `:instead` which
+  #   means that the block should be called instead of the provider. In earlier versions (before 20081031) it
+  #   was possible to specify a value of `:before` or `:after` for the purpose of calling
+  #   both the block and the provider. Use of these deprecated options will now raise an exception later
+  #   in the process when the _is_ value is set (see Puppet::Property#set).
+  # @option options [Symbol] :invalidate_refreshes True if a change on this property should invalidate and
+  #   remove any scheduled refreshes (from notify or subscribe) targeted at the same resource. For example, if
+  #   a change in this property takes into account any changes that a scheduled refresh would have performed,
+  #   then the scheduled refresh would be deleted.
+  # @option options [Object] _any_ Any other option is treated as a call to a setter having the given
+  #   option name (e.g. `:required_features` calls `required_features=` with the option's value as an
+  #   argument).
+  # @api private
+  #
+  def newvalue(name, options = {}, &block)
+    value = Puppet::Parameter::Value.new(name)
+    @values[value.name] = value
+    if value.regex?
+      @regexes << value
+    else
+      @strings << value
+    end
+
+    options.each { |opt, arg| value.send(opt.to_s + "=", arg) }
+    if block_given?
+      value.block = block
+    else
+      value.call = options[:call] || :none
+    end
+
+    value.method ||= "set_#{value.name}" if block_given? and ! value.regex?
+
+    value
+  end
+
+  # Defines one or more valid values (literal or regexp) for a parameter or property.
+  # @return [void]
+  # @dsl type
+  # @api private
+  #
+  def newvalues(*names)
+    names.each { |name| newvalue(name) }
+  end
+
+  # @return [Array<String>] An array of the regular expressions in string form, configured as matching valid values.
+  # @api private
+  #
+  def regexes
+    @regexes.collect { |r| r.name.inspect }
+  end
+
+  # Validates the given value against the set of valid literal values and regular expressions.
+  # @raise [ArgumentError] if the value is not accepted
+  # @return [void]
+  # @api private
+  #
+  def validate(value)
+    return if empty?
+
+    unless @values.detect { |name, v| v.match?(value) }
+      str = "Invalid value #{value.inspect}. "
+
+      str += "Valid values are #{values.join(", ")}. " unless values.empty?
+
+      str += "Valid values match #{regexes.join(", ")}." unless regexes.empty?
+
+      raise ArgumentError, str
+    end
+  end
+
+  # Returns a valid value matcher (a literal or regular expression)
+  # @todo This looks odd, asking for an instance that matches a symbol, or an instance that has
+  #   a regexp. What is the intention here? Marking as api private...
+  #
+  # @return [Puppet::Parameter::Value] a valid valud matcher
+  # @api private
+  #
+  def value(name)
+    @values[name]
+  end
+
+  # @return [Array<Symbol>] Returns a list of valid literal values.
+  # @see regexes
+  # @api private
+  #
+  def values
+    @strings.collect { |s| s.name }
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser.rb
new file mode 100644
index 0000000..e01ca1f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser.rb
@@ -0,0 +1,7 @@
+# @api public
+module Puppet::Parser; end
+
+require 'puppet/parser/parser'
+require 'puppet/parser/compiler'
+require 'puppet/resource/type_collection'
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast.rb
new file mode 100644
index 0000000..ed2c66b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast.rb
@@ -0,0 +1,129 @@
+# the parent class for all of our syntactical objects
+
+require 'puppet'
+require 'puppet/util/autoload'
+
+# The base class for all of the objects that make up the parse trees.
+# Handles things like file name, line #, and also does the initialization
+# for all of the parameters of all of the child objects.
+class Puppet::Parser::AST
+  # Do this so I don't have to type the full path in all of the subclasses
+  AST = Puppet::Parser::AST
+
+  include Puppet::Util::Errors
+  include Puppet::Util::MethodHelper
+  include Puppet::Util::Docs
+
+  attr_accessor :parent, :scope, :file, :line, :pos
+
+  def inspect
+    "( #{self.class} #{self.to_s} #{@children.inspect} )"
+  end
+
+  # don't fetch lexer comment by default
+  def use_docs
+    self.class.use_docs
+  end
+
+  # allow our subclass to specify they want documentation
+  class << self
+    attr_accessor :use_docs
+    def associates_doc
+      self.use_docs = true
+    end
+  end
+
+  # Evaluate the current object.  Just a stub method, since the subclass
+  # should override this method.
+  def evaluate(*options)
+  end
+
+  # Throw a parse error.
+  def parsefail(message)
+    self.fail(Puppet::ParseError, message)
+  end
+
+  # Wrap a statemp in a reusable way so we always throw a parse error.
+  def parsewrap
+    exceptwrap :type => Puppet::ParseError do
+      yield
+    end
+  end
+
+  # The version of the evaluate method that should be called, because it
+  # correctly handles errors.  It is critical to use this method because
+  # it can enable you to catch the error where it happens, rather than
+  # much higher up the stack.
+  def safeevaluate(*options)
+    # We duplicate code here, rather than using exceptwrap, because this
+    # is called so many times during parsing.
+    begin
+      return self.evaluate(*options)
+    rescue Puppet::Error => detail
+      raise adderrorcontext(detail)
+    rescue => detail
+      error = Puppet::ParseError.new(detail.to_s, nil, nil, detail)
+      # We can't use self.fail here because it always expects strings,
+      # not exceptions.
+      raise adderrorcontext(error, detail)
+    end
+  end
+
+  # Initialize the object.  Requires a hash as the argument, and
+  # takes each of the parameters of the hash and calls the settor
+  # method for them.  This is probably pretty inefficient and should
+  # likely be changed at some point.
+  def initialize(args)
+    set_options(args)
+  end
+
+  # evaluate ourselves, and match
+  def evaluate_match(value, scope)
+    obj = self.safeevaluate(scope)
+
+    obj   = obj.downcase   if obj.respond_to?(:downcase)
+    value = value.downcase if value.respond_to?(:downcase)
+
+    obj   = Puppet::Parser::Scope.number?(obj)   || obj
+    value = Puppet::Parser::Scope.number?(value) || value
+
+    # "" == undef for case/selector/if
+    obj == value or (obj == "" and value == :undef) or (obj == :undef and value == "")
+  end
+end
+
+# And include all of the AST subclasses.
+require 'puppet/parser/ast/arithmetic_operator'
+require 'puppet/parser/ast/astarray'
+require 'puppet/parser/ast/asthash'
+require 'puppet/parser/ast/boolean_operator'
+require 'puppet/parser/ast/branch'
+require 'puppet/parser/ast/caseopt'
+require 'puppet/parser/ast/casestatement'
+require 'puppet/parser/ast/collection'
+require 'puppet/parser/ast/collexpr'
+require 'puppet/parser/ast/comparison_operator'
+require 'puppet/parser/ast/definition'
+require 'puppet/parser/ast/else'
+require 'puppet/parser/ast/function'
+require 'puppet/parser/ast/hostclass'
+require 'puppet/parser/ast/ifstatement'
+require 'puppet/parser/ast/in_operator'
+require 'puppet/parser/ast/lambda'
+require 'puppet/parser/ast/leaf'
+require 'puppet/parser/ast/match_operator'
+require 'puppet/parser/ast/method_call'
+require 'puppet/parser/ast/minus'
+require 'puppet/parser/ast/node'
+require 'puppet/parser/ast/nop'
+require 'puppet/parser/ast/not'
+require 'puppet/parser/ast/relationship'
+require 'puppet/parser/ast/resource'
+require 'puppet/parser/ast/resource_defaults'
+require 'puppet/parser/ast/resource_instance'
+require 'puppet/parser/ast/resource_override'
+require 'puppet/parser/ast/resource_reference'
+require 'puppet/parser/ast/resourceparam'
+require 'puppet/parser/ast/selector'
+require 'puppet/parser/ast/vardef'
+require 'puppet/parser/code_merger'
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/arithmetic_operator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/arithmetic_operator.rb
new file mode 100644
index 0000000..46f01a1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/arithmetic_operator.rb
@@ -0,0 +1,91 @@
+require 'puppet'
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST
+  class ArithmeticOperator < AST::Branch
+
+    attr_accessor :operator, :lval, :rval
+
+    # Iterate across all of our children.
+    def each
+      [@lval,@rval,@operator].each { |child| yield child }
+    end
+
+    # Produces an object which is the result of the applying the operator to the of lval and rval operands.
+    # * Supports +, -, *, /, %, and <<, >> on numeric strings.
+    # * Supports + on arrays (concatenate), and hashes (merge)
+    # * Supports << on arrays (append)
+    #
+    def evaluate(scope)
+      # evaluate the operands, should return a boolean value
+      left = @lval.safeevaluate(scope)
+      right = @rval.safeevaluate(scope)
+
+      if left.is_a?(Array) || right.is_a?(Array)
+        eval_array(left, right)
+      elsif left.is_a?(Hash) || right.is_a?(Hash)
+        eval_hash(left, right)
+      else
+        eval_numeric(left, right)
+      end
+    end
+
+    # Concatenates (+) two arrays, or appends (<<) any object to a newly created array.
+    #
+    def eval_array(left, right)
+      assert_concatenation_supported()
+
+      raise ArgumentError, "operator #{@operator} is not applicable when one of the operands is an Array." unless %w{+ <<}.include?(@operator)
+      raise ArgumentError, "left operand of #{@operator} must be an Array" unless left.is_a?(Array)
+      if @operator == '+'
+        raise ArgumentError, "right operand of #{@operator} must be an Array when left is an Array." unless right.is_a?(Array)
+        return left + right
+      end
+      # only append case remains, left asserted to be an array, and right may be any object
+      # wrapping right in an array and adding it ensures a new copy (operator << mutates).
+      #
+      left + [right]
+    end
+
+    # Merges two hashes.
+    #
+    def eval_hash(left, right)
+      assert_concatenation_supported()
+
+      raise ArgumentError, "operator #{@operator} is not applicable when one of the operands is an Hash." unless @operator == '+'
+      raise ArgumentError, "left operand of #{@operator} must be an Hash" unless left.is_a?(Hash)
+      raise ArgumentError, "right operand of #{@operator} must be an Hash" unless right.is_a?(Hash)
+      # merge produces a merged copy
+      left.merge(right)
+    end
+
+    def eval_numeric(left, right)
+      left = Puppet::Parser::Scope.number?(left)
+      right = Puppet::Parser::Scope.number?(right)
+      raise ArgumentError, "left operand of #{@operator} is not a number" unless left != nil
+      raise ArgumentError, "right operand of #{@operator} is not a number" unless right != nil
+
+      # compute result
+      left.send(@operator, right)
+    end
+
+    def assert_concatenation_supported
+      return if Puppet.future_parser?
+      raise ParseError.new("Unsupported Operation: Array concatenation available with '--parser future' setting only.")
+    end
+
+    def initialize(hash)
+      super
+
+      raise ArgumentError, "Invalid arithmetic operator #{@operator}" unless %w{+ - * / % << >>}.include?(@operator)
+    end
+  end
+
+  # Used by future parser instead of ArithmeticOperator to enable concatenation
+  class ArithmeticOperator2 < ArithmeticOperator
+    # Overrides the arithmetic operator to allow concatenation
+    def assert_concatenation_supported
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/astarray.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/astarray.rb
new file mode 100644
index 0000000..42a47a1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/astarray.rb
@@ -0,0 +1,50 @@
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST
+  # The basic container class.  This object behaves almost identically
+  # to a normal array except at initialization time.  Note that its name
+  # is 'AST::ASTArray', rather than plain 'AST::Array'; I had too many
+  # bugs when it was just 'AST::Array', because things like
+  # 'object.is_a?(Array)' never behaved as I expected.
+  class ASTArray < Branch
+    include Enumerable
+
+    # Return a child by index. Used (at least) by tests.
+    def [](index)
+      @children[index]
+    end
+
+    # Evaluate our children.
+    def evaluate(scope)
+      result = []
+      @children.each do |child|
+        # Skip things that respond to :instantiate (classes, nodes,
+        # and definitions), because they have already been
+        # instantiated.
+        if !child.respond_to?(:instantiate)
+          item = child.safeevaluate(scope)
+          if !item.nil?
+            # nil values are implicitly removed.
+            result.push(item)
+          end
+        end
+      end
+      result
+    end
+
+    def push(*ary)
+      ary.each { |child|
+        #Puppet.debug "adding %s(%s) of type %s to %s" %
+        #    [child, child.object_id, child.class.to_s.sub(/.+::/,''),
+        #    self.object_id]
+        @children.push(child)
+      }
+
+      self
+    end
+
+    def to_s
+      "[" + @children.collect { |c| c.to_s }.join(', ') + "]"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/asthash.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/asthash.rb
new file mode 100644
index 0000000..ae81d35
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/asthash.rb
@@ -0,0 +1,37 @@
+require 'puppet/parser/ast/leaf'
+
+class Puppet::Parser::AST
+  class ASTHash < Leaf
+    include Enumerable
+
+    # Evaluate our children.
+    def evaluate(scope)
+      items = {}
+
+      @value.each_pair do |k,v|
+        key = k.respond_to?(:safeevaluate) ? k.safeevaluate(scope) : k
+        items.merge!({ key => v.safeevaluate(scope) })
+      end
+
+      items
+    end
+
+    def merge(hash)
+      case hash
+      when ASTHash
+        @value = @value.merge(hash.value)
+      when Hash
+        @value = @value.merge(hash)
+      end
+    end
+
+    def to_s
+      "{" + @value.collect { |v| v.collect { |a| a.to_s }.join(' => ') }.join(', ') + "}"
+    end
+
+    def initialize(args)
+      super(args)
+      @value ||= {}
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/block_expression.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/block_expression.rb
new file mode 100644
index 0000000..b6b7e66
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/block_expression.rb
@@ -0,0 +1,40 @@
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST
+  class BlockExpression < Branch
+    include Enumerable
+
+    # Evaluate contained expressions, produce result of the last
+    def evaluate(scope)
+      result = nil
+      @children.each do |child|
+        result = child.safeevaluate(scope)
+      end
+      result
+    end
+
+    # Return a child by index.
+    def [](index)
+      @children[index]
+    end
+
+    def push(*ary)
+      ary.each { |child|
+        #Puppet.debug "adding %s(%s) of type %s to %s" %
+        #    [child, child.object_id, child.class.to_s.sub(/.+::/,''),
+        #    self.object_id]
+        @children.push(child)
+      }
+
+      self
+    end
+
+    def sequence_with(other)
+      Puppet::Parser::AST::BlockExpression.new(:children => self.children + other.children)
+    end
+
+    def to_s
+      "[" + @children.collect { |c| c.to_s }.join(', ') + "]"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/boolean_operator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/boolean_operator.rb
new file mode 100644
index 0000000..8481e4f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/boolean_operator.rb
@@ -0,0 +1,46 @@
+require 'puppet'
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST
+  class BooleanOperator < AST::Branch
+
+    attr_accessor :operator, :lval, :rval
+
+    # Iterate across all of our children.
+    def each
+      [@lval,@rval,@operator].each { |child| yield child }
+    end
+
+    # Returns a boolean which is the result of the boolean operation
+    # of lval and rval operands
+    def evaluate(scope)
+      # evaluate the first operand, should return a boolean value
+      lval = @lval.safeevaluate(scope)
+
+      # return result
+      # lazy evaluate right operand
+      case @operator
+      when "and"
+        if Puppet::Parser::Scope.true?(lval)
+          rval = @rval.safeevaluate(scope)
+          Puppet::Parser::Scope.true?(rval)
+        else # false and false == false
+          false
+        end
+      when "or"
+        if Puppet::Parser::Scope.true?(lval)
+          true
+        else
+          rval = @rval.safeevaluate(scope)
+          Puppet::Parser::Scope.true?(rval)
+        end
+      end
+    end
+
+    def initialize(hash)
+      super
+
+      raise ArgumentError, "Invalid boolean operator #{@operator}" unless %w{and or}.include?(@operator)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/branch.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/branch.rb
new file mode 100644
index 0000000..83155b3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/branch.rb
@@ -0,0 +1,22 @@
+class Puppet::Parser::AST
+  # The parent class of all AST objects that contain other AST objects.
+  # Everything but the really simple objects descend from this.  It is
+  # important to note that Branch objects contain other AST objects only --
+  # if you want to contain values, use a descendent of the AST::Leaf class.
+  class Branch < AST
+    include Enumerable
+    attr_accessor :pin, :children
+
+    def each
+      @children.each { |child|
+        yield child
+      }
+    end
+
+    def initialize(arghash)
+      super(arghash)
+
+      @children ||= []
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/caseopt.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/caseopt.rb
new file mode 100644
index 0000000..db4c2b0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/caseopt.rb
@@ -0,0 +1,52 @@
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST
+  # Each individual option in a case statement.
+  class CaseOpt < AST::Branch
+    attr_accessor :value, :statements
+
+    # CaseOpt is a bit special -- we just want the value first,
+    # so that CaseStatement can compare, and then it will selectively
+    # decide whether to fully evaluate this option
+
+    def each
+      [@value,@statements].each { |child| yield child }
+    end
+
+    # Are we the default option?
+    def default?
+      # Cache the @default value.
+      return @default if defined?(@default)
+
+      @value.each { |subval|
+        if subval.is_a?(AST::Default)
+          @default = true
+          break
+        end
+      }
+
+      @default ||= false
+
+      @default
+    end
+
+    # You can specify a list of values; return each in turn.
+    def eachvalue(scope)
+      @value.each { |subval|
+        yield subval.safeevaluate(scope)
+      }
+    end
+
+    def eachopt
+      @value.each { |subval|
+        yield subval
+      }
+    end
+
+    # Evaluate the actual statements; this only gets called if
+    # our option matched.
+    def evaluate(scope)
+      @statements.safeevaluate(scope)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/casestatement.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/casestatement.rb
new file mode 100644
index 0000000..67510ca
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/casestatement.rb
@@ -0,0 +1,41 @@
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST
+  # The basic logical structure in Puppet.  Supports a list of
+  # tests and statement arrays.
+  class CaseStatement < AST::Branch
+    attr_accessor :test, :options, :default
+
+    associates_doc
+
+    # Short-curcuit evaluation.  Return the value of the statements for
+    # the first option that matches.
+    def evaluate(scope)
+      level = scope.ephemeral_level
+
+      value = @test.safeevaluate(scope)
+
+      # Iterate across the options looking for a match.
+      default = nil
+      @options.each do |option|
+        option.eachopt do |opt|
+          return option.safeevaluate(scope) if opt.evaluate_match(value, scope)
+        end
+
+        default = option if option.default?
+      end
+
+      # Unless we found something, look for the default.
+      return default.safeevaluate(scope) if default
+
+      Puppet.debug "No true answers and no default"
+      return nil
+    ensure
+      scope.unset_ephemeral_var(level)
+    end
+
+    def each
+      [@test,@options].each { |child| yield child }
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/collection.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/collection.rb
new file mode 100644
index 0000000..0f4b175
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/collection.rb
@@ -0,0 +1,53 @@
+require 'puppet'
+require 'puppet/parser/ast/branch'
+require 'puppet/parser/collector'
+
+# An object that collects stored objects from the central cache and returns
+# them to the current host, yo.
+class Puppet::Parser::AST
+  class Collection < AST::Branch
+    attr_accessor :type, :query, :form
+    attr_reader :override
+
+    associates_doc
+
+    # We return an object that does a late-binding evaluation.
+    def evaluate(scope)
+      match, code = query && query.safeevaluate(scope)
+
+      if @type == 'class'
+        fail "Classes cannot be collected"
+      end
+
+      resource_type = scope.find_resource_type(@type)
+      fail "Resource type #{@type} doesn't exist" unless resource_type
+      newcoll = Puppet::Parser::Collector.new(scope, resource_type.name, match, code, self.form)
+
+      scope.compiler.add_collection(newcoll)
+
+      # overrides if any
+      # Evaluate all of the specified params.
+      if @override
+        params = @override.collect { |param| param.safeevaluate(scope) }
+        newcoll.add_override(
+          :parameters => params,
+          :file       => @file,
+          :line       => @line,
+          :source     => scope.source,
+          :scope      => scope
+        )
+      end
+
+      newcoll
+    end
+
+    # Handle our parameter ourselves
+    def override=(override)
+      @override = if override.is_a?(AST::ASTArray)
+        override
+      else
+        AST::ASTArray.new(:line => override.line,:file => override.file,:children => [override])
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/collexpr.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/collexpr.rb
new file mode 100644
index 0000000..bc19c7c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/collexpr.rb
@@ -0,0 +1,109 @@
+require 'puppet'
+require 'puppet/parser/ast/branch'
+require 'puppet/parser/collector'
+
+# An object that collects stored objects from the central cache and returns
+# them to the current host, yo.
+class Puppet::Parser::AST
+class CollExpr < AST::Branch
+  attr_accessor :test1, :test2, :oper, :form, :type, :parens
+
+  def evaluate(scope)
+    if Puppet.future_parser?
+      evaluate4x(scope)
+    else
+      evaluate3x(scope)
+    end
+  end
+
+  # We return an object that does a late-binding evaluation.
+  def evaluate3x(scope)
+    # Make sure our contained expressions have all the info they need.
+    [@test1, @test2].each do |t|
+      if t.is_a?(self.class)
+        t.form ||= self.form
+        t.type ||= self.type
+      end
+    end
+
+    # The code is only used for virtual lookups
+    match1, code1 = @test1.safeevaluate scope
+    match2, code2 = @test2.safeevaluate scope
+
+    # First build up the virtual code.
+    # If we're a conjunction operator, then we're calling code.  I did
+    # some speed comparisons, and it's at least twice as fast doing these
+    # case statements as doing an eval here.
+    code = proc do |resource|
+      case @oper
+      when "and"; code1.call(resource) and code2.call(resource)
+      when "or"; code1.call(resource) or code2.call(resource)
+      when "=="
+        if match1 == "tag"
+          resource.tagged?(match2)
+        else
+          if resource[match1].is_a?(Array)
+            resource[match1].include?(match2)
+          else
+            resource[match1] == match2
+          end
+        end
+      when "!="; resource[match1] != match2
+      end
+    end
+
+    match = [match1, @oper, match2]
+    return match, code
+  end
+
+  # Late binding evaluation of a collect expression (as done in 3x), but with proper Puppet Language
+  # semantics for equals and include
+  #
+  def evaluate4x(scope)
+    # Make sure our contained expressions have all the info they need.
+    [@test1, @test2].each do |t|
+      if t.is_a?(self.class)
+        t.form ||= self.form
+        t.type ||= self.type
+      end
+    end
+
+    # The code is only used for virtual lookups
+    match1, code1 = @test1.safeevaluate scope
+    match2, code2 = @test2.safeevaluate scope
+
+    # First build up the virtual code.
+    # If we're a conjunction operator, then we're calling code.  I did
+    # some speed comparisons, and it's at least twice as fast doing these
+    # case statements as doing an eval here.
+    code = proc do |resource|
+      case @oper
+      when "and"; code1.call(resource) and code2.call(resource)
+      when "or"; code1.call(resource) or code2.call(resource)
+      when "=="
+        if match1 == "tag"
+          resource.tagged?(match2)
+        else
+          if resource[match1].is_a?(Array)
+            @@compare_operator.include?(resource[match1], match2, scope)
+          else
+            @@compare_operator.equals(resource[match1], match2)
+          end
+        end
+      when "!="; ! @@compare_operator.equals(resource[match1], match2)
+      end
+    end
+
+    match = [match1, @oper, match2]
+    return match, code
+  end
+
+  def initialize(hash = {})
+    super
+    if Puppet.future_parser?
+      @@compare_operator ||= Puppet::Pops::Evaluator::CompareOperator.new
+    end
+    raise ArgumentError, "Invalid operator #{@oper}" unless %w{== != and or}.include?(@oper)
+  end
+end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/comparison_operator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/comparison_operator.rb
new file mode 100644
index 0000000..039c81d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/comparison_operator.rb
@@ -0,0 +1,38 @@
+require 'puppet'
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST
+  class ComparisonOperator < AST::Branch
+
+    attr_accessor :operator, :lval, :rval
+
+    # Iterate across all of our children.
+    def each
+      [@lval,@rval,@operator].each { |child| yield child }
+    end
+
+    # Returns a boolean which is the result of the boolean operation
+    # of lval and rval operands
+    def evaluate(scope)
+      # evaluate the operands, should return a boolean value
+      lval = @lval.safeevaluate(scope)
+
+      case @operator
+      when "==","!="
+        @rval.evaluate_match(lval, scope) ? @operator == '==' : @operator == '!='
+      else
+        rval = @rval.safeevaluate(scope)
+        rval = Puppet::Parser::Scope.number?(rval) || rval
+        lval = Puppet::Parser::Scope.number?(lval) || lval
+
+        lval.send(@operator,rval)
+      end
+    end
+
+    def initialize(hash)
+      super
+
+      raise ArgumentError, "Invalid comparison operator #{@operator}" unless %w{== != < > <= >=}.include?(@operator)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/definition.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/definition.rb
new file mode 100644
index 0000000..c43422f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/definition.rb
@@ -0,0 +1,17 @@
+require 'puppet/parser/ast/top_level_construct'
+
+class Puppet::Parser::AST::Definition < Puppet::Parser::AST::TopLevelConstruct
+  attr_accessor :context
+
+  def initialize(name, context = {}, &ruby_code)
+    @name = name
+    @context = context
+    @ruby_code = ruby_code
+  end
+
+  def instantiate(modname)
+    new_definition = Puppet::Resource::Type.new(:definition, @name, @context.merge(:module_name => modname))
+    new_definition.ruby_code = @ruby_code if @ruby_code
+    [new_definition]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/else.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/else.rb
new file mode 100644
index 0000000..1721491
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/else.rb
@@ -0,0 +1,22 @@
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST
+  # A separate ElseIf statement; can function as an 'else' if there's no
+  # test.
+  class Else < AST::Branch
+
+    associates_doc
+
+    attr_accessor :statements
+
+    def each
+      yield @statements
+    end
+
+    # Evaluate the actual statements; this only gets called if
+    # our test was true matched.
+    def evaluate(scope)
+      @statements.safeevaluate(scope)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/function.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/function.rb
new file mode 100644
index 0000000..5d2dc6f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/function.rb
@@ -0,0 +1,59 @@
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST
+  # An AST object to call a function.
+  class Function < AST::Branch
+
+    associates_doc
+
+    attr_accessor :name, :arguments, :pblock
+
+    def evaluate(scope)
+      # Make sure it's a defined function
+      raise Puppet::ParseError, "Unknown function #{@name}" unless Puppet::Parser::Functions.function(@name)
+
+      # Now check that it's been used correctly
+      case @ftype
+      when :rvalue
+        raise Puppet::ParseError, "Function '#{@name}' does not return a value" unless Puppet::Parser::Functions.rvalue?(@name)
+
+      when :statement
+        # It is harmless to produce an ignored rvalue, the alternative is to mark functions
+        # as appropriate for both rvalue and statements
+        # Keeping the old behavior when a pblock is not present. This since it is not known
+        # if the lambda contains a statement or not (at least not without a costly search).
+        # The purpose of the check is to protect a user for producing a meaningless rvalue where the
+        # operation has no side effects.
+        #
+        if !pblock && Puppet::Parser::Functions.rvalue?(@name)
+          raise Puppet::ParseError,
+            "Function '#{@name}' must be the value of a statement"
+        end
+      else
+        raise Puppet::DevError, "Invalid function type #{@ftype.inspect}"
+      end
+
+      # We don't need to evaluate the name, because it's plaintext
+      args = @arguments.safeevaluate(scope).map { |x| x == :undef ? '' : x }
+
+      # append a puppet lambda (unevaluated) if it is defined
+      args << pblock if pblock
+
+      scope.send("function_#{@name}", args)
+    end
+
+    def initialize(hash)
+      @ftype = hash[:ftype] || :rvalue
+      hash.delete(:ftype) if hash.include? :ftype
+
+      super(hash)
+
+      # Lastly, check the parity
+    end
+
+    def to_s
+      args = arguments.is_a?(ASTArray) ? arguments.to_s.gsub(/\[(.*)\]/,'\1') : arguments
+      "#{name}(#{args})"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/hostclass.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/hostclass.rb
new file mode 100644
index 0000000..cab5e4a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/hostclass.rb
@@ -0,0 +1,29 @@
+require 'puppet/parser/ast/top_level_construct'
+
+class Puppet::Parser::AST::Hostclass < Puppet::Parser::AST::TopLevelConstruct
+  attr_accessor :name, :context
+
+  def initialize(name, context = {}, &ruby_code)
+    @context = context
+    @name = name
+    @ruby_code = ruby_code
+  end
+
+  def instantiate(modname)
+    new_class = Puppet::Resource::Type.new(:hostclass, @name, @context.merge(:module_name => modname))
+    new_class.ruby_code = @ruby_code if @ruby_code
+    all_types = [new_class]
+    if code
+      code.each do |nested_ast_node|
+        if nested_ast_node.respond_to? :instantiate
+          all_types += nested_ast_node.instantiate(modname)
+        end
+      end
+    end
+    return all_types
+  end
+
+  def code()
+    @context[:code]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/ifstatement.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/ifstatement.rb
new file mode 100644
index 0000000..7fd8a57
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/ifstatement.rb
@@ -0,0 +1,34 @@
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST
+  # A basic 'if/elsif/else' statement.
+  class IfStatement < AST::Branch
+
+    associates_doc
+
+    attr_accessor :test, :else, :statements
+
+    def each
+      [@test,@else,@statements].each { |child| yield child }
+    end
+
+    # Short-curcuit evaluation.  If we're true, evaluate our statements,
+    # else if there's an 'else' setting, evaluate it.
+    # the first option that matches.
+    def evaluate(scope)
+      level = scope.ephemeral_level
+      value = @test.safeevaluate(scope)
+
+      # let's emulate a new scope for each branches
+      begin
+        if Puppet::Parser::Scope.true?(value)
+          return @statements.safeevaluate(scope)
+        else
+          return defined?(@else) ? @else.safeevaluate(scope) : nil
+        end
+      ensure
+        scope.unset_ephemeral_var(level)
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/in_operator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/in_operator.rb
new file mode 100644
index 0000000..2a163e7
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/in_operator.rb
@@ -0,0 +1,24 @@
+require 'puppet'
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST
+  class InOperator < AST::Branch
+
+    attr_accessor :lval, :rval
+
+    # Returns a boolean which is the result of the 'in' operation
+    # of lval and rval operands
+    def evaluate(scope)
+
+      # evaluate the operands, should return a boolean value
+      lval = @lval.safeevaluate(scope)
+      raise ArgumentError, "'#{lval}' from left operand of 'in' expression is not a string" unless lval.is_a?(::String)
+
+      rval = @rval.safeevaluate(scope)
+      unless rval.respond_to?(:include?)
+        raise ArgumentError, "'#{rval}' from right operand of 'in' expression is not of a supported type (string, array or hash)"
+      end
+      rval.include?(lval)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/lambda.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/lambda.rb
new file mode 100644
index 0000000..64d78d4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/lambda.rb
@@ -0,0 +1,135 @@
+require 'puppet/parser/ast/block_expression'
+
+class Puppet::Parser::AST
+  # A block of statements/expressions with additional parameters
+  # Requires scope to contain the values for the defined parameters when evaluated
+  # If evaluated without a prepared scope, the lambda will behave like its super class.
+  #
+  class Lambda < AST::BlockExpression
+
+    # The lambda parameters.
+    # These are encoded as an array where each entry is an array of one or two object. The first
+    # is the parameter name, and the optional second object is the value expression (that will
+    # be evaluated when bound to a scope).
+    # The value expression is the default value for the parameter. All default values must be
+    # at the end of the parameter list.
+    #
+    # @return [Array<Array<String,String>>] list of parameter names with optional value expression
+    attr_accessor :parameters
+    # Evaluates each expression/statement and produce the last expression evaluation result
+    # @return [Object] what the last expression evaluated to
+    def evaluate(scope)
+      if @children.is_a? Puppet::Parser::AST::ASTArray
+        result = nil
+        @children.each {|expr| result = expr.evaluate(scope) }
+        result
+      else
+        @children.evaluate(scope)
+      end
+    end
+
+    # Calls the lambda.
+    # Assigns argument values in a nested local scope that should be used to evaluate the lambda
+    # and then evaluates the lambda.
+    # @param scope [Puppet::Scope] the calling scope
+    # @return [Object] the result of evaluating the expression(s) in the lambda
+    #
+    def call(scope, *args)
+      raise Puppet::ParseError, "Too many arguments: #{args.size} for #{parameters.size}" unless args.size <= parameters.size
+
+      # associate values with parameters
+      merged = parameters.zip(args)
+      # calculate missing arguments
+      missing = parameters.slice(args.size, parameters.size - args.size).select {|e| e.size == 1}
+      unless missing.empty?
+        optional = parameters.count { |p| p.size == 2 }
+        raise Puppet::ParseError, "Too few arguments; #{args.size} for #{optional > 0 ? ' min ' : ''}#{parameters.size - optional}"
+      end
+
+      evaluated = merged.collect do |m|
+        # m can be one of
+        # m = [["name"], "given"]
+        #   | [["name", default_expr], "given"]
+        #
+        # "given" is always an optional entry. If a parameter was provided then
+        # the entry will be in the array, otherwise the m array will be a
+        # single element.
+        given_argument = m[1]
+        argument_name = m[0][0]
+        default_expression = m[0][1]
+
+        value = if m.size == 1
+          default_expression.safeevaluate(scope)
+        else
+          given_argument
+        end
+        [argument_name, value]
+      end
+
+      # Store the evaluated name => value associations in a new inner/local/ephemeral scope
+      # (This is made complicated due to the fact that the implementation of scope is overloaded with
+      # functionality and an inner ephemeral scope must be used (as opposed to just pushing a local scope
+      # on a scope "stack").
+
+      # Ensure variable exists with nil value if error occurs. 
+      # Some ruby implementations does not like creating variable on return
+      result = nil
+      begin
+        elevel = scope.ephemeral_level
+        scope.ephemeral_from(Hash[evaluated], file, line)
+        result = safeevaluate(scope)
+      ensure
+        scope.unset_ephemeral_var(elevel)
+      end
+      result
+    end
+
+    # Validates the lambda.
+    # Validation checks if parameters with default values are at the end of the list. (It is illegal
+    # to have a parameter with default value followed by one without).
+    #
+    # @raise [Puppet::ParseError] if a parameter with a default comes before a parameter without default value
+    #
+    def validate
+      params = parameters || []
+      defaults = params.drop_while {|p| p.size < 2 }
+      trailing = defaults.drop_while {|p| p.size == 2 }
+      raise Puppet::ParseError, "Lambda parameters with default values must be placed last" unless trailing.empty?
+    end
+
+    # Returns the number of parameters (required and optional)
+    # @return [Integer] the total number of accepted parameters
+    def parameter_count
+      @parameters.size
+    end
+
+    # Returns the number of optional parameters.
+    # @return [Integer] the number of optional accepted parameters
+    def optional_parameter_count
+      @parameters.count {|p| p.size == 2 }
+    end
+
+    def initialize(options)
+      super(options)
+      # ensure there is an empty parameters structure if not given by creator
+      @parameters = [] unless options[:parameters]
+      validate
+    end
+
+    def to_s
+      result = ["{|"]
+      result += @parameters.collect {|p| "#{p[0]}" + (p.size == 2 && p[1]) ? p[1].to_s() : '' }.join(', ')
+      result << "| ... }"
+      result.join('')
+    end
+
+    # marker method checked with respond_to :puppet_lambda
+    def puppet_lambda()
+      true
+    end
+
+    def parameter_names
+      @parameters.collect {|p| p[0] }
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/leaf.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/leaf.rb
new file mode 100644
index 0000000..b8049af
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/leaf.rb
@@ -0,0 +1,232 @@
+class Puppet::Parser::AST
+  # The base class for all of the leaves of the parse trees.  These
+  # basically just have types and values.  Both of these parameters
+  # are simple values, not AST objects.
+  class Leaf < AST
+    attr_accessor :value, :type
+
+    # Return our value.
+    def evaluate(scope)
+      @value
+    end
+
+    def match(value)
+      @value == value
+    end
+
+    def to_s
+      @value.to_s unless @value.nil?
+    end
+  end
+
+  # The boolean class.  True or false.  Converts the string it receives
+  # to a Ruby boolean.
+  class Boolean < AST::Leaf
+    def initialize(hash)
+      super
+
+      unless @value == true or @value == false
+        raise Puppet::DevError, "'#{@value}' is not a boolean"
+      end
+      @value
+    end
+  end
+
+  # The base string class.
+  class String < AST::Leaf
+    def evaluate(scope)
+      @value.dup
+    end
+
+    def to_s
+      @value.inspect
+    end
+  end
+
+  # An uninterpreted string.
+  class FlatString < AST::Leaf
+    def evaluate(scope)
+      @value
+    end
+
+    def to_s
+      @value.inspect
+    end
+  end
+
+  class Concat < AST::Leaf
+    def evaluate(scope)
+      @value.collect { |x| x.evaluate(scope) }.collect{ |x| x == :undef ? '' : x }.join
+    end
+
+    def to_s
+      "#{@value.map { |s| s.to_s.gsub(/^"(.*)"$/, '\1') }.join}"
+    end
+  end
+
+  # The 'default' option on case statements and selectors.
+  class Default < AST::Leaf; end
+
+  # Capitalized words; used mostly for type-defaults, but also
+  # get returned by the lexer any other time an unquoted capitalized
+  # word is found.
+  class Type < AST::Leaf; end
+
+  # Lower-case words.
+  class Name < AST::Leaf; end
+
+  # double-colon separated class names
+  class ClassName < AST::Leaf; end
+
+  # undef values; equiv to nil
+  class Undef < AST::Leaf; end
+
+  # Host names, either fully qualified or just the short name, or even a regex
+  class HostName < AST::Leaf
+    def initialize(hash)
+      super
+
+      # Note that this is an AST::Regex, not a Regexp
+      unless @value.is_a?(Regex)
+        @value = @value.to_s.downcase
+        @value =~ /[^-\w.]/ and
+          raise Puppet::DevError, "'#{@value}' is not a valid hostname"
+      end
+    end
+
+    # implementing eql? and hash so that when an HostName is stored
+    # in a hash it has the same hashing properties as the underlying value
+    def eql?(value)
+      value = value.value if value.is_a?(HostName)
+      @value.eql?(value)
+    end
+
+    def hash
+      @value.hash
+    end
+  end
+
+  # A simple variable.  This object is only used during interpolation;
+  # the VarDef class is used for assignment.
+  class Variable < Name
+    # Looks up the value of the object in the scope tree (does
+    # not include syntactical constructs, like '$' and '{}').
+    def evaluate(scope)
+      parsewrap do
+        if scope.include?(@value)
+          scope[@value, {:file => file, :line => line}]
+        else
+          :undef
+        end
+      end
+    end
+
+    def to_s
+      "\$#{value}"
+    end
+  end
+
+  class HashOrArrayAccess < AST::Leaf
+    attr_accessor :variable, :key
+
+    def evaluate_container(scope)
+      container = variable.respond_to?(:evaluate) ? variable.safeevaluate(scope) : variable
+      if container.is_a?(Hash) || container.is_a?(Array)
+        container
+      elsif container.is_a?(::String)
+        scope[container, {:file => file, :line => line}]
+      else
+        raise Puppet::ParseError, "#{variable} is #{container.inspect}, not a hash or array"
+      end
+    end
+
+    def evaluate_key(scope)
+      key.respond_to?(:evaluate) ? key.safeevaluate(scope) : key
+    end
+
+    def array_index_or_key(object, key)
+      if object.is_a?(Array)
+        raise Puppet::ParseError, "#{key} is not an integer, but is used as an index of an array" unless key = Puppet::Parser::Scope.number?(key)
+      end
+      key
+    end
+
+    def evaluate(scope)
+      object = evaluate_container(scope)
+      accesskey = evaluate_key(scope)
+      raise Puppet::ParseError, "#{variable} is not a hash or array when accessing it with #{accesskey}" unless object.is_a?(Hash) or object.is_a?(Array)
+
+      result = object[array_index_or_key(object, accesskey)]
+      result.nil? ? :undef : result
+    end
+
+    # Assign value to this hashkey or array index
+    def assign(scope, value)
+      object = evaluate_container(scope)
+      accesskey = evaluate_key(scope)
+
+      if object.is_a?(Hash) and object.include?(accesskey)
+        raise Puppet::ParseError, "Assigning to the hash '#{variable}' with an existing key '#{accesskey}' is forbidden"
+      end
+
+      mutation_deprecation()
+
+      # assign to hash or array
+      object[array_index_or_key(object, accesskey)] = value
+    end
+
+    def to_s
+      "\$#{variable.to_s}[#{key.to_s}]"
+    end
+
+    def mutation_deprecation
+      deprecation_location_text =
+      if file && line
+        " at #{file}:#{line}"
+      elsif file
+        " in file #{file}"
+      elsif line
+        " at #{line}"
+      end
+      Puppet.warning(["The use of mutating operations on Array/Hash is deprecated#{deprecation_location_text}.",
+         " See http://links.puppetlabs.com/puppet-mutation-deprecation"].join(''))
+    end
+  end
+
+  class Regex < AST::Leaf
+    def initialize(hash)
+      super
+      @value = Regexp.new(@value) unless @value.is_a?(Regexp)
+    end
+
+    # we're returning self here to wrap the regexp and to be used in places
+    # where a string would have been used, without modifying any client code.
+    # For instance, in many places we have the following code snippet:
+    #  val = @val.safeevaluate(@scope)
+    #  if val.match(otherval)
+    #      ...
+    #  end
+    # this way, we don't have to modify this test specifically for handling
+    # regexes.
+    def evaluate(scope)
+      self
+    end
+
+    def evaluate_match(value, scope, options = {})
+      value = value == :undef ? '' : value.to_s
+
+      if matched = @value.match(value)
+        scope.ephemeral_from(matched, options[:file], options[:line])
+      end
+      matched
+    end
+
+    def match(value)
+      @value.match(value)
+    end
+
+    def to_s
+      "/#{@value.source}/"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/match_operator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/match_operator.rb
new file mode 100644
index 0000000..6207a8c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/match_operator.rb
@@ -0,0 +1,28 @@
+require 'puppet'
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST
+  class MatchOperator < AST::Branch
+
+    attr_accessor :lval, :rval, :operator
+
+    # Iterate across all of our children.
+    def each
+      [@lval,@rval].each { |child| yield child }
+    end
+
+    # Returns a boolean which is the result of the boolean operation
+    # of lval and rval operands
+    def evaluate(scope)
+      lval = @lval.safeevaluate(scope)
+
+      return(rval.evaluate_match(lval, scope) ? @operator == "=~" : @operator == "!~")
+    end
+
+    def initialize(hash)
+      super
+
+      raise ArgumentError, "Invalid regexp operator #{@operator}" unless %w{!~ =~}.include?(@operator)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/method_call.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/method_call.rb
new file mode 100644
index 0000000..d613674
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/method_call.rb
@@ -0,0 +1,77 @@
+require 'puppet/parser/ast/branch'
+require 'puppet/parser/methods'
+
+class Puppet::Parser::AST
+  # An AST object to call a method
+  class MethodCall < AST::Branch
+
+    associates_doc
+
+    # An AST that evaluates to the object the method is applied to
+    # @return [Puppet::Parser::AST]
+    attr_accessor :receiver
+
+    # The name of the method
+    # @return [String]
+    attr_accessor :name
+
+    # The arguments to evaluate as arguments to the method.
+    # @return [Array<Puppet::Parser::AST>]
+    attr_accessor :arguments
+
+    # An optional lambda/block that will be yielded to by the called method (if it supports this)
+    # @return [Puppet::Parser::AST::Lambda]
+    attr_accessor :lambda
+
+    # Evaluates the method call and returns what the called method/function returns.
+    # The evaluation evaluates all arguments in the calling scope and then delegates
+    # to a "method" instance produced by Puppet::Parser::Methods for this method call.
+    # @see Puppet::Parser::Methods
+    # @return [Object] what the called method/function returns
+    def evaluate(scope)
+      # Make sure it's a defined method for the receiver
+      r = @receiver.evaluate(scope)
+      raise Puppet::ParseError, "No object to apply method #{@name} to" unless r
+      m = Puppet::Parser::Methods.find_method(scope, r, @name)
+      raise Puppet::ParseError, "Unknown method #{@name} for #{r}" unless m
+
+      # Now check if rvalue is required (in expressions)
+      case @ftype
+      when :rvalue
+        raise Puppet::ParseError, "Method '#{@name}' does not return a value" unless m.is_rvalue?
+      when :statement
+        # When used as a statement, ignore if it produces a rvalue (it is simply not used)
+      else
+        raise Puppet::DevError, "Invalid method type #{@ftype.inspect}"
+      end
+
+      # Evaluate arguments
+      args = @arguments ? @arguments.safeevaluate(scope).map { |x| x == :undef ? '' : x } : []
+
+      # There is no need to evaluate the name, since it is a literal ruby string
+
+      # call the method (it is already bound to the receiver and name)
+      m.invoke(scope, args, @lambda)
+    end
+
+    def initialize(hash)
+      @ftype = hash[:ftype] || :rvalue
+      hash.delete(:ftype) if hash.include? :ftype
+
+      super(hash)
+
+      # Lastly, check the parity
+    end
+
+    # Sets this method call in statement mode where a produced rvalue is ignored.
+    # @return [void]
+    def ignore_rvalue
+      @ftype = :statement
+    end
+
+    def to_s
+      args = arguments.is_a?(ASTArray) ? arguments.to_s.gsub(/\[(.*)\]/,'\1') : arguments
+      "#{@receiver.to_s}.#{name} (#{args})" + (@lambda ? " #{@lambda.to_s}" : '')
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/minus.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/minus.rb
new file mode 100644
index 0000000..d7a362a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/minus.rb
@@ -0,0 +1,23 @@
+require 'puppet'
+require 'puppet/parser/ast/branch'
+
+# An object that returns a boolean which is the boolean not
+# of the given value.
+class Puppet::Parser::AST
+  class Minus < AST::Branch
+    attr_accessor :value
+
+    def each
+      yield @value
+    end
+
+    def evaluate(scope)
+      val = @value.safeevaluate(scope)
+      val = Puppet::Parser::Scope.number?(val)
+      if val == nil
+        raise ArgumentError, "minus operand #{val} is not a number"
+      end
+      -val
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/node.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/node.rb
new file mode 100644
index 0000000..fd64433
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/node.rb
@@ -0,0 +1,25 @@
+require 'puppet/parser/ast/top_level_construct'
+
+class Puppet::Parser::AST::Node < Puppet::Parser::AST::TopLevelConstruct
+  attr_accessor :names, :context
+
+  def initialize(names, context = {}, &ruby_code)
+    raise ArgumentError, "names should be an array" unless names.is_a? Array
+    if context[:parent]
+      msg = "Deprecation notice: Node inheritance is not supported in Puppet >= 4.0.0. See http://links.puppetlabs.com/puppet-node-inheritance-deprecation"
+      Puppet.puppet_deprecation_warning(msg, :key => "node-inheritance-#{names.join}", :file => context[:file], :line => context[:line])
+    end
+
+    @names = names
+    @context = context
+    @ruby_code = ruby_code
+  end
+
+  def instantiate(modname)
+    @names.collect do |name|
+      new_node = Puppet::Resource::Type.new(:node, name, @context.merge(:module_name => modname))
+      new_node.ruby_code = @ruby_code if @ruby_code
+      new_node
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/nop.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/nop.rb
new file mode 100644
index 0000000..15383aa
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/nop.rb
@@ -0,0 +1,11 @@
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST
+  # This class is a no-op, it doesn't produce anything
+  # when evaluated, hence its name :-)
+  class Nop < AST::Leaf
+    def evaluate(scope)
+      # nothing to do
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/not.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/not.rb
new file mode 100644
index 0000000..30fa6d5
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/not.rb
@@ -0,0 +1,19 @@
+require 'puppet'
+require 'puppet/parser/ast/branch'
+
+# An object that returns a boolean which is the boolean not
+# of the given value.
+class Puppet::Parser::AST
+  class Not < AST::Branch
+    attr_accessor :value
+
+    def each
+      yield @value
+    end
+
+    def evaluate(scope)
+      val = @value.safeevaluate(scope)
+      ! Puppet::Parser::Scope.true?(val)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/pops_bridge.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/pops_bridge.rb
new file mode 100644
index 0000000..4ebf00d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/pops_bridge.rb
@@ -0,0 +1,248 @@
+require 'puppet/parser/ast/top_level_construct'
+require 'puppet/pops'
+
+# The AST::Bridge contains classes that bridges between the new Pops based model
+# and the 3.x AST. This is required to be able to reuse the Puppet::Resource::Type which is
+# fundamental for the rest of the logic.
+#
+class Puppet::Parser::AST::PopsBridge
+
+  # Bridges to one Pops Model Expression
+  # The @value is the expression
+  # This is used to represent the body of a class, definition, or node, and for each parameter's default value
+  # expression.
+  #
+  class Expression < Puppet::Parser::AST::Leaf
+
+    def initialize args
+      super
+      @@evaluator ||= Puppet::Pops::Parser::EvaluatingParser.new()
+    end
+
+    def to_s
+      Puppet::Pops::Model::ModelTreeDumper.new.dump(@value)
+    end
+
+    def source_text
+      source_adapter = Puppet::Pops::Utils.find_closest_positioned(@value)
+      source_adapter ? source_adapter.extract_text() : nil
+    end
+
+    def evaluate(scope)
+      object = @@evaluator.evaluate(scope, @value)
+      @@evaluator.convert_to_3x(object, scope)
+    end
+
+    # Adapts to 3x where top level constructs needs to have each to iterate over children. Short circuit this
+    # by yielding self. By adding this there is no need to wrap a pops expression inside an AST::BlockExpression
+    #
+    def each
+      yield self
+    end
+
+    def sequence_with(other)
+      if value.nil?
+        # This happens when testing and not having a complete setup
+        other
+      else
+        # When does this happen ? Ever ?
+        raise "sequence_with called on Puppet::Parser::AST::PopsBridge::Expression - please report use case"
+        # What should be done if the above happens (We don't want this to happen).
+        # Puppet::Parser::AST::BlockExpression.new(:children => [self] + other.children)
+      end
+    end
+
+    # The 3x requires code plugged in to an AST to have this in certain positions in the tree. The purpose
+    # is to either print the content, or to look for things that needs to be defined. This implementation
+    # cheats by always returning an empty array. (This allows simple files to not require a "Program" at the top.
+    #
+    def children
+      []
+    end
+  end
+
+  # Bridges the top level "Program" produced by the pops parser.
+  # Its main purpose is to give one point where all definitions are instantiated (actually defined since the
+  # Puppet 3x terminology is somewhat misleading - the definitions are instantiated, but instances of the created types
+  # are not created, that happens when classes are included / required, nodes are matched and when resources are instantiated
+  # by a resource expression (which is also used to instantiate a host class).
+  #
+  class Program < Puppet::Parser::AST::TopLevelConstruct
+    attr_reader :program_model, :context
+
+    def initialize(program_model, context = {})
+      @program_model = program_model
+      @context = context
+      @ast_transformer ||= Puppet::Pops::Model::AstTransformer.new(@context[:file])
+      @@evaluator ||= Puppet::Pops::Parser::EvaluatingParser.new()
+    end
+
+    # This is the 3x API, the 3x AST searches through all code to find the instructions that can be instantiated.
+    # This Pops-model based instantiation relies on the parser to build this list while parsing (which is more
+    # efficient as it avoids one full scan of all logic via recursive enumeration/yield)
+    #
+    def instantiate(modname)
+      @program_model.definitions.collect do |d|
+        case d
+        when Puppet::Pops::Model::HostClassDefinition
+          instantiate_HostClassDefinition(d, modname)
+        when Puppet::Pops::Model::ResourceTypeDefinition
+          instantiate_ResourceTypeDefinition(d, modname)
+        when Puppet::Pops::Model::NodeDefinition
+          instantiate_NodeDefinition(d, modname)
+        else
+          raise Puppet::ParseError, "Internal Error: Unknown type of definition - got '#{d.class}'"
+        end
+      end.flatten().compact() # flatten since node definition may have returned an array
+                              # Compact since functions are not understood by compiler
+    end
+
+    def evaluate(scope)
+      @@evaluator.evaluate(scope, program_model)
+    end
+
+    # Adapts to 3x where top level constructs needs to have each to iterate over children. Short circuit this
+    # by yielding self. This means that the HostClass container will call this bridge instance with `instantiate`.
+    #
+    def each
+      yield self
+    end
+
+    private
+
+    def instantiate_Parameter(o)
+      # 3x needs parameters as an array of `[name]` or `[name, value_expr]`
+      if o.value
+        [o.name, Expression.new(:value => o.value)]
+      else
+        [o.name]
+      end
+    end
+
+    def create_type_map(definition)
+      result = {}
+      # No need to do anything if there are no parameters
+      return result unless definition.parameters.size > 0
+
+      # No need to do anything if there are no typed parameters
+      typed_parameters = definition.parameters.select {|p| p.type_expr }
+      return result if typed_parameters.empty?
+
+      # If there are typed parameters, they need to be evaluated to produce the corresponding type
+      # instances. This evaluation requires a scope. A scope is not available when doing deserialization
+      # (there is also no initialized evaluator). When running apply and test however, the environment is
+      # reused and we may reenter without a scope (which is fine). A debug message is then output in case
+      # there is the need to track down the odd corner case. See {#obtain_scope}.
+      #
+      if scope = obtain_scope
+        typed_parameters.each do |p|
+          result[p.name] =  @@evaluator.evaluate(scope, p.type_expr)
+        end
+      end
+      result
+    end
+
+    # Obtains the scope or issues a warning if :global_scope is not bound
+    def obtain_scope
+      scope = Puppet.lookup(:global_scope) do
+        # This occurs when testing and when applying a catalog (there is no scope available then), and
+        # when running tests that run a partial setup.
+        # This is bad if the logic is trying to compile, but a warning can not be issues since it is a normal
+        # use case that there is no scope when requesting the type in order to just get the parameters.
+        Puppet.debug("Instantiating Resource with type checked parameters - scope is missing, skipping type checking.")
+        nil
+      end
+      scope
+    end
+
+    # Produces a hash with data for Definition and HostClass
+    def args_from_definition(o, modname)
+      args = {
+       :arguments => o.parameters.collect {|p| instantiate_Parameter(p) },
+       :argument_types => create_type_map(o),
+       :module_name => modname
+      }
+      unless is_nop?(o.body)
+        args[:code] = Expression.new(:value => o.body)
+      end
+      @ast_transformer.merge_location(args, o)
+    end
+
+    def instantiate_HostClassDefinition(o, modname)
+      args = args_from_definition(o, modname)
+      args[:parent] = absolute_reference(o.parent_class)
+      Puppet::Resource::Type.new(:hostclass, o.name, @context.merge(args))
+    end
+
+    def instantiate_ResourceTypeDefinition(o, modname)
+      Puppet::Resource::Type.new(:definition, o.name, @context.merge(args_from_definition(o, modname)))
+    end
+
+    def instantiate_NodeDefinition(o, modname)
+      args = { :module_name => modname }
+
+      unless is_nop?(o.body)
+        args[:code] = Expression.new(:value => o.body)
+      end
+
+      unless is_nop?(o.parent)
+        args[:parent] = @ast_transformer.hostname(o.parent)
+      end
+
+      host_matches = @ast_transformer.hostname(o.host_matches)
+      @ast_transformer.merge_location(args, o)
+      host_matches.collect do |name|
+        Puppet::Resource::Type.new(:node, name, @context.merge(args))
+      end
+    end
+
+    # Propagates a found Function to the appropriate loader.
+    # This is for 4x future-evaluator/loader
+    #
+    def instantiate_FunctionDefinition(function_definition, modname)
+      loaders = (Puppet.lookup(:loaders) { nil })
+      unless loaders
+        raise Puppet::ParseError, "Internal Error: Puppet Context ':loaders' missing - cannot define any functions"
+      end
+      loader =
+      if modname.nil? || modname == ""
+        # TODO : Later when functions can be private, a decision is needed regarding what that means.
+        #        A private environment loader could be used for logic outside of modules, then only that logic
+        #        would see the function.
+        #
+        # Use the private loader, this function may see the environment's dependencies (currently, all modules)
+        loaders.private_environment_loader()
+      else
+        # TODO : Later check if function is private, and then add it to
+        #        private_loader_for_module
+        #
+        loaders.public_loader_for_module(modname)
+      end
+      unless loader
+        raise Puppet::ParseError, "Internal Error: did not find public loader for module: '#{modname}'"
+      end
+
+      # Instantiate Function, and store it in the environment loader
+      typed_name, f = Puppet::Pops::Loader::PuppetFunctionInstantiator.create_from_model(function_definition, loader)
+      loader.set_entry(typed_name, f, Puppet::Pops::Adapters::SourcePosAdapter.adapt(function_definition).to_uri)
+
+      nil # do not want the function to inadvertently leak into 3x
+    end
+
+    def code()
+      Expression.new(:value => @value)
+    end
+
+    def is_nop?(o)
+      @ast_transformer.is_nop?(o)
+    end
+
+    def absolute_reference(ref)
+      if ref.nil? || ref.empty? || ref.start_with?('::')
+        ref
+      else
+        "::#{ref}"
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/relationship.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/relationship.rb
new file mode 100644
index 0000000..37ead31
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/relationship.rb
@@ -0,0 +1,47 @@
+require 'puppet/parser/ast'
+require 'puppet/parser/ast/branch'
+require 'puppet/parser/relationship'
+
+class Puppet::Parser::AST::Relationship < Puppet::Parser::AST::Branch
+  RELATIONSHIP_TYPES = %w{-> <- ~> <~}
+
+  attr_accessor :left, :right, :arrow, :type
+
+  # Evaluate our object, but just return a simple array of the type
+  # and name.
+  def evaluate(scope)
+    real_left = left.safeevaluate(scope)
+    real_right = right.safeevaluate(scope)
+
+    source, target = sides2edge(real_left, real_right)
+    scope.compiler.add_relationship Puppet::Parser::Relationship.new(source, target, type)
+
+    real_right
+  end
+
+  def initialize(left, right, arrow, args = {})
+    super(args)
+    unless RELATIONSHIP_TYPES.include?(arrow)
+      raise ArgumentError, "Invalid relationship type #{arrow.inspect}; valid types are #{RELATIONSHIP_TYPES.collect { |r| r.to_s }.join(", ")}"
+    end
+    @left, @right, @arrow = left, right, arrow
+  end
+
+  def type
+    subscription? ? :subscription : :relationship
+  end
+
+  def sides2edge(left, right)
+    out_edge? ? [left, right] : [right, left]
+  end
+
+  private
+
+  def out_edge?
+    ["->", "~>"].include?(arrow)
+  end
+
+  def subscription?
+    ["~>", "<~"].include?(arrow)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/resource.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/resource.rb
new file mode 100644
index 0000000..5f5f1ab
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/resource.rb
@@ -0,0 +1,67 @@
+require 'puppet/parser/ast/resource_reference'
+
+# Any normal puppet resource declaration.  Can point to a definition or a
+# builtin type.
+class Puppet::Parser::AST
+class Resource < AST::Branch
+
+  associates_doc
+
+  attr_accessor :type, :instances, :exported, :virtual
+
+  # Does not actually return an object; instead sets an object
+  # in the current scope.
+  def evaluate(scope)
+    # We want virtual to be true if exported is true.  We can't
+    # just set :virtual => self.virtual in the initialization,
+    # because sometimes the :virtual attribute is set *after*
+    # :exported, in which case it clobbers :exported if :exported
+    # is true.  Argh, this was a very tough one to track down.
+    virt = self.virtual || self.exported
+
+    # First level of implicit iteration: build a resource for each
+    # instance.  This handles things like:
+    # file { '/foo': owner => blah; '/bar': owner => blah }
+    @instances.collect { |instance|
+
+      # Evaluate all of the specified params.
+      paramobjects = instance.parameters.collect { |param|
+        param.safeevaluate(scope)
+      }
+
+      resource_titles = instance.title.safeevaluate(scope)
+
+      # it's easier to always use an array, even for only one name
+      resource_titles = [resource_titles] unless resource_titles.is_a?(Array)
+
+      fully_qualified_type, resource_titles = scope.resolve_type_and_titles(type, resource_titles)
+
+      # Second level of implicit iteration; build a resource for each
+      # title.  This handles things like:
+      # file { ['/foo', '/bar']: owner => blah }
+      resource_titles.flatten.collect { |resource_title|
+        exceptwrap :type => Puppet::ParseError do
+          resource = Puppet::Parser::Resource.new(
+            fully_qualified_type, resource_title,
+            :parameters => paramobjects,
+            :file => self.file,
+            :line => self.line,
+            :exported => self.exported,
+            :virtual => virt,
+            :source => scope.source,
+            :scope => scope,
+            :strict => true
+          )
+
+          if resource.resource_type.is_a? Puppet::Resource::Type
+            resource.resource_type.instantiate_resource(scope, resource)
+          end
+          scope.compiler.add_resource(scope, resource)
+          scope.compiler.evaluate_classes([resource_title], scope, false, true) if fully_qualified_type == 'class'
+          resource
+        end
+      }
+    }.flatten.reject { |resource| resource.nil? }
+  end
+end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/resource_defaults.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/resource_defaults.rb
new file mode 100644
index 0000000..9dfed28
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/resource_defaults.rb
@@ -0,0 +1,24 @@
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST
+  # A statement syntactically similar to an ResourceDef, but uses a
+  # capitalized object type and cannot have a name.
+  class ResourceDefaults < AST::Branch
+    attr_accessor :type, :parameters
+
+    associates_doc
+
+    # As opposed to ResourceDef, this stores each default for the given
+    # object type.
+    def evaluate(scope)
+      # Use a resource reference to canonize the type
+      ref = Puppet::Resource.new(@type, "whatever")
+      type = ref.type
+      params = @parameters.safeevaluate(scope)
+
+      parsewrap do
+        scope.define_settings(type, params)
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/resource_instance.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/resource_instance.rb
new file mode 100644
index 0000000..ebfb17b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/resource_instance.rb
@@ -0,0 +1,9 @@
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST
+  class ResourceInstance < Branch
+    # A simple container for a parameter for an object.  Consists of a
+    # title and a set of parameters.
+    attr_accessor :title, :parameters
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/resource_override.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/resource_override.rb
new file mode 100644
index 0000000..78fe741
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/resource_override.rb
@@ -0,0 +1,62 @@
+require 'puppet/parser/ast/resource'
+
+class Puppet::Parser::AST
+  # Set a parameter on a resource specification created somewhere else in the
+  # configuration.  The object is responsible for verifying that this is allowed.
+  class ResourceOverride < AST::Branch
+
+    associates_doc
+
+    attr_accessor :object, :parameters
+
+    # Iterate across all of our children.
+    def each
+      [@object,@parameters].flatten.each { |param|
+        #Puppet.debug("yielding param #{param}")
+        yield param
+      }
+    end
+
+    # Does not actually return an object; instead sets an object
+    # in the current scope.
+    def evaluate(scope)
+      # Get our object reference.
+      resource = @object.safeevaluate(scope)
+
+      # Evaluate all of the specified params.
+      params = @parameters.collect { |param|
+        param.safeevaluate(scope)
+      }
+
+      # Now we just create a normal resource, but we call a very different
+      # method on the scope.
+      resource = [resource] unless resource.is_a?(Array)
+
+      resource = resource.collect do |r|
+
+        res = Puppet::Parser::Resource.new(
+        r.type, r.title,
+          :parameters => params,
+          :file => file,
+          :line => line,
+          :source => scope.source,
+          :scope => scope
+        )
+
+        # Now we tell the scope that it's an override, and it behaves as
+        # necessary.
+        scope.compiler.add_override(res)
+
+        res
+      end
+      # decapsulate array in case of only one item
+      return(resource.length == 1 ? resource.pop : resource)
+    end
+
+    # Create our ResourceDef.  Handles type checking for us.
+    def initialize(hash)
+      @checked = false
+      super
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/resource_reference.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/resource_reference.rb
new file mode 100644
index 0000000..256a99d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/resource_reference.rb
@@ -0,0 +1,28 @@
+require 'puppet/parser/ast'
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST::ResourceReference < Puppet::Parser::AST::Branch
+  attr_accessor :title, :type
+
+  # Evaluate our object, but just return a simple array of the type
+  # and name.
+  def evaluate(scope)
+    titles = Array(title.safeevaluate(scope)).flatten
+
+    a_type, titles = scope.resolve_type_and_titles(type, titles)
+
+    resources = titles.collect{ |a_title|
+      Puppet::Resource.new(a_type, a_title)
+    }
+
+    return(resources.length == 1 ? resources.pop : resources)
+  end
+
+  def to_s
+    if title.is_a?(Puppet::Parser::AST::ASTArray)
+      "#{type.to_s.capitalize}#{title}"
+    else
+      "#{type.to_s.capitalize}[#{title}]"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/resourceparam.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/resourceparam.rb
new file mode 100644
index 0000000..04e945c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/resourceparam.rb
@@ -0,0 +1,27 @@
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST
+  # The AST object for the parameters inside ResourceDefs and Selectors.
+  class ResourceParam < AST::Branch
+    attr_accessor :value, :param, :add
+
+    def each
+      [@param,@value].each { |child| yield child }
+    end
+
+    # Return the parameter and the value.
+    def evaluate(scope)
+      value = @value.safeevaluate(scope)
+      return Puppet::Parser::Resource::Param.new(
+        :name   => @param,
+        :value  => value.nil? ? :undef : value,
+        :source => scope.source, :line => self.line, :file => self.file,
+        :add    => self.add
+      )
+    end
+
+    def to_s
+      "#{@param} => #{@value.to_s}"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/selector.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/selector.rb
new file mode 100644
index 0000000..04f0b18
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/selector.rb
@@ -0,0 +1,50 @@
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST
+  # The inline conditional operator.  Unlike CaseStatement, which executes
+  # code, we just return a value.
+  class Selector < AST::Branch
+    attr_accessor :param, :values
+
+    def each
+      [@param,@values].each { |child| yield child }
+    end
+
+    # Find the value that corresponds with the test.
+    def evaluate(scope)
+      level = scope.ephemeral_level
+      # Get our parameter.
+      paramvalue = @param.safeevaluate(scope)
+
+      default = nil
+
+      @values = [@values] unless @values.instance_of? AST::ASTArray or @values.instance_of? Array
+
+      # Then look for a match in the options.
+      @values.each do |obj|
+        # short circuit asap if we have a match
+        return obj.value.safeevaluate(scope) if obj.param.evaluate_match(paramvalue, scope)
+
+        # Store the default, in case it's necessary.
+        default = obj if obj.param.is_a?(Default)
+      end
+
+      # Unless we found something, look for the default.
+      return default.value.safeevaluate(scope) if default
+
+      self.fail Puppet::ParseError, "No matching value for selector param '#{paramvalue}'"
+    ensure
+      scope.unset_ephemeral_var(level)
+    end
+
+    def to_s
+      if @values.instance_of? AST::ASTArray or @values.instance_of? Array
+        v = @values
+      else
+        v = [@values]
+      end
+
+      param.to_s + " ? { " + v.collect { |v| v.to_s }.join(', ') + " }"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/top_level_construct.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/top_level_construct.rb
new file mode 100644
index 0000000..901a939
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/top_level_construct.rb
@@ -0,0 +1,4 @@
+# The base class for AST nodes representing top level things:
+# hostclasses, definitions, and nodes.
+class Puppet::Parser::AST::TopLevelConstruct < Puppet::Parser::AST
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/vardef.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/vardef.rb
new file mode 100644
index 0000000..07999f3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/ast/vardef.rb
@@ -0,0 +1,38 @@
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST
+  # Define a variable.  Stores the value in the current scope.
+  class VarDef < AST::Branch
+
+    associates_doc
+
+    attr_accessor :name, :value, :append
+
+    # Look up our name and value, and store them appropriately.  The
+    # lexer strips off the syntax stuff like '$'.
+    def evaluate(scope)
+      value = @value.safeevaluate(scope)
+      if name.is_a?(HashOrArrayAccess)
+        name.assign(scope, value)
+      else
+        name = @name.safeevaluate(scope)
+
+        parsewrap do
+          scope.setvar(name,value, :file => file, :line => line, :append => @append)
+        end
+      end
+      if @append
+        # Produce resulting value from append operation
+        scope[name]
+      else
+        # Produce assigned value
+        value
+      end
+    end
+
+    def each
+      [@name,@value].each { |child| yield child }
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/code_merger.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/code_merger.rb
new file mode 100644
index 0000000..e8913b8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/code_merger.rb
@@ -0,0 +1,13 @@
+
+class Puppet::Parser::CodeMerger
+
+  # Concatenates the logic in the array of parse results into one parse result
+  # @return Puppet::Parser::AST::BlockExpression
+  #
+  def concatenate(parse_results)
+    children = parse_results.select {|x| !x.nil? && x.code}.reduce([]) do |memo, parsed_class|
+      memo + parsed_class.code.children
+    end
+    Puppet::Parser::AST::BlockExpression.new(:children => children)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/collector.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/collector.rb
new file mode 100644
index 0000000..7a15bfb
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/collector.rb
@@ -0,0 +1,177 @@
+# An object that collects stored objects from the central cache and returns
+# them to the current host, yo.
+class Puppet::Parser::Collector
+  attr_accessor :type, :scope, :vquery, :equery, :form
+  attr_accessor :resources, :overrides, :collected
+
+  # Call the collection method, mark all of the returned objects as
+  # non-virtual, optionally applying parameter overrides. The collector can
+  # also delete himself from the compiler if there is no more resources to
+  # collect (valid only for resource fixed-set collector which get their
+  # resources from +collect_resources+ and not from the catalog)
+  def evaluate
+    # Shortcut if we're not using storeconfigs and they're trying to collect
+    # exported resources.
+    if form == :exported and Puppet[:storeconfigs] != true
+      Puppet.warning "Not collecting exported resources without storeconfigs"
+      return false
+    end
+
+    if self.resources
+      unless objects = collect_resources and ! objects.empty?
+        return false
+      end
+    else
+      method = "collect_#{@form.to_s}"
+      objects = send(method).each do |obj|
+        obj.virtual = false
+      end
+      return false if objects.empty?
+    end
+
+    # we have an override for the collected resources
+    if @overrides and !objects.empty?
+      # force the resource to be always child of any other resource
+      overrides[:source].meta_def(:child_of?) do |klass|
+        true
+      end
+
+      # tell the compiler we have some override for him unless we already
+      # overrided those resources
+      objects.each do |res|
+        unless @collected.include?(res.ref)
+          newres = Puppet::Parser::Resource.
+            new(res.type, res.title,
+                :parameters => overrides[:parameters],
+                :file       => overrides[:file],
+                :line       => overrides[:line],
+                :source     => overrides[:source],
+                :scope      => overrides[:scope])
+
+          scope.compiler.add_override(newres)
+        end
+      end
+    end
+
+    # filter out object that this collector has previously found.
+    objects.reject! { |o| @collected.include?(o.ref) }
+
+    return false if objects.empty?
+
+    # keep an eye on the resources we have collected
+    objects.inject(@collected) { |c,o| c[o.ref]=o; c }
+
+    # return our newly collected resources
+    objects
+  end
+
+  def initialize(scope, type, equery, vquery, form)
+    @scope  = scope
+    @vquery = vquery
+    @equery = equery
+
+    # initialisation
+    @collected = {}
+
+    # Canonize the type
+    @type = Puppet::Resource.new(type, "whatever").type
+
+    unless [:exported, :virtual].include?(form)
+      raise ArgumentError, "Invalid query form #{form}"
+    end
+    @form = form
+  end
+
+  # add a resource override to the soon to be exported/realized resources
+  def add_override(hash)
+    raise ArgumentError, "Exported resource try to override without parameters" unless hash[:parameters]
+
+    # schedule an override for an upcoming collection
+    @overrides = hash
+  end
+
+  private
+
+  # Collect exported objects.
+  def collect_exported
+    resources = []
+
+    time = Puppet::Util.thinmark do
+      # First get everything from the export table.  Just reuse our
+      # collect_virtual method but tell it to use 'exported? for the test.
+      resources = collect_virtual(true).reject { |r| ! r.virtual? }
+
+      # key is '#{type}/#{name}', and host and filter.
+      found = Puppet::Resource.indirection.
+        search(@type, :host => @scope.compiler.node.name, :filter => @equery, :scope => @scope)
+
+      found_resources = found.map {|x| x.is_a?(Puppet::Parser::Resource) ? x : x.to_resource(@scope)}
+
+      found_resources.each do |item|
+        if existing = @scope.findresource(item.type, item.title)
+          unless existing.collector_id == item.collector_id
+            # unless this is the one we've already collected
+            raise Puppet::ParseError,
+              "A duplicate resource was found while collecting exported resources, with the type and title #{item.ref}"
+          end
+        else
+          item.exported = false
+          @scope.compiler.add_resource(@scope, item)
+          resources << item
+        end
+      end
+    end
+
+    scope.debug("Collected %s %s resource%s in %.2f seconds" %
+                [resources.length, @type, resources.length == 1 ? "" : "s", time])
+
+    resources
+  end
+
+  def collect_resources
+    @resources = [@resources] unless @resources.is_a?(Array)
+    method = "collect_#{form.to_s}_resources"
+    send(method)
+  end
+
+  def collect_exported_resources
+    raise Puppet::ParseError, "realize() is not yet implemented for exported resources"
+  end
+
+  # Collect resources directly; this is the result of using 'realize',
+  # which specifies resources, rather than using a normal collection.
+  def collect_virtual_resources
+    return [] unless defined?(@resources) and ! @resources.empty?
+    result = @resources.dup.collect do |ref|
+      if res = @scope.findresource(ref.to_s)
+        @resources.delete(ref)
+        res
+      end
+    end.reject { |r| r.nil? }.each do |res|
+      res.virtual = false
+    end
+
+    # If there are no more resources to find, delete this from the list
+    # of collections.
+    @scope.compiler.delete_collection(self) if @resources.empty?
+
+    result
+  end
+
+  # Collect just virtual objects, from our local compiler.
+  def collect_virtual(exported = false)
+    scope.compiler.resources.find_all do |resource|
+      resource.type == @type and (exported ? resource.exported? : true) and match?(resource)
+    end
+  end
+
+  # Does the resource match our tests?  We don't yet support tests,
+  # so it's always true at the moment.
+  def match?(resource)
+    if self.vquery
+      return self.vquery.call(resource)
+    else
+      return true
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/compiler.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/compiler.rb
new file mode 100644
index 0000000..65c7707
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/compiler.rb
@@ -0,0 +1,634 @@
+require 'forwardable'
+
+require 'puppet/node'
+require 'puppet/resource/catalog'
+require 'puppet/util/errors'
+
+require 'puppet/resource/type_collection_helper'
+
+# Maintain a graph of scopes, along with a bunch of data
+# about the individual catalog we're compiling.
+class Puppet::Parser::Compiler
+  extend Forwardable
+
+  include Puppet::Util
+  include Puppet::Util::Errors
+  include Puppet::Util::MethodHelper
+  include Puppet::Resource::TypeCollectionHelper
+
+  def self.compile(node)
+    $env_module_directories = nil
+    node.environment.check_for_reparse
+
+    if node.environment.conflicting_manifest_settings?
+      errmsg = [
+        "The 'disable_per_environment_manifest' setting is true, and this '#{node.environment}'",
+        "has an environment.conf manifest that conflicts with the 'default_manifest' setting.",
+        "Compilation has been halted in order to avoid running a catalog which may be using",
+        "unexpected manifests. For more information, see",
+        "http://docs.puppetlabs.com/puppet/latest/reference/environments.html",
+      ]
+      raise(Puppet::Error, errmsg.join(' '))
+    end
+
+    new(node).compile {|resulting_catalog| resulting_catalog.to_resource }
+  rescue Puppet::ParseErrorWithIssue => detail
+    detail.node = node.name
+    Puppet.log_exception(detail)
+    raise
+  rescue => detail
+    message = "#{detail} on node #{node.name}"
+    Puppet.log_exception(detail, message)
+    raise Puppet::Error, message, detail.backtrace
+ end
+
+  attr_reader :node, :facts, :collections, :catalog, :resources, :relationships, :topscope
+
+  # The injector that provides lookup services, or nil if accessed before the compiler has started compiling and
+  # bootstrapped. The injector is initialized and available before any manifests are evaluated.
+  #
+  # @return [Puppet::Pops::Binder::Injector, nil] The injector that provides lookup services for this compiler/environment
+  # @api public
+  #
+  attr_accessor :injector
+
+  # Access to the configured loaders for 4x
+  # @return [Puppet::Pops::Loader::Loaders] the configured loaders
+  # @api private
+  attr_reader :loaders
+
+  # The injector that provides lookup services during the creation of the {#injector}.
+  # @return [Puppet::Pops::Binder::Injector, nil] The injector that provides lookup services during injector creation
+  #   for this compiler/environment
+  #
+  # @api private
+  #
+  attr_accessor :boot_injector
+
+  # Add a collection to the global list.
+  def_delegator :@collections,   :<<, :add_collection
+  def_delegator :@relationships, :<<, :add_relationship
+
+  # Store a resource override.
+  def add_override(override)
+    # If possible, merge the override in immediately.
+    if resource = @catalog.resource(override.ref)
+      resource.merge(override)
+    else
+      # Otherwise, store the override for later; these
+      # get evaluated in Resource#finish.
+      @resource_overrides[override.ref] << override
+    end
+  end
+
+  def add_resource(scope, resource)
+    @resources << resource
+
+    # Note that this will fail if the resource is not unique.
+    @catalog.add_resource(resource)
+
+    if not resource.class? and resource[:stage]
+      raise ArgumentError, "Only classes can set 'stage'; normal resources like #{resource} cannot change run stage"
+    end
+
+    # Stages should not be inside of classes.  They are always a
+    # top-level container, regardless of where they appear in the
+    # manifest.
+    return if resource.stage?
+
+    # This adds a resource to the class it lexically appears in in the
+    # manifest.
+    unless resource.class?
+      return @catalog.add_edge(scope.resource, resource)
+    end
+  end
+
+  # Do we use nodes found in the code, vs. the external node sources?
+  def_delegator :known_resource_types, :nodes?, :ast_nodes?
+
+  # Store the fact that we've evaluated a class
+  def add_class(name)
+    @catalog.add_class(name) unless name == ""
+  end
+
+
+  # Return a list of all of the defined classes.
+  def_delegator :@catalog, :classes, :classlist
+
+  # Compiler our catalog.  This mostly revolves around finding and evaluating classes.
+  # This is the main entry into our catalog.
+  def compile
+    Puppet.override( @context_overrides , "For compiling #{node.name}") do
+      @catalog.environment_instance = environment
+
+      # Set the client's parameters into the top scope.
+      Puppet::Util::Profiler.profile("Compile: Set node parameters", [:compiler, :set_node_params]) { set_node_parameters }
+
+      Puppet::Util::Profiler.profile("Compile: Created settings scope", [:compiler, :create_settings_scope]) { create_settings_scope }
+
+      if is_binder_active?
+        # create injector, if not already created - this is for 3x that does not trigger
+        # lazy loading of injector via context
+        Puppet::Util::Profiler.profile("Compile: Created injector", [:compiler, :create_injector]) { injector }
+      end
+
+      Puppet::Util::Profiler.profile("Compile: Evaluated main", [:compiler, :evaluate_main]) { evaluate_main }
+
+      Puppet::Util::Profiler.profile("Compile: Evaluated AST node", [:compiler, :evaluate_ast_node]) { evaluate_ast_node }
+
+      Puppet::Util::Profiler.profile("Compile: Evaluated node classes", [:compiler, :evaluate_node_classes]) { evaluate_node_classes }
+
+      Puppet::Util::Profiler.profile("Compile: Evaluated generators", [:compiler, :evaluate_generators]) { evaluate_generators }
+
+      Puppet::Util::Profiler.profile("Compile: Finished catalog", [:compiler, :finish_catalog]) { finish }
+
+      fail_on_unevaluated
+
+      if block_given?
+        yield @catalog
+      else
+        @catalog
+      end
+    end
+  end
+
+  # Constructs the overrides for the context
+  def context_overrides()
+    if Puppet.future_parser?(environment)
+      {
+        :current_environment => environment,
+        :global_scope => @topscope,             # 4x placeholder for new global scope
+        :loaders  => lambda {|| loaders() },    # 4x loaders
+        :injector => lambda {|| injector() }    # 4x API - via context instead of via compiler
+      }
+    else
+      {
+        :current_environment => environment,
+      }
+    end
+  end
+
+  def_delegator :@collections, :delete, :delete_collection
+
+  # Return the node's environment.
+  def environment
+    node.environment
+  end
+
+  # Evaluate all of the classes specified by the node.
+  # Classes with parameters are evaluated as if they were declared.
+  # Classes without parameters or with an empty set of parameters are evaluated
+  # as if they were included. This means classes with an empty set of
+  # parameters won't conflict even if the class has already been included.
+  def evaluate_node_classes
+    if @node.classes.is_a? Hash
+      classes_with_params, classes_without_params = @node.classes.partition {|name,params| params and !params.empty?}
+
+      # The results from Hash#partition are arrays of pairs rather than hashes,
+      # so we have to convert to the forms evaluate_classes expects (Hash, and
+      # Array of class names)
+      classes_with_params = Hash[classes_with_params]
+      classes_without_params.map!(&:first)
+    else
+      classes_with_params = {}
+      classes_without_params = @node.classes
+    end
+
+    evaluate_classes(classes_with_params, @node_scope || topscope)
+    evaluate_classes(classes_without_params, @node_scope || topscope)
+  end
+
+  # Evaluate each specified class in turn.  If there are any classes we can't
+  # find, raise an error.  This method really just creates resource objects
+  # that point back to the classes, and then the resources are themselves
+  # evaluated later in the process.
+  #
+  # Sometimes we evaluate classes with a fully qualified name already, in which
+  # case, we tell scope.find_hostclass we've pre-qualified the name so it
+  # doesn't need to search its namespaces again.  This gets around a weird
+  # edge case of duplicate class names, one at top scope and one nested in our
+  # namespace and the wrong one (or both!) getting selected. See ticket #13349
+  # for more detail.  --jeffweiss 26 apr 2012
+  def evaluate_classes(classes, scope, lazy_evaluate = true, fqname = false)
+    raise Puppet::DevError, "No source for scope passed to evaluate_classes" unless scope.source
+    class_parameters = nil
+    # if we are a param class, save the classes hash
+    # and transform classes to be the keys
+    if classes.class == Hash
+      class_parameters = classes
+      classes = classes.keys
+    end
+
+    hostclasses = classes.collect do |name|
+      scope.find_hostclass(name, :assume_fqname => fqname) or raise Puppet::Error, "Could not find class #{name} for #{node.name}"
+    end
+
+    if class_parameters
+      resources = ensure_classes_with_parameters(scope, hostclasses, class_parameters)
+      if !lazy_evaluate
+        resources.each(&:evaluate)
+      end
+
+      resources
+    else
+      already_included, newly_included = ensure_classes_without_parameters(scope, hostclasses)
+      if !lazy_evaluate
+        newly_included.each(&:evaluate)
+      end
+
+      already_included + newly_included
+    end
+  end
+
+  def evaluate_relationships
+    @relationships.each { |rel| rel.evaluate(catalog) }
+  end
+
+  # Return a resource by either its ref or its type and title.
+  def_delegator :@catalog, :resource, :findresource
+
+  def initialize(node, options = {})
+    @node = node
+    set_options(options)
+    initvars
+  end
+
+  # Create a new scope, with either a specified parent scope or
+  # using the top scope.
+  def newscope(parent, options = {})
+    parent ||= topscope
+    scope = Puppet::Parser::Scope.new(self, options)
+    scope.parent = parent
+    scope
+  end
+
+  # Return any overrides for the given resource.
+  def resource_overrides(resource)
+    @resource_overrides[resource.ref]
+  end
+
+  def injector
+    create_injector if @injector.nil?
+    @injector
+  end
+
+  def loaders
+    @loaders ||= Puppet::Pops::Loaders.new(environment)
+  end
+
+  def boot_injector
+    create_boot_injector(nil) if @boot_injector.nil?
+    @boot_injector
+  end
+
+  # Creates the boot injector from registered system, default, and injector config.
+  # @return [Puppet::Pops::Binder::Injector] the created boot injector
+  # @api private Cannot be 'private' since it is called from the BindingsComposer.
+  #
+  def create_boot_injector(env_boot_bindings)
+    assert_binder_active()
+    pb = Puppet::Pops::Binder
+    boot_contribution = pb::SystemBindings.injector_boot_contribution(env_boot_bindings)
+    final_contribution = pb::SystemBindings.final_contribution
+    binder = pb::Binder.new(pb::BindingsFactory.layered_bindings(final_contribution, boot_contribution))
+    @boot_injector = pb::Injector.new(binder)
+  end
+
+  # Answers if Puppet Binder should be active or not, and if it should and is not active, then it is activated.
+  # @return [Boolean] true if the Puppet Binder should be activated
+  def is_binder_active?
+    should_be_active = Puppet[:binder] || Puppet.future_parser?
+    if should_be_active
+      # TODO: this should be in a central place, not just for ParserFactory anymore...
+      Puppet::Parser::ParserFactory.assert_rgen_installed()
+      @@binder_loaded ||= false
+      unless @@binder_loaded
+        require 'puppet/pops'
+        require 'puppetx'
+        @@binder_loaded = true
+      end
+    end
+    should_be_active
+  end
+
+  private
+
+  def ensure_classes_with_parameters(scope, hostclasses, parameters)
+    hostclasses.collect do |klass|
+      klass.ensure_in_catalog(scope, parameters[klass.name] || {})
+    end
+  end
+
+  def ensure_classes_without_parameters(scope, hostclasses)
+    already_included = []
+    newly_included = []
+    hostclasses.each do |klass|
+      class_scope = scope.class_scope(klass)
+      if class_scope
+        already_included << class_scope.resource
+      else
+        newly_included << klass.ensure_in_catalog(scope)
+      end
+    end
+
+    [already_included, newly_included]
+  end
+
+  # If ast nodes are enabled, then see if we can find and evaluate one.
+  def evaluate_ast_node
+    return unless ast_nodes?
+
+    # Now see if we can find the node.
+    astnode = nil
+    @node.names.each do |name|
+      break if astnode = known_resource_types.node(name.to_s.downcase)
+    end
+
+    unless (astnode ||= known_resource_types.node("default"))
+      raise Puppet::ParseError, "Could not find default node or by name with '#{node.names.join(", ")}'"
+    end
+
+    # Create a resource to model this node, and then add it to the list
+    # of resources.
+    resource = astnode.ensure_in_catalog(topscope)
+
+    resource.evaluate
+
+    @node_scope = topscope.class_scope(astnode)
+  end
+
+  # Evaluate our collections and return true if anything returned an object.
+  # The 'true' is used to continue a loop, so it's important.
+  def evaluate_collections
+    return false if @collections.empty?
+
+    exceptwrap do
+      # We have to iterate over a dup of the array because
+      # collections can delete themselves from the list, which
+      # changes its length and causes some collections to get missed.
+      Puppet::Util::Profiler.profile("Evaluated collections", [:compiler, :evaluate_collections]) do
+        found_something = false
+        @collections.dup.each do |collection|
+          found_something = true if collection.evaluate
+        end
+        found_something
+      end
+    end
+  end
+
+  # Make sure all of our resources have been evaluated into native resources.
+  # We return true if any resources have, so that we know to continue the
+  # evaluate_generators loop.
+  def evaluate_definitions
+    exceptwrap do
+      Puppet::Util::Profiler.profile("Evaluated definitions", [:compiler, :evaluate_definitions]) do
+        !unevaluated_resources.each do |resource|
+          resource.evaluate
+        end.empty?
+      end
+    end
+  end
+
+  # Iterate over collections and resources until we're sure that the whole
+  # compile is evaluated.  This is necessary because both collections
+  # and defined resources can generate new resources, which themselves could
+  # be defined resources.
+  def evaluate_generators
+    count = 0
+    loop do
+      done = true
+
+      Puppet::Util::Profiler.profile("Iterated (#{count + 1}) on generators", [:compiler, :iterate_on_generators]) do
+        # Call collections first, then definitions.
+        done = false if evaluate_collections
+        done = false if evaluate_definitions
+      end
+
+      break if done
+
+      count += 1
+
+      if count > 1000
+        raise Puppet::ParseError, "Somehow looped more than 1000 times while evaluating host catalog"
+      end
+    end
+  end
+
+  # Find and evaluate our main object, if possible.
+  def evaluate_main
+    @main = known_resource_types.find_hostclass([""], "") || known_resource_types.add(Puppet::Resource::Type.new(:hostclass, ""))
+    @topscope.source = @main
+    @main_resource = Puppet::Parser::Resource.new("class", :main, :scope => @topscope, :source => @main)
+    @topscope.resource = @main_resource
+
+    add_resource(@topscope, @main_resource)
+
+    @main_resource.evaluate
+  end
+
+  # Make sure the entire catalog is evaluated.
+  def fail_on_unevaluated
+    fail_on_unevaluated_overrides
+    fail_on_unevaluated_resource_collections
+  end
+
+  # If there are any resource overrides remaining, then we could
+  # not find the resource they were supposed to override, so we
+  # want to throw an exception.
+  def fail_on_unevaluated_overrides
+    remaining = @resource_overrides.values.flatten.collect(&:ref)
+
+    if !remaining.empty?
+      fail Puppet::ParseError,
+        "Could not find resource(s) #{remaining.join(', ')} for overriding"
+    end
+  end
+
+  # Make sure we don't have any remaining collections that specifically
+  # look for resources, because we want to consider those to be
+  # parse errors.
+  def fail_on_unevaluated_resource_collections
+    if Puppet.future_parser?
+      remaining = @collections.collect(&:unresolved_resources).flatten.compact
+    else
+      remaining = @collections.collect(&:resources).flatten.compact
+    end
+
+    if !remaining.empty?
+      raise Puppet::ParseError, "Failed to realize virtual resources #{remaining.join(', ')}"
+    end
+  end
+
+  # Make sure all of our resources and such have done any last work
+  # necessary.
+  def finish
+    evaluate_relationships
+
+    resources.each do |resource|
+      # Add in any resource overrides.
+      if overrides = resource_overrides(resource)
+        overrides.each do |over|
+          resource.merge(over)
+        end
+
+        # Remove the overrides, so that the configuration knows there
+        # are none left.
+        overrides.clear
+      end
+
+      resource.finish if resource.respond_to?(:finish)
+    end
+
+    add_resource_metaparams
+  end
+
+  def add_resource_metaparams
+    unless main = catalog.resource(:class, :main)
+      raise "Couldn't find main"
+    end
+
+    names = Puppet::Type.metaparams.select do |name|
+      !Puppet::Parser::Resource.relationship_parameter?(name)
+    end
+
+    data = {}
+    catalog.walk(main, :out) do |source, target|
+      if source_data = data[source] || metaparams_as_data(source, names)
+        # only store anything in the data hash if we've actually got
+        # data
+        data[source] ||= source_data
+        source_data.each do |param, value|
+          target[param] = value if target[param].nil?
+        end
+        data[target] = source_data.merge(metaparams_as_data(target, names))
+      end
+
+      target.tag(*(source.tags))
+    end
+  end
+
+  def metaparams_as_data(resource, params)
+    data = nil
+    params.each do |param|
+      unless resource[param].nil?
+        # Because we could be creating a hash for every resource,
+        # and we actually probably don't often have any data here at all,
+        # we're optimizing a bit by only creating a hash if there's
+        # any data to put in it.
+        data ||= {}
+        data[param] = resource[param]
+      end
+    end
+    data
+  end
+
+  # Set up all of our internal variables.
+  def initvars
+    # The list of overrides.  This is used to cache overrides on objects
+    # that don't exist yet.  We store an array of each override.
+    @resource_overrides = Hash.new do |overs, ref|
+      overs[ref] = []
+    end
+
+    # The list of collections that have been created.  This is a global list,
+    # but they each refer back to the scope that created them.
+    @collections = []
+
+    # The list of relationships to evaluate.
+    @relationships = []
+
+    # For maintaining the relationship between scopes and their resources.
+    @catalog = Puppet::Resource::Catalog.new(@node.name, @node.environment)
+
+    # MOVED HERE - SCOPE IS NEEDED (MOVE-SCOPE)
+    # Create the initial scope, it is needed early
+    @topscope = Puppet::Parser::Scope.new(self)
+
+    # Need to compute overrides here, and remember them, because we are about to
+    # enter the magic zone of known_resource_types and intial import.
+    # Expensive entries in the context are bound lazily.
+    @context_overrides = context_overrides()
+
+    # This construct ensures that initial import (triggered by instantiating
+    # the structure 'known_resource_types') has a configured context
+    # It cannot survive the initvars method, and is later reinstated
+    # as part of compiling...
+    #
+    Puppet.override( @context_overrides , "For initializing compiler") do
+      # THE MAGIC STARTS HERE ! This triggers parsing, loading etc.
+      @catalog.version = known_resource_types.version
+    end
+
+    @catalog.add_resource(Puppet::Parser::Resource.new("stage", :main, :scope => @topscope))
+
+    # local resource array to maintain resource ordering
+    @resources = []
+
+    # Make sure any external node classes are in our class list
+    if @node.classes.class == Hash
+      @catalog.add_class(*@node.classes.keys)
+    else
+      @catalog.add_class(*@node.classes)
+    end
+  end
+
+  # Set the node's parameters into the top-scope as variables.
+  def set_node_parameters
+    node.parameters.each do |param, value|
+      @topscope[param.to_s] = value
+    end
+    # These might be nil.
+    catalog.client_version = node.parameters["clientversion"]
+    catalog.server_version = node.parameters["serverversion"]
+    if Puppet[:trusted_node_data]
+      @topscope.set_trusted(node.trusted_data)
+    end
+    if(Puppet[:immutable_node_data])
+      facts_hash = node.facts.nil? ? {} : node.facts.values
+      @topscope.set_facts(facts_hash)
+    end
+  end
+
+  def create_settings_scope
+    settings_type = Puppet::Resource::Type.new :hostclass, "settings"
+    environment.known_resource_types.add(settings_type)
+
+    settings_resource = Puppet::Parser::Resource.new("class", "settings", :scope => @topscope)
+
+    @catalog.add_resource(settings_resource)
+
+    settings_type.evaluate_code(settings_resource)
+
+    scope = @topscope.class_scope(settings_type)
+
+    env = environment
+    Puppet.settings.each do |name, setting|
+      next if name == :name
+      scope[name.to_s] = env[name]
+    end
+  end
+
+  # Return an array of all of the unevaluated resources.  These will be definitions,
+  # which need to get evaluated into native resources.
+  def unevaluated_resources
+    # The order of these is significant for speed due to short-circuting
+    resources.reject { |resource| resource.evaluated? or resource.virtual? or resource.builtin_type? }
+  end
+
+  # Creates the injector from bindings found in the current environment.
+  # @return [void]
+  # @api private
+  #
+  def create_injector
+    assert_binder_active()
+    composer = Puppet::Pops::Binder::BindingsComposer.new()
+    layered_bindings = composer.compose(topscope)
+    @injector = Puppet::Pops::Binder::Injector.new(Puppet::Pops::Binder::Binder.new(layered_bindings))
+  end
+
+  def assert_binder_active
+    unless is_binder_active?
+      raise ArgumentError, "The Puppet Binder is only available when either '--binder true' or '--parser future' is used"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/e4_parser_adapter.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/e4_parser_adapter.rb
new file mode 100644
index 0000000..00911b5
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/e4_parser_adapter.rb
@@ -0,0 +1,81 @@
+require 'puppet/pops'
+
+module Puppet; module Parser; end; end;
+# Adapts an egrammar/eparser to respond to the public API of the classic parser
+# and makes use of the new evaluator.
+#
+class Puppet::Parser::E4ParserAdapter
+
+  # Empty adapter fulfills watch_file contract without doing anything.
+  # @api private
+  class NullFileWatcher
+    def watch_file(file)
+      #nop
+    end
+  end
+
+  # @param file_watcher [#watch_file] something that can watch a file
+  def initialize(file_watcher = nil)
+    @file_watcher = file_watcher || NullFileWatcher.new
+    @file = ''
+    @string = ''
+    @use = :unspecified
+    @@evaluating_parser ||= Puppet::Pops::Parser::EvaluatingParser.new()
+  end
+
+  def file=(file)
+    @file = file
+    @use = :file
+    # watch if possible, but only if the file is something worth watching
+    @file_watcher.watch_file(file) if !file.nil? && file != ''
+  end
+
+  def parse(string = nil)
+    self.string= string if string
+
+    if @file =~ /\.rb$/ && @use != :string
+      # Will throw an error
+      parse_ruby_file
+    end
+
+    parse_result =
+    if @use == :string
+      # Parse with a source_file to set in created AST objects (it was either given, or it may be unknown
+      # if caller did not set a file and the present a string.
+      #
+      @@evaluating_parser.parse_string(@string, @file || "unknown-source-location")
+    else
+      @@evaluating_parser.parse_file(@file)
+    end
+
+    # the parse_result may be
+    # * empty / nil (no input)
+    # * a Model::Program
+    # * a Model::Expression
+    #
+    model = parse_result.nil? ? nil : parse_result.current 
+    args = {}
+    Puppet::Pops::Model::AstTransformer.new(@file).merge_location(args, model)
+
+    ast_code =
+    if model.is_a? Puppet::Pops::Model::Program
+      Puppet::Parser::AST::PopsBridge::Program.new(model, args)
+    else
+      args[:value] = model
+      Puppet::Parser::AST::PopsBridge::Expression.new(args)
+    end
+
+    # Create the "main" class for the content - this content will get merged with all other "main" content
+    Puppet::Parser::AST::Hostclass.new('', :code => ast_code)
+
+  end
+
+  def string=(string)
+    @string = string
+    @use = :string
+  end
+
+  def parse_ruby_file
+    raise Puppet::ParseError, "Ruby DSL is no longer supported. Attempt to parse #{@file}"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/files.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/files.rb
new file mode 100644
index 0000000..81c523f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/files.rb
@@ -0,0 +1,137 @@
+require 'puppet/module'
+
+module Puppet::Parser::Files
+
+  module_function
+
+  # Return a list of manifests as absolute filenames matching the given
+  # pattern.
+  #
+  # @param pattern [String] A reference for a file in a module. It is the format "<modulename>/<file glob>"
+  # @param environment [Puppet::Node::Environment] the environment of modules
+  #
+  # @return [Array(String, Array<String>)] the module name and the list of files found
+  # @api private
+  def find_manifests_in_modules(pattern, environment)
+    module_name, file_pattern = split_file_path(pattern)
+    begin
+      if mod = environment.module(module_name)
+        return [mod.name, mod.match_manifests(file_pattern)]
+      end
+    rescue Puppet::Module::InvalidName
+      # one of the modules being loaded might have an invalid name and so
+      # looking for one might blow up since we load them lazily.
+    end
+    [nil, []]
+  end
+
+  # Find the path to the given file selector. Files can be selected in
+  # one of two ways:
+  #   * absolute path: the path is simply returned
+  #   * modulename/filename selector: a file is found in the file directory
+  #     of the named module.
+  #
+  # In the second case a nil is returned if there isn't a file found. In the
+  # first case (absolute path), there is no existence check done and so the
+  # path will be returned even if there isn't a file available.
+  #
+  # @param template [String] the file selector
+  # @param environment [Puppet::Node::Environment] the environment in which to search
+  # @return [String, nil] the absolute path to the file or nil if there is no file found
+  #
+  # @api private
+  def find_file(file, environment)
+    if Puppet::Util.absolute_path?(file)
+      file
+    else
+      path, module_file = split_file_path(file)
+      mod = environment.module(path)
+
+      if module_file && mod
+        mod.file(module_file)
+      else
+        nil
+      end
+    end
+  end
+
+  # Find the path to the given template selector. Templates can be selected in
+  # a number of ways:
+  #   * absolute path: the path is simply returned
+  #   * path relative to the templatepath setting: a file is found and the path
+  #     is returned
+  #   * modulename/filename selector: a file is found in the template directory
+  #     of the named module.
+  #
+  # In the last two cases a nil is returned if there isn't a file found. In the
+  # first case (absolute path), there is no existence check done and so the
+  # path will be returned even if there isn't a file available.
+  #
+  # @param template [String] the template selector
+  # @param environment [Puppet::Node::Environment] the environment in which to search
+  # @return [String, nil] the absolute path to the template file or nil if there is no file found
+  #
+  # @api private
+  def find_template(template, environment)
+    if Puppet::Util.absolute_path?(template)
+      template
+    else
+      in_templatepath = find_template_in_templatepath(template, environment)
+      if in_templatepath
+        in_templatepath
+      else
+        find_template_in_module(template, environment)
+      end
+    end
+  end
+
+  # Templatepaths are deprecated functionality, this will be going away in
+  # Puppet 4.
+  #
+  # @api private
+  def find_template_in_templatepath(template, environment)
+    template_paths = templatepath(environment)
+    if template_paths
+      template_paths.collect do |path|
+        File::join(path, template)
+      end.find do |f|
+        Puppet::FileSystem.exist?(f)
+      end
+    else
+      nil
+    end
+  end
+
+  # @api private
+  def find_template_in_module(template, environment)
+    path, file = split_file_path(template)
+    mod = environment.module(path)
+
+    if file && mod
+      mod.template(file)
+    else
+      nil
+    end
+  end
+
+  # Return an array of paths by splitting the +templatedir+ config
+  # parameter.
+  # @api private
+  def templatepath(environment)
+    dirs = Puppet.settings.value(:templatedir, environment.to_s).split(File::PATH_SEPARATOR)
+    dirs.select do |p|
+      File::directory?(p)
+    end
+  end
+
+  # Split the path into the module and the rest of the path, or return
+  # nil if the path is empty or absolute (starts with a /).
+  # @api private
+  def split_file_path(path)
+    if path == "" || Puppet::Util.absolute_path?(path)
+      nil
+    else
+      path.split(File::SEPARATOR, 2)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions.rb
new file mode 100644
index 0000000..be104d8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions.rb
@@ -0,0 +1,262 @@
+require 'puppet/util/autoload'
+require 'puppet/parser/scope'
+
+# A module for managing parser functions.  Each specified function
+# is added to a central module that then gets included into the Scope
+# class.
+#
+# @api public
+module Puppet::Parser::Functions
+  Environment = Puppet::Node::Environment
+
+  class << self
+    include Puppet::Util
+  end
+
+  # Reset the list of loaded functions.
+  #
+  # @api private
+  def self.reset
+    @modules = {}
+
+    # Runs a newfunction to create a function for each of the log levels
+    Puppet::Util::Log.levels.each do |level|
+      newfunction(level,
+                  :environment => Puppet.lookup(:root_environment),
+                  :doc => "Log a message on the server at level #{level.to_s}.") do |vals|
+        send(level, vals.join(" "))
+      end
+    end
+  end
+
+  # Accessor for singleton autoloader
+  #
+  # @api private
+  def self.autoloader
+    @autoloader ||= Puppet::Util::Autoload.new(
+      self, "puppet/parser/functions", :wrap => false
+    )
+  end
+
+  # Get the module that functions are mixed into corresponding to an
+  # environment
+  #
+  # @api private
+  def self.environment_module(env)
+    @modules[env.name] ||= Module.new do
+      @metadata = {}
+
+      def self.all_function_info
+        @metadata
+      end
+
+      def self.get_function_info(name)
+        @metadata[name]
+      end
+
+      def self.add_function_info(name, info)
+        @metadata[name] = info
+      end
+    end
+  end
+
+  # Create a new Puppet DSL function.
+  #
+  # **The {newfunction} method provides a public API.**
+  #
+  # This method is used both internally inside of Puppet to define parser
+  # functions.  For example, template() is defined in
+  # {file:lib/puppet/parser/functions/template.rb template.rb} using the
+  # {newfunction} method.  Third party Puppet modules such as
+  # [stdlib](https://forge.puppetlabs.com/puppetlabs/stdlib) use this method to
+  # extend the behavior and functionality of Puppet.
+  #
+  # See also [Docs: Custom
+  # Functions](http://docs.puppetlabs.com/guides/custom_functions.html)
+  #
+  # @example Define a new Puppet DSL Function
+  #     >> Puppet::Parser::Functions.newfunction(:double, :arity => 1,
+  #          :doc => "Doubles an object, typically a number or string.",
+  #          :type => :rvalue) {|i| i[0]*2 }
+  #     => {:arity=>1, :type=>:rvalue,
+  #         :name=>"function_double",
+  #         :doc=>"Doubles an object, typically a number or string."}
+  #
+  # @example Invoke the double function from irb as is done in RSpec examples:
+  #     >> require 'puppet_spec/scope'
+  #     >> scope = PuppetSpec::Scope.create_test_scope_for_node('example')
+  #     => Scope()
+  #     >> scope.function_double([2])
+  #     => 4
+  #     >> scope.function_double([4])
+  #     => 8
+  #     >> scope.function_double([])
+  #     ArgumentError: double(): Wrong number of arguments given (0 for 1)
+  #     >> scope.function_double([4,8])
+  #     ArgumentError: double(): Wrong number of arguments given (2 for 1)
+  #     >> scope.function_double(["hello"])
+  #     => "hellohello"
+  #
+  # @param [Symbol] name the name of the function represented as a ruby Symbol.
+  #   The {newfunction} method will define a Ruby method based on this name on
+  #   the parser scope instance.
+  #
+  # @param [Proc] block the block provided to the {newfunction} method will be
+  #   executed when the Puppet DSL function is evaluated during catalog
+  #   compilation.  The arguments to the function will be passed as an array to
+  #   the first argument of the block.  The return value of the block will be
+  #   the return value of the Puppet DSL function for `:rvalue` functions.
+  #
+  # @option options [:rvalue, :statement] :type (:statement) the type of function.
+  #   Either `:rvalue` for functions that return a value, or `:statement` for
+  #   functions that do not return a value.
+  #
+  # @option options [String] :doc ('') the documentation for the function.
+  #   This string will be extracted by documentation generation tools.
+  #
+  # @option options [Integer] :arity (-1) the
+  #   [arity](http://en.wikipedia.org/wiki/Arity) of the function.  When
+  #   specified as a positive integer the function is expected to receive
+  #   _exactly_ the specified number of arguments.  When specified as a
+  #   negative number, the function is expected to receive _at least_ the
+  #   absolute value of the specified number of arguments incremented by one.
+  #   For example, a function with an arity of `-4` is expected to receive at
+  #   minimum 3 arguments.  A function with the default arity of `-1` accepts
+  #   zero or more arguments.  A function with an arity of 2 must be provided
+  #   with exactly two arguments, no more and no less.  Added in Puppet 3.1.0.
+  #
+  # @option options [Puppet::Node::Environment] :environment (nil) can
+  #   explicitly pass the environment we wanted the function added to.  Only used
+  #   to set logging functions in root environment
+  #
+  # @return [Hash] describing the function.
+  #
+  # @api public
+  def self.newfunction(name, options = {}, &block)
+    name = name.intern
+    environment = options[:environment] || Puppet.lookup(:current_environment)
+
+    Puppet.warning "Overwriting previous definition for function #{name}" if get_function(name, environment)
+
+    arity = options[:arity] || -1
+    ftype = options[:type] || :statement
+
+    unless ftype == :statement or ftype == :rvalue
+      raise Puppet::DevError, "Invalid statement type #{ftype.inspect}"
+    end
+
+    # the block must be installed as a method because it may use "return",
+    # which is not allowed from procs.
+    real_fname = "real_function_#{name}"
+    environment_module(environment).send(:define_method, real_fname, &block)
+
+    fname = "function_#{name}"
+    env_module = environment_module(environment)
+
+    env_module.send(:define_method, fname) do |*args|
+      Puppet::Util::Profiler.profile("Called #{name}", [:functions, name]) do
+        if args[0].is_a? Array
+          if arity >= 0 and args[0].size != arity
+            raise ArgumentError, "#{name}(): Wrong number of arguments given (#{args[0].size} for #{arity})"
+          elsif arity < 0 and args[0].size < (arity+1).abs
+            raise ArgumentError, "#{name}(): Wrong number of arguments given (#{args[0].size} for minimum #{(arity+1).abs})"
+          end
+          self.send(real_fname, args[0])
+        else
+          raise ArgumentError, "custom functions must be called with a single array that contains the arguments. For example, function_example([1]) instead of function_example(1)"
+        end
+      end
+    end
+
+    func = {:arity => arity, :type => ftype, :name => fname}
+    func[:doc] = options[:doc] if options[:doc]
+
+    env_module.add_function_info(name, func)
+
+    func
+  end
+
+  # Determine if a function is defined
+  #
+  # @param [Symbol] name the function
+  # @param [Puppet::Node::Environment] environment the environment to find the function in
+  #
+  # @return [Symbol, false] The name of the function if it's defined,
+  #   otherwise false.
+  #
+  # @api public
+  def self.function(name, environment = Puppet.lookup(:current_environment))
+    name = name.intern
+
+    func = nil
+    unless func = get_function(name, environment)
+      autoloader.load(name, environment)
+      func = get_function(name, environment)
+    end
+
+    if func
+      func[:name]
+    else
+      false
+    end
+  end
+
+  def self.functiondocs(environment = Puppet.lookup(:current_environment))
+    autoloader.loadall
+
+    ret = ""
+
+    merged_functions(environment).sort { |a,b| a[0].to_s <=> b[0].to_s }.each do |name, hash|
+      ret << "#{name}\n#{"-" * name.to_s.length}\n"
+      if hash[:doc]
+        ret << Puppet::Util::Docs.scrub(hash[:doc])
+      else
+        ret << "Undocumented.\n"
+      end
+
+      ret << "\n\n- *Type*: #{hash[:type]}\n\n"
+    end
+
+    ret
+  end
+
+  # Determine whether a given function returns a value.
+  #
+  # @param [Symbol] name the function
+  # @param [Puppet::Node::Environment] environment The environment to find the function in
+  # @return [Boolean] whether it is an rvalue function
+  #
+  # @api public
+  def self.rvalue?(name, environment = Puppet.lookup(:current_environment))
+    func = get_function(name, environment)
+    func ? func[:type] == :rvalue : false
+  end
+
+  # Return the number of arguments a function expects.
+  #
+  # @param [Symbol] name the function
+  # @param [Puppet::Node::Environment] environment The environment to find the function in
+  # @return [Integer] The arity of the function. See {newfunction} for
+  #   the meaning of negative values.
+  #
+  # @api public
+  def self.arity(name, environment = Puppet.lookup(:current_environment))
+    func = get_function(name, environment)
+    func ? func[:arity] : -1
+  end
+
+  class << self
+    private
+
+    def merged_functions(environment)
+      root = environment_module(Puppet.lookup(:root_environment))
+      env = environment_module(environment)
+
+      root.all_function_info.merge(env.all_function_info)
+    end
+
+    def get_function(name, environment)
+      environment_module(environment).get_function_info(name.intern) || environment_module(Puppet.lookup(:root_environment)).get_function_info(name.intern)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/assert_type.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/assert_type.rb
new file mode 100644
index 0000000..5776974
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/assert_type.rb
@@ -0,0 +1,31 @@
+Puppet::Parser::Functions::newfunction(
+  :assert_type,
+  :type => :rvalue,
+  :arity => -3,
+  :doc => "Returns the given value if it is an instance of the given type, and raises an error otherwise.
+Optionally, if a block is given (accepting two parameters), it will be called instead of raising
+an error. This to enable giving the user richer feedback, or to supply a default value.
+
+Example: assert that `$b` is a non empty `String` and assign to `$a`:
+
+  $a = assert_type(String[1], $b)
+
+Example using custom error message:
+
+  $a = assert_type(String[1], $b) |$expected, $actual| {
+    fail('The name cannot be empty')
+  }
+
+Example, using a warning and a default:
+
+  $a = assert_type(String[1], $b) |$expected, $actual| {
+    warning('Name is empty, using default')
+    'anonymous'
+  }
+
+See the documentation for 'The Puppet Type System' for more information about types.
+- since Puppet 3.7
+- requires future parser/evaluator
+") do |args|
+  function_fail(["assert_type() is only available when parser/evaluator future is in effect"])
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/contain.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/contain.rb
new file mode 100644
index 0000000..9c94476
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/contain.rb
@@ -0,0 +1,36 @@
+# Called within a class definition, establishes a containment
+# relationship with another class
+
+Puppet::Parser::Functions::newfunction(
+  :contain,
+  :arity => -2,
+  :doc => "Contain one or more classes inside the current class. If any of
+these classes are undeclared, they will be declared as if called with the
+`include` function. Accepts a class name, an array of class names, or a
+comma-separated list of class names.
+
+A contained class will not be applied before the containing class is
+begun, and will be finished before the containing class is finished.
+
+When the future parser is used, you must use the class's full name;
+relative names are no longer allowed. In addition to names in string form,
+you may also directly use Class and Resource Type values that are produced by
+the future parser's resource and relationship expressions.
+"
+) do |classes|
+  scope = self
+
+  # Make call patterns uniform and protected against nested arrays, also make
+  # names absolute if so desired.
+  classes = transform_and_assert_classnames(classes.is_a?(Array) ? classes.flatten : [classes])
+
+  containing_resource = scope.resource
+
+  # This is the same as calling the include function but faster and does not rely on the include
+  # function (which is a statement) to return something (it should not).
+  (compiler.evaluate_classes(classes, self, false) || []).each do |resource|
+    if ! scope.catalog.edge?(containing_resource, resource)
+      scope.catalog.add_edge(containing_resource, resource)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/create_resources.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/create_resources.rb
new file mode 100644
index 0000000..f99b1a5
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/create_resources.rb
@@ -0,0 +1,74 @@
+Puppet::Parser::Functions::newfunction(:create_resources, :arity => -3, :doc => <<-'ENDHEREDOC') do |args|
+    Converts a hash into a set of resources and adds them to the catalog.
+
+    This function takes two mandatory arguments: a resource type, and a hash describing
+    a set of resources. The hash should be in the form `{title => {parameters} }`:
+
+        # A hash of user resources:
+        $myusers = {
+          'nick' => { uid    => '1330',
+                      gid    => allstaff,
+                      groups => ['developers', 'operations', 'release'], },
+          'dan'  => { uid    => '1308',
+                      gid    => allstaff,
+                      groups => ['developers', 'prosvc', 'release'], },
+        }
+
+        create_resources(user, $myusers)
+
+    A third, optional parameter may be given, also as a hash:
+
+        $defaults = {
+          'ensure'   => present,
+          'provider' => 'ldap',
+        }
+
+        create_resources(user, $myusers, $defaults)
+
+    The values given on the third argument are added to the parameters of each resource
+    present in the set given on the second argument. If a parameter is present on both
+    the second and third arguments, the one on the second argument takes precedence.
+
+    This function can be used to create defined resources and classes, as well
+    as native resources.
+
+    Virtual and Exported resources may be created by prefixing the type name
+    with @ or @@ respectively.  For example, the $myusers hash may be exported
+    in the following manner:
+
+        create_resources("@@user", $myusers)
+
+    The $myusers may be declared as virtual resources using:
+
+        create_resources("@user", $myusers)
+
+  ENDHEREDOC
+  raise ArgumentError, ("create_resources(): wrong number of arguments (#{args.length}; must be 2 or 3)") if args.length > 3
+  raise ArgumentError, ('create_resources(): second argument must be a hash') unless args[1].is_a?(Hash)
+  if args.length == 3
+    raise ArgumentError, ('create_resources(): third argument, if provided, must be a hash') unless args[2].is_a?(Hash)
+  end
+
+
+  type, instances, defaults = args
+  defaults ||= {}
+
+  resource = Puppet::Parser::AST::Resource.new(:type => type.sub(/^@{1,2}/, '').downcase, :instances =>
+    instances.collect do |title, params|
+      Puppet::Parser::AST::ResourceInstance.new(
+        :title => Puppet::Parser::AST::Leaf.new(:value => title),
+        :parameters => defaults.merge(params).collect do |name, value|
+          Puppet::Parser::AST::ResourceParam.new(
+            :param => name,
+            :value => Puppet::Parser::AST::Leaf.new(:value => value))
+        end)
+    end)
+
+  if type.start_with? '@@'
+    resource.exported = true
+  elsif type.start_with? '@'
+    resource.virtual = true
+  end
+
+  resource.safeevaluate(self)
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/defined.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/defined.rb
new file mode 100644
index 0000000..37a3b69
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/defined.rb
@@ -0,0 +1,98 @@
+# Test whether a given class or definition is defined
+Puppet::Parser::Functions::newfunction(:defined, :type => :rvalue, :arity => -2, :doc => "Determine whether
+  a given class or resource type is defined. This function can also determine whether a
+  specific resource has been declared, or whether a variable has been assigned a value
+  (including undef...as opposed to never having been assigned anything). Returns true
+  or false. Accepts class names, type names, resource references, and variable
+  reference strings of the form '$name'.  When more than one argument is
+  supplied, defined() returns true if any are defined.
+
+  The `defined` function checks both native and defined types, including types
+  provided as plugins via modules. Types and classes are both checked using their names:
+
+      defined(\"file\")
+      defined(\"customtype\")
+      defined(\"foo\")
+      defined(\"foo::bar\")
+      defined(\'$name\')
+
+  Resource declarations are checked using resource references, e.g.
+  `defined( File['/tmp/myfile'] )`. Checking whether a given resource
+  has been declared is, unfortunately, dependent on the parse order of
+  the configuration, and the following code will not work:
+
+      if defined(File['/tmp/foo']) {
+          notify { \"This configuration includes the /tmp/foo file.\":}
+      }
+      file { \"/tmp/foo\":
+          ensure => present,
+      }
+
+  However, this order requirement refers to parse order only, and ordering of
+  resources in the configuration graph (e.g. with `before` or `require`) does not
+  affect the behavior of `defined`.
+
+  If the future parser is in effect, you may also search using types:
+
+      defined(Resource[\'file\',\'/some/file\'])
+      defined(File[\'/some/file\'])
+      defined(Class[\'foo\'])
+
+  The `defined` function does not answer if 4.x data types (e.g. `Integer`) are defined. If
+  given the string 'integer' the result is false, and if given a non CatalogEntry type,
+  an error is raised.
+
+  The rules for asking for undef, empty strings, and the main class are different from 3.x
+  (non future parser) and 4.x (with future parser or in Puppet 4.0.0 and later):
+
+      defined('')     # 3.x => true, 4.x => false
+      defined(undef)  # 3.x => true, 4.x => error
+      defined('main') # 3.x => false, 4.x => true
+
+  With the future parser, it is also possible to ask specifically if a name is
+  a resource type (built in or defined), or a class, by giving its type:
+
+      defined(Type[Class['foo']])
+      defined(Type[Resource['foo']])
+
+  Which is different from asking:
+
+      defined('foo')
+
+  Since the later returns true if 'foo' is either a class, a built-in resource type, or a user defined
+  resource type, and a specific request like `Type[Class['foo']]` only returns true if `'foo'` is a class.
+
+ - Since 2.7.0
+ - Since 3.6.0 variable reference and future parser types
+ - Since 3.8.1 type specific requests with future parser") do |vals|
+    vals = [vals] unless vals.is_a?(Array)
+    vals.any? do |val|
+      case val
+      when String
+        if m = /^\$(.+)$/.match(val)
+          exist?(m[1])
+        else
+          find_resource_type(val) or find_definition(val) or find_hostclass(val)
+        end
+      when Puppet::Resource
+        compiler.findresource(val.type, val.title)
+      else
+        if Puppet.future_parser?
+          case val
+          when Puppet::Pops::Types::PResourceType
+            raise ArgumentError, "The given resource type is a reference to all kind of types" if val.type_name.nil?
+            if val.title.nil?
+              find_builtin_resource_type(val.type_name) || find_definition(val.type_name)
+            else
+              compiler.findresource(val.type_name, val.title)
+            end
+          when Puppet::Pops::Types::PHostClassType
+            raise  ArgumentError, "The given class type is a reference to all classes" if val.class_name.nil?
+            find_hostclass(val.class_name)
+          end
+        else
+          raise ArgumentError, "Invalid argument of type '#{val.class}' to 'defined'"
+        end
+      end
+    end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/digest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/digest.rb
new file mode 100644
index 0000000..8cd75c3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/digest.rb
@@ -0,0 +1,5 @@
+require 'puppet/util/checksums'
+Puppet::Parser::Functions::newfunction(:digest, :type => :rvalue, :arity => 1, :doc => "Returns a hash value from a provided string using the digest_algorithm setting from the Puppet config file.") do |args|
+  algo = Puppet[:digest_algorithm]
+  Puppet::Util::Checksums.method(algo.intern).call args[0]
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/each.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/each.rb
new file mode 100644
index 0000000..3f4437e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/each.rb
@@ -0,0 +1,48 @@
+Puppet::Parser::Functions::newfunction(
+  :each,
+  :type => :rvalue,
+  :arity => -3,
+  :doc => <<-DOC
+Applies a parameterized block to each element in a sequence of selected entries from the first
+argument and returns the first argument.
+
+This function takes two mandatory arguments: the first should be an Array or a Hash or something that is
+of enumerable type (integer, Integer range, or String), and the second
+a parameterized block as produced by the puppet syntax:
+
+      $a.each |$x| { ... }
+      each($a) |$x| { ... }
+
+When the first argument is an Array (or of enumerable type other than Hash), the parameterized block
+should define one or two block parameters.
+For each application of the block, the next element from the array is selected, and it is passed to
+the block if the block has one parameter. If the block has two parameters, the first is the elements
+index, and the second the value. The index starts from 0.
+
+      $a.each |$index, $value| { ... }
+      each($a) |$index, $value| { ... }
+
+When the first argument is a Hash, the parameterized block should define one or two parameters.
+When one parameter is defined, the iteration is performed with each entry as an array of `[key, value]`,
+and when two parameters are defined the iteration is performed with key and value.
+
+      $a.each |$entry|       { ..."key ${$entry[0]}, value ${$entry[1]}" }
+      $a.each |$key, $value| { ..."key ${key}, value ${value}" }
+
+Example using each:
+
+      [1,2,3].each |$val| { ... }                       # 1, 2, 3
+      [5,6,7].each |$index, $val| { ... }               # (0, 5), (1, 6), (2, 7)
+      {a=>1, b=>2, c=>3}].each |$val| { ... }           # ['a', 1], ['b', 2], ['c', 3]
+      {a=>1, b=>2, c=>3}.each |$key, $val| { ... }      # ('a', 1), ('b', 2), ('c', 3)
+      Integer[ 10, 20 ].each |$index, $value| { ... }   # (0, 10), (1, 11) ...
+      "hello".each |$char| { ... }                      # 'h', 'e', 'l', 'l', 'o'
+      3.each |$number| { ... }                          # 0, 1, 2
+
+- since 3.2 for Array and Hash
+- since 3.5 for other enumerables
+- note requires `parser = future`
+DOC
+) do |args|
+  function_fail(["each() is only available when parser/evaluator future is in effect"])
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/epp.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/epp.rb
new file mode 100644
index 0000000..5127aec
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/epp.rb
@@ -0,0 +1,45 @@
+Puppet::Parser::Functions::newfunction(:epp, :type => :rvalue, :arity => -2, :doc =>
+"Evaluates an Embedded Puppet Template (EPP) file and returns the rendered text result as a String.
+
+The first argument to this function should be a `<MODULE NAME>/<TEMPLATE FILE>`
+reference, which will load `<TEMPLATE FILE>` from a module's `templates`
+directory. (For example, the reference `apache/vhost.conf.epp` will load the
+file `<MODULES DIRECTORY>/apache/templates/vhost.conf.epp`.)
+
+The second argument is optional; if present, it should be a hash containing parameters for the
+template. (See below.)
+
+EPP supports the following tags:
+
+* `<%= puppet expression %>` - This tag renders the value of the expression it contains.
+* `<% puppet expression(s) %>` - This tag will execute the expression(s) it contains, but renders nothing.
+* `<%# comment %>` - The tag and its content renders nothing.
+* `<%%` or `%%>` - Renders a literal `<%` or `%>` respectively.
+* `<%-` - Same as `<%` but suppresses any leading whitespace.
+* `-%>` - Same as `%>` but suppresses any trailing whitespace on the same line (including line break).
+* `<%- |parameters| -%>` - When placed as the first tag declares the template's parameters.
+
+File based EPP supports the following visibilities of variables in scope:
+
+* Global scope (i.e. top + node scopes) - global scope is always visible
+* Global + all given arguments - if the EPP template does not declare parameters, and arguments are given
+* Global + declared parameters - if the EPP declares parameters, given argument names must match
+
+EPP supports parameters by placing an optional parameter list as the very first element in the EPP. As an example,
+`<%- |$x, $y, $z = 'unicorn'| -%>` when placed first in the EPP text declares that the parameters `x` and `y` must be
+given as template arguments when calling `inline_epp`, and that `z` if not given as a template argument
+defaults to `'unicorn'`. Template parameters are available as variables, e.g.arguments `$x`, `$y` and `$z` in the example.
+Note that `<%-` must be used or any leading whitespace will be interpreted as text
+
+Arguments are passed to the template by calling `epp` with a Hash as the last argument, where parameters
+are bound to values, e.g. `epp('...', {'x'=>10, 'y'=>20})`. Excess arguments may be given
+(i.e. undeclared parameters) only if the EPP templates does not declare any parameters at all.
+Template parameters shadow variables in outer scopes. File based epp does never have access to variables in the
+scope where the `epp` function is called from.
+
+- See function inline_epp for examples of EPP
+- Since 3.5
+- Requires Future Parser") do |args|
+
+  function_fail(["epp() is only available when parser/evaluator future is in effect"])
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/extlookup.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/extlookup.rb
new file mode 100644
index 0000000..359c9b4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/extlookup.rb
@@ -0,0 +1,153 @@
+require 'csv'
+
+module Puppet::Parser::Functions
+  newfunction(:extlookup,
+  :type => :rvalue,
+  :arity => -2,
+  :doc => "This is a parser function to read data from external files, this version
+uses CSV files but the concept can easily be adjust for databases, yaml
+or any other queryable data source.
+
+The object of this is to make it obvious when it's being used, rather than
+magically loading data in when a module is loaded I prefer to look at the code
+and see statements like:
+
+    $snmp_contact = extlookup(\"snmp_contact\")
+
+The above snippet will load the snmp_contact value from CSV files, this in its
+own is useful but a common construct in puppet manifests is something like this:
+
+    case $domain {
+      \"myclient.com\": { $snmp_contact = \"John Doe <john@myclient.com>\" }
+      default:        { $snmp_contact = \"My Support <support@my.com>\" }
+    }
+
+Over time there will be a lot of this kind of thing spread all over your manifests
+and adding an additional client involves grepping through manifests to find all the
+places where you have constructs like this.
+
+This is a data problem and shouldn't be handled in code, and using this function you
+can do just that.
+
+First you configure it in site.pp:
+
+    $extlookup_datadir = \"/etc/puppet/manifests/extdata\"
+    $extlookup_precedence = [\"%{fqdn}\", \"domain_%{domain}\", \"common\"]
+
+The array tells the code how to resolve values, first it will try to find it in
+web1.myclient.com.csv then in domain_myclient.com.csv and finally in common.csv
+
+Now create the following data files in /etc/puppet/manifests/extdata:
+
+    domain_myclient.com.csv:
+      snmp_contact,John Doe <john@myclient.com>
+      root_contact,support@%{domain}
+      client_trusted_ips,192.168.1.130,192.168.10.0/24
+
+    common.csv:
+      snmp_contact,My Support <support@my.com>
+      root_contact,support@my.com
+
+Now you can replace the case statement with the simple single line to achieve
+the exact same outcome:
+
+    $snmp_contact = extlookup(\"snmp_contact\")
+
+The above code shows some other features, you can use any fact or variable that
+is in scope by simply using %{varname} in your data files, you can return arrays
+by just having multiple values in the csv after the initial variable name.
+
+In the event that a variable is nowhere to be found a critical error will be raised
+that will prevent your manifest from compiling, this is to avoid accidentally putting
+in empty values etc.  You can however specify a default value:
+
+    $ntp_servers = extlookup(\"ntp_servers\", \"1.${country}.pool.ntp.org\")
+
+In this case it will default to \"1.${country}.pool.ntp.org\" if nothing is defined in
+any data file.
+
+You can also specify an additional data file to search first before any others at use
+time, for example:
+
+    $version = extlookup(\"rsyslog_version\", \"present\", \"packages\")
+    package{\"rsyslog\": ensure => $version }
+
+This will look for a version configured in packages.csv and then in the rest as configured
+by $extlookup_precedence if it's not found anywhere it will default to `present`, this kind
+of use case makes puppet a lot nicer for managing large amounts of packages since you do not
+need to edit a load of manifests to do simple things like adjust a desired version number.
+
+Precedence values can have variables embedded in them in the form %{fqdn}, you could for example do:
+
+    $extlookup_precedence = [\"hosts/%{fqdn}\", \"common\"]
+
+This will result in /path/to/extdata/hosts/your.box.com.csv being searched.
+
+This is for back compatibility to interpolate variables with %. % interpolation is a workaround for a problem that has been fixed: Puppet variable interpolation at top scope used to only happen on each run.") do |args|
+
+  key = args[0]
+
+  default  = args[1]
+  datafile = args[2]
+
+  raise ArgumentError, ("extlookup(): wrong number of arguments (#{args.length}; must be <= 3)") if args.length > 3
+
+  extlookup_datadir = undef_as('',self['::extlookup_datadir'])
+
+  extlookup_precedence = undef_as([],self['::extlookup_precedence']).collect { |var| var.gsub(/%\{(.+?)\}/) { self["::#{$1}"] } }
+
+  datafiles = Array.new
+
+  # if we got a custom data file, put it first in the array of search files
+  if datafile != ""
+    datafiles << extlookup_datadir + "/#{datafile}.csv" if Puppet::FileSystem.exist?(extlookup_datadir + "/#{datafile}.csv")
+  end
+
+  extlookup_precedence.each do |d|
+    datafiles << extlookup_datadir + "/#{d}.csv"
+  end
+
+  desired = nil
+
+  datafiles.each do |file|
+    if desired.nil?
+      if Puppet::FileSystem.exist?(file)
+        result = CSV.read(file).find_all do |r|
+          r[0] == key
+        end
+
+        # return just the single result if theres just one,
+        # else take all the fields in the csv and build an array
+        if result.length > 0
+          if result[0].length == 2
+            val = result[0][1].to_s
+
+            # parse %{}'s in the CSV into local variables using the current scope
+            while val =~ /%\{(.+?)\}/
+              val.gsub!(/%\{#{$1}\}/, self[$1])
+            end
+
+            desired = val
+          elsif result[0].length > 1
+            length = result[0].length
+            cells = result[0][1,length]
+
+            # Individual cells in a CSV result are a weird data type and throws
+            # puppets yaml parsing, so just map it all to plain old strings
+            desired = cells.map do |c|
+              # parse %{}'s in the CSV into local variables using the current scope
+              while c =~ /%\{(.+?)\}/
+                c.gsub!(/%\{#{$1}\}/, self[$1])
+              end
+
+              c.to_s
+            end
+          end
+        end
+      end
+    end
+  end
+
+  desired || default or raise Puppet::ParseError, "No match found for '#{key}' in any data file during extlookup()"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/fail.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/fail.rb
new file mode 100644
index 0000000..34c99b6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/fail.rb
@@ -0,0 +1,4 @@
+Puppet::Parser::Functions::newfunction(:fail, :arity => -1, :doc => "Fail with a parse error.") do |vals|
+    vals = vals.collect { |s| s.to_s }.join(" ") if vals.is_a? Array
+    raise Puppet::ParseError, vals.to_s
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/file.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/file.rb
new file mode 100644
index 0000000..e8ae32a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/file.rb
@@ -0,0 +1,33 @@
+require 'puppet/file_system'
+
+Puppet::Parser::Functions::newfunction(
+  :file, :arity => -2, :type => :rvalue,
+  :doc => "Loads a file from a module and returns its contents as a string.
+
+  The argument to this function should be a `<MODULE NAME>/<FILE>`
+  reference, which will load `<FILE>` from a module's `files`
+  directory. (For example, the reference `mysql/mysqltuner.pl` will load the
+  file `<MODULES DIRECTORY>/mysql/files/mysqltuner.pl`.)
+
+  This function can also accept:
+
+  * An absolute path, which can load a file from anywhere on disk.
+  * Multiple arguments, which will return the contents of the **first** file
+  found, skipping any files that don't exist.
+  "
+) do |vals|
+    path = nil
+    vals.each do |file|
+      found = Puppet::Parser::Files.find_file(file, compiler.environment)
+      if found && Puppet::FileSystem.exist?(found)
+        path = found
+        break
+      end
+    end
+
+    if path
+      Puppet::FileSystem.read_preserve_line_endings(path)
+    else
+      raise Puppet::ParseError, "Could not find any files from #{vals.join(", ")}"
+    end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/filter.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/filter.rb
new file mode 100644
index 0000000..365de9f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/filter.rb
@@ -0,0 +1,44 @@
+Puppet::Parser::Functions::newfunction(
+  :filter,
+  :arity => -3,
+  :doc => <<-DOC
+ Applies a parameterized block to each element in a sequence of entries from the first
+ argument and returns an array or hash (same type as left operand for array/hash, and array for
+ other enumerable types) with the entries for which the block evaluates to `true`.
+
+ This function takes two mandatory arguments: the first should be an Array, a Hash, or an
+ Enumerable object (integer, Integer range, or String),
+ and the second a parameterized block as produced by the puppet syntax:
+
+       $a.filter |$x| { ... }
+       filter($a) |$x| { ... }
+
+ When the first argument is something other than a Hash, the block is called with each entry in turn.
+ When the first argument is a Hash the entry is an array with `[key, value]`.
+
+ Example Using filter with one parameter
+
+       # selects all that end with berry
+       $a = ["raspberry", "blueberry", "orange"]
+       $a.filter |$x| { $x =~ /berry$/ }          # rasberry, blueberry
+
+ If the block defines two parameters, they will be set to `index, value` (with index starting at 0) for all
+ enumerables except Hash, and to `key, value` for a Hash.
+
+Example Using filter with two parameters
+
+     # selects all that end with 'berry' at an even numbered index
+     $a = ["raspberry", "blueberry", "orange"]
+     $a.filter |$index, $x| { $index % 2 == 0 and $x =~ /berry$/ } # raspberry
+
+     # selects all that end with 'berry' and value >= 1
+     $a = {"raspberry"=>0, "blueberry"=>1, "orange"=>1}
+     $a.filter |$key, $x| { $x =~ /berry$/ and $x >= 1 } # blueberry
+
+- since 3.4 for Array and Hash
+- since 3.5 for other enumerables
+- note requires `parser = future`
+DOC
+) do |args|
+  function_fail(["filter() is only available when parser/evaluator future is in effect"])
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/fqdn_rand.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/fqdn_rand.rb
new file mode 100644
index 0000000..ffdb64e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/fqdn_rand.rb
@@ -0,0 +1,21 @@
+require 'digest/md5'
+
+Puppet::Parser::Functions::newfunction(:fqdn_rand, :arity => -2, :type => :rvalue, :doc =>
+  "Usage: `fqdn_rand(MAX, [SEED])`. MAX is required and must be a positive
+  integer; SEED is optional and may be any number or string.
+
+  Generates a random whole number greater than or equal to 0 and less than MAX,
+  combining the `$fqdn` fact and the value of SEED for repeatable randomness.
+  (That is, each node will get a different random number from this function, but
+  a given node's result will be the same every time unless its hostname changes.)
+
+  This function is usually used for spacing out runs of resource-intensive cron
+  tasks that run on many nodes, which could cause a thundering herd or degrade
+  other services if they all fire at once. Adding a SEED can be useful when you
+  have more than one such task and need several unrelated random numbers per
+  node. (For example, `fqdn_rand(30)`, `fqdn_rand(30, 'expensive job 1')`, and
+  `fqdn_rand(30, 'expensive job 2')` will produce totally different numbers.)") do |args|
+    max = args.shift.to_i
+    seed = Digest::MD5.hexdigest([self['::fqdn'],args].join(':')).hex
+    Puppet::Util.deterministic_rand(seed,max)
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/generate.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/generate.rb
new file mode 100644
index 0000000..8a71cfb
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/generate.rb
@@ -0,0 +1,37 @@
+# Runs an external command and returns the results
+Puppet::Parser::Functions::newfunction(:generate, :arity => -2, :type => :rvalue,
+    :doc => "Calls an external command on the Puppet master and returns
+    the results of the command.  Any arguments are passed to the external command as
+    arguments.  If the generator does not exit with return code of 0,
+    the generator is considered to have failed and a parse error is
+    thrown.  Generators can only have file separators, alphanumerics, dashes,
+    and periods in them.  This function will attempt to protect you from
+    malicious generator calls (e.g., those with '..' in them), but it can
+    never be entirely safe.  No subshell is used to execute
+    generators, so all shell metacharacters are passed directly to
+    the generator.") do |args|
+
+      raise Puppet::ParseError, "Generators must be fully qualified" unless Puppet::Util.absolute_path?(args[0])
+
+      if Puppet.features.microsoft_windows?
+        valid = args[0] =~ /^[a-z]:(?:[\/\\][-.~\w]+)+$/i
+      else
+        valid = args[0] =~ /^[-\/\w.+]+$/
+      end
+
+      unless valid
+        raise Puppet::ParseError,
+          "Generators can only contain alphanumerics, file separators, and dashes"
+      end
+
+      if args[0] =~ /\.\./
+        raise Puppet::ParseError,
+          "Can not use generators with '..' in them."
+      end
+
+      begin
+        Dir.chdir(File.dirname(args[0])) { Puppet::Util::Execution.execute(args).to_str }
+      rescue Puppet::ExecutionFailure => detail
+        raise Puppet::ParseError, "Failed to execute generator #{args[0]}: #{detail}", detail.backtrace
+      end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/hiera.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/hiera.rb
new file mode 100644
index 0000000..c57c94e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/hiera.rb
@@ -0,0 +1,35 @@
+require 'hiera_puppet'
+
+module Puppet::Parser::Functions
+  newfunction(:hiera, :type => :rvalue, :arity => -2, :doc => "Performs a
+  standard priority lookup and returns the most specific value for a given key.
+  The returned value can be data of any type (strings, arrays, or hashes)
+
+  The function can be called in one of three ways:
+  1. Using 1 to 3 arguments where the arguments are:
+     'key'      [String] Required
+           The key to lookup.
+     'default`  [Any] Optional
+           A value to return when there's no match for `key`. Optional
+     `override` [Any] Optional
+           An argument in the third position, providing a data source
+           to consult for matching values, even if it would not ordinarily be
+           part of the matched hierarchy. If Hiera doesn't find a matching key
+           in the named override data source, it will continue to search through the
+           rest of the hierarchy.
+
+  2. Using a 'key' and an optional 'override' parameter like in #1 but with a block to
+     provide the default value. The block is called with one parameter (the key) and
+     should return the value. This option can only be used with the 3x future parser or
+     from 4.0.0.
+
+  3. Like #1 but with all arguments passed in an array.
+
+  More thorough examples of `hiera` are available at:
+  <http://docs.puppetlabs.com/hiera/1/puppet.html#hiera-lookup-functions>
+  ") do |*args|
+    key, default, override = HieraPuppet.parse_args(args)
+    HieraPuppet.lookup(key, default, self, override, :priority)
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/hiera_array.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/hiera_array.rb
new file mode 100644
index 0000000..b4ca287
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/hiera_array.rb
@@ -0,0 +1,37 @@
+require 'hiera_puppet'
+
+module Puppet::Parser::Functions
+  newfunction(:hiera_array, :type => :rvalue, :arity => -2,:doc => "Returns all
+  matches throughout the hierarchy --- not just the first match --- as a flattened array of unique values.
+  If any of the matched values are arrays, they're flattened and included in the results.
+
+  The function can be called in one of three ways:
+  1. Using 1 to 3 arguments where the arguments are:
+     'key'      [String] Required
+           The key to lookup.
+     'default`  [Any] Optional
+           A value to return when there's no match for `key`. Optional
+     `override` [Any] Optional
+           An argument in the third position, providing a data source
+           to consult for matching values, even if it would not ordinarily be
+           part of the matched hierarchy. If Hiera doesn't find a matching key
+           in the named override data source, it will continue to search through the
+           rest of the hierarchy.
+
+  2. Using a 'key' and an optional 'override' parameter like in #1 but with a block to
+     provide the default value. The block is called with one parameter (the key) and
+     should return the value. This option can only be used with the 3x future parser or
+     from 4.0.0.
+
+  3. Like #1 but with all arguments passed in an array.
+
+  If any matched value is a hash, puppet will raise a type mismatch error.
+
+  More thorough examples of `hiera` are available at:
+  <http://docs.puppetlabs.com/hiera/1/puppet.html#hiera-lookup-functions>
+  ") do |*args|
+    key, default, override = HieraPuppet.parse_args(args)
+    HieraPuppet.lookup(key, default, self, override, :array)
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/hiera_hash.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/hiera_hash.rb
new file mode 100644
index 0000000..01369de
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/hiera_hash.rb
@@ -0,0 +1,39 @@
+require 'hiera_puppet'
+
+module Puppet::Parser::Functions
+  newfunction(:hiera_hash, :type => :rvalue, :arity => -2, :doc =>
+  "Returns a merged hash of matches from throughout the hierarchy. In cases where two or
+  more hashes share keys, the hierarchy  order determines which key/value pair will be
+  used in the returned hash, with the pair in the highest priority data source winning.
+
+  The function can be called in one of three ways:
+  1. Using 1 to 3 arguments where the arguments are:
+     'key'      [String] Required
+           The key to lookup.
+     'default`  [Any] Optional
+           A value to return when there's no match for `key`. Optional
+     `override` [Any] Optional
+           An argument in the third position, providing a data source
+           to consult for matching values, even if it would not ordinarily be
+           part of the matched hierarchy. If Hiera doesn't find a matching key
+           in the named override data source, it will continue to search through the
+           rest of the hierarchy.
+
+  2. Using a 'key' and an optional 'override' parameter like in #1 but with a block to
+     provide the default value. The block is called with one parameter (the key) and
+     should return the value. This option can only be used with the 3x future parser or
+     from 4.0.0.
+
+  3. Like #1 but with all arguments passed in an array.
+
+  `hiera_hash` expects that all values returned will be hashes. If any of the values 
+  found in the data sources are strings or arrays, puppet will raise a type mismatch error.
+
+  More thorough examples of `hiera_hash` are available at:
+  <http://docs.puppetlabs.com/hiera/1/puppet.html#hiera-lookup-functions>
+  ") do |*args|
+    key, default, override = HieraPuppet.parse_args(args)
+    HieraPuppet.lookup(key, default, self, override, :hash)
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/hiera_include.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/hiera_include.rb
new file mode 100644
index 0000000..9c9c953
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/hiera_include.rb
@@ -0,0 +1,55 @@
+require 'hiera_puppet'
+
+module Puppet::Parser::Functions
+  newfunction(:hiera_include, :arity => -2, :doc => "Assigns classes to a node
+  using an array merge lookup that retrieves the value for a user-specified key
+  from a Hiera data source.
+
+  To use `hiera_include`, the following configuration is required:
+
+  - A key name to use for classes, e.g. `classes`.
+  - A line in the puppet `sites.pp` file (e.g. `/etc/puppet/manifests/sites.pp`)
+    reading `hiera_include('classes')`. Note that this line must be outside any node
+    definition and below any top-scope variables in use for Hiera lookups.
+  - Class keys in the appropriate data sources. In a data source keyed to a node's role,
+    one might have:
+
+            ---
+            classes:
+              - apache
+              - apache::passenger
+
+  The function can be called in one of three ways:
+  1. Using 1 to 3 arguments where the arguments are:
+     'key'      [String] Required
+           The key to lookup.
+     'default`  [Any] Optional
+           A value to return when there's no match for `key`. Optional
+     `override` [Any] Optional
+           An argument in the third position, providing a data source
+           to consult for matching values, even if it would not ordinarily be
+           part of the matched hierarchy. If Hiera doesn't find a matching key
+           in the named override data source, it will continue to search through the
+           rest of the hierarchy.
+
+  2. Using a 'key' and an optional 'override' parameter like in #1 but with a block to
+     provide the default value. The block is called with one parameter (the key) and
+     should return the array to be used in the subsequent call to include.
+     This option can only be used with the 3x future parser or
+     from 4.0.0.
+
+  3. Like #1 but with all arguments passed in an array.
+
+  More thorough examples of `hiera_include` are available at:
+  <http://docs.puppetlabs.com/hiera/1/puppet.html#hiera-lookup-functions>
+  ") do |*args|
+    key, default, override = HieraPuppet.parse_args(args)
+    if answer = HieraPuppet.lookup(key, default, self, override, :array)
+      method = Puppet::Parser::Functions.function(:include)
+      send(method, [answer])
+    else
+      raise Puppet::ParseError, "Could not find data item #{key}"
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/include.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/include.rb
new file mode 100644
index 0000000..2bebbba
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/include.rb
@@ -0,0 +1,35 @@
+# Include the specified classes
+Puppet::Parser::Functions::newfunction(:include, :arity => -2, :doc =>
+"Declares one or more classes, causing the resources in them to be
+evaluated and added to the catalog. Accepts a class name, an array of class
+names, or a comma-separated list of class names.
+
+The `include` function can be used multiple times on the same class and will
+only declare a given class once. If a class declared with `include` has any
+parameters, Puppet will automatically look up values for them in Hiera, using
+`<class name>::<parameter name>` as the lookup key.
+
+Contrast this behavior with resource-like class declarations
+(`class {'name': parameter => 'value',}`), which must be used in only one place
+per class and can directly set parameters. You should avoid using both `include`
+and resource-like declarations with the same class.
+
+The `include` function does not cause classes to be contained in the class
+where they are declared. For that, see the `contain` function. It also
+does not create a dependency relationship between the declared class and the
+surrounding class; for that, see the `require` function.
+
+When the future parser is used, you must use the class's full name;
+relative names are no longer allowed. In addition to names in string form,
+you may also directly use Class and Resource Type values that are produced by
+the future parser's resource and relationship expressions.
+
+") do |vals|
+
+  # Unify call patterns (if called with nested arrays), make names absolute if
+  # wanted and evaluate the classes
+  compiler.evaluate_classes(
+  transform_and_assert_classnames(
+      vals.is_a?(Array) ? vals.flatten : [vals]),
+      self, false)
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/inline_epp.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/inline_epp.rb
new file mode 100644
index 0000000..1e8af8f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/inline_epp.rb
@@ -0,0 +1,76 @@
+Puppet::Parser::Functions::newfunction(:inline_epp, :type => :rvalue, :arity => -2, :doc =>
+"Evaluates an Embedded Puppet Template (EPP) string and returns the rendered text result as a String.
+
+EPP support the following tags:
+
+* `<%= puppet expression %>` - This tag renders the value of the expression it contains.
+* `<% puppet expression(s) %>` - This tag will execute the expression(s) it contains, but renders nothing.
+* `<%# comment %>` - The tag and its content renders nothing.
+* `<%%` or `%%>` - Renders a literal `<%` or `%>` respectively.
+* `<%-` - Same as `<%` but suppresses any leading whitespace.
+* `-%>` - Same as `%>` but suppresses any trailing whitespace on the same line (including line break).
+* `<%- |parameters| -%>` - When placed as the first tag declares the template's parameters.
+
+Inline EPP supports the following visibilities of variables in scope which depends on how EPP parameters
+are used - see further below:
+
+* Global scope (i.e. top + node scopes) - global scope is always visible
+* Global + Enclosing scope - if the EPP template does not declare parameters, and no arguments are given
+* Global + all given arguments - if the EPP template does not declare parameters, and arguments are given
+* Global + declared parameters - if the EPP declares parameters, given argument names must match
+
+EPP supports parameters by placing an optional parameter list as the very first element in the EPP. As an example,
+`<%- |$x, $y, $z='unicorn'| -%>` when placed first in the EPP text declares that the parameters `x` and `y` must be
+given as template arguments when calling `inline_epp`, and that `z` if not given as a template argument
+defaults to `'unicorn'`. Template parameters are available as variables, e.g.arguments `$x`, `$y` and `$z` in the example.
+Note that `<%-` must be used or any leading whitespace will be interpreted as text
+
+Arguments are passed to the template by calling `inline_epp` with a Hash as the last argument, where parameters
+are bound to values, e.g. `inline_epp('...', {'x'=>10, 'y'=>20})`. Excess arguments may be given
+(i.e. undeclared parameters) only if the EPP templates does not declare any parameters at all.
+Template parameters shadow variables in outer scopes.
+
+Note: An inline template is best stated using a single-quoted string, or a heredoc since a double-quoted string
+is subject to expression interpolation before the string is parsed as an EPP template. Here are examples
+(using heredoc to define the EPP text):
+
+    # produces 'Hello local variable world!'
+    $x ='local variable'
+    inline_epptemplate(@(END:epp))
+    <%- |$x| -%>
+    Hello <%= $x %> world!
+    END
+
+    # produces 'Hello given argument world!'
+    $x ='local variable world'
+    inline_epptemplate(@(END:epp), { x =>'given argument'})
+    <%- |$x| -%>
+    Hello <%= $x %> world!
+    END
+
+    # produces 'Hello given argument world!'
+    $x ='local variable world'
+    inline_epptemplate(@(END:epp), { x =>'given argument'})
+    <%- |$x| -%>
+    Hello <%= $x %>!
+    END
+
+    # results in error, missing value for y
+    $x ='local variable world'
+    inline_epptemplate(@(END:epp), { x =>'given argument'})
+    <%- |$x, $y| -%>
+    Hello <%= $x %>!
+    END
+
+    # Produces 'Hello given argument planet'
+    $x ='local variable world'
+    inline_epptemplate(@(END:epp), { x =>'given argument'})
+    <%- |$x, $y=planet| -%>
+    Hello <%= $x %> <%= $y %>!
+    END
+
+- Since 3.5
+- Requires Future Parser") do |arguments|
+
+  function_fail(["inline_epp() is only available when parser/evaluator future is in effect"])
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/inline_template.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/inline_template.rb
new file mode 100644
index 0000000..b3ab9d3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/inline_template.rb
@@ -0,0 +1,21 @@
+Puppet::Parser::Functions::newfunction(:inline_template, :type => :rvalue, :arity => -2, :doc =>
+  "Evaluate a template string and return its value.  See
+  [the templating docs](http://docs.puppetlabs.com/guides/templating.html) for
+  more information.  Note that if multiple template strings are specified, their
+  output is all concatenated and returned as the output of the function.") do |vals|
+
+  require 'erb'
+
+    vals.collect do |string|
+      # Use a wrapper, so the template can't get access to the full
+      # Scope object.
+
+      wrapper = Puppet::Parser::TemplateWrapper.new(self)
+      begin
+        wrapper.result(string)
+      rescue => detail
+        raise Puppet::ParseError,
+          "Failed to parse inline template: #{detail}", detail.backtrace
+      end
+    end.join("")
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/lookup.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/lookup.rb
new file mode 100644
index 0000000..58160b5
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/lookup.rb
@@ -0,0 +1,144 @@
+Puppet::Parser::Functions.newfunction(:lookup, :type => :rvalue, :arity => -2, :doc => <<-'ENDHEREDOC') do |args|
+Looks up data defined using Puppet Bindings and Hiera.
+The function is callable with one to three arguments and optionally with a code block to further process the result.
+
+The lookup function can be called in one of these ways:
+
+    lookup(name)
+    lookup(name, type)
+    lookup(name, type, default)
+    lookup(options_hash)
+    lookup(name, options_hash)
+
+The function may optionally be called with a code block / lambda with the following signatures:
+
+    lookup(...) |$result| { ... }
+    lookup(...) |$name, $result| { ... }
+    lookup(...) |$name, $result, $default| { ... }
+
+The longer signatures are useful when the block needs to raise an error (it can report the name), or
+if it needs to know if the given default value was selected.
+
+The code block receives the following three arguments:
+
+* The `$name` is the last name that was looked up (*the* name if only one name was looked up)
+* The `$result` is the looked up value (or the default value if not found).
+* The `$default` is the given default value (`undef` if not given).
+
+The block, if present, is called with the result from the lookup. The value produced by the block is also what is
+produced by the `lookup` function.
+When a block is used, it is the users responsibility to call `error` if the result does not meet additional
+criteria, or if an undef value is not acceptable. If a value is not found, and a default has been
+specified, the default value is given to the block.
+
+The content of the options hash is:
+
+* `name` - The name or array of names to lookup (first found is returned)
+* `type` - The type to assert (a Type or a type specification in string form)
+* `default` - The default value if there was no value found (must comply with the data type)
+* `accept_undef` - (default `false`) An `undef` result is accepted if this options is set to `true`.
+* `override` - a hash with map from names to values that are used instead of the underlying bindings. If the name
+  is found here it wins. Defaults to an empty hash.
+* `extra` - a hash with map from names to values that are used as a last resort to obtain a value. Defaults to an
+  empty hash.
+
+When the call is on the form `lookup(name, options_hash)`, or `lookup(name, type, options_hash)`, the given name
+argument wins over the `options_hash['name']`.
+
+The search order is `override` (if given), then `binder`, then `hiera` and finally `extra` (if given). The first to produce
+a value other than undef for a given name wins.
+
+The type specification is one of:
+
+  * A type in the Puppet Type System, e.g.:
+    * `Integer`, an integral value with optional range e.g.:
+      * `Integer[0, default]` - 0 or positive
+      * `Integer[default, -1]` - negative, 
+      * `Integer[1,100]` - value between 1 and 100 inclusive
+    * `String`- any string
+    * `Float` - floating point number (same signature as for Integer for `Integer` ranges)
+    * `Boolean` - true of false (strict)
+    * `Array` - an array (of Data by default), or parameterized as `Array[<element_type>]`, where
+      `<element_type>` is the expected type of elements
+    * `Hash`,  - a hash (of default `Literal` keys and `Data` values), or parameterized as
+      `Hash[<value_type>]`, `Hash[<key_type>, <value_type>]`, where `<key_type>`, and
+      `<value_type>` are the types of the keys and values respectively
+      (key is `Literal` by default).
+    * `Data` - abstract type representing any `Literal`, `Array[Data]`, or `Hash[Literal, Data]`
+    * `Pattern[<p1>, <p2>, ..., <pn>]` - an enumeration of valid patterns (one or more) where
+       a pattern is a regular expression string or regular expression,
+       e.g. `Pattern['.com$', '.net$']`, `Pattern[/[a-z]+[0-9]+/]` 
+    * `Enum[<s1>, <s2>, ..., <sn>]`, - an enumeration of exact string values (one or more)
+       e.g. `Enum[blue, red, green]`.
+    * `Variant[<t1>, <t2>,...<tn>]` - matches one of the listed types (at least one must be given)
+      e.g. `Variant[Integer[8000,8999], Integer[20000, 99999]]` to accept a value in either range
+    * `Regexp`- a regular expression (i.e. the result is a regular expression, not a string
+       matching a regular expression).
+  * A string containing a type description - one of the types as shown above but in string form.
+
+If the function is called without specifying a default value, and nothing is bound to the given name 
+an error is raised unless the option `accept_undef` is true. If a block is given it must produce an acceptable
+value (or call `error`). If the block does not produce an acceptable value an error is
+raised.
+
+Examples:
+
+When called with one argument; **the name**, it
+returns the bound value with the given name after having  asserted it has the default datatype `Data`:
+
+    lookup('the_name')
+
+When called with two arguments; **the name**, and **the expected type**, it
+returns the bound value with the given name after having asserted it has the given data
+type ('String' in the example):
+
+    lookup('the_name', 'String') # 3.x
+    lookup('the_name', String)   # parser future
+
+When called with three arguments, **the name**, the **expected type**, and a **default**, it
+returns the bound value with the given name, or the default after having asserted the value
+has the given data type (`String` in the example above):
+
+    lookup('the_name', 'String', 'Fred') # 3x
+    lookup('the_name', String, 'Fred')   # parser future
+
+Using a lambda to process the looked up result - asserting that it starts with an upper case letter:
+
+    # only with parser future
+    lookup('the_size', Integer[1,100]) |$result| {
+      if $large_value_allowed and $result > 10
+        { error 'Values larger than 10 are not allowed'}
+      $result
+    }
+
+Including the name in the error
+
+    # only with parser future
+    lookup('the_size', Integer[1,100]) |$name, $result| {
+      if $large_value_allowed and $result > 10
+        { error 'The bound value for '${name}' can not be larger than 10 in this configuration'}
+      $result
+    }
+
+When using a block, the value it produces is also asserted against the given type, and it may not be
+`undef` unless the option `'accept_undef'` is `true`.
+
+All options work as the corresponding (direct) argument. The `first_found` option and
+`accept_undef` are however only available as options.
+
+Using first_found semantics option to return the first name that has a bound value:
+
+    lookup(['apache::port', 'nginx::port'], 'Integer', 80)
+
+If you want to make lookup return undef when no value was found instead of raising an error:
+
+     $are_you_there = lookup('peekaboo', { accept_undef => true} )
+     $are_you_there = lookup('peekaboo', { accept_undef => true}) |$result| { $result }
+
+ENDHEREDOC
+
+  unless Puppet[:binder] || Puppet.future_parser?
+    raise Puppet::ParseError, "The lookup function is only available with settings --binder true, or --parser future"
+  end
+  Puppet::Pops::Binder::Lookup.lookup(self, args)
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/map.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/map.rb
new file mode 100644
index 0000000..c2ca3aa
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/map.rb
@@ -0,0 +1,43 @@
+Puppet::Parser::Functions::newfunction(
+  :map,
+  :type => :rvalue,
+  :arity => -3,
+  :doc => <<-DOC
+Applies a parameterized block to each element in a sequence of entries from the first
+argument and returns an array with the result of each invocation of the parameterized block.
+
+This function takes two mandatory arguments: the first should be an Array, Hash, or of Enumerable type
+(integer, Integer range, or String), and the second a parameterized block as produced by the puppet syntax:
+
+      $a.map |$x| { ... }
+      map($a) |$x| { ... }
+
+When the first argument `$a` is an Array or of enumerable type, the block is called with each entry in turn.
+When the first argument is a hash the entry is an array with `[key, value]`.
+
+Example Using map with two arguments
+
+     # Turns hash into array of values
+     $a.map |$x|{ $x[1] }
+
+     # Turns hash into array of keys
+     $a.map |$x| { $x[0] }
+
+When using a block with 2 parameters, the element's index (starting from 0) for an array, and the key for a hash
+is given to the block's first parameter, and the value is given to the block's second parameter.args.
+
+Example Using map with two arguments
+
+     # Turns hash into array of values
+     $a.map |$key,$val|{ $val }
+
+     # Turns hash into array of keys
+     $a.map |$key,$val|{ $key }
+
+- since 3.4 for Array and Hash
+- since 3.5 for other enumerables, and support for blocks with 2 parameters
+- note requires `parser = future`
+DOC
+) do |args|
+  function_fail(["map() is only available when parser/evaluator future is in effect"])
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/match.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/match.rb
new file mode 100644
index 0000000..33bdf3e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/match.rb
@@ -0,0 +1,28 @@
+Puppet::Parser::Functions::newfunction(
+  :match,
+  :arity => 2,
+  :doc => <<-DOC
+Returns the match result of matching a String or Array[String] with one of:
+
+* Regexp
+* String - transformed to a Regexp
+* Pattern type
+* Regexp type
+
+Returns An Array with the entire match at index 0, and each subsequent submatch at index 1-n.
+If there was no match `undef` is returned. If the value to match is an Array, a array
+with mapped match results is returned.
+
+Example matching:
+
+  "abc123".match(/([a-z]+)[1-9]+/)    # => ["abc"]
+  "abc123".match(/([a-z]+)([1-9]+)/)  # => ["abc", "123"]
+
+See the documentation for "The Puppet Type System" for more information about types.
+
+- since 3.7.0
+- note requires future parser
+DOC
+) do |args|
+  function_fail(["match() is only available when parser/evaluator future is in effect"])
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/md5.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/md5.rb
new file mode 100644
index 0000000..d9e1ee8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/md5.rb
@@ -0,0 +1,5 @@
+require 'digest/md5'
+
+Puppet::Parser::Functions::newfunction(:md5, :type => :rvalue, :arity => 1, :doc => "Returns a MD5 hash value from a provided string.") do |args|
+      Digest::MD5.hexdigest(args[0])
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/realize.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/realize.rb
new file mode 100644
index 0000000..c8bd91e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/realize.rb
@@ -0,0 +1,19 @@
+# This is just syntactic sugar for a collection, although it will generally
+# be a good bit faster.
+
+Puppet::Parser::Functions::newfunction(:realize, :arity => -2, :doc => "Make a virtual object real.  This is useful
+    when you want to know the name of the virtual object and don't want to
+    bother with a full collection.  It is slightly faster than a collection,
+    and, of course, is a bit shorter.  You must pass the object using a
+    reference; e.g.: `realize User[luke]`." ) do |vals|
+
+    vals = [vals] unless vals.is_a?(Array)
+    if Puppet.future_parser?
+      coll = Puppet::Pops::Evaluator::Collectors::FixedSetCollector.new(self, vals.flatten)
+    else
+      coll = Puppet::Parser::Collector.new(self, :nomatter, nil, nil, :virtual)
+      coll.resources = vals.flatten
+    end
+
+    compiler.add_collection(coll)
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/reduce.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/reduce.rb
new file mode 100644
index 0000000..4fe90a2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/reduce.rb
@@ -0,0 +1,71 @@
+Puppet::Parser::Functions::newfunction(
+  :reduce,
+  :type => :rvalue,
+  :arity => -3,
+  :doc => <<-DOC
+Applies a parameterized block to each element in a sequence of entries from the first
+argument (_the enumerable_) and returns the last result of the invocation of the parameterized block.
+
+This function takes two mandatory arguments: the first should be an Array, Hash, or something of
+enumerable type, and the last a parameterized block as produced by the puppet syntax:
+
+      $a.reduce |$memo, $x| { ... }
+      reduce($a) |$memo, $x| { ... }
+
+When the first argument is an Array or someting of an enumerable type, the block is called with each entry in turn.
+When the first argument is a hash each entry is converted to an array with `[key, value]` before being
+fed to the block. An optional 'start memo' value may be supplied as an argument between the array/hash
+and mandatory block.
+
+      $a.reduce(start) |$memo, $x| { ... }
+      reduce($a, start) |$memo, $x| { ... }
+
+If no 'start memo' is given, the first invocation of the parameterized block will be given the first and second
+elements of the enumeration, and if the enumerable has fewer than 2 elements, the first
+element is produced as the result of the reduction without invocation of the block.
+
+On each subsequent invocation, the produced value of the invoked parameterized block is given as the memo in the
+next invocation.
+
+Example Using reduce
+
+      # Reduce an array
+      $a = [1,2,3]
+      $a.reduce |$memo, $entry| { $memo + $entry }
+      #=> 6
+
+      # Reduce hash values
+      $a = {a => 1, b => 2, c => 3}
+      $a.reduce |$memo, $entry| { [sum, $memo[1]+$entry[1]] }
+      #=> [sum, 6]
+
+      # reverse a string
+      "abc".reduce |$memo, $char| { "$char$memo" }
+      #=>"cbe"
+
+It is possible to provide a starting 'memo' as an argument.
+
+Example Using reduce with given start 'memo'
+
+      # Reduce an array
+      $a = [1,2,3]
+      $a.reduce(4) |$memo, $entry| { $memo + $entry }
+      #=> 10
+
+      # Reduce hash values
+      $a = {a => 1, b => 2, c => 3}
+      $a.reduce([na, 4]) |$memo, $entry| { [sum, $memo[1]+$entry[1]] }
+      #=> [sum, 10]
+
+Example Using reduce with an Integer range
+
+      Integer[1,4].reduce |$memo, $x| { $memo + $x }
+      #=> 10
+
+- since 3.2 for Array and Hash
+- since 3.5 for additional enumerable types
+- note requires `parser = future`.
+DOC
+) do |args|
+  function_fail(["reduce() is only available when parser/evaluator future is in effect"])
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/regsubst.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/regsubst.rb
new file mode 100644
index 0000000..a22dc53
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/regsubst.rb
@@ -0,0 +1,116 @@
+# Copyright (C) 2009 Thomas Bellman
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THOMAS BELLMAN BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of Thomas Bellman shall
+# not be used in advertising or otherwise to promote the sale, use or
+# other dealings in this Software without prior written authorization
+# from Thomas Bellman.
+
+Puppet::Parser::Functions::newfunction(
+  :regsubst, :type => :rvalue,
+  :arity => -4,
+
+  :doc => "
+Perform regexp replacement on a string or array of strings.
+
+* *Parameters* (in order):
+    * _target_  The string or array of strings to operate on.  If an array, the replacement will be performed on each of the elements in the array, and the return value will be an array.
+    * _regexp_  The regular expression matching the target string.  If you want it anchored at the start and or end of the string, you must do that with ^ and $ yourself.
+    * _replacement_  Replacement string. Can contain backreferences to what was matched using \\0 (whole match), \\1 (first set of parentheses), and so on.
+    * _flags_  Optional. String of single letter flags for how the regexp is interpreted:
+        - *E*         Extended regexps
+        - *I*         Ignore case in regexps
+        - *M*         Multiline regexps
+        - *G*         Global replacement; all occurrences of the regexp in each target string will be replaced.  Without this, only the first occurrence will be replaced.
+    * _encoding_  Optional.  How to handle multibyte characters.  A single-character string with the following values:
+        - *N*         None
+        - *E*         EUC
+        - *S*         SJIS
+        - *U*         UTF-8
+
+* *Examples*
+
+Get the third octet from the node's IP address:
+
+    $i3 = regsubst($ipaddress,'^(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)$','\\3')
+
+Put angle brackets around each octet in the node's IP address:
+
+    $x = regsubst($ipaddress, '([0-9]+)', '<\\1>', 'G')
+") do |args|
+  unless args.length.between?(3, 5)
+
+    raise(
+      ArgumentError,
+
+        "regsubst(): got #{args.length} arguments, expected 3 to 5")
+  end
+  target, regexp, replacement, flags, lang = args
+  reflags = 0
+  operation = :sub
+  if flags == nil
+    flags = []
+  elsif flags.respond_to?(:split)
+    flags = flags.split('')
+  else
+
+    raise(
+      Puppet::ParseError,
+
+        "regsubst(): bad flags parameter #{flags.class}:`#{flags}'")
+  end
+  flags.each do |f|
+    case f
+    when 'G' then operation = :gsub
+    when 'E' then reflags |= Regexp::EXTENDED
+    when 'I' then reflags |= Regexp::IGNORECASE
+    when 'M' then reflags |= Regexp::MULTILINE
+    else raise(Puppet::ParseError, "regsubst(): bad flag `#{f}'")
+    end
+  end
+  begin
+    re = Regexp.compile(regexp, reflags, lang)
+  rescue RegexpError, TypeError
+
+    raise(
+      Puppet::ParseError,
+
+        "regsubst(): Bad regular expression `#{regexp}'")
+  end
+  if target.respond_to?(operation)
+    # String parameter -> string result
+    result = target.send(operation, re, replacement)
+  elsif target.respond_to?(:collect) and
+    target.respond_to?(:all?) and
+    target.all? { |e| e.respond_to?(operation) }
+    # Array parameter -> array result
+    result = target.collect { |e|
+      e.send(operation, re, replacement)
+    }
+  else
+
+    raise(
+      Puppet::ParseError,
+
+        "regsubst(): bad target #{target.class}:`#{target}'")
+  end
+  return result
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/require.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/require.rb
new file mode 100644
index 0000000..d6350fc
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/require.rb
@@ -0,0 +1,61 @@
+# Requires the specified classes
+
+  Puppet::Parser::Functions::newfunction(
+    :require,
+    :arity => -2,
+    :doc =>"Evaluate one or more classes,  adding the required class as a dependency.
+
+The relationship metaparameters work well for specifying relationships
+between individual resources, but they can be clumsy for specifying
+relationships between classes.  This function is a superset of the
+'include' function, adding a class relationship so that the requiring
+class depends on the required class.
+
+Warning: using require in place of include can lead to unwanted dependency cycles.
+
+For instance the following manifest, with 'require' instead of 'include' would produce a nasty dependence cycle, because notify imposes a before between File[/foo] and Service[foo]:
+
+    class myservice {
+      service { foo: ensure => running }
+    }
+
+    class otherstuff {
+      include myservice
+      file { '/foo': notify => Service[foo] }
+    }
+
+Note that this function only works with clients 0.25 and later, and it will
+fail if used with earlier clients.
+
+When the future parser is used, you must use the class's full name;
+relative names are no longer allowed. In addition to names in string form,
+you may also directly use Class and Resource Type values that are produced by
+the future parser's resource and relationship expressions.
+") do |vals|
+  # Make call patterns uniform and protected against nested arrays, also make
+  # names absolute if so desired.
+  vals = transform_and_assert_classnames(vals.is_a?(Array) ? vals.flatten : [vals])
+
+  # This is the same as calling the include function (but faster) since it again
+  # would otherwise need to perform the optional absolute name transformation
+  # (for no reason since they are already made absolute here).
+  #
+  compiler.evaluate_classes(vals, self, false)
+
+  vals.each do |klass|
+    # lookup the class in the scopes
+    if classobj = find_hostclass(klass)
+      klass = classobj.name
+    else
+      raise Puppet::ParseError, "Could not find class #{klass}"
+    end
+
+    # This is a bit hackish, in some ways, but it's the only way
+    # to configure a dependency that will make it to the client.
+    # The 'obvious' way is just to add an edge in the catalog,
+    # but that is considered a containment edge, not a dependency
+    # edge, so it usually gets lost on the client.
+    ref = Puppet::Resource.new(:class, klass)
+    resource.set_parameter(:require, [resource[:require]].flatten.compact << ref)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/scanf.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/scanf.rb
new file mode 100644
index 0000000..8872ae2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/scanf.rb
@@ -0,0 +1,44 @@
+require 'scanf'
+
+Puppet::Parser::Functions::newfunction(
+  :scanf,
+  :type => :rvalue,
+  :arity => 2,
+  :doc => <<-DOC
+Scans a string and returns an array of one or more converted values as directed by a given format string.args
+See the documenation of Ruby's String::scanf method for details about the supported formats (which
+are similar but not identical to the formats used in Puppet's `sprintf` function.
+
+This function takes two mandatory arguments: the first is the String to
+convert, and the second the format String. The result of the scan is an Array,
+with each sucessfully scanned and transformed value.args The scanning stops if
+a scan is unsuccesful and the scanned result up to that point is returned. If
+there was no succesful scan at all, the result is an empty Array.
+
+      scanf("42", "%i")[0] == 42
+
+
+When used with the future parser, an optional parameterized block may be given.  
+The block is called with the result that is produced by scanf if no block is
+present, the result of the block is then returned by the function.
+
+The optional code block is typically used to assert that the scan was
+succesful, and either produce the same input, or perform unwrapping of
+the result:
+
+      "42".scanf("%i")
+      "42".scanf("%i") |$x| {
+        unless $x[0] =~ Integer {
+          fail "Expected a well formed integer value, got '$x[0]'"
+        }
+        $x[0]
+      }
+
+- since 3.7.4 with `parser = future`
+- since 3.7.5 with classic parser
+DOC
+) do |args|
+  data = args[0]
+  format = args[1]
+  result = data.scanf(format)
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/search.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/search.rb
new file mode 100644
index 0000000..8055e38
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/search.rb
@@ -0,0 +1,12 @@
+Puppet::Parser::Functions::newfunction(:search, :arity => -2, :doc => "Add another namespace for this class to search.
+    This allows you to create classes with sets of definitions and add
+    those classes to another class's search path.
+
+    Deprecated in Puppet 3.7.0, to be removed in Puppet 4.0.0.") do |vals|
+
+    Puppet.deprecation_warning("The 'search' function is deprecated. See http://links.puppetlabs.com/search-function-deprecation")
+
+    vals.each do |val|
+      add_namespace(val)
+    end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/sha1.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/sha1.rb
new file mode 100644
index 0000000..7c565cf
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/sha1.rb
@@ -0,0 +1,5 @@
+require 'digest/sha1'
+
+Puppet::Parser::Functions::newfunction(:sha1, :type => :rvalue, :arity => 1, :doc => "Returns a SHA1 hash value from a provided string.") do |args|
+      Digest::SHA1.hexdigest(args[0])
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/shellquote.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/shellquote.rb
new file mode 100644
index 0000000..1cf6b1b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/shellquote.rb
@@ -0,0 +1,61 @@
+# Copyright (C) 2009 Thomas Bellman
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THOMAS BELLMAN BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of Thomas Bellman shall
+# not be used in advertising or otherwise to promote the sale, use or
+# other dealings in this Software without prior written authorization
+# from Thomas Bellman.
+
+Puppet::Parser::Functions.newfunction(:shellquote, :type => :rvalue, :arity => -1, :doc => "\
+    Quote and concatenate arguments for use in Bourne shell.
+
+    Each argument is quoted separately, and then all are concatenated
+    with spaces.  If an argument is an array, the elements of that
+    array is interpolated within the rest of the arguments; this makes
+    it possible to have an array of arguments and pass that array to
+    shellquote instead of having to specify each argument
+    individually in the call.
+    ") \
+do |args|
+  safe = 'a-zA-Z0-9@%_+=:,./-'    # Safe unquoted
+  dangerous = '!"`$\\'            # Unsafe inside double quotes
+
+  result = []
+  args.flatten.each do |word|
+    if word.length != 0 and word.count(safe) == word.length
+      result << word
+    elsif word.count(dangerous) == 0
+      result << ('"' + word + '"')
+    elsif word.count("'") == 0
+      result << ("'" + word + "'")
+    else
+      r = '"'
+      word.each_byte do |c|
+        r += "\\" if dangerous.include?(c.chr)
+        r += c.chr
+      end
+      r += '"'
+      result << r
+    end
+  end
+
+  return result.join(" ")
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/slice.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/slice.rb
new file mode 100644
index 0000000..d57b99c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/slice.rb
@@ -0,0 +1,48 @@
+Puppet::Parser::Functions::newfunction(
+  :slice,
+  :type => :rvalue,
+  :arity => -3,
+  :doc => <<-DOC
+Applies a parameterized block to each _slice_ of elements in a sequence of selected entries from the first
+argument and returns the first argument, or if no block is given returns a new array with a concatenation of
+the slices.
+
+This function takes two mandatory arguments: the first, `$a`, should be an Array, Hash, or something of
+enumerable type (integer, Integer range, or String), and the second, `$n`, the number of elements to include
+in each slice. The optional third argument should be a a parameterized block as produced by the puppet syntax:
+
+    $a.slice($n) |$x| { ... }
+    slice($a) |$x| { ... }
+
+The parameterized block should have either one parameter (receiving an array with the slice), or the same number
+of parameters as specified by the slice size (each parameter receiving its part of the slice).
+In case there are fewer remaining elements than the slice size for the last slice it will contain the remaining
+elements. When the block has multiple parameters, excess parameters are set to undef for an array or
+enumerable type, and to empty arrays for a Hash.
+
+    $a.slice(2) |$first, $second| { ... }
+
+When the first argument is a Hash, each `key,value` entry is counted as one, e.g, a slice size of 2 will produce
+an array of two arrays with key, and value.
+
+Example Using slice with Hash
+
+    $a.slice(2) |$entry|          { notice "first ${$entry[0]}, second ${$entry[1]}" }
+    $a.slice(2) |$first, $second| { notice "first ${first}, second ${second}" }
+
+When called without a block, the function produces a concatenated result of the slices.
+
+Example Using slice without a block
+
+    slice([1,2,3,4,5,6], 2) # produces [[1,2], [3,4], [5,6]]
+    slice(Integer[1,6], 2)  # produces [[1,2], [3,4], [5,6]]
+    slice(4,2)              # produces [[0,1], [2,3]]
+    slice('hello',2)        # produces [[h, e], [l, l], [o]]
+
+- since 3.2 for Array and Hash
+- since 3.5 for additional enumerable types
+- note requires `parser = future`.
+DOC
+) do |args|
+  function_fail(["slice() is only available when parser/evaluator future is in effect"])
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/split.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/split.rb
new file mode 100644
index 0000000..0485a5e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/split.rb
@@ -0,0 +1,28 @@
+module Puppet::Parser::Functions
+
+  newfunction(
+  :split, :type => :rvalue,
+  :arity => 2,
+
+    :doc => "\
+Split a string variable into an array using the specified split regexp.
+
+*Example:*
+
+    $string     = 'v1.v2:v3.v4'
+    $array_var1 = split($string, ':')
+    $array_var2 = split($string, '[.]')
+    $array_var3 = split($string, '[.:]')
+
+`$array_var1` now holds the result `['v1.v2', 'v3.v4']`,
+while `$array_var2` holds `['v1', 'v2:v3', 'v4']`, and
+`$array_var3` holds `['v1', 'v2', 'v3', 'v4']`.
+
+Note that in the second example, we split on a literal string that contains
+a regexp meta-character (.), which must be escaped.  A simple
+way to do that for a single character is to enclose it in square
+brackets; a backslash will also escape a single character.") do |args|
+
+  return args[0].split(Regexp.compile(args[1]))
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/sprintf.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/sprintf.rb
new file mode 100644
index 0000000..09b57f5
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/sprintf.rb
@@ -0,0 +1,36 @@
+# Copyright (C) 2009 Thomas Bellman
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THOMAS BELLMAN BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of Thomas Bellman shall
+# not be used in advertising or otherwise to promote the sale, use or
+# other dealings in this Software without prior written authorization
+# from Thomas Bellman.
+
+Puppet::Parser::Functions::newfunction(
+  :sprintf, :type => :rvalue,
+  :arity => -2,
+  :doc => "Perform printf-style formatting of text.
+
+      The first parameter is format string describing how the rest of the parameters should be formatted.  See the documentation for the `Kernel::sprintf` function in Ruby for all the details."
+) do |args|
+  fmt = args.shift
+  return sprintf(fmt, *args)
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/tag.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/tag.rb
new file mode 100644
index 0000000..b4b1b69
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/tag.rb
@@ -0,0 +1,6 @@
+# Tag the current scope with each passed name
+Puppet::Parser::Functions::newfunction(:tag, :arity => -2, :doc => "Add the specified tags to the containing class
+  or definition.  All contained objects will then acquire that tag, also.
+  ") do |vals|
+    self.resource.tag(*vals)
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/tagged.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/tagged.rb
new file mode 100644
index 0000000..72fb16e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/tagged.rb
@@ -0,0 +1,18 @@
+# Test whether a given tag is set.  This functions as a big OR -- if any of the specified tags are unset, we return false.
+Puppet::Parser::Functions::newfunction(:tagged, :type => :rvalue, :arity => -2, :doc => "A boolean function that
+  tells you whether the current container is tagged with the specified tags.
+  The tags are ANDed, so that all of the specified tags must be included for
+  the function to return true.") do |vals|
+    configtags = compiler.catalog.tags
+    resourcetags = resource.tags
+
+    retval = true
+    vals.each do |val|
+      unless configtags.include?(val) or resourcetags.include?(val)
+        retval = false
+        break
+      end
+    end
+
+    return retval
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/template.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/template.rb
new file mode 100644
index 0000000..c789347
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/template.rb
@@ -0,0 +1,30 @@
+Puppet::Parser::Functions::newfunction(:template, :type => :rvalue, :arity => -2, :doc =>
+  "Loads an ERB template from a module, evaluates it, and returns the resulting
+  value as a string.
+
+  The argument to this function should be a `<MODULE NAME>/<TEMPLATE FILE>`
+  reference, which will load `<TEMPLATE FILE>` from a module's `templates`
+  directory. (For example, the reference `apache/vhost.conf.erb` will load the
+  file `<MODULES DIRECTORY>/apache/templates/vhost.conf.erb`.)
+
+  This function can also accept:
+
+  * An absolute path, which can load a template file from anywhere on disk.
+  * Multiple arguments, which will evaluate all of the specified templates and
+  return their outputs concatenated into a single string.") do |vals|
+    vals.collect do |file|
+      # Use a wrapper, so the template can't get access to the full
+      # Scope object.
+      debug "Retrieving template #{file}"
+
+      wrapper = Puppet::Parser::TemplateWrapper.new(self)
+      wrapper.file = file
+      begin
+        wrapper.result
+      rescue => detail
+        info = detail.backtrace.first.split(':')
+        raise Puppet::ParseError,
+          "Failed to parse template #{file}:\n  Filepath: #{info[0]}\n  Line: #{info[1]}\n  Detail: #{detail}\n"
+      end
+    end.join("")
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/versioncmp.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/versioncmp.rb
new file mode 100644
index 0000000..302250d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/versioncmp.rb
@@ -0,0 +1,30 @@
+require 'puppet/util/package'
+
+Puppet::Parser::Functions::newfunction( :versioncmp, :type => :rvalue, :arity => 2, :doc =>
+"Compares two version numbers.
+
+Prototype:
+
+    \$result = versioncmp(a, b)
+
+Where a and b are arbitrary version strings.
+
+This function returns:
+
+* `1` if version a is greater than version b
+* `0` if the versions are equal
+* `-1` if version a is less than version b
+
+Example:
+
+    if versioncmp('2.6-1', '2.4.5') > 0 {
+        notice('2.6-1 is > than 2.4.5')
+    }
+
+This function uses the same version comparison algorithm used by Puppet's
+`package` type.
+
+") do |args|
+
+  return Puppet::Util::Package.versioncmp(args[0], args[1])
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/with.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/with.rb
new file mode 100644
index 0000000..07beff6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/functions/with.rb
@@ -0,0 +1,21 @@
+Puppet::Parser::Functions::newfunction(
+  :with,
+  :type => :rvalue,
+  :arity => -1,
+  :doc => <<-DOC
+Call a lambda code block with the given arguments. Since the parameters of the lambda
+are local to the lambda's scope, this can be used to create private sections
+of logic in a class so that the variables are not visible outside of the
+class.
+
+Example:
+
+     # notices the array [1, 2, 'foo']
+     with(1, 2, 'foo') |$x, $y, $z| { notice [$x, $y, $z] }
+
+- since 3.7.0
+- note requires future parser
+DOC
+) do |args|
+  function_fail(["with() is only available when parser/evaluator future is in effect"])
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/grammar.ra b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/grammar.ra
new file mode 100644
index 0000000..c7b83fe
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/grammar.ra
@@ -0,0 +1,806 @@
+# vim: syntax=ruby
+
+# the parser
+
+class Puppet::Parser::Parser
+
+token STRING DQPRE DQMID DQPOST
+token LBRACK  RBRACK LBRACE RBRACE SYMBOL FARROW COMMA TRUE
+token FALSE EQUALS APPENDS LESSEQUAL NOTEQUAL DOT COLON LLCOLLECT RRCOLLECT
+token QMARK LPAREN RPAREN ISEQUAL GREATEREQUAL GREATERTHAN LESSTHAN
+token IF ELSE IMPORT DEFINE ELSIF VARIABLE CLASS INHERITS NODE BOOLEAN
+token NAME SEMIC CASE DEFAULT AT LCOLLECT RCOLLECT CLASSREF
+token NOT OR AND UNDEF PARROW PLUS MINUS TIMES DIV LSHIFT RSHIFT UMINUS
+token MATCH NOMATCH REGEX IN_EDGE OUT_EDGE IN_EDGE_SUB OUT_EDGE_SUB
+token IN UNLESS MODULO
+
+prechigh
+  right NOT
+  nonassoc UMINUS
+  left  IN MATCH NOMATCH
+  left  TIMES DIV MODULO
+  left  MINUS PLUS
+  left  LSHIFT RSHIFT
+  left  NOTEQUAL ISEQUAL
+  left  GREATEREQUAL GREATERTHAN LESSTHAN LESSEQUAL
+  left  AND
+  left  OR
+preclow
+
+rule
+program:    statements_and_declarations
+  | nil
+
+  statements_and_declarations:   statement_or_declaration {
+    result = ast AST::BlockExpression, :children => (val[0] ? [val[0]] : [])
+  }
+  | statements_and_declarations statement_or_declaration {
+    if val[1]
+      val[0].push(val[1])
+    end
+    result = val[0]
+  }
+
+# statements is like statements_and_declarations, but it doesn't allow
+# nested definitions, classes, or nodes.
+statements: statements_and_declarations {
+  val[0].each do |stmt|
+    if stmt.is_a?(AST::TopLevelConstruct)
+      error "Classes, definitions, and nodes may only appear at toplevel or inside other classes", \
+          :line => stmt.context[:line], :file => stmt.context[:file]
+    end
+  end
+  result = val[0]
+}
+
+# The main list of valid statements
+statement_or_declaration:    resource
+  | virtualresource
+  | collection
+  | assignment
+  | casestatement
+  | ifstatement_begin
+  | unlessstatement
+  | import
+  | fstatement
+  | definition
+  | hostclass
+  | nodedef
+  | resourceoverride
+  | append
+  | relationship
+
+keyword: AND
+ | CASE
+ | CLASS
+ | DEFAULT
+ | DEFINE
+ | ELSE
+ | ELSIF
+ | IF
+ | IN
+ | IMPORT
+ | INHERITS
+ | NODE
+ | OR
+ | UNDEF
+ | UNLESS
+
+relationship: relationship_side edge relationship_side {
+  result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context)
+}
+  | relationship edge relationship_side {
+    result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context)
+}
+
+relationship_side: resource
+  | resourceref
+  | collection
+  | variable
+  | quotedtext
+  | selector
+  | casestatement
+  | hasharrayaccesses
+
+edge: IN_EDGE | OUT_EDGE | IN_EDGE_SUB | OUT_EDGE_SUB
+
+fstatement:   NAME LPAREN expressions RPAREN {
+  result = ast AST::Function,
+    :name => val[0][:value],
+    :line => val[0][:line],
+    :arguments => val[2],
+    :ftype => :statement
+}
+| NAME LPAREN expressions COMMA RPAREN {
+  result = ast AST::Function,
+    :name => val[0][:value],
+    :line => val[0][:line],
+    :arguments => val[2],
+    :ftype => :statement
+}            | NAME LPAREN RPAREN {
+  result = ast AST::Function,
+    :name => val[0][:value],
+    :line => val[0][:line],
+    :arguments => AST::ASTArray.new({}),
+    :ftype => :statement
+}
+  | NAME funcvalues {
+    result = ast AST::Function,
+    :name => val[0][:value],
+    :line => val[0][:line],
+    :arguments => val[1],
+    :ftype => :statement
+}
+
+funcvalues: rvalue { result = aryfy(val[0]) }
+# This rvalue could be an expression
+  | funcvalues COMMA rvalue {
+    val[0].push(val[2])
+    result = val[0]
+}
+
+expressions: expression               { result = aryfy(val[0]) }
+       | expressions comma expression { result = val[0].push(val[2]) }
+
+rvalue:       quotedtext
+  | name
+  | type
+  | boolean
+  | selector
+  | variable
+  | array
+  | hasharrayaccesses
+  | resourceref
+  | funcrvalue
+  | undef
+
+resource:       classname LBRACE resourceinstances endsemi RBRACE {
+  @lexer.commentpop
+  result = ast(AST::Resource, :type => val[0], :instances => val[2])
+}           | classname LBRACE params endcomma RBRACE {
+  # This is a deprecated syntax.
+  error "All resource specifications require names"
+}           | type LBRACE params endcomma RBRACE {
+  # a defaults setting for a type
+  @lexer.commentpop
+  result = ast(AST::ResourceDefaults, :type => val[0].value, :parameters => val[2])
+}
+
+# Override a value set elsewhere in the configuration.
+resourceoverride:     resourceref LBRACE anyparams endcomma RBRACE {
+  @lexer.commentpop
+  result = ast AST::ResourceOverride, :object => val[0], :parameters => val[2]
+}
+
+# Exported and virtual resources; these don't get sent to the client
+# unless they get collected elsewhere in the db.
+virtualresource:  at resource {
+  type = val[0]
+
+  if (type == :exported and ! Puppet[:storeconfigs])
+    Puppet.warning addcontext("You cannot collect without storeconfigs being set")
+  end
+
+  error "Defaults are not virtualizable" if val[1].is_a? AST::ResourceDefaults
+
+  method = type.to_s + "="
+
+  # Just mark our resource as exported and pass it through.
+  val[1].send(method, true)
+
+  result = val[1]
+}
+
+at:   AT { result = :virtual }
+  | AT AT { result = :exported }
+
+# A collection statement.  Currently supports no arguments at all, but eventually
+# will, I assume.
+collection:     type collectrhand LBRACE anyparams endcomma RBRACE {
+  @lexer.commentpop
+  type = val[0].value.downcase
+  args = {:type => type}
+
+  if val[1].is_a?(AST::CollExpr)
+    args[:query] = val[1]
+    args[:query].type = type
+    args[:form] = args[:query].form
+  else
+    args[:form] = val[1]
+  end
+  if args[:form] == :exported and ! Puppet[:storeconfigs]
+    Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored")
+  end
+  args[:override] = val[3]
+  result = ast AST::Collection, args
+}
+  | type collectrhand {
+  type = val[0].value.downcase
+  args = {:type => type }
+
+  if val[1].is_a?(AST::CollExpr)
+    args[:query] = val[1]
+    args[:query].type = type
+    args[:form] = args[:query].form
+  else
+    args[:form] = val[1]
+  end
+  if args[:form] == :exported and ! Puppet[:storeconfigs]
+    Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored")
+  end
+  result = ast AST::Collection, args
+}
+
+
+collectrhand:     LCOLLECT collstatements RCOLLECT {
+  if val[1]
+    result = val[1]
+    result.form = :virtual
+  else
+    result = :virtual
+  end
+}
+  | LLCOLLECT collstatements RRCOLLECT {
+    if val[1]
+    result = val[1]
+    result.form = :exported
+  else
+    result = :exported
+  end
+}
+
+# A mini-language for handling collection comparisons.  This is organized
+# to avoid the need for precedence indications.
+collstatements:           nil
+  | collstatement
+  | collstatements colljoin collstatement {
+    result = ast AST::CollExpr, :test1 => val[0], :oper => val[1], :test2 => val[2]
+}
+
+collstatement:            collexpr
+  | LPAREN collstatements RPAREN {
+    result = val[1]
+    result.parens = true
+}
+
+colljoin:                 AND { result=val[0][:value] }
+  | OR  { result=val[0][:value] }
+
+collexpr:                 colllval ISEQUAL expression {
+  result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2]
+  #result = ast AST::CollExpr
+  #result.push *val
+}
+  | colllval NOTEQUAL expression {
+    result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2]
+    #result = ast AST::CollExpr
+    #result.push *val
+}
+
+colllval:                 variable
+  | name
+
+resourceinst:   resourcename COLON params endcomma {
+  result = ast AST::ResourceInstance, :title => val[0], :parameters => val[2]
+}
+
+resourceinstances:   resourceinst { result = aryfy(val[0]) }
+  | resourceinstances SEMIC resourceinst {
+    val[0].push val[2]
+    result = val[0]
+}
+
+endsemi:      # nothing
+  | SEMIC
+
+undef:         UNDEF {
+  result = ast AST::Undef, :value => :undef
+}
+
+name:         NAME {
+  result = ast AST::Name, :value => val[0][:value], :line => val[0][:line]
+}
+
+type:         CLASSREF {
+  result = ast AST::Type, :value => val[0][:value], :line => val[0][:line]
+}
+
+resourcename:   quotedtext
+  | name
+  | type
+  | selector
+  | variable
+  | array
+  | hasharrayaccesses
+
+assignment:     VARIABLE EQUALS expression {
+  raise Puppet::ParseError, "Cannot assign to variables in other namespaces" if val[0][:value] =~ /::/
+  # this is distinct from referencing a variable
+  variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line]
+  result = ast AST::VarDef, :name => variable, :value => val[2], :line => val[0][:line]
+}
+  | hasharrayaccess EQUALS expression {
+    result = ast AST::VarDef, :name => val[0], :value => val[2]
+}
+
+append:     VARIABLE APPENDS expression {
+  variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line]
+  result = ast AST::VarDef, :name => variable, :value => val[2], :append => true, :line => val[0][:line]
+}
+
+params:   # nothing
+{
+  result = ast AST::ASTArray
+}
+  | param { result = aryfy(val[0]) }
+  | params COMMA param {
+    val[0].push(val[2])
+    result = val[0]
+}
+
+param_name: NAME 
+  | keyword 
+  | BOOLEAN
+
+param:        param_name FARROW expression {
+  result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2]
+}
+
+addparam:     NAME PARROW expression {
+  result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2],
+    :add => true
+}
+
+anyparam:     param
+  | addparam
+
+anyparams:   # nothing
+{
+  result = ast AST::ASTArray
+}
+  | anyparam { result = aryfy(val[0]) }
+  | anyparams COMMA anyparam {
+    val[0].push(val[2])
+    result = val[0]
+}
+
+# We currently require arguments in these functions.
+funcrvalue:   NAME LPAREN expressions RPAREN {
+  result = ast AST::Function,
+    :name => val[0][:value], :line => val[0][:line],
+    :arguments => val[2],
+    :ftype => :rvalue
+}           | NAME LPAREN RPAREN {
+  result = ast AST::Function,
+    :name => val[0][:value], :line => val[0][:line],
+    :arguments => AST::ASTArray.new({}),
+    :ftype => :rvalue
+}
+
+quotedtext: STRING       { result = ast AST::String, :value => val[0][:value],                  :line => val[0][:line] }
+  | DQPRE dqrval { result = ast AST::Concat, :value => [ast(AST::String,val[0])]+val[1], :line => val[0][:line] }
+
+dqrval: expression dqtail { result = [val[0]] + val[1] }
+
+dqtail: DQPOST        { result = [ast(AST::String,val[0])]          }
+  | DQMID dqrval  { result = [ast(AST::String,val[0])] + val[1] }
+
+boolean:    BOOLEAN {
+  result = ast AST::Boolean, :value => val[0][:value], :line => val[0][:line]
+}
+
+resourceref: NAME LBRACK expressions RBRACK {
+  Puppet.warning addcontext("Deprecation notice:  Resource references should now be capitalized")
+  result = ast AST::ResourceReference, :type => val[0][:value], :line => val[0][:line], :title => val[2]
+}               | type LBRACK expressions RBRACK {
+  result = ast AST::ResourceReference, :type => val[0].value, :title => val[2]
+}
+
+unlessstatement: UNLESS expression LBRACE statements RBRACE {
+  @lexer.commentpop
+  args = {
+    :test => ast(AST::Not, :value => val[1]),
+    :statements => val[3]
+  }
+
+  result = ast AST::IfStatement, args
+}
+  | UNLESS expression LBRACE RBRACE {
+    @lexer.commentpop
+    args = {
+      :test => ast(AST::Not, :value => val[1]), 
+      :statements => ast(AST::Nop)
+    }
+    result = ast AST::IfStatement, args
+}
+
+ifstatement_begin: IF ifstatement {
+  result = val[1]
+}
+
+ifstatement:      expression LBRACE statements RBRACE else {
+  @lexer.commentpop
+  args = {
+    :test => val[0],
+    :statements => val[2]
+  }
+
+  args[:else] = val[4] if val[4]
+
+  result = ast AST::IfStatement, args
+}
+  | expression LBRACE RBRACE else {
+    @lexer.commentpop
+    args = {
+      :test => val[0],
+      :statements => ast(AST::Nop)
+  }
+
+  args[:else] = val[3] if val[3]
+
+  result = ast AST::IfStatement, args
+}
+
+else:             # nothing
+  | ELSIF ifstatement {
+    result = ast AST::Else, :statements => val[1]
+}
+  | ELSE LBRACE statements RBRACE {
+    @lexer.commentpop
+    result = ast AST::Else, :statements => val[2]
+}
+  | ELSE LBRACE RBRACE {
+    @lexer.commentpop
+    result = ast AST::Else, :statements => ast(AST::Nop)
+}
+
+# Unlike yacc/bison, it seems racc
+# gives tons of shift/reduce warnings
+# with the following syntax:
+#
+# expression: ...
+#            | expression arithop expressio { ... }
+#
+# arithop: PLUS | MINUS | DIVIDE | TIMES ...
+#
+# So I had to develop the expression by adding one rule
+# per operator :-(
+
+expression:   rvalue
+  | hash
+  | expression IN expression {
+    result = ast AST::InOperator, :lval => val[0], :rval => val[2]
+}
+  | expression MATCH regex {
+    result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+}
+  | expression NOMATCH regex {
+    result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+}
+  | expression PLUS expression {
+    result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+}
+  | expression MINUS expression {
+    result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+}
+  | expression DIV expression {
+    result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+}
+  | expression TIMES expression {
+    result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+}
+  | expression MODULO expression {
+    result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+}
+  | expression LSHIFT expression {
+    result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+}
+  | expression RSHIFT expression {
+    result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+}
+  | MINUS expression =UMINUS {
+    result = ast AST::Minus, :value => val[1]
+}
+  | expression NOTEQUAL expression {
+    result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+}
+  | expression ISEQUAL expression {
+    result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+}
+  | expression GREATERTHAN expression {
+    result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+}
+  | expression GREATEREQUAL expression {
+    result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+}
+  | expression LESSTHAN expression {
+    result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+}
+  | expression LESSEQUAL expression {
+    result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+}
+  | NOT expression {
+    result = ast AST::Not, :value => val[1]
+}
+  | expression AND expression {
+    result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+}
+  | expression OR expression {
+    result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+}
+  | LPAREN expression RPAREN {
+    result = val[1]
+}
+
+casestatement:  CASE expression LBRACE caseopts RBRACE {
+  @lexer.commentpop
+  result = ast AST::CaseStatement, :test => val[1], :options => val[3]
+}
+
+caseopts:     caseopt { result = aryfy(val[0]) }
+  | caseopts caseopt {
+    val[0].push val[1]
+    result = val[0]
+}
+
+caseopt:        casevalues COLON LBRACE statements RBRACE {
+  @lexer.commentpop
+  result = ast AST::CaseOpt, :value => val[0], :statements => val[3]
+}               | casevalues COLON LBRACE RBRACE {
+  @lexer.commentpop
+
+    result = ast(
+    AST::CaseOpt,
+    :value => val[0],
+
+    :statements => ast(AST::BlockExpression)
+  )
+}
+
+casevalues:       selectlhand { result = aryfy(val[0]) }
+  | casevalues COMMA selectlhand {
+    val[0].push(val[2])
+    result = val[0]
+}
+
+selector:     selectlhand QMARK svalues {
+  result = ast AST::Selector, :param => val[0], :values => val[2]
+}
+
+svalues:      selectval
+  | LBRACE sintvalues endcomma RBRACE {
+    @lexer.commentpop
+    result = val[1]
+}
+
+sintvalues:   selectval
+  | sintvalues comma selectval {
+    if val[0].instance_of?(AST::ASTArray)
+    val[0].push(val[2])
+    result = val[0]
+  else
+    result = ast AST::ASTArray, :children => [val[0],val[2]]
+  end
+}
+
+selectval:        selectlhand FARROW rvalue {
+  result = ast AST::ResourceParam, :param => val[0], :value => val[2]
+}
+
+selectlhand:  name
+  | type
+  | quotedtext
+  | variable
+  | funcrvalue
+  | boolean
+  | undef
+  | hasharrayaccess
+  | DEFAULT {
+    result = ast AST::Default, :value => val[0][:value], :line => val[0][:line]
+}
+  | regex
+
+# These are only used for importing, and we don't interpolate there.
+string:        STRING       { result = [val[0][:value]] }
+strings:       string
+  |  strings COMMA string { result = val[0] += val[2] }
+
+import: IMPORT strings {
+  val[1].each do |file|
+    import(file)
+  end
+
+  result = nil
+}
+
+# Disable definition inheritance for now. 8/27/06, luke
+#definition: DEFINE NAME argumentlist parent LBRACE statements RBRACE {
+definition: DEFINE classname argumentlist LBRACE statements RBRACE {
+  @lexer.commentpop
+  result = Puppet::Parser::AST::Definition.new(classname(val[1]),
+                                               ast_context(true).merge(:arguments => val[2], :code => val[4],
+                                                                       :line => val[0][:line]))
+  @lexer.indefine = false
+
+#}           | DEFINE NAME argumentlist parent LBRACE RBRACE {
+}           | DEFINE classname argumentlist LBRACE RBRACE {
+  @lexer.commentpop
+  result = Puppet::Parser::AST::Definition.new(classname(val[1]),
+                                               ast_context(true).merge(:arguments => val[2], :line => val[0][:line]))
+  @lexer.indefine = false
+}
+
+#hostclass: CLASS NAME argumentlist parent LBRACE statements RBRACE {
+hostclass: CLASS classname argumentlist classparent LBRACE statements_and_declarations RBRACE {
+  @lexer.commentpop
+  # Our class gets defined in the parent namespace, not our own.
+  @lexer.namepop
+  result = Puppet::Parser::AST::Hostclass.new(classname(val[1]),
+                                              ast_context(true).merge(:arguments => val[2], :parent => val[3],
+                                                                      :code => val[5], :line => val[0][:line]))
+}           | CLASS classname argumentlist classparent LBRACE RBRACE {
+  @lexer.commentpop
+  # Our class gets defined in the parent namespace, not our own.
+  @lexer.namepop
+  result = Puppet::Parser::AST::Hostclass.new(classname(val[1]),
+                                              ast_context(true).merge(:arguments => val[2], :parent => val[3],
+                                                                      :line => val[0][:line]))
+}
+
+nodedef: NODE hostnames nodeparent LBRACE statements RBRACE {
+  @lexer.commentpop
+  result = Puppet::Parser::AST::Node.new(val[1],
+                                         ast_context(true).merge(:parent => val[2], :code => val[4],
+                                                                 :line => val[0][:line]))
+}       |  NODE hostnames nodeparent LBRACE RBRACE {
+  @lexer.commentpop
+  result = Puppet::Parser::AST::Node.new(val[1], ast_context(true).merge(:parent => val[2], :line => val[0][:line]))
+}
+
+classname:      NAME { result = val[0][:value] }
+  | CLASS { result = "class" }
+
+# Multiple hostnames, as used for node names.  These are all literal
+# strings, not AST objects.
+hostnames:    nodename {
+    result = [result]
+}
+  | hostnames COMMA nodename {
+    result = val[0]
+    result << val[2]
+}
+
+nodename: hostname {
+  result = ast AST::HostName, :value => val[0]
+}
+
+hostname: NAME { result = val[0][:value] }
+  | STRING { result = val[0][:value] }
+  | DEFAULT { result = val[0][:value] }
+  | regex
+
+nil:    {
+  result = nil
+}
+
+nothing:    {
+  result = ast AST::ASTArray, :children => []
+}
+
+argumentlist: nil
+  | LPAREN nothing RPAREN {
+    result = nil
+}
+  | LPAREN arguments endcomma RPAREN {
+    result = val[1]
+    result = [result] unless result[0].is_a?(Array)
+}
+
+arguments:    argument
+  | arguments COMMA argument {
+    result = val[0]
+    result = [result] unless result[0].is_a?(Array)
+    result << val[2]
+}
+
+argument:
+ VARIABLE EQUALS expression { result = [val[0][:value], val[2]] }
+| VARIABLE { result = [val[0][:value]] }
+
+nodeparent:       nil
+  | INHERITS hostname {
+    result = val[1]
+}
+
+classparent:       nil
+  | INHERITS classnameordefault {
+    result = val[1]
+}
+
+classnameordefault: classname | DEFAULT
+
+variable:     VARIABLE {
+  result = ast AST::Variable, :value => val[0][:value], :line => val[0][:line]
+}
+
+array: LBRACK expressions       RBRACK { result = val[1] }
+     | LBRACK expressions COMMA RBRACK { result = val[1] }
+     | LBRACK               RBRACK { result = ast AST::ASTArray }
+
+comma:        FARROW
+  | COMMA
+
+endcomma:     # nothing
+  | COMMA { result = nil }
+
+regex:        REGEX {
+  result = ast AST::Regex, :value => val[0][:value]
+}
+
+hash:        LBRACE hashpairs RBRACE {
+  @lexer.commentpop
+  if val[1].instance_of?(AST::ASTHash)
+    result = val[1]
+  else
+    result = ast AST::ASTHash, { :value => val[1] }
+  end
+}
+  | LBRACE hashpairs COMMA RBRACE {
+    @lexer.commentpop
+    if val[1].instance_of?(AST::ASTHash)
+    result = val[1]
+  else
+    result = ast AST::ASTHash, { :value => val[1] }
+  end
+}           | LBRACE RBRACE {
+  @lexer.commentpop
+  result = ast AST::ASTHash
+}
+
+hashpairs:  hashpair
+  | hashpairs COMMA hashpair {
+    if val[0].instance_of?(AST::ASTHash)
+    result = val[0].merge(val[2])
+  else
+    result = ast AST::ASTHash, :value => val[0]
+    result.merge(val[2])
+  end
+}
+
+hashpair:   key FARROW expression {
+  result = ast AST::ASTHash, { :value => { val[0] => val[2] } }
+}
+
+key:      NAME { result = val[0][:value] }
+  | quotedtext { result = val[0] }
+
+hasharrayaccess: VARIABLE LBRACK expression RBRACK {
+  result = ast AST::HashOrArrayAccess, :variable => val[0][:value], :key => val[2]
+}
+
+hasharrayaccesses:    hasharrayaccess
+  | hasharrayaccesses LBRACK expression RBRACK {
+    result = ast AST::HashOrArrayAccess, :variable => val[0], :key => val[2]
+}
+
+end
+---- header ----
+require 'puppet'
+require 'puppet/parser/lexer'
+require 'puppet/parser/ast'
+
+module Puppet
+  class ParseError < Puppet::Error; end
+  class ImportError < Racc::ParseError; end
+  class AlreadyImportedError < ImportError; end
+end
+
+---- inner ----
+
+# It got too annoying having code in a file that needs to be compiled.
+require 'puppet/parser/parser_support'
+
+# Make emacs happy
+# Local Variables:
+# mode: ruby
+# End:
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/lexer.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/lexer.rb
new file mode 100644
index 0000000..de12499
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/lexer.rb
@@ -0,0 +1,608 @@
+# the scanner/lexer
+
+require 'forwardable'
+require 'strscan'
+require 'puppet'
+require 'puppet/util/methodhelper'
+
+
+module Puppet
+  class LexError < RuntimeError; end
+end
+
+module Puppet::Parser; end
+
+class Puppet::Parser::Lexer
+  extend Forwardable
+
+  attr_reader :last, :file, :lexing_context, :token_queue
+
+  attr_accessor :line, :indefine
+  alias :indefine? :indefine
+
+  # Returns the position on the line.
+  # This implementation always returns nil. It is here for API reasons in Puppet::Error
+  # which needs to support both --parser current, and --parser future.
+  #
+  def pos
+    # Make the lexer comply with newer API. It does not produce a pos...
+    nil
+  end
+
+  def lex_error msg
+    raise Puppet::LexError.new(msg)
+  end
+
+  class Token
+    ALWAYS_ACCEPTABLE = Proc.new { |context| true }
+
+    include Puppet::Util::MethodHelper
+
+    attr_accessor :regex, :name, :string, :skip, :incr_line, :skip_text, :accumulate
+    alias skip? skip
+    alias accumulate? accumulate
+
+    def initialize(string_or_regex, name, options = {})
+      if string_or_regex.is_a?(String)
+        @name, @string = name, string_or_regex
+        @regex = Regexp.new(Regexp.escape(string_or_regex))
+      else
+        @name, @regex = name, string_or_regex
+      end
+
+      set_options(options)
+      @acceptable_when = ALWAYS_ACCEPTABLE
+    end
+
+    def to_s
+      string or @name.to_s
+    end
+
+    def acceptable?(context={})
+      @acceptable_when.call(context)
+    end
+
+    # Define when the token is able to match.
+    # This provides context that cannot be expressed otherwise, such as feature flags.
+    #
+    # @param block [Proc] a proc that given a context returns a boolean
+    def acceptable_when(block)
+      @acceptable_when = block
+    end
+  end
+
+  # Maintain a list of tokens.
+  class TokenList
+    extend Forwardable
+
+    attr_reader :regex_tokens, :string_tokens
+    def_delegator :@tokens, :[]
+
+    # Create a new token.
+    def add_token(name, regex, options = {}, &block)
+      raise(ArgumentError, "Token #{name} already exists") if @tokens.include?(name)
+      token = Token.new(regex, name, options)
+      @tokens[token.name] = token
+      if token.string
+        @string_tokens << token
+        @tokens_by_string[token.string] = token
+      else
+        @regex_tokens << token
+      end
+
+      token.meta_def(:convert, &block) if block_given?
+
+      token
+    end
+
+    def initialize
+      @tokens = {}
+      @regex_tokens = []
+      @string_tokens = []
+      @tokens_by_string = {}
+    end
+
+    # Look up a token by its value, rather than name.
+    def lookup(string)
+      @tokens_by_string[string]
+    end
+
+    # Define more tokens.
+    def add_tokens(hash)
+      hash.each do |regex, name|
+        add_token(name, regex)
+      end
+    end
+
+    # Sort our tokens by length, so we know once we match, we're done.
+    # This helps us avoid the O(n^2) nature of token matching.
+    def sort_tokens
+      @string_tokens.sort! { |a, b| b.string.length <=> a.string.length }
+    end
+
+    # Yield each token name and value in turn.
+    def each
+      @tokens.each {|name, value| yield name, value }
+    end
+  end
+
+  TOKENS = TokenList.new
+  TOKENS.add_tokens(
+    '['   => :LBRACK,
+    ']'   => :RBRACK,
+    '{'   => :LBRACE,
+    '}'   => :RBRACE,
+    '('   => :LPAREN,
+    ')'   => :RPAREN,
+    '='   => :EQUALS,
+    '+='  => :APPENDS,
+    '=='  => :ISEQUAL,
+    '>='  => :GREATEREQUAL,
+    '>'   => :GREATERTHAN,
+    '<'   => :LESSTHAN,
+    '<='  => :LESSEQUAL,
+    '!='  => :NOTEQUAL,
+    '!'   => :NOT,
+    ','   => :COMMA,
+    '.'   => :DOT,
+    ':'   => :COLON,
+    '@'   => :AT,
+    '<<|' => :LLCOLLECT,
+    '|>>' => :RRCOLLECT,
+    '->'  => :IN_EDGE,
+    '<-'  => :OUT_EDGE,
+    '~>'  => :IN_EDGE_SUB,
+    '<~'  => :OUT_EDGE_SUB,
+    '<|'  => :LCOLLECT,
+    '|>'  => :RCOLLECT,
+    ';'   => :SEMIC,
+    '?'   => :QMARK,
+    '\\'  => :BACKSLASH,
+    '=>'  => :FARROW,
+    '+>'  => :PARROW,
+    '+'   => :PLUS,
+    '-'   => :MINUS,
+    '/'   => :DIV,
+    '*'   => :TIMES,
+    '%'   => :MODULO,
+    '<<'  => :LSHIFT,
+    '>>'  => :RSHIFT,
+    '=~'  => :MATCH,
+    '!~'  => :NOMATCH,
+    %r{((::){0,1}[A-Z][-\w]*)+} => :CLASSREF,
+    "<string>" => :STRING,
+    "<dqstring up to first interpolation>" => :DQPRE,
+    "<dqstring between two interpolations>" => :DQMID,
+    "<dqstring after final interpolation>" => :DQPOST,
+    "<boolean>" => :BOOLEAN
+  )
+
+  module Contextual
+    QUOTE_TOKENS = [:DQPRE,:DQMID]
+    REGEX_INTRODUCING_TOKENS = [:NODE,:LBRACE,:RBRACE,:MATCH,:NOMATCH,:COMMA]
+
+    NOT_INSIDE_QUOTES = Proc.new do |context|
+      !QUOTE_TOKENS.include? context[:after]
+    end
+
+    INSIDE_QUOTES = Proc.new do |context|
+      QUOTE_TOKENS.include? context[:after]
+    end
+
+    IN_REGEX_POSITION = Proc.new do |context|
+      REGEX_INTRODUCING_TOKENS.include? context[:after]
+    end
+
+    IN_STRING_INTERPOLATION = Proc.new do |context|
+      context[:string_interpolation_depth] > 0
+    end
+
+    DASHED_VARIABLES_ALLOWED = Proc.new do |context|
+      Puppet[:allow_variables_with_dashes]
+    end
+
+    VARIABLE_AND_DASHES_ALLOWED = Proc.new do |context|
+      Contextual::DASHED_VARIABLES_ALLOWED.call(context) and TOKENS[:VARIABLE].acceptable?(context)
+    end
+  end
+
+  # Numbers are treated separately from names, so that they may contain dots.
+  TOKENS.add_token :NUMBER, %r{\b(?:0[xX][0-9A-Fa-f]+|0?\d+(?:\.\d+)?(?:[eE]-?\d+)?)\b} do |lexer, value|
+    [TOKENS[:NAME], value]
+  end
+  TOKENS[:NUMBER].acceptable_when Contextual::NOT_INSIDE_QUOTES
+
+  TOKENS.add_token :NAME, %r{((::)?[a-z0-9][-\w]*)(::[a-z0-9][-\w]*)*} do |lexer, value|
+    string_token = self
+    # we're looking for keywords here
+    if tmp = KEYWORDS.lookup(value)
+      string_token = tmp
+      if [:TRUE, :FALSE].include?(string_token.name)
+        value = eval(value)
+        string_token = TOKENS[:BOOLEAN]
+      end
+    end
+    [string_token, value]
+  end
+  [:NAME, :CLASSREF].each do |name_token|
+    TOKENS[name_token].acceptable_when Contextual::NOT_INSIDE_QUOTES
+  end
+
+  TOKENS.add_token :COMMENT, %r{#.*}, :accumulate => true, :skip => true do |lexer,value|
+    value.sub!(/# ?/,'')
+    [self, value]
+  end
+
+  TOKENS.add_token :MLCOMMENT, %r{/\*(.*?)\*/}m, :accumulate => true, :skip => true do |lexer, value|
+    lexer.line += value.count("\n")
+    value.sub!(/^\/\* ?/,'')
+    value.sub!(/ ?\*\/$/,'')
+    [self,value]
+  end
+
+  TOKENS.add_token :REGEX, %r{/[^/\n]*/} do |lexer, value|
+    # Make sure we haven't matched an escaped /
+    while value[-2..-2] == '\\'
+      other = lexer.scan_until(%r{/})
+      value += other
+    end
+    regex = value.sub(%r{\A/}, "").sub(%r{/\Z}, '').gsub("\\/", "/")
+    [self, Regexp.new(regex)]
+  end
+  TOKENS[:REGEX].acceptable_when Contextual::IN_REGEX_POSITION
+
+  TOKENS.add_token :RETURN, "\n", :skip => true, :incr_line => true, :skip_text => true
+
+  TOKENS.add_token :SQUOTE, "'" do |lexer, value|
+    [TOKENS[:STRING], lexer.slurpstring(value,["'"],:ignore_invalid_escapes).first ]
+  end
+
+  DQ_initial_token_types      = {'$' => :DQPRE,'"' => :STRING}
+  DQ_continuation_token_types = {'$' => :DQMID,'"' => :DQPOST}
+
+  TOKENS.add_token :DQUOTE, /"/ do |lexer, value|
+    lexer.tokenize_interpolated_string(DQ_initial_token_types)
+  end
+
+  TOKENS.add_token :DQCONT, /\}/ do |lexer, value|
+    lexer.tokenize_interpolated_string(DQ_continuation_token_types)
+  end
+  TOKENS[:DQCONT].acceptable_when Contextual::IN_STRING_INTERPOLATION
+
+  TOKENS.add_token :DOLLAR_VAR_WITH_DASH, %r{\$(?:::)?(?:[-\w]+::)*[-\w]+} do |lexer, value|
+    lexer.warn_if_variable_has_hyphen(value)
+
+    [TOKENS[:VARIABLE], value[1..-1]]
+  end
+  TOKENS[:DOLLAR_VAR_WITH_DASH].acceptable_when Contextual::DASHED_VARIABLES_ALLOWED
+
+  TOKENS.add_token :DOLLAR_VAR, %r{\$(::)?(\w+::)*\w+} do |lexer, value|
+    [TOKENS[:VARIABLE],value[1..-1]]
+  end
+
+  TOKENS.add_token :VARIABLE_WITH_DASH, %r{(?:::)?(?:[-\w]+::)*[-\w]+} do |lexer, value|
+    lexer.warn_if_variable_has_hyphen(value)
+
+    [TOKENS[:VARIABLE], value]
+  end
+  TOKENS[:VARIABLE_WITH_DASH].acceptable_when Contextual::VARIABLE_AND_DASHES_ALLOWED
+
+  TOKENS.add_token :VARIABLE, %r{(::)?(\w+::)*\w+}
+  TOKENS[:VARIABLE].acceptable_when Contextual::INSIDE_QUOTES
+
+  TOKENS.sort_tokens
+
+  @@pairs = {
+    "{"   => "}",
+    "("   => ")",
+    "["   => "]",
+    "<|"  => "|>",
+    "<<|" => "|>>"
+  }
+
+  KEYWORDS = TokenList.new
+  KEYWORDS.add_tokens(
+    "case"     => :CASE,
+    "class"    => :CLASS,
+    "default"  => :DEFAULT,
+    "define"   => :DEFINE,
+    "import"   => :IMPORT,
+    "if"       => :IF,
+    "elsif"    => :ELSIF,
+    "else"     => :ELSE,
+    "inherits" => :INHERITS,
+    "node"     => :NODE,
+    "and"      => :AND,
+    "or"       => :OR,
+    "undef"    => :UNDEF,
+    "false"    => :FALSE,
+    "true"     => :TRUE,
+    "in"       => :IN,
+    "unless"   => :UNLESS
+  )
+
+  def clear
+    initvars
+  end
+
+  def expected
+    return nil if @expected.empty?
+    name = @expected[-1]
+    TOKENS.lookup(name) or lex_error "Could not find expected token #{name}"
+  end
+
+  # scan the whole file
+  # basically just used for testing
+  def fullscan
+    array = []
+
+    self.scan { |token, str|
+      # Ignore any definition nesting problems
+      @indefine = false
+      array.push([token,str])
+    }
+    array
+  end
+
+  def file=(file)
+    @file = file
+    @line = 1
+    contents = Puppet::FileSystem.exist?(file) ? Puppet::FileSystem.read(file) : ""
+    @scanner = StringScanner.new(contents)
+  end
+
+  def_delegator :@token_queue, :shift, :shift_token
+
+  def find_string_token
+    # We know our longest string token is three chars, so try each size in turn
+    # until we either match or run out of chars.  This way our worst-case is three
+    # tries, where it is otherwise the number of string token we have.  Also,
+    # the lookups are optimized hash lookups, instead of regex scans.
+    #
+    s = @scanner.peek(3)
+    token = TOKENS.lookup(s[0,3]) || TOKENS.lookup(s[0,2]) || TOKENS.lookup(s[0,1])
+    [ token, token && @scanner.scan(token.regex) ]
+  end
+
+  # Find the next token that matches a regex.  We look for these first.
+  def find_regex_token
+    best_token = nil
+    best_length = 0
+
+    # I tried optimizing based on the first char, but it had
+    # a slightly negative affect and was a good bit more complicated.
+    TOKENS.regex_tokens.each do |token|
+      if length = @scanner.match?(token.regex) and token.acceptable?(lexing_context)
+        # We've found a longer match
+        if length > best_length
+          best_length = length
+          best_token = token
+        end
+      end
+    end
+
+    return best_token, @scanner.scan(best_token.regex) if best_token
+  end
+
+  # Find the next token, returning the string and the token.
+  def find_token
+    shift_token || find_regex_token || find_string_token
+  end
+
+  def initialize
+    initvars
+  end
+
+  def initvars
+    @line = 1
+    @previous_token = nil
+    @scanner = nil
+    @file = nil
+    # AAARRGGGG! okay, regexes in ruby are bloody annoying
+    # no one else has "\n" =~ /\s/
+    @skip = %r{[ \t\r]+}
+
+    @namestack = []
+    @token_queue = []
+    @indefine = false
+    @expected = []
+    @commentstack = [ ['', @line] ]
+    @lexing_context = {
+      :after => nil,
+      :start_of_line => true,
+      :string_interpolation_depth => 0
+      }
+  end
+
+  # Make any necessary changes to the token and/or value.
+  def munge_token(token, value)
+    @line += 1 if token.incr_line
+
+    skip if token.skip_text
+
+    return if token.skip and not token.accumulate?
+
+    token, value = token.convert(self, value) if token.respond_to?(:convert)
+
+    return unless token
+
+    if token.accumulate?
+      comment = @commentstack.pop
+      comment[0] << value + "\n"
+      @commentstack.push(comment)
+    end
+
+    return if token.skip
+
+    return token, { :value => value, :line => @line }
+  end
+
+  # Handling the namespace stack
+  def_delegator :@namestack, :pop, :namepop
+  # This value might have :: in it, but we don't care -- it'll be handled
+  # normally when joining, and when popping we want to pop this full value,
+  # however long the namespace is.
+  def_delegator :@namestack, :<<, :namestack
+
+  # Collect the current namespace.
+  def namespace
+    @namestack.join("::")
+  end
+
+  def_delegator :@scanner, :rest
+
+  # this is the heart of the lexer
+  def scan
+    #Puppet.debug("entering scan")
+    lex_error "Invalid or empty string" unless @scanner
+
+    # Skip any initial whitespace.
+    skip
+
+    until token_queue.empty? and @scanner.eos? do
+      matched_token, value = find_token
+
+      # error out if we didn't match anything at all
+      lex_error "Could not match #{@scanner.rest[/^(\S+|\s+|.*)/]}" unless matched_token
+
+      newline = matched_token.name == :RETURN
+
+      # this matches a blank line; eat the previously accumulated comments
+      getcomment if lexing_context[:start_of_line] and newline
+      lexing_context[:start_of_line] = newline
+
+      final_token, token_value = munge_token(matched_token, value)
+
+      unless final_token
+        skip
+        next
+      end
+
+      final_token_name = final_token.name
+      lexing_context[:after]         = final_token_name unless newline
+      lexing_context[:string_interpolation_depth] += 1 if final_token_name == :DQPRE
+      lexing_context[:string_interpolation_depth] -= 1 if final_token_name == :DQPOST
+
+      value = token_value[:value]
+
+      if match = @@pairs[value] and final_token_name != :DQUOTE and final_token_name != :SQUOTE
+        @expected << match
+      elsif exp = @expected[-1] and exp == value and final_token_name != :DQUOTE and final_token_name != :SQUOTE
+        @expected.pop
+      end
+
+      if final_token_name == :LBRACE or final_token_name == :LPAREN
+        commentpush
+      end
+      if final_token_name == :RPAREN
+        commentpop
+      end
+
+      yield [final_token_name, token_value]
+
+      if @previous_token
+        namestack(value) if @previous_token.name == :CLASS and value != '{'
+
+        if @previous_token.name == :DEFINE
+          if indefine?
+            msg = "Cannot nest definition #{value} inside #{@indefine}"
+            self.indefine = false
+            raise Puppet::ParseError, msg
+          end
+
+          @indefine = value
+        end
+      end
+      @previous_token = final_token
+      skip
+    end
+    @scanner = nil
+
+    # This indicates that we're done parsing.
+    yield [false,false]
+  end
+
+  # Skip any skipchars in our remaining string.
+  def skip
+    @scanner.skip(@skip)
+  end
+
+  # Provide some limited access to the scanner, for those
+  # tokens that need it.
+  def_delegator :@scanner, :scan_until
+
+  # we've encountered the start of a string...
+  # slurp in the rest of the string and return it
+  def slurpstring(terminators,escapes=%w{ \\  $ ' " r n t s }+["\n"],ignore_invalid_escapes=false)
+    # we search for the next quote that isn't preceded by a
+    # backslash; the caret is there to match empty strings
+    str = @scanner.scan_until(/([^\\]|^|[^\\])([\\]{2})*[#{terminators}]/) or lex_error "Unclosed quote after '#{last}' in '#{rest}'"
+    @line += str.count("\n") # literal carriage returns add to the line count.
+    str.gsub!(/\\(.)/m) {
+      ch = $1
+      if escapes.include? ch
+        case ch
+        when 'r'; "\r"
+        when 'n'; "\n"
+        when 't'; "\t"
+        when 's'; " "
+        when "\n"; ''
+        else      ch
+        end
+      else
+        Puppet.warning "Unrecognised escape sequence '\\#{ch}'#{file && " in file #{file}"}#{line && " at line #{line}"}" unless ignore_invalid_escapes
+        "\\#{ch}"
+      end
+    }
+    [ str[0..-2],str[-1,1] ]
+  end
+
+  def tokenize_interpolated_string(token_type,preamble='')
+    value,terminator = slurpstring('"$')
+    token_queue << [TOKENS[token_type[terminator]],preamble+value]
+    variable_regex = if Puppet[:allow_variables_with_dashes]
+                       TOKENS[:VARIABLE_WITH_DASH].regex
+                     else
+                       TOKENS[:VARIABLE].regex
+                     end
+    if terminator != '$' or @scanner.scan(/\{/)
+      token_queue.shift
+    elsif var_name = @scanner.scan(variable_regex)
+      warn_if_variable_has_hyphen(var_name)
+      token_queue << [TOKENS[:VARIABLE],var_name]
+      tokenize_interpolated_string(DQ_continuation_token_types)
+    else
+      tokenize_interpolated_string(token_type,token_queue.pop.last + terminator)
+    end
+  end
+
+  # just parse a string, not a whole file
+  def string=(string)
+    @scanner = StringScanner.new(string)
+  end
+
+  # returns the content of the currently accumulated content cache
+  def commentpop
+    @commentstack.pop[0]
+  end
+
+  def getcomment(line = nil)
+    comment = @commentstack.last
+    if line.nil? or comment[1] <= line
+      @commentstack.pop
+      @commentstack.push(['', @line])
+      return comment[0]
+    end
+    ''
+  end
+
+  def commentpush
+    @commentstack.push(['', @line])
+  end
+
+  def warn_if_variable_has_hyphen(var_name)
+    if var_name.include?('-')
+      Puppet.deprecation_warning("Using `-` in variable names is deprecated at #{file || '<string>'}:#{line}. See http://links.puppetlabs.com/puppet-hyphenated-variable-deprecation")
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/makefile b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/makefile
new file mode 100644
index 0000000..c4911d0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/makefile
@@ -0,0 +1,8 @@
+#parser.rb: grammar.ry
+#	ryacc --output parser grammar
+
+parser.rb: grammar.ra
+	racc -o$@ grammar.ra
+
+grammar.output: grammar.ra
+	racc -v -o$@ grammar.ra
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/methods.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/methods.rb
new file mode 100644
index 0000000..af19b2a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/methods.rb
@@ -0,0 +1,69 @@
+require 'puppet/util/autoload'
+require 'puppet/parser/scope'
+require 'puppet/parser/functions'
+require 'monitor'
+
+# A module for handling finding and invoking methods (functions invokable as a method).
+# A method call on the form:
+#
+#  $a.meth(1,2,3] {|...| ...}
+#
+# will lookup a function called 'meth' and call it with the arguments ($a, 1, 2, 3, <lambda>)
+#
+# @see Puppet::Parser::AST::Lambda
+# @see Puppet::Parser::AST::MethodCall
+#
+# @api public
+# @since 3.2
+#
+module Puppet::Parser::Methods
+  Environment = Puppet::Node::Environment
+  # Represents an invokable method configured to be invoked for a given object.
+  #
+  class Method
+    def initialize(receiver, obj, method_name, rvalue)
+      @receiver = receiver
+      @o = obj
+      @method_name = method_name
+      @rvalue = rvalue
+    end
+
+    # Invoke this method's function in the given scope with the given arguments and parameterized block.
+    # A method call on the form:
+    #
+    #  $a.meth(1,2,3) {|...| ...}
+    #
+    # results in the equivalent:
+    #
+    #  meth($a, 1, 2, 3, {|...| ... })
+    #
+    # @param scope [Puppet::Parser::Scope] the scope the call takes place in
+    # @param args [Array<Object>] arguments 1..n to pass to the function
+    # @param pblock [Puppet::Parser::AST::Lambda] optional parameterized block to pass as the last argument
+    #   to the called function
+    #
+    def invoke(scope, args=[], pblock=nil)
+      arguments = [@o] + args
+      arguments << pblock if pblock
+      @receiver.send(@method_name, arguments)
+    end
+
+    # @return [Boolean] whether the method function produces an rvalue or not.
+    def is_rvalue?
+      @rvalue
+    end
+  end
+
+  class << self
+    include Puppet::Util
+  end
+
+  # Finds a function and returns an instance of Method configured to perform invocation.
+  # @return [Method, nil] configured method or nil if method not found
+  def self.find_method(scope, receiver, name)
+    fname = Puppet::Parser::Functions.function(name)
+    rvalue = Puppet::Parser::Functions.rvalue?(name)
+    return Method.new(scope, receiver, fname, rvalue) if fname
+    nil
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/parser.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/parser.rb
new file mode 100644
index 0000000..16872ee
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/parser.rb
@@ -0,0 +1,2559 @@
+#
+# DO NOT MODIFY!!!!
+# This file is automatically generated by Racc 1.4.9
+# from Racc grammer file "".
+#
+
+require 'racc/parser.rb'
+
+require 'puppet'
+require 'puppet/parser/lexer'
+require 'puppet/parser/ast'
+
+module Puppet
+  class ParseError < Puppet::Error; end
+  class ImportError < Racc::ParseError; end
+  class AlreadyImportedError < ImportError; end
+end
+
+module Puppet
+  module Parser
+    class Parser < Racc::Parser
+
+module_eval(<<'...end grammar.ra/module_eval...', 'grammar.ra', 799)
+
+# It got too annoying having code in a file that needs to be compiled.
+require 'puppet/parser/parser_support'
+
+# Make emacs happy
+# Local Variables:
+# mode: ruby
+# End:
+...end grammar.ra/module_eval...
+##### State transition tables begin ###
+
+clist = [
+'35,36,199,198,246,159,-130,86,-112,82,277,357,361,379,356,215,210,159',
+'276,-197,360,158,85,158,211,213,212,214,39,248,48,49,267,33,50,158,51',
+'37,26,-129,40,46,30,35,36,32,84,217,216,31,398,203,204,206,205,208,209',
+'-122,201,202,52,-130,-130,-130,-130,200,38,207,35,36,278,39,86,48,49',
+'350,33,50,90,51,37,26,89,40,46,30,35,36,32,-178,94,253,31,257,280,257',
+'364,274,273,92,93,215,210,52,257,255,226,336,62,38,211,213,212,214,39',
+'338,48,49,254,33,50,339,51,37,26,347,40,46,30,35,36,32,-180,217,216',
+'31,310,203,204,206,205,208,209,341,201,202,52,35,36,274,273,200,38,207',
+'223,303,-178,39,304,48,49,-177,33,50,185,51,37,26,95,40,46,30,35,36',
+'32,190,-184,281,31,397,189,344,90,201,202,226,89,215,210,52,200,357',
+'250,32,356,38,211,213,212,214,39,-179,48,49,268,33,50,90,51,37,26,89',
+'40,46,30,35,36,32,185,217,216,31,395,203,204,206,205,208,209,190,201',
+'202,52,119,189,201,202,200,38,207,201,202,200,39,119,48,49,200,33,50',
+'185,51,37,26,267,40,46,30,35,36,32,190,185,90,31,392,189,89,119,265',
+'375,118,337,190,120,52,257,280,189,302,-96,38,118,257,263,120,39,-185',
+'48,49,52,33,50,52,51,37,26,-123,40,46,30,35,36,32,52,103,118,31,252',
+'120,279,206,205,251,257,280,201,202,52,250,243,243,262,200,38,207,257',
+'263,52,137,135,139,134,136,80,132,140,141,177,168,240,131,162,35,36',
+'82,32,180,142,130,163,271,94,-184,274,273,203,204,206,205,-183,52,-181',
+'201,202,62,138,144,-180,353,200,39,207,48,49,354,33,50,330,51,37,26',
+'-182,40,46,30,35,36,32,-177,52,-179,31,367,203,204,206,205,157,368,370',
+'201,202,52,35,36,371,372,200,38,207,122,327,326,39,110,48,49,109,33',
+'50,267,51,37,26,334,40,46,30,35,36,32,91,81,62,31,377,80,90,323,-179',
+'37,128,382,40,46,52,35,36,32,383,-180,38,31,385,61,-228,39,387,48,49',
+'388,33,50,52,51,37,26,323,40,46,30,35,36,32,319,110,393,31,308,80,90',
+'317,305,37,128,158,40,46,52,53,399,32,400,,38,31,,,,39,,48,49,,33,50',
+'52,51,37,26,,40,46,30,230,,32,,,,31,,,215,210,56,57,58,59,,,52,211,213',
+'212,214,,38,203,204,206,205,208,209,,201,202,56,57,58,59,,200,,207,217',
+'216,210,,203,204,206,205,208,209,211,201,202,228,-38,-38,-38,-38,200',
+',207,,215,210,-44,-44,-44,-44,,,,211,213,212,214,,,203,204,206,205,208',
+'209,,201,202,-40,-40,-40,-40,,200,,207,217,216,,,203,204,206,205,208',
+'209,,201,202,229,,,,,200,,207,,215,210,206,205,,,,201,202,211,213,212',
+'214,,200,,207,,,,35,36,,,103,,104,,,,,,217,216,,,203,204,206,205,208',
+'209,102,201,202,35,36,,,103,200,104,207,80,,,,37,77,,,46,,,,32,101,102',
+',31,35,36,100,,103,,104,,80,,52,,37,77,,,46,,,,32,101,102,,31,35,36',
+'100,,103,,104,,80,,52,,37,77,,,46,,,,32,101,102,,31,35,36,100,,103,',
+'104,,80,,52,,37,77,,,46,,,,32,101,102,,31,35,36,100,,103,,104,,80,,52',
+',37,77,,,46,,,,32,101,102,,31,35,36,100,,103,,104,,80,,52,,37,77,,,46',
+',,,32,101,102,,31,35,36,100,,103,,104,,80,,52,,37,77,,,46,,,,32,101',
+'102,,31,35,36,100,,103,,104,,80,,52,,37,77,,,46,,,,32,101,102,,31,35',
+'36,100,,103,,104,,80,,52,,37,77,,,46,,,,32,101,102,,31,35,36,100,,103',
+',104,,80,,52,,37,77,,,46,,,,32,101,102,,31,35,36,100,,103,,104,,80,',
+'52,,37,77,,,46,,,,32,101,102,,31,35,36,100,,103,,104,,80,,52,,37,77',
+',,46,35,36,,32,101,102,155,31,,,100,,,35,36,,80,103,52,,37,77,,,46,',
+',,32,101,35,36,31,80,103,100,104,37,231,,,46,,52,,32,80,,,31,37,77,102',
+',46,35,36,,32,103,52,104,31,80,,35,36,37,77,,,46,358,52,,32,101,102',
+',31,,,100,35,36,,,,80,,52,,37,77,,,46,,80,,32,101,37,231,31,,46,100',
+',,32,,,,31,52,80,,,,37,231,,,46,52,,,32,35,36,,31,103,,104,,,,,,,,52',
+',,35,36,,,103,102,104,,,,,,,,,,80,,,,37,77,102,,46,,,,32,101,,,31,80',
+',100,,37,77,,,46,,52,,32,101,35,36,31,,103,100,104,,,,35,36,,52,103',
+',104,,,,35,36,102,,103,161,104,,,,,,102,80,,,,37,77,,,46,102,80,,32',
+'101,37,77,31,,46,100,80,,32,101,37,77,31,52,46,100,,,32,101,35,36,31',
+'52,103,100,104,,,,35,36,,52,103,,104,,,,35,36,102,,103,,104,,,,,,102',
+'80,,,,37,77,,,46,102,80,,32,101,37,77,31,,46,100,80,,32,101,37,77,31',
+'52,46,100,,,32,101,35,36,31,52,103,100,104,,,,35,36,,52,78,,-197,,,',
+'35,36,102,,103,,104,,,,,,63,80,,,,37,77,,,46,102,80,,32,101,37,77,31',
+',46,100,80,,32,,37,77,31,52,46,,,,32,101,35,36,31,52,103,100,104,,,',
+'35,36,,52,103,,104,,,,35,36,102,,103,,104,,,,,,102,80,,,,37,77,,,46',
+'102,80,,32,101,37,77,31,,46,100,80,,32,101,37,77,31,52,46,100,,,32,101',
+'35,36,31,52,103,100,104,,,,35,36,,52,103,,104,,,,35,36,102,,103,,104',
+',,,,,102,80,,,,37,77,,,46,102,80,,32,101,37,77,31,,46,100,80,,32,101',
+'37,77,31,52,46,100,,,32,101,35,36,31,52,103,100,104,,,,35,36,,52,103',
+',104,,,,35,36,102,,103,,104,,,,,,102,80,,,,37,77,,,46,102,80,,32,101',
+'37,77,31,,46,100,80,,32,101,37,77,31,52,46,100,,,32,101,35,36,31,52',
+'103,100,104,,,,35,36,,52,103,161,104,,,,35,36,102,,103,,104,,,,,,102',
+'80,,,,37,77,,,46,102,80,,32,101,37,77,31,,46,100,80,,32,101,37,77,31',
+'52,46,100,,,32,101,35,36,31,52,103,100,104,,,,35,36,,52,,,,,,,35,36',
+'102,,,,234,,,,35,36,,80,103,,,37,77,,,46,,80,,32,101,37,231,31,,46,100',
+'80,,32,,37,231,31,52,46,,80,,32,,37,231,31,52,46,35,36,,32,103,,104',
+'31,52,,35,36,,,103,,104,,52,,35,36,102,,,,,,,,,,102,80,,,,37,77,,,46',
+',80,,32,101,37,77,31,,46,100,80,,32,101,37,231,31,52,46,100,,,32,,35',
+'36,31,52,103,,104,,,,,,,52,,,,35,36,,,103,102,104,,,,,,,,,,80,,,,37',
+'77,102,260,46,,35,36,32,101,103,,31,80,,100,,37,77,,,46,,52,,32,101',
+'35,36,31,,103,100,104,,,,,,80,52,,,37,77,,,46,,102,,32,,210,,31,,,,',
+'80,211,,,37,77,52,,46,,,,32,101,215,210,31,,,100,,,,211,213,212,214',
+'52,203,204,206,205,208,209,,201,202,210,,,,,200,,207,211,217,216,,,203',
+'204,206,205,208,209,,201,202,215,210,,,,200,,207,,211,213,212,214,203',
+'204,206,205,208,209,,201,202,,210,,,,200,,207,,211,217,216,,,203,204',
+'206,205,208,209,,201,202,215,210,,,,200,,207,,211,213,212,214,203,204',
+'206,205,208,209,,201,202,,,,,,200,,207,,,217,216,,,203,204,206,205,208',
+'209,,201,202,215,210,,,,200,,207,,211,213,212,214,203,204,206,205,208',
+'209,,201,202,,,,,,200,,207,,,217,216,,,203,204,206,205,208,209,,201',
+'202,215,210,,,,200,,207,301,211,213,212,214,,,,,215,210,,,,,,,,211,213',
+'212,214,,,217,216,,,203,204,206,205,208,209,,201,202,,,,,,200,,207,203',
+'204,206,205,208,209,,201,202,215,210,,,,200,,207,,211,213,212,214,,',
+',,,,,,215,210,,,,,,,,211,213,212,214,,,203,204,206,205,208,209,,201',
+'202,,,,,,200,,207,217,216,,,203,204,206,205,208,209,,201,202,215,210',
+',,,200,,207,,211,213,212,214,,,,,,,,,,,,,,,,,,,,,216,,,203,204,206,205',
+'208,209,,201,202,215,210,,,,200,,207,,211,213,212,214,,,,,,,,,,,,,,',
+',,,,,217,216,,,203,204,206,205,208,209,,201,202,215,210,,,,200,,207',
+',211,213,212,214,,,,,215,210,,,,,,,,211,213,212,214,,,217,216,,,203',
+'204,206,205,208,209,,201,202,,,,,,200,,207,203,204,206,205,208,209,',
+'201,202,215,210,,,,200,,207,,211,213,212,214,,,,,,,,,,,,,,,,,,,,217',
+'216,,,203,204,206,205,208,209,,201,202,215,210,,,,200,,207,,211,213',
+'212,214,,,,,,,,,,,,,,,,,,,,217,216,,,203,204,206,205,208,209,,201,202',
+',,,,,200,,207,137,135,139,134,136,,132,140,141,148,179,,131,133,,,,',
+',142,130,143,137,135,139,134,136,,132,140,141,148,146,,131,133,,138',
+'144,,,142,130,143,137,135,139,134,136,,132,140,141,148,146,,131,133',
+',138,144,,,142,130,143,137,135,139,134,136,,132,140,141,148,179,,131',
+'133,,138,144,,,142,130,143,137,135,139,134,136,,132,140,141,148,179',
+',131,133,,138,144,,,142,130,143,137,135,139,134,136,,132,140,141,148',
+'146,,131,133,,138,144,,,142,130,143,,,,,,,,,,,,,,,,138,144' ]
+        racc_action_table = arr = ::Array.new(2588, nil)
+        idx = 0
+        clist.each do |str|
+          str.split(',', -1).each do |i|
+            arr[idx] = i.to_i unless i.empty?
+            idx += 1
+          end
+        end
+
+clist = [
+'0,0,97,97,115,77,262,28,168,28,186,354,313,345,354,97,97,128,186,128',
+'313,168,28,77,97,97,97,97,0,115,0,0,178,0,0,128,0,0,0,177,0,0,0,391',
+'391,0,28,97,97,0,391,97,97,97,97,97,97,254,97,97,0,262,262,262,262,97',
+'0,97,304,304,191,391,68,391,391,304,391,391,49,391,391,391,49,391,391',
+'391,2,2,391,68,33,153,391,259,259,315,315,191,191,33,33,153,153,391',
+'154,154,304,259,175,391,153,153,153,153,2,263,2,2,154,2,2,264,2,2,2',
+'275,2,2,2,229,229,2,173,153,153,2,229,153,153,153,153,153,153,266,153',
+'153,2,104,104,275,275,153,2,153,104,222,171,229,222,229,229,170,229',
+'229,84,229,229,229,34,229,229,229,383,383,229,84,34,195,229,383,84,269',
+'29,288,288,104,29,195,195,229,288,310,270,29,310,229,195,195,195,195',
+'383,169,383,383,166,383,383,50,383,383,383,50,383,383,383,382,382,383',
+'185,195,195,383,382,195,195,195,195,195,195,185,195,195,383,51,185,290',
+'290,195,383,195,289,289,290,382,248,382,382,289,382,382,272,382,382',
+'382,165,382,382,382,372,372,382,272,85,326,382,372,272,326,246,164,326',
+'51,261,85,51,382,261,261,85,221,163,382,248,221,221,248,372,162,372',
+'372,201,372,372,51,372,372,372,155,372,372,372,81,81,372,248,81,246',
+'372,149,246,192,287,287,146,192,192,287,287,372,145,114,113,160,287',
+'372,287,160,160,246,81,81,81,81,81,81,81,81,81,81,81,112,81,81,306,306',
+'87,81,83,81,81,81,181,80,79,181,181,292,292,292,292,76,81,75,292,292',
+'73,81,81,71,307,292,306,292,306,306,309,306,306,249,306,306,306,69,306',
+'306,306,319,319,306,67,202,66,306,319,291,291,291,291,64,320,321,291',
+'291,306,55,55,323,324,291,306,291,53,245,244,319,48,319,319,41,319,319',
+'343,319,319,319,255,319,319,319,327,327,319,30,27,25,319,327,55,55,243',
+'23,55,55,357,55,55,319,60,60,55,360,22,319,55,362,21,364,327,366,327',
+'327,369,327,327,55,327,327,327,370,327,327,327,228,228,327,241,240,376',
+'327,228,60,60,235,225,60,60,231,60,60,327,1,394,60,396,,327,60,,,,228',
+',228,228,,228,228,60,228,228,228,,228,228,228,108,,228,,,,228,,,108',
+'108,20,20,20,20,,,228,108,108,108,108,,228,294,294,294,294,294,294,',
+'294,294,19,19,19,19,,294,,294,108,108,296,,108,108,108,108,108,108,296',
+'108,108,105,5,5,5,5,108,,108,,105,105,9,9,9,9,,,,105,105,105,105,,,296',
+'296,296,296,296,296,,296,296,7,7,7,7,,296,,296,105,105,,,105,105,105',
+'105,105,105,,105,105,107,,,,,105,,105,,107,107,286,286,,,,286,286,107',
+'107,107,107,,286,,286,,,,204,204,,,204,,204,,,,,,107,107,,,107,107,107',
+'107,107,107,204,107,107,36,36,,,36,107,36,107,204,,,,204,204,,,204,',
+',,204,204,36,,204,38,38,204,,38,,38,,36,,204,,36,36,,,36,,,,36,36,38',
+',36,39,39,36,,39,,39,,38,,36,,38,38,,,38,,,,38,38,39,,38,40,40,38,,40',
+',40,,39,,38,,39,39,,,39,,,,39,39,40,,39,214,214,39,,214,,214,,40,,39',
+',40,40,,,40,,,,40,40,214,,40,213,213,40,,213,,213,,214,,40,,214,214',
+',,214,,,,214,214,213,,214,212,212,214,,212,,212,,213,,214,,213,213,',
+',213,,,,213,213,212,,213,211,211,213,,211,,211,,212,,213,,212,212,,',
+'212,,,,212,212,211,,212,210,210,212,,210,,210,,211,,212,,211,211,,,211',
+',,,211,211,210,,211,209,209,211,,209,,209,,210,,211,,210,210,,,210,',
+',,210,210,209,,210,356,356,210,,356,,356,,209,,210,,209,209,,,209,,',
+',209,209,356,,209,63,63,209,,63,,63,,356,,209,,356,356,,,356,361,361',
+',356,356,63,63,356,,,356,,,317,317,,63,317,356,,63,63,,,63,,,,63,63',
+'208,208,63,361,208,63,208,361,361,,,361,,63,,361,317,,,361,317,317,208',
+',317,207,207,,317,207,361,207,317,208,,311,311,208,208,,,208,311,317',
+',208,208,207,,208,,,208,363,363,,,,207,,208,,207,207,,,207,,311,,207',
+'207,311,311,207,,311,207,,,311,,,,311,207,363,,,,363,363,,,363,311,',
+',363,305,305,,363,305,,305,,,,,,,,363,,,206,206,,,206,305,206,,,,,,',
+',,,305,,,,305,305,206,,305,,,,305,305,,,305,206,,305,,206,206,,,206',
+',305,,206,206,205,205,206,,205,206,205,,,,215,215,,206,215,,215,,,,78',
+'78,205,,78,78,78,,,,,,215,205,,,,205,205,,,205,78,215,,205,205,215,215',
+'205,,215,205,78,,215,215,78,78,215,205,78,215,,,78,78,203,203,78,215',
+'203,78,203,,,,371,371,,78,371,,371,,,,200,200,203,,200,,200,,,,,,371',
+'203,,,,203,203,,,203,200,371,,203,203,371,371,203,,371,203,200,,371',
+'371,200,200,371,203,200,371,,,200,200,199,199,200,371,199,200,199,,',
+',26,26,,200,26,,26,,,,251,251,199,,251,,251,,,,,,26,199,,,,199,199,',
+',199,251,26,,199,199,26,26,199,,26,199,251,,26,,251,251,26,199,251,',
+',,251,251,86,86,251,26,86,251,86,,,,252,252,,251,252,,252,,,,92,92,86',
+',92,,92,,,,,,252,86,,,,86,86,,,86,92,252,,86,86,252,252,86,,252,86,92',
+',252,252,92,92,252,86,92,252,,,92,92,93,93,92,252,93,92,93,,,,94,94',
+',92,94,,94,,,,95,95,93,,95,,95,,,,,,94,93,,,,93,93,,,93,95,94,,93,93',
+'94,94,93,,94,93,95,,94,94,95,95,94,93,95,94,,,95,95,216,216,95,94,216',
+'95,216,,,,100,100,,95,100,,100,,,,101,101,216,,101,,101,,,,,,100,216',
+',,,216,216,,,216,101,100,,216,216,100,100,216,,100,216,101,,100,100',
+'101,101,100,216,101,100,,,101,101,102,102,101,100,102,101,102,,,,103',
+'103,,101,103,103,103,,,,256,256,102,,256,,256,,,,,,103,102,,,,102,102',
+',,102,256,103,,102,102,103,103,102,,103,102,256,,103,103,256,256,103',
+'102,256,103,,,256,256,217,217,256,103,217,256,217,,,,234,234,,256,,',
+',,,,109,109,217,,,,109,,,,265,265,,217,265,,,217,217,,,217,,234,,217',
+'217,234,234,217,,234,217,109,,234,,109,109,234,217,109,,265,,109,,265',
+'265,109,234,265,276,276,,265,276,,276,265,109,,277,277,,,277,,277,,265',
+',230,230,276,,,,,,,,,,277,276,,,,276,276,,,276,,277,,276,276,277,277',
+'276,,277,276,230,,277,277,230,230,277,276,230,277,,,230,,159,159,230',
+'277,159,,159,,,,,,,230,,,,158,158,,,158,159,158,,,,,,,,,,159,,,,159',
+'159,158,158,159,,157,157,159,159,157,,159,158,,159,,158,158,,,158,,159',
+',158,158,62,62,158,,62,158,62,,,,,,157,158,,,157,157,,,157,,62,,157',
+',298,,157,,,,,62,298,,,62,62,157,,62,,,,62,62,335,335,62,,,62,,,,335',
+'335,335,335,62,298,298,298,298,298,298,,298,298,295,,,,,298,,298,295',
+'335,335,,,335,335,335,335,335,335,,335,335,390,390,,,,335,,335,,390',
+'390,390,390,295,295,295,295,295,295,,295,295,,297,,,,295,,295,,297,390',
+'390,,,390,390,390,390,390,390,,390,390,156,156,,,,390,,390,,156,156',
+'156,156,297,297,297,297,297,297,,297,297,,,,,,297,,297,,,156,156,,,156',
+'156,156,156,156,156,,156,156,194,194,,,,156,,156,,194,194,194,194,293',
+'293,293,293,293,293,,293,293,,,,,,293,,293,,,194,194,,,194,194,194,194',
+'194,194,,194,194,220,220,,,,194,,194,220,220,220,220,220,,,,,348,348',
+',,,,,,,348,348,348,348,,,220,220,,,220,220,220,220,220,220,,220,220',
+',,,,,220,,220,348,348,348,348,348,348,,348,348,349,349,,,,348,,348,',
+'349,349,349,349,,,,,,,,,333,333,,,,,,,,333,333,333,333,,,349,349,349',
+'349,349,349,,349,349,,,,,,349,,349,333,333,,,333,333,333,333,333,333',
+',333,333,300,300,,,,333,,333,,300,300,300,300,,,,,,,,,,,,,,,,,,,,,300',
+',,300,300,300,300,300,300,,300,300,352,352,,,,300,,300,,352,352,352',
+'352,,,,,,,,,,,,,,,,,,,,352,352,,,352,352,352,352,352,352,,352,352,196',
+'196,,,,352,,352,,196,196,196,196,,,,,299,299,,,,,,,,299,299,299,299',
+',,196,196,,,196,196,196,196,196,196,,196,196,,,,,,196,,196,299,299,299',
+'299,299,299,,299,299,193,193,,,,299,,299,,193,193,193,193,,,,,,,,,,',
+',,,,,,,,,193,193,,,193,193,193,193,193,193,,193,193,332,332,,,,193,',
+'193,,332,332,332,332,,,,,,,,,,,,,,,,,,,,332,332,,,332,332,332,332,332',
+'332,,332,332,,,,,,332,,332,268,268,268,268,268,,268,268,268,268,268',
+',268,268,,,,,,268,268,268,180,180,180,180,180,,180,180,180,180,180,',
+'180,180,,268,268,,,180,180,180,61,61,61,61,61,,61,61,61,61,61,,61,61',
+',180,180,,,61,61,61,267,267,267,267,267,,267,267,267,267,267,,267,267',
+',61,61,,,267,267,267,82,82,82,82,82,,82,82,82,82,82,,82,82,,267,267',
+',,82,82,82,250,250,250,250,250,,250,250,250,250,250,,250,250,,82,82',
+',,250,250,250,,,,,,,,,,,,,,,,250,250' ]
+        racc_action_check = arr = ::Array.new(2588, nil)
+        idx = 0
+        clist.each do |str|
+          str.split(',', -1).each do |i|
+            arr[idx] = i.to_i unless i.empty?
+            idx += 1
+          end
+        end
+
+racc_action_pointer = [
+    -2,   490,    84,   nil,   nil,   507,   nil,   539,   nil,   517,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   485,
+   463,   447,   428,   417,   nil,   428,  1304,   425,     1,   146,
+   388,   nil,   nil,    84,   153,   nil,   675,   nil,   700,   725,
+   750,   395,   nil,   nil,   nil,   nil,   nil,   nil,   413,    42,
+   171,   231,   nil,   411,   nil,   402,   nil,   nil,   nil,   nil,
+   445,  2453,  1832,   950,   386,   nil,   368,   366,    66,   359,
+   nil,   345,   nil,   359,   nil,   339,   337,    -1,  1180,   330,
+   346,   299,  2497,   339,   140,   238,  1361,   337,   nil,   nil,
+   nil,   nil,  1381,  1428,  1438,  1448,   nil,    -2,   nil,   nil,
+  1505,  1515,  1562,  1572,   145,   561,   nil,   615,   507,  1649,
+   nil,   nil,   328,   297,   296,    -8,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,    11,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   307,   261,   nil,   nil,   297,
+   nil,   nil,   nil,    84,    93,   274,  1954,  1811,  1785,  1768,
+   315,   nil,   264,   257,   228,   242,   184,   nil,    -3,   178,
+   138,   133,   nil,   109,   nil,   102,   nil,    16,    20,   nil,
+  2431,   305,   nil,   nil,   nil,   194,    -8,   nil,   nil,   nil,
+   nil,    48,   303,  2324,  1999,   170,  2262,   nil,   nil,  1294,
+  1247,   228,   328,  1227,   650,  1160,  1113,  1022,   997,   900,
+   875,   850,   825,   800,   775,  1170,  1495,  1629,   nil,   nil,
+  2044,   272,   146,   nil,   nil,   472,   nil,   nil,   470,   127,
+  1721,   462,   nil,   nil,  1639,   471,   nil,   nil,   nil,   nil,
+   474,   467,   nil,   404,   376,   404,   266,   nil,   242,   369,
+  2519,  1314,  1371,   nil,    34,   400,  1582,   nil,   nil,    82,
+   nil,   265,    -2,   108,   112,  1659,   134,  2475,  2409,   172,
+   180,   nil,   226,   nil,   nil,   100,  1701,  1711,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   579,   256,   123,   180,
+   175,   341,   303,  1976,   486,  1886,   540,  1931,  1842,  2279,
+  2172,   nil,   nil,   nil,    66,  1096,   341,   360,   nil,   366,
+   160,  1032,   nil,     0,   nil,    84,   nil,   980,   nil,   384,
+   374,   388,   nil,   391,   399,   nil,   227,   427,   nil,   nil,
+   nil,   nil,  2369,  2127,   nil,  1864,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   409,   nil,     4,   nil,   nil,  2061,  2106,
+   nil,   nil,  2217,   nil,   -20,   nil,   925,   435,   nil,   nil,
+   442,   967,   445,  1050,   447,   nil,   449,   nil,   nil,   436,
+   433,  1237,   256,   nil,   nil,   nil,   468,   nil,   nil,   nil,
+   nil,   nil,   213,   170,   nil,   nil,   nil,   nil,   nil,   nil,
+  1909,    41,   nil,   nil,   482,   nil,   484,   nil,   nil,   nil,
+   nil ]
+
+racc_action_default = [
+  -206,  -241,    -1,    -2,    -3,    -6,    -7,    -8,    -9,   -10,
+   -11,   -12,   -13,   -14,   -15,   -16,   -17,   -18,   -19,   -20,
+  -241,   -39,   -41,   -42,   -43,   -45,   -97,  -241,  -178,  -241,
+   -74,   -96,   -98,  -221,  -239,  -124,  -241,  -129,  -241,  -241,
+  -241,  -241,  -177,  -181,  -182,  -183,  -185,  -186,  -241,  -241,
+  -198,  -241,  -229,  -241,    -4,  -241,   -46,   -47,   -48,   -49,
+  -241,  -119,  -241,  -241,   -53,   -54,   -58,   -59,   -60,   -61,
+   -62,   -63,   -64,   -65,   -66,   -67,   -68,   -97,  -241,  -239,
+  -221,  -109,  -109,   -77,  -206,  -206,  -241,  -241,   -73,  -197,
+  -198,   -75,  -241,  -241,  -241,  -241,  -125,  -241,  -141,  -142,
+  -241,  -241,  -241,  -241,  -241,  -241,  -134,  -241,  -241,  -241,
+  -187,  -188,  -190,  -206,  -206,  -206,  -199,  -201,  -202,  -203,
+  -204,  -205,   401,   -37,   -38,   -39,   -40,   -44,   -97,   -36,
+   -21,   -22,   -23,   -24,   -25,   -26,   -27,   -28,   -29,   -30,
+   -31,   -32,   -33,   -34,   -35,  -227,  -112,  -113,  -114,  -241,
+  -117,  -118,  -120,  -241,  -241,   -52,   -56,  -241,  -241,  -241,
+  -241,  -224,   -24,   -34,   -94,  -227,  -241,   -92,   -97,   -99,
+  -100,  -101,  -102,  -103,  -104,  -105,  -110,  -114,  -227,  -112,
+  -119,  -241,   -80,   -81,   -83,  -206,  -241,   -89,   -90,   -97,
+  -221,  -241,  -241,  -106,  -108,  -241,  -107,  -126,  -127,  -241,
+  -241,  -241,  -241,  -241,  -241,  -241,  -241,  -241,  -241,  -241,
+  -241,  -241,  -241,  -241,  -241,  -241,  -241,  -241,  -153,  -160,
+  -241,  -241,  -241,  -232,  -233,  -241,  -236,  -237,  -241,  -241,
+  -241,   -97,  -171,  -172,  -241,  -241,  -178,  -179,  -180,  -184,
+  -241,  -241,  -208,  -207,  -206,  -241,  -241,  -215,  -241,  -241,
+  -228,  -241,  -241,  -240,   -50,  -226,  -241,  -225,   -55,  -241,
+  -123,  -241,  -222,  -226,  -241,   -95,  -241,  -228,  -109,  -241,
+  -227,   -78,  -241,   -85,   -86,  -241,  -241,  -241,   -79,  -131,
+  -226,  -238,  -128,  -143,  -144,  -145,  -146,  -147,  -148,  -149,
+  -150,  -151,  -152,  -154,  -155,  -156,  -157,  -158,  -159,  -161,
+  -162,  -163,  -222,  -230,  -241,  -241,    -5,  -241,  -133,  -241,
+  -137,  -241,  -165,  -241,  -169,  -227,  -174,  -241,  -189,  -241,
+  -241,  -227,  -211,  -214,  -241,  -217,  -241,  -241,  -200,  -216,
+   -72,  -121,  -116,  -115,   -51,   -57,  -122,  -130,  -223,   -69,
+   -93,   -70,  -111,  -227,   -71,  -241,   -82,   -84,   -87,   -88,
+  -231,  -234,  -235,  -132,  -137,  -136,  -241,  -241,  -164,  -166,
+  -241,  -241,  -241,  -241,  -226,  -176,  -241,  -192,  -209,  -241,
+  -228,  -241,  -241,  -218,  -219,  -220,  -241,  -196,   -91,   -76,
+  -135,  -138,  -241,  -241,  -170,  -173,  -175,  -191,  -210,  -212,
+  -213,  -241,  -194,  -195,  -241,  -140,  -241,  -168,  -193,  -139,
+  -167 ]
+
+racc_goto_table = [
+    28,     2,    28,    42,   224,    42,    54,    65,   106,   233,
+   113,   114,   235,   121,   116,    44,   174,    44,    43,   111,
+    43,   249,   167,    96,   307,   309,     3,   322,   145,    87,
+    25,    88,    25,   165,   178,   176,   176,    83,   312,   355,
+   123,   266,   181,   191,   311,   129,   127,   331,   126,   154,
+    24,   127,    24,   126,   269,    28,   346,   124,    42,   232,
+    28,   197,   124,    42,   160,    55,    60,   241,   244,   315,
+    44,   264,   192,    43,   112,    44,   164,   324,    43,   115,
+   245,   171,   363,   380,   170,    25,   329,   188,   188,   221,
+    25,   320,   321,    64,   373,   222,    44,     1,   nil,    43,
+   nil,   nil,   nil,   nil,   nil,    24,   nil,   nil,   nil,   236,
+    24,   175,    42,   nil,   nil,   366,   nil,   nil,    34,   359,
+    34,   nil,   nil,   376,    44,   nil,   nil,    43,   nil,   nil,
+   nil,   172,   nil,   314,   316,   nil,   nil,   235,   258,   242,
+   242,   247,   nil,   275,   259,   261,   345,   270,   nil,   nil,
+   nil,   nil,   nil,   nil,   389,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   284,   285,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   394,   396,
+   nil,   nil,   nil,   nil,   nil,   nil,   282,   nil,   188,   nil,
+   nil,   362,   nil,   nil,   nil,   nil,   nil,   369,   nil,   nil,
+   174,   nil,   nil,   nil,   351,   nil,   340,   nil,   121,   328,
+   121,   318,   nil,   nil,   314,   nil,   nil,   nil,   nil,   378,
+   343,   342,   176,   nil,   nil,   nil,   nil,   239,    28,    28,
+   236,    42,    42,    42,   236,   nil,   nil,    42,   nil,   nil,
+   nil,   nil,   nil,    44,    44,    44,    43,    43,    43,    44,
+   nil,   nil,    43,   nil,   nil,   nil,   nil,   nil,    25,    25,
+   nil,   nil,   nil,   386,   384,   171,   235,   nil,   170,   nil,
+   325,   nil,   nil,   nil,   nil,   188,   nil,   nil,    24,    24,
+    44,   nil,   nil,    43,    23,   nil,    23,   374,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   175,   nil,   nil,   365,    45,
+   nil,    45,   nil,   nil,   nil,   nil,    28,   nil,   nil,    42,
+    54,   236,   nil,   nil,    42,   172,   nil,   nil,   nil,    28,
+   nil,    44,    42,   nil,    43,   381,    44,    28,   nil,    43,
+    42,   nil,   nil,   nil,    44,   nil,    25,    43,   nil,    23,
+   nil,   nil,    44,   nil,    23,    43,    34,    34,   239,    25,
+   nil,   nil,   239,   nil,    45,   nil,    24,    25,   nil,    45,
+   nil,   236,   nil,   236,    42,   169,    42,   nil,    22,    24,
+    22,   nil,    28,   391,   nil,    42,    44,    24,    44,    43,
+    45,    43,    28,    28,   nil,    42,    42,    44,   227,   nil,
+    43,    28,   nil,   237,    42,    54,   nil,    44,    44,   nil,
+    43,    43,    25,    21,   nil,    21,    44,   nil,    45,    43,
+   nil,   nil,    25,    25,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,    25,    24,    22,    34,   nil,   nil,   nil,    22,   239,
+   nil,   nil,    24,    24,   nil,   nil,   nil,    34,   nil,   nil,
+   nil,    24,   nil,   nil,   nil,    34,   nil,   nil,   nil,   173,
+   nil,   nil,   187,   187,   nil,   nil,   nil,   nil,   125,   nil,
+   nil,   nil,   nil,   125,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   238,   nil,   239,
+   nil,   239,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+    34,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+    34,    34,   nil,   nil,   nil,   nil,   nil,   nil,   nil,    34,
+   nil,   nil,    23,    23,   237,   nil,   nil,   nil,   237,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,    45,    45,    45,
+   nil,   nil,   nil,    45,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   169,
+   nil,   nil,   nil,   187,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,    45,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   227,   nil,
+    23,   nil,   nil,   nil,   nil,   237,    22,    22,   238,   nil,
+   nil,   nil,   238,    23,   nil,    45,   nil,   nil,   nil,   nil,
+    45,    23,   nil,   nil,   nil,   nil,   nil,   nil,    45,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,    45,   nil,   nil,   nil,
+   nil,    21,    21,   173,   nil,    97,   nil,   105,   107,   108,
+   187,   nil,   nil,   nil,   nil,   237,   nil,   237,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,    23,   nil,   nil,   nil,
+    45,   153,    45,   nil,   nil,   nil,    23,    23,   nil,   nil,
+   nil,    45,   nil,   nil,    22,    23,   nil,   nil,   nil,   238,
+   nil,    45,    45,   nil,   nil,   nil,   nil,    22,   nil,   nil,
+    45,   193,   194,   195,   196,    22,   nil,   nil,   nil,   218,
+   219,   220,   nil,   nil,   nil,   nil,   nil,   nil,   nil,    21,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,    21,   nil,   nil,   nil,   nil,   nil,   nil,   238,
+    21,   238,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+    22,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+    22,    22,   nil,   nil,   nil,   nil,   nil,   nil,   nil,    22,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,    21,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,    21,    21,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,    21,   nil,   nil,   nil,    97,   283,
+   nil,   nil,   286,   287,   288,   289,   290,   291,   292,   293,
+   294,   295,   296,   297,   298,   299,   300,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   332,   333,   nil,   nil,   nil,   335,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   348,   349,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   352,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   107,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   390 ]
+
+racc_goto_check = [
+    35,     2,    35,    34,    86,    34,     4,    31,    62,    71,
+    40,    40,    69,    65,    79,    36,    37,    36,    38,    73,
+    38,    44,    53,    60,     5,     5,     3,    83,    45,    35,
+    28,     6,    28,    43,    43,    56,    56,    47,    67,    63,
+    22,    44,    48,    48,    66,    22,    10,    59,     8,    29,
+    27,    10,    27,     8,    44,    35,    49,     6,    34,    70,
+    35,    61,     6,    34,    29,    23,    23,    75,    75,    72,
+    36,    42,    29,    38,    74,    36,    41,    76,    38,    77,
+    78,    35,    33,    63,    34,    28,    80,    34,    34,    29,
+    28,    81,    82,    30,    84,    85,    36,     1,   nil,    38,
+   nil,   nil,   nil,   nil,   nil,    27,   nil,   nil,   nil,    35,
+    27,    28,    34,   nil,   nil,     5,   nil,   nil,    55,    67,
+    55,   nil,   nil,     5,    36,   nil,   nil,    38,   nil,   nil,
+   nil,    27,   nil,    69,    71,   nil,   nil,    69,    31,     3,
+     3,     3,   nil,    48,    29,    29,    44,    45,   nil,   nil,
+   nil,   nil,   nil,   nil,    83,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,    65,    65,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,     5,     5,
+   nil,   nil,   nil,   nil,   nil,   nil,    60,   nil,    34,   nil,
+   nil,    44,   nil,   nil,   nil,   nil,   nil,    44,   nil,   nil,
+    37,   nil,   nil,   nil,    86,   nil,    53,   nil,    65,    79,
+    65,    73,   nil,   nil,    69,   nil,   nil,   nil,   nil,    44,
+    43,    56,    56,   nil,   nil,   nil,   nil,    55,    35,    35,
+    35,    34,    34,    34,    35,   nil,   nil,    34,   nil,   nil,
+   nil,   nil,   nil,    36,    36,    36,    38,    38,    38,    36,
+   nil,   nil,    38,   nil,   nil,   nil,   nil,   nil,    28,    28,
+   nil,   nil,   nil,    71,    69,    35,    69,   nil,    34,   nil,
+     3,   nil,   nil,   nil,   nil,    34,   nil,   nil,    27,    27,
+    36,   nil,   nil,    38,    26,   nil,    26,    40,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,    28,   nil,   nil,    31,    39,
+   nil,    39,   nil,   nil,   nil,   nil,    35,   nil,   nil,    34,
+     4,    35,   nil,   nil,    34,    27,   nil,   nil,   nil,    35,
+   nil,    36,    34,   nil,    38,    62,    36,    35,   nil,    38,
+    34,   nil,   nil,   nil,    36,   nil,    28,    38,   nil,    26,
+   nil,   nil,    36,   nil,    26,    38,    55,    55,    55,    28,
+   nil,   nil,    55,   nil,    39,   nil,    27,    28,   nil,    39,
+   nil,    35,   nil,    35,    34,    26,    34,   nil,    25,    27,
+    25,   nil,    35,     2,   nil,    34,    36,    27,    36,    38,
+    39,    38,    35,    35,   nil,    34,    34,    36,    26,   nil,
+    38,    35,   nil,    26,    34,     4,   nil,    36,    36,   nil,
+    38,    38,    28,    24,   nil,    24,    36,   nil,    39,    38,
+   nil,   nil,    28,    28,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,    28,    27,    25,    55,   nil,   nil,   nil,    25,    55,
+   nil,   nil,    27,    27,   nil,   nil,   nil,    55,   nil,   nil,
+   nil,    27,   nil,   nil,   nil,    55,   nil,   nil,   nil,    25,
+   nil,   nil,    25,    25,   nil,   nil,   nil,   nil,    24,   nil,
+   nil,   nil,   nil,    24,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,    25,   nil,    55,
+   nil,    55,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+    55,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+    55,    55,   nil,   nil,   nil,   nil,   nil,   nil,   nil,    55,
+   nil,   nil,    26,    26,    26,   nil,   nil,   nil,    26,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,    39,    39,    39,
+   nil,   nil,   nil,    39,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,    26,
+   nil,   nil,   nil,    25,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,    39,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,    26,   nil,
+    26,   nil,   nil,   nil,   nil,    26,    25,    25,    25,   nil,
+   nil,   nil,    25,    26,   nil,    39,   nil,   nil,   nil,   nil,
+    39,    26,   nil,   nil,   nil,   nil,   nil,   nil,    39,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,    39,   nil,   nil,   nil,
+   nil,    24,    24,    25,   nil,    32,   nil,    32,    32,    32,
+    25,   nil,   nil,   nil,   nil,    26,   nil,    26,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,    26,   nil,   nil,   nil,
+    39,    32,    39,   nil,   nil,   nil,    26,    26,   nil,   nil,
+   nil,    39,   nil,   nil,    25,    26,   nil,   nil,   nil,    25,
+   nil,    39,    39,   nil,   nil,   nil,   nil,    25,   nil,   nil,
+    39,    32,    32,    32,    32,    25,   nil,   nil,   nil,    32,
+    32,    32,   nil,   nil,   nil,   nil,   nil,   nil,   nil,    24,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,    24,   nil,   nil,   nil,   nil,   nil,   nil,    25,
+    24,    25,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+    25,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+    25,    25,   nil,   nil,   nil,   nil,   nil,   nil,   nil,    25,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,    24,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,    24,    24,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,    24,   nil,   nil,   nil,    32,    32,
+   nil,   nil,    32,    32,    32,    32,    32,    32,    32,    32,
+    32,    32,    32,    32,    32,    32,    32,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+    32,    32,   nil,   nil,   nil,    32,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,    32,    32,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,    32,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,    32,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+    32 ]
+
+racc_goto_pointer = [
+   nil,    97,     1,    26,     4,  -204,     2,   nil,    -7,   nil,
+    -9,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   -15,    46,   403,   368,   284,    50,    30,   -14,
+    67,   -19,   599,  -233,     3,     0,    15,   -65,    18,   299,
+   -39,    -5,   -93,   -48,  -124,   -33,   nil,     9,   -42,  -216,
+   nil,   nil,   nil,   -59,   nil,   118,   -46,   nil,   nil,  -203,
+   -13,   -36,   -31,  -271,   nil,   -38,  -186,  -192,   nil,   -97,
+   -50,  -100,  -165,   -29,    26,   -46,  -167,    28,   -35,   -37,
+  -162,  -152,  -151,  -216,  -232,    -9,  -100,   nil ]
+
+racc_goto_default = [
+   nil,   nil,   306,   182,     4,   nil,     5,     6,     7,     8,
+     9,    10,    11,    12,    13,    14,    15,    16,    17,    18,
+    19,   147,    20,   nil,    74,    71,    66,    70,    73,   nil,
+   nil,    98,   156,   256,    67,    68,    69,    72,    75,    76,
+    27,   nil,   nil,   nil,   nil,   nil,    29,   nil,   nil,   183,
+   272,   184,   186,   nil,   166,    79,   150,   149,   151,   152,
+   nil,   nil,   nil,   nil,    99,    47,   nil,   nil,   313,    41,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   117,   nil,   nil,   nil,   nil,   nil,   nil,   225 ]
+
+racc_reduce_table = [
+  0, 0, :racc_error,
+  1, 71, :_reduce_none,
+  1, 71, :_reduce_none,
+  1, 72, :_reduce_3,
+  2, 72, :_reduce_4,
+  1, 75, :_reduce_5,
+  1, 74, :_reduce_none,
+  1, 74, :_reduce_none,
+  1, 74, :_reduce_none,
+  1, 74, :_reduce_none,
+  1, 74, :_reduce_none,
+  1, 74, :_reduce_none,
+  1, 74, :_reduce_none,
+  1, 74, :_reduce_none,
+  1, 74, :_reduce_none,
+  1, 74, :_reduce_none,
+  1, 74, :_reduce_none,
+  1, 74, :_reduce_none,
+  1, 74, :_reduce_none,
+  1, 74, :_reduce_none,
+  1, 74, :_reduce_none,
+  1, 91, :_reduce_none,
+  1, 91, :_reduce_none,
+  1, 91, :_reduce_none,
+  1, 91, :_reduce_none,
+  1, 91, :_reduce_none,
+  1, 91, :_reduce_none,
+  1, 91, :_reduce_none,
+  1, 91, :_reduce_none,
+  1, 91, :_reduce_none,
+  1, 91, :_reduce_none,
+  1, 91, :_reduce_none,
+  1, 91, :_reduce_none,
+  1, 91, :_reduce_none,
+  1, 91, :_reduce_none,
+  1, 91, :_reduce_none,
+  3, 90, :_reduce_36,
+  3, 90, :_reduce_37,
+  1, 92, :_reduce_none,
+  1, 92, :_reduce_none,
+  1, 92, :_reduce_none,
+  1, 92, :_reduce_none,
+  1, 92, :_reduce_none,
+  1, 92, :_reduce_none,
+  1, 92, :_reduce_none,
+  1, 92, :_reduce_none,
+  1, 93, :_reduce_none,
+  1, 93, :_reduce_none,
+  1, 93, :_reduce_none,
+  1, 93, :_reduce_none,
+  4, 84, :_reduce_50,
+  5, 84, :_reduce_51,
+  3, 84, :_reduce_52,
+  2, 84, :_reduce_53,
+  1, 100, :_reduce_54,
+  3, 100, :_reduce_55,
+  1, 99, :_reduce_56,
+  3, 99, :_reduce_57,
+  1, 101, :_reduce_none,
+  1, 101, :_reduce_none,
+  1, 101, :_reduce_none,
+  1, 101, :_reduce_none,
+  1, 101, :_reduce_none,
+  1, 101, :_reduce_none,
+  1, 101, :_reduce_none,
+  1, 101, :_reduce_none,
+  1, 101, :_reduce_none,
+  1, 101, :_reduce_none,
+  1, 101, :_reduce_none,
+  5, 76, :_reduce_69,
+  5, 76, :_reduce_70,
+  5, 76, :_reduce_71,
+  5, 88, :_reduce_72,
+  2, 77, :_reduce_73,
+  1, 116, :_reduce_74,
+  2, 116, :_reduce_75,
+  6, 78, :_reduce_76,
+  2, 78, :_reduce_77,
+  3, 117, :_reduce_78,
+  3, 117, :_reduce_79,
+  1, 118, :_reduce_none,
+  1, 118, :_reduce_none,
+  3, 118, :_reduce_82,
+  1, 119, :_reduce_none,
+  3, 119, :_reduce_84,
+  1, 120, :_reduce_85,
+  1, 120, :_reduce_86,
+  3, 121, :_reduce_87,
+  3, 121, :_reduce_88,
+  1, 122, :_reduce_none,
+  1, 122, :_reduce_none,
+  4, 123, :_reduce_91,
+  1, 111, :_reduce_92,
+  3, 111, :_reduce_93,
+  0, 112, :_reduce_none,
+  1, 112, :_reduce_none,
+  1, 109, :_reduce_96,
+  1, 104, :_reduce_97,
+  1, 105, :_reduce_98,
+  1, 124, :_reduce_none,
+  1, 124, :_reduce_none,
+  1, 124, :_reduce_none,
+  1, 124, :_reduce_none,
+  1, 124, :_reduce_none,
+  1, 124, :_reduce_none,
+  1, 124, :_reduce_none,
+  3, 79, :_reduce_106,
+  3, 79, :_reduce_107,
+  3, 89, :_reduce_108,
+  0, 113, :_reduce_109,
+  1, 113, :_reduce_110,
+  3, 113, :_reduce_111,
+  1, 127, :_reduce_none,
+  1, 127, :_reduce_none,
+  1, 127, :_reduce_none,
+  3, 126, :_reduce_115,
+  3, 128, :_reduce_116,
+  1, 129, :_reduce_none,
+  1, 129, :_reduce_none,
+  0, 115, :_reduce_119,
+  1, 115, :_reduce_120,
+  3, 115, :_reduce_121,
+  4, 108, :_reduce_122,
+  3, 108, :_reduce_123,
+  1, 96, :_reduce_124,
+  2, 96, :_reduce_125,
+  2, 130, :_reduce_126,
+  1, 131, :_reduce_127,
+  2, 131, :_reduce_128,
+  1, 106, :_reduce_129,
+  4, 94, :_reduce_130,
+  4, 94, :_reduce_131,
+  5, 82, :_reduce_132,
+  4, 82, :_reduce_133,
+  2, 81, :_reduce_134,
+  5, 132, :_reduce_135,
+  4, 132, :_reduce_136,
+  0, 133, :_reduce_none,
+  2, 133, :_reduce_138,
+  4, 133, :_reduce_139,
+  3, 133, :_reduce_140,
+  1, 102, :_reduce_none,
+  1, 102, :_reduce_none,
+  3, 102, :_reduce_143,
+  3, 102, :_reduce_144,
+  3, 102, :_reduce_145,
+  3, 102, :_reduce_146,
+  3, 102, :_reduce_147,
+  3, 102, :_reduce_148,
+  3, 102, :_reduce_149,
+  3, 102, :_reduce_150,
+  3, 102, :_reduce_151,
+  3, 102, :_reduce_152,
+  2, 102, :_reduce_153,
+  3, 102, :_reduce_154,
+  3, 102, :_reduce_155,
+  3, 102, :_reduce_156,
+  3, 102, :_reduce_157,
+  3, 102, :_reduce_158,
+  3, 102, :_reduce_159,
+  2, 102, :_reduce_160,
+  3, 102, :_reduce_161,
+  3, 102, :_reduce_162,
+  3, 102, :_reduce_163,
+  5, 80, :_reduce_164,
+  1, 136, :_reduce_165,
+  2, 136, :_reduce_166,
+  5, 137, :_reduce_167,
+  4, 137, :_reduce_168,
+  1, 138, :_reduce_169,
+  3, 138, :_reduce_170,
+  3, 97, :_reduce_171,
+  1, 140, :_reduce_none,
+  4, 140, :_reduce_173,
+  1, 142, :_reduce_none,
+  3, 142, :_reduce_175,
+  3, 141, :_reduce_176,
+  1, 139, :_reduce_none,
+  1, 139, :_reduce_none,
+  1, 139, :_reduce_none,
+  1, 139, :_reduce_none,
+  1, 139, :_reduce_none,
+  1, 139, :_reduce_none,
+  1, 139, :_reduce_none,
+  1, 139, :_reduce_none,
+  1, 139, :_reduce_185,
+  1, 139, :_reduce_none,
+  1, 143, :_reduce_187,
+  1, 144, :_reduce_none,
+  3, 144, :_reduce_189,
+  2, 83, :_reduce_190,
+  6, 85, :_reduce_191,
+  5, 85, :_reduce_192,
+  7, 86, :_reduce_193,
+  6, 86, :_reduce_194,
+  6, 87, :_reduce_195,
+  5, 87, :_reduce_196,
+  1, 110, :_reduce_197,
+  1, 110, :_reduce_198,
+  1, 147, :_reduce_199,
+  3, 147, :_reduce_200,
+  1, 149, :_reduce_201,
+  1, 150, :_reduce_202,
+  1, 150, :_reduce_203,
+  1, 150, :_reduce_204,
+  1, 150, :_reduce_none,
+  0, 73, :_reduce_206,
+  0, 151, :_reduce_207,
+  1, 145, :_reduce_none,
+  3, 145, :_reduce_209,
+  4, 145, :_reduce_210,
+  1, 152, :_reduce_none,
+  3, 152, :_reduce_212,
+  3, 153, :_reduce_213,
+  1, 153, :_reduce_214,
+  1, 148, :_reduce_none,
+  2, 148, :_reduce_216,
+  1, 146, :_reduce_none,
+  2, 146, :_reduce_218,
+  1, 154, :_reduce_none,
+  1, 154, :_reduce_none,
+  1, 95, :_reduce_221,
+  3, 107, :_reduce_222,
+  4, 107, :_reduce_223,
+  2, 107, :_reduce_224,
+  1, 103, :_reduce_none,
+  1, 103, :_reduce_none,
+  0, 114, :_reduce_none,
+  1, 114, :_reduce_228,
+  1, 135, :_reduce_229,
+  3, 134, :_reduce_230,
+  4, 134, :_reduce_231,
+  2, 134, :_reduce_232,
+  1, 155, :_reduce_none,
+  3, 155, :_reduce_234,
+  3, 156, :_reduce_235,
+  1, 157, :_reduce_236,
+  1, 157, :_reduce_237,
+  4, 125, :_reduce_238,
+  1, 98, :_reduce_none,
+  4, 98, :_reduce_240 ]
+
+racc_reduce_n = 241
+
+racc_shift_n = 401
+
+racc_token_table = {
+  false => 0,
+  :error => 1,
+  :STRING => 2,
+  :DQPRE => 3,
+  :DQMID => 4,
+  :DQPOST => 5,
+  :LBRACK => 6,
+  :RBRACK => 7,
+  :LBRACE => 8,
+  :RBRACE => 9,
+  :SYMBOL => 10,
+  :FARROW => 11,
+  :COMMA => 12,
+  :TRUE => 13,
+  :FALSE => 14,
+  :EQUALS => 15,
+  :APPENDS => 16,
+  :LESSEQUAL => 17,
+  :NOTEQUAL => 18,
+  :DOT => 19,
+  :COLON => 20,
+  :LLCOLLECT => 21,
+  :RRCOLLECT => 22,
+  :QMARK => 23,
+  :LPAREN => 24,
+  :RPAREN => 25,
+  :ISEQUAL => 26,
+  :GREATEREQUAL => 27,
+  :GREATERTHAN => 28,
+  :LESSTHAN => 29,
+  :IF => 30,
+  :ELSE => 31,
+  :IMPORT => 32,
+  :DEFINE => 33,
+  :ELSIF => 34,
+  :VARIABLE => 35,
+  :CLASS => 36,
+  :INHERITS => 37,
+  :NODE => 38,
+  :BOOLEAN => 39,
+  :NAME => 40,
+  :SEMIC => 41,
+  :CASE => 42,
+  :DEFAULT => 43,
+  :AT => 44,
+  :LCOLLECT => 45,
+  :RCOLLECT => 46,
+  :CLASSREF => 47,
+  :NOT => 48,
+  :OR => 49,
+  :AND => 50,
+  :UNDEF => 51,
+  :PARROW => 52,
+  :PLUS => 53,
+  :MINUS => 54,
+  :TIMES => 55,
+  :DIV => 56,
+  :LSHIFT => 57,
+  :RSHIFT => 58,
+  :UMINUS => 59,
+  :MATCH => 60,
+  :NOMATCH => 61,
+  :REGEX => 62,
+  :IN_EDGE => 63,
+  :OUT_EDGE => 64,
+  :IN_EDGE_SUB => 65,
+  :OUT_EDGE_SUB => 66,
+  :IN => 67,
+  :UNLESS => 68,
+  :MODULO => 69 }
+
+racc_nt_base = 70
+
+racc_use_result_var = true
+
+Racc_arg = [
+  racc_action_table,
+  racc_action_check,
+  racc_action_default,
+  racc_action_pointer,
+  racc_goto_table,
+  racc_goto_check,
+  racc_goto_default,
+  racc_goto_pointer,
+  racc_nt_base,
+  racc_reduce_table,
+  racc_token_table,
+  racc_shift_n,
+  racc_reduce_n,
+  racc_use_result_var ]
+
+Racc_token_to_s_table = [
+  "$end",
+  "error",
+  "STRING",
+  "DQPRE",
+  "DQMID",
+  "DQPOST",
+  "LBRACK",
+  "RBRACK",
+  "LBRACE",
+  "RBRACE",
+  "SYMBOL",
+  "FARROW",
+  "COMMA",
+  "TRUE",
+  "FALSE",
+  "EQUALS",
+  "APPENDS",
+  "LESSEQUAL",
+  "NOTEQUAL",
+  "DOT",
+  "COLON",
+  "LLCOLLECT",
+  "RRCOLLECT",
+  "QMARK",
+  "LPAREN",
+  "RPAREN",
+  "ISEQUAL",
+  "GREATEREQUAL",
+  "GREATERTHAN",
+  "LESSTHAN",
+  "IF",
+  "ELSE",
+  "IMPORT",
+  "DEFINE",
+  "ELSIF",
+  "VARIABLE",
+  "CLASS",
+  "INHERITS",
+  "NODE",
+  "BOOLEAN",
+  "NAME",
+  "SEMIC",
+  "CASE",
+  "DEFAULT",
+  "AT",
+  "LCOLLECT",
+  "RCOLLECT",
+  "CLASSREF",
+  "NOT",
+  "OR",
+  "AND",
+  "UNDEF",
+  "PARROW",
+  "PLUS",
+  "MINUS",
+  "TIMES",
+  "DIV",
+  "LSHIFT",
+  "RSHIFT",
+  "UMINUS",
+  "MATCH",
+  "NOMATCH",
+  "REGEX",
+  "IN_EDGE",
+  "OUT_EDGE",
+  "IN_EDGE_SUB",
+  "OUT_EDGE_SUB",
+  "IN",
+  "UNLESS",
+  "MODULO",
+  "$start",
+  "program",
+  "statements_and_declarations",
+  "nil",
+  "statement_or_declaration",
+  "statements",
+  "resource",
+  "virtualresource",
+  "collection",
+  "assignment",
+  "casestatement",
+  "ifstatement_begin",
+  "unlessstatement",
+  "import",
+  "fstatement",
+  "definition",
+  "hostclass",
+  "nodedef",
+  "resourceoverride",
+  "append",
+  "relationship",
+  "keyword",
+  "relationship_side",
+  "edge",
+  "resourceref",
+  "variable",
+  "quotedtext",
+  "selector",
+  "hasharrayaccesses",
+  "expressions",
+  "funcvalues",
+  "rvalue",
+  "expression",
+  "comma",
+  "name",
+  "type",
+  "boolean",
+  "array",
+  "funcrvalue",
+  "undef",
+  "classname",
+  "resourceinstances",
+  "endsemi",
+  "params",
+  "endcomma",
+  "anyparams",
+  "at",
+  "collectrhand",
+  "collstatements",
+  "collstatement",
+  "colljoin",
+  "collexpr",
+  "colllval",
+  "resourceinst",
+  "resourcename",
+  "hasharrayaccess",
+  "param",
+  "param_name",
+  "addparam",
+  "anyparam",
+  "dqrval",
+  "dqtail",
+  "ifstatement",
+  "else",
+  "hash",
+  "regex",
+  "caseopts",
+  "caseopt",
+  "casevalues",
+  "selectlhand",
+  "svalues",
+  "selectval",
+  "sintvalues",
+  "string",
+  "strings",
+  "argumentlist",
+  "classparent",
+  "hostnames",
+  "nodeparent",
+  "nodename",
+  "hostname",
+  "nothing",
+  "arguments",
+  "argument",
+  "classnameordefault",
+  "hashpairs",
+  "hashpair",
+  "key" ]
+
+Racc_debug_parser = false
+
+##### State transition tables end #####
+
+# reduce 0 omitted
+
+# reduce 1 omitted
+
+# reduce 2 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 34)
+  def _reduce_3(val, _values, result)
+        result = ast AST::BlockExpression, :children => (val[0] ? [val[0]] : [])
+  
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 37)
+  def _reduce_4(val, _values, result)
+        if val[1]
+      val[0].push(val[1])
+    end
+    result = val[0]
+  
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 46)
+  def _reduce_5(val, _values, result)
+      val[0].each do |stmt|
+    if stmt.is_a?(AST::TopLevelConstruct)
+      error "Classes, definitions, and nodes may only appear at toplevel or inside other classes", \
+          :line => stmt.context[:line], :file => stmt.context[:file]
+    end
+  end
+  result = val[0]
+
+    result
+  end
+.,.,
+
+# reduce 6 omitted
+
+# reduce 7 omitted
+
+# reduce 8 omitted
+
+# reduce 9 omitted
+
+# reduce 10 omitted
+
+# reduce 11 omitted
+
+# reduce 12 omitted
+
+# reduce 13 omitted
+
+# reduce 14 omitted
+
+# reduce 15 omitted
+
+# reduce 16 omitted
+
+# reduce 17 omitted
+
+# reduce 18 omitted
+
+# reduce 19 omitted
+
+# reduce 20 omitted
+
+# reduce 21 omitted
+
+# reduce 22 omitted
+
+# reduce 23 omitted
+
+# reduce 24 omitted
+
+# reduce 25 omitted
+
+# reduce 26 omitted
+
+# reduce 27 omitted
+
+# reduce 28 omitted
+
+# reduce 29 omitted
+
+# reduce 30 omitted
+
+# reduce 31 omitted
+
+# reduce 32 omitted
+
+# reduce 33 omitted
+
+# reduce 34 omitted
+
+# reduce 35 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 89)
+  def _reduce_36(val, _values, result)
+      result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context)
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 92)
+  def _reduce_37(val, _values, result)
+        result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context)
+
+    result
+  end
+.,.,
+
+# reduce 38 omitted
+
+# reduce 39 omitted
+
+# reduce 40 omitted
+
+# reduce 41 omitted
+
+# reduce 42 omitted
+
+# reduce 43 omitted
+
+# reduce 44 omitted
+
+# reduce 45 omitted
+
+# reduce 46 omitted
+
+# reduce 47 omitted
+
+# reduce 48 omitted
+
+# reduce 49 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 107)
+  def _reduce_50(val, _values, result)
+      result = ast AST::Function,
+    :name => val[0][:value],
+    :line => val[0][:line],
+    :arguments => val[2],
+    :ftype => :statement
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 114)
+  def _reduce_51(val, _values, result)
+      result = ast AST::Function,
+    :name => val[0][:value],
+    :line => val[0][:line],
+    :arguments => val[2],
+    :ftype => :statement
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 120)
+  def _reduce_52(val, _values, result)
+      result = ast AST::Function,
+    :name => val[0][:value],
+    :line => val[0][:line],
+    :arguments => AST::ASTArray.new({}),
+    :ftype => :statement
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 127)
+  def _reduce_53(val, _values, result)
+        result = ast AST::Function,
+    :name => val[0][:value],
+    :line => val[0][:line],
+    :arguments => val[1],
+    :ftype => :statement
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 134)
+  def _reduce_54(val, _values, result)
+     result = aryfy(val[0]) 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 137)
+  def _reduce_55(val, _values, result)
+        val[0].push(val[2])
+    result = val[0]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 141)
+  def _reduce_56(val, _values, result)
+     result = aryfy(val[0]) 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 142)
+  def _reduce_57(val, _values, result)
+     result = val[0].push(val[2]) 
+    result
+  end
+.,.,
+
+# reduce 58 omitted
+
+# reduce 59 omitted
+
+# reduce 60 omitted
+
+# reduce 61 omitted
+
+# reduce 62 omitted
+
+# reduce 63 omitted
+
+# reduce 64 omitted
+
+# reduce 65 omitted
+
+# reduce 66 omitted
+
+# reduce 67 omitted
+
+# reduce 68 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 157)
+  def _reduce_69(val, _values, result)
+      @lexer.commentpop
+  result = ast(AST::Resource, :type => val[0], :instances => val[2])
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 160)
+  def _reduce_70(val, _values, result)
+      # This is a deprecated syntax.
+  error "All resource specifications require names"
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 163)
+  def _reduce_71(val, _values, result)
+      # a defaults setting for a type
+  @lexer.commentpop
+  result = ast(AST::ResourceDefaults, :type => val[0].value, :parameters => val[2])
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 170)
+  def _reduce_72(val, _values, result)
+      @lexer.commentpop
+  result = ast AST::ResourceOverride, :object => val[0], :parameters => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 177)
+  def _reduce_73(val, _values, result)
+      type = val[0]
+
+  if (type == :exported and ! Puppet[:storeconfigs])
+    Puppet.warning addcontext("You cannot collect without storeconfigs being set")
+  end
+
+  error "Defaults are not virtualizable" if val[1].is_a? AST::ResourceDefaults
+
+  method = type.to_s + "="
+
+  # Just mark our resource as exported and pass it through.
+  val[1].send(method, true)
+
+  result = val[1]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 193)
+  def _reduce_74(val, _values, result)
+     result = :virtual 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 194)
+  def _reduce_75(val, _values, result)
+     result = :exported 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 199)
+  def _reduce_76(val, _values, result)
+      @lexer.commentpop
+  type = val[0].value.downcase
+  args = {:type => type}
+
+  if val[1].is_a?(AST::CollExpr)
+    args[:query] = val[1]
+    args[:query].type = type
+    args[:form] = args[:query].form
+  else
+    args[:form] = val[1]
+  end
+  if args[:form] == :exported and ! Puppet[:storeconfigs]
+    Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored")
+  end
+  args[:override] = val[3]
+  result = ast AST::Collection, args
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 217)
+  def _reduce_77(val, _values, result)
+      type = val[0].value.downcase
+  args = {:type => type }
+
+  if val[1].is_a?(AST::CollExpr)
+    args[:query] = val[1]
+    args[:query].type = type
+    args[:form] = args[:query].form
+  else
+    args[:form] = val[1]
+  end
+  if args[:form] == :exported and ! Puppet[:storeconfigs]
+    Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored")
+  end
+  result = ast AST::Collection, args
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 235)
+  def _reduce_78(val, _values, result)
+      if val[1]
+    result = val[1]
+    result.form = :virtual
+  else
+    result = :virtual
+  end
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 243)
+  def _reduce_79(val, _values, result)
+        if val[1]
+    result = val[1]
+    result.form = :exported
+  else
+    result = :exported
+  end
+
+    result
+  end
+.,.,
+
+# reduce 80 omitted
+
+# reduce 81 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 256)
+  def _reduce_82(val, _values, result)
+        result = ast AST::CollExpr, :test1 => val[0], :oper => val[1], :test2 => val[2]
+
+    result
+  end
+.,.,
+
+# reduce 83 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 261)
+  def _reduce_84(val, _values, result)
+        result = val[1]
+    result.parens = true
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 265)
+  def _reduce_85(val, _values, result)
+     result=val[0][:value] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 266)
+  def _reduce_86(val, _values, result)
+     result=val[0][:value] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 269)
+  def _reduce_87(val, _values, result)
+      result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2]
+  #result = ast AST::CollExpr
+  #result.push *val
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 274)
+  def _reduce_88(val, _values, result)
+        result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2]
+    #result = ast AST::CollExpr
+    #result.push *val
+
+    result
+  end
+.,.,
+
+# reduce 89 omitted
+
+# reduce 90 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 283)
+  def _reduce_91(val, _values, result)
+      result = ast AST::ResourceInstance, :title => val[0], :parameters => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 286)
+  def _reduce_92(val, _values, result)
+     result = aryfy(val[0]) 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 288)
+  def _reduce_93(val, _values, result)
+        val[0].push val[2]
+    result = val[0]
+
+    result
+  end
+.,.,
+
+# reduce 94 omitted
+
+# reduce 95 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 296)
+  def _reduce_96(val, _values, result)
+      result = ast AST::Undef, :value => :undef
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 300)
+  def _reduce_97(val, _values, result)
+      result = ast AST::Name, :value => val[0][:value], :line => val[0][:line]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 304)
+  def _reduce_98(val, _values, result)
+      result = ast AST::Type, :value => val[0][:value], :line => val[0][:line]
+
+    result
+  end
+.,.,
+
+# reduce 99 omitted
+
+# reduce 100 omitted
+
+# reduce 101 omitted
+
+# reduce 102 omitted
+
+# reduce 103 omitted
+
+# reduce 104 omitted
+
+# reduce 105 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 316)
+  def _reduce_106(val, _values, result)
+      raise Puppet::ParseError, "Cannot assign to variables in other namespaces" if val[0][:value] =~ /::/
+  # this is distinct from referencing a variable
+  variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line]
+  result = ast AST::VarDef, :name => variable, :value => val[2], :line => val[0][:line]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 322)
+  def _reduce_107(val, _values, result)
+        result = ast AST::VarDef, :name => val[0], :value => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 326)
+  def _reduce_108(val, _values, result)
+      variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line]
+  result = ast AST::VarDef, :name => variable, :value => val[2], :append => true, :line => val[0][:line]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 332)
+  def _reduce_109(val, _values, result)
+      result = ast AST::ASTArray
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 334)
+  def _reduce_110(val, _values, result)
+     result = aryfy(val[0]) 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 336)
+  def _reduce_111(val, _values, result)
+        val[0].push(val[2])
+    result = val[0]
+
+    result
+  end
+.,.,
+
+# reduce 112 omitted
+
+# reduce 113 omitted
+
+# reduce 114 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 345)
+  def _reduce_115(val, _values, result)
+      result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 349)
+  def _reduce_116(val, _values, result)
+      result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2],
+    :add => true
+
+    result
+  end
+.,.,
+
+# reduce 117 omitted
+
+# reduce 118 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 358)
+  def _reduce_119(val, _values, result)
+      result = ast AST::ASTArray
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 360)
+  def _reduce_120(val, _values, result)
+     result = aryfy(val[0]) 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 362)
+  def _reduce_121(val, _values, result)
+        val[0].push(val[2])
+    result = val[0]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 368)
+  def _reduce_122(val, _values, result)
+      result = ast AST::Function,
+    :name => val[0][:value], :line => val[0][:line],
+    :arguments => val[2],
+    :ftype => :rvalue
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 373)
+  def _reduce_123(val, _values, result)
+      result = ast AST::Function,
+    :name => val[0][:value], :line => val[0][:line],
+    :arguments => AST::ASTArray.new({}),
+    :ftype => :rvalue
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 379)
+  def _reduce_124(val, _values, result)
+     result = ast AST::String, :value => val[0][:value],                  :line => val[0][:line] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 380)
+  def _reduce_125(val, _values, result)
+     result = ast AST::Concat, :value => [ast(AST::String,val[0])]+val[1], :line => val[0][:line] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 382)
+  def _reduce_126(val, _values, result)
+     result = [val[0]] + val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 384)
+  def _reduce_127(val, _values, result)
+     result = [ast(AST::String,val[0])]          
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 385)
+  def _reduce_128(val, _values, result)
+     result = [ast(AST::String,val[0])] + val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 388)
+  def _reduce_129(val, _values, result)
+      result = ast AST::Boolean, :value => val[0][:value], :line => val[0][:line]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 392)
+  def _reduce_130(val, _values, result)
+      Puppet.warning addcontext("Deprecation notice:  Resource references should now be capitalized")
+  result = ast AST::ResourceReference, :type => val[0][:value], :line => val[0][:line], :title => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 395)
+  def _reduce_131(val, _values, result)
+      result = ast AST::ResourceReference, :type => val[0].value, :title => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 399)
+  def _reduce_132(val, _values, result)
+      @lexer.commentpop
+  args = {
+    :test => ast(AST::Not, :value => val[1]),
+    :statements => val[3]
+  }
+
+  result = ast AST::IfStatement, args
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 408)
+  def _reduce_133(val, _values, result)
+        @lexer.commentpop
+    args = {
+      :test => ast(AST::Not, :value => val[1]), 
+      :statements => ast(AST::Nop)
+    }
+    result = ast AST::IfStatement, args
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 417)
+  def _reduce_134(val, _values, result)
+      result = val[1]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 421)
+  def _reduce_135(val, _values, result)
+      @lexer.commentpop
+  args = {
+    :test => val[0],
+    :statements => val[2]
+  }
+
+  args[:else] = val[4] if val[4]
+
+  result = ast AST::IfStatement, args
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 432)
+  def _reduce_136(val, _values, result)
+        @lexer.commentpop
+    args = {
+      :test => val[0],
+      :statements => ast(AST::Nop)
+  }
+
+  args[:else] = val[3] if val[3]
+
+  result = ast AST::IfStatement, args
+
+    result
+  end
+.,.,
+
+# reduce 137 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 445)
+  def _reduce_138(val, _values, result)
+        result = ast AST::Else, :statements => val[1]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 448)
+  def _reduce_139(val, _values, result)
+        @lexer.commentpop
+    result = ast AST::Else, :statements => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 452)
+  def _reduce_140(val, _values, result)
+        @lexer.commentpop
+    result = ast AST::Else, :statements => ast(AST::Nop)
+
+    result
+  end
+.,.,
+
+# reduce 141 omitted
+
+# reduce 142 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 471)
+  def _reduce_143(val, _values, result)
+        result = ast AST::InOperator, :lval => val[0], :rval => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 474)
+  def _reduce_144(val, _values, result)
+        result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 477)
+  def _reduce_145(val, _values, result)
+        result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 480)
+  def _reduce_146(val, _values, result)
+        result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 483)
+  def _reduce_147(val, _values, result)
+        result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 486)
+  def _reduce_148(val, _values, result)
+        result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 489)
+  def _reduce_149(val, _values, result)
+        result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 492)
+  def _reduce_150(val, _values, result)
+        result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 495)
+  def _reduce_151(val, _values, result)
+        result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 498)
+  def _reduce_152(val, _values, result)
+        result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 501)
+  def _reduce_153(val, _values, result)
+        result = ast AST::Minus, :value => val[1]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 504)
+  def _reduce_154(val, _values, result)
+        result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 507)
+  def _reduce_155(val, _values, result)
+        result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 510)
+  def _reduce_156(val, _values, result)
+        result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 513)
+  def _reduce_157(val, _values, result)
+        result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 516)
+  def _reduce_158(val, _values, result)
+        result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 519)
+  def _reduce_159(val, _values, result)
+        result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 522)
+  def _reduce_160(val, _values, result)
+        result = ast AST::Not, :value => val[1]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 525)
+  def _reduce_161(val, _values, result)
+        result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 528)
+  def _reduce_162(val, _values, result)
+        result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 531)
+  def _reduce_163(val, _values, result)
+        result = val[1]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 535)
+  def _reduce_164(val, _values, result)
+      @lexer.commentpop
+  result = ast AST::CaseStatement, :test => val[1], :options => val[3]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 539)
+  def _reduce_165(val, _values, result)
+     result = aryfy(val[0]) 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 541)
+  def _reduce_166(val, _values, result)
+        val[0].push val[1]
+    result = val[0]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 546)
+  def _reduce_167(val, _values, result)
+      @lexer.commentpop
+  result = ast AST::CaseOpt, :value => val[0], :statements => val[3]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 549)
+  def _reduce_168(val, _values, result)
+      @lexer.commentpop
+
+    result = ast(
+    AST::CaseOpt,
+    :value => val[0],
+
+    :statements => ast(AST::BlockExpression)
+  )
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 559)
+  def _reduce_169(val, _values, result)
+     result = aryfy(val[0]) 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 561)
+  def _reduce_170(val, _values, result)
+        val[0].push(val[2])
+    result = val[0]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 566)
+  def _reduce_171(val, _values, result)
+      result = ast AST::Selector, :param => val[0], :values => val[2]
+
+    result
+  end
+.,.,
+
+# reduce 172 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 571)
+  def _reduce_173(val, _values, result)
+        @lexer.commentpop
+    result = val[1]
+
+    result
+  end
+.,.,
+
+# reduce 174 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 577)
+  def _reduce_175(val, _values, result)
+        if val[0].instance_of?(AST::ASTArray)
+    val[0].push(val[2])
+    result = val[0]
+  else
+    result = ast AST::ASTArray, :children => [val[0],val[2]]
+  end
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 586)
+  def _reduce_176(val, _values, result)
+      result = ast AST::ResourceParam, :param => val[0], :value => val[2]
+
+    result
+  end
+.,.,
+
+# reduce 177 omitted
+
+# reduce 178 omitted
+
+# reduce 179 omitted
+
+# reduce 180 omitted
+
+# reduce 181 omitted
+
+# reduce 182 omitted
+
+# reduce 183 omitted
+
+# reduce 184 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 598)
+  def _reduce_185(val, _values, result)
+        result = ast AST::Default, :value => val[0][:value], :line => val[0][:line]
+
+    result
+  end
+.,.,
+
+# reduce 186 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 603)
+  def _reduce_187(val, _values, result)
+     result = [val[0][:value]] 
+    result
+  end
+.,.,
+
+# reduce 188 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 605)
+  def _reduce_189(val, _values, result)
+     result = val[0] += val[2] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 608)
+  def _reduce_190(val, _values, result)
+      val[1].each do |file|
+    import(file)
+  end
+
+  result = nil
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 618)
+  def _reduce_191(val, _values, result)
+      @lexer.commentpop
+  result = Puppet::Parser::AST::Definition.new(classname(val[1]),
+                                               ast_context(true).merge(:arguments => val[2], :code => val[4],
+                                                                       :line => val[0][:line]))
+  @lexer.indefine = false
+
+#}           | DEFINE NAME argumentlist parent LBRACE RBRACE {
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 626)
+  def _reduce_192(val, _values, result)
+      @lexer.commentpop
+  result = Puppet::Parser::AST::Definition.new(classname(val[1]),
+                                               ast_context(true).merge(:arguments => val[2], :line => val[0][:line]))
+  @lexer.indefine = false
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 634)
+  def _reduce_193(val, _values, result)
+      @lexer.commentpop
+  # Our class gets defined in the parent namespace, not our own.
+  @lexer.namepop
+  result = Puppet::Parser::AST::Hostclass.new(classname(val[1]),
+                                              ast_context(true).merge(:arguments => val[2], :parent => val[3],
+                                                                      :code => val[5], :line => val[0][:line]))
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 641)
+  def _reduce_194(val, _values, result)
+      @lexer.commentpop
+  # Our class gets defined in the parent namespace, not our own.
+  @lexer.namepop
+  result = Puppet::Parser::AST::Hostclass.new(classname(val[1]),
+                                              ast_context(true).merge(:arguments => val[2], :parent => val[3],
+                                                                      :line => val[0][:line]))
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 650)
+  def _reduce_195(val, _values, result)
+      @lexer.commentpop
+  result = Puppet::Parser::AST::Node.new(val[1],
+                                         ast_context(true).merge(:parent => val[2], :code => val[4],
+                                                                 :line => val[0][:line]))
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 655)
+  def _reduce_196(val, _values, result)
+      @lexer.commentpop
+  result = Puppet::Parser::AST::Node.new(val[1], ast_context(true).merge(:parent => val[2], :line => val[0][:line]))
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 659)
+  def _reduce_197(val, _values, result)
+     result = val[0][:value] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 660)
+  def _reduce_198(val, _values, result)
+     result = "class" 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 665)
+  def _reduce_199(val, _values, result)
+        result = [result]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 668)
+  def _reduce_200(val, _values, result)
+        result = val[0]
+    result << val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 673)
+  def _reduce_201(val, _values, result)
+      result = ast AST::HostName, :value => val[0]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 676)
+  def _reduce_202(val, _values, result)
+     result = val[0][:value] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 677)
+  def _reduce_203(val, _values, result)
+     result = val[0][:value] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 678)
+  def _reduce_204(val, _values, result)
+     result = val[0][:value] 
+    result
+  end
+.,.,
+
+# reduce 205 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 682)
+  def _reduce_206(val, _values, result)
+      result = nil
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 686)
+  def _reduce_207(val, _values, result)
+      result = ast AST::ASTArray, :children => []
+
+    result
+  end
+.,.,
+
+# reduce 208 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 691)
+  def _reduce_209(val, _values, result)
+        result = nil
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 694)
+  def _reduce_210(val, _values, result)
+        result = val[1]
+    result = [result] unless result[0].is_a?(Array)
+
+    result
+  end
+.,.,
+
+# reduce 211 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 700)
+  def _reduce_212(val, _values, result)
+        result = val[0]
+    result = [result] unless result[0].is_a?(Array)
+    result << val[2]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 706)
+  def _reduce_213(val, _values, result)
+     result = [val[0][:value], val[2]] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 707)
+  def _reduce_214(val, _values, result)
+     result = [val[0][:value]] 
+    result
+  end
+.,.,
+
+# reduce 215 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 711)
+  def _reduce_216(val, _values, result)
+        result = val[1]
+
+    result
+  end
+.,.,
+
+# reduce 217 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 716)
+  def _reduce_218(val, _values, result)
+        result = val[1]
+
+    result
+  end
+.,.,
+
+# reduce 219 omitted
+
+# reduce 220 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 722)
+  def _reduce_221(val, _values, result)
+      result = ast AST::Variable, :value => val[0][:value], :line => val[0][:line]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 725)
+  def _reduce_222(val, _values, result)
+     result = val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 726)
+  def _reduce_223(val, _values, result)
+     result = val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 727)
+  def _reduce_224(val, _values, result)
+     result = ast AST::ASTArray 
+    result
+  end
+.,.,
+
+# reduce 225 omitted
+
+# reduce 226 omitted
+
+# reduce 227 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 733)
+  def _reduce_228(val, _values, result)
+     result = nil 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 736)
+  def _reduce_229(val, _values, result)
+      result = ast AST::Regex, :value => val[0][:value]
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 740)
+  def _reduce_230(val, _values, result)
+      @lexer.commentpop
+  if val[1].instance_of?(AST::ASTHash)
+    result = val[1]
+  else
+    result = ast AST::ASTHash, { :value => val[1] }
+  end
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 748)
+  def _reduce_231(val, _values, result)
+        @lexer.commentpop
+    if val[1].instance_of?(AST::ASTHash)
+    result = val[1]
+  else
+    result = ast AST::ASTHash, { :value => val[1] }
+  end
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 755)
+  def _reduce_232(val, _values, result)
+      @lexer.commentpop
+  result = ast AST::ASTHash
+
+    result
+  end
+.,.,
+
+# reduce 233 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 761)
+  def _reduce_234(val, _values, result)
+        if val[0].instance_of?(AST::ASTHash)
+    result = val[0].merge(val[2])
+  else
+    result = ast AST::ASTHash, :value => val[0]
+    result.merge(val[2])
+  end
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 770)
+  def _reduce_235(val, _values, result)
+      result = ast AST::ASTHash, { :value => { val[0] => val[2] } }
+
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 773)
+  def _reduce_236(val, _values, result)
+     result = val[0][:value] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 774)
+  def _reduce_237(val, _values, result)
+     result = val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'grammar.ra', 777)
+  def _reduce_238(val, _values, result)
+      result = ast AST::HashOrArrayAccess, :variable => val[0][:value], :key => val[2]
+
+    result
+  end
+.,.,
+
+# reduce 239 omitted
+
+module_eval(<<'.,.,', 'grammar.ra', 782)
+  def _reduce_240(val, _values, result)
+        result = ast AST::HashOrArrayAccess, :variable => val[0], :key => val[2]
+
+    result
+  end
+.,.,
+
+def _reduce_none(val, _values, result)
+  val[0]
+end
+
+    end   # class Parser
+    end   # module Parser
+  end   # module Puppet
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/parser_factory.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/parser_factory.rb
new file mode 100644
index 0000000..bf09975
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/parser_factory.rb
@@ -0,0 +1,76 @@
+module Puppet; end
+
+module Puppet::Parser
+  # The ParserFactory makes selection of parser possible.
+  # Currently, it is possible to switch between two different parsers:
+  # * classic_parser, the parser in 3.1
+  # * eparser, the Expression Based Parser
+  #
+  class ParserFactory
+    # Produces a parser instance for the given environment
+    def self.parser(environment)
+      if Puppet.future_parser?
+        evaluating_parser(environment)
+      else
+        classic_parser(environment)
+      end
+    end
+
+    # Creates an instance of the classic parser.
+    #
+    def self.classic_parser(environment)
+      # avoid expensive require if already loaded
+      require 'puppet/parser' unless defined? Puppet::Parser::Parser
+      Puppet::Parser::Parser.new(environment)
+    end
+
+    # Creates an instance of an E4ParserAdapter that adapts an
+    # EvaluatingParser to the 3x way of parsing.
+    #
+    def self.evaluating_parser(file_watcher)
+      # Since RGen is optional, test that it is installed
+      assert_rgen_installed()
+      unless defined?(Puppet::Pops::Parser::E4ParserAdapter)
+        require 'puppet/parser/e4_parser_adapter'
+        require 'puppet/pops/parser/code_merger'
+      end
+      E4ParserAdapter.new(file_watcher)
+    end
+
+    # Asserts that RGen >= 0.6.6 is installed by checking that certain behavior is available.
+    # Note that this assert is expensive as it also requires puppet/pops (if not already loaded).
+    #
+    def self.assert_rgen_installed
+      @@asserted ||= false
+      return if @@asserted
+      @@asserted = true
+      begin
+        require 'rgen/metamodel_builder'
+      rescue LoadError
+        raise Puppet::DevError.new("The gem 'rgen' version >= 0.7.0 is required when using the setting '--parser future'. Please install 'rgen'.")
+      end
+      # Since RGen is optional, there is nothing specifying its version.
+      # It is not installed in any controlled way, so not possible to use gems to check (it may be installed some other way).
+      # Instead check that "eContainer, and eContainingFeature" has been installed.
+      require 'puppet/pops'
+      begin
+        litstring = Puppet::Pops::Model::LiteralString.new();
+        container = Puppet::Pops::Model::ArithmeticExpression.new();
+        container.left_expr = litstring
+        raise "no eContainer" if litstring.eContainer() != container
+        raise "no eContainingFeature" if litstring.eContainingFeature() != :left_expr
+      rescue => e
+        # TODO: RGen can raise exceptions for other reasons!
+        raise Puppet::DevError.new("The gem 'rgen' version >= 0.7.0 is required when using '--parser future'. An older version is installed, please update.")
+      end
+    end
+
+    def self.code_merger
+      if Puppet.future_parser?
+        Puppet::Pops::Parser::CodeMerger.new
+      else
+        Puppet::Parser::CodeMerger.new
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/parser_support.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/parser_support.rb
new file mode 100644
index 0000000..963e4d1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/parser_support.rb
@@ -0,0 +1,195 @@
+# I pulled this into a separate file, because I got
+# tired of rebuilding the parser.rb file all the time.
+require 'forwardable'
+
+class Puppet::Parser::Parser
+  extend Forwardable
+
+  require 'puppet/parser/functions'
+  require 'puppet/parser/files'
+  require 'puppet/resource/type_collection'
+  require 'puppet/resource/type_collection_helper'
+  require 'puppet/resource/type'
+  require 'monitor'
+
+  AST = Puppet::Parser::AST
+
+  include Puppet::Resource::TypeCollectionHelper
+
+  attr_reader :version, :environment
+  attr_accessor :files
+
+  attr_accessor :lexer
+
+  # Add context to a message; useful for error messages and such.
+  def addcontext(message, obj = nil)
+    obj ||= @lexer
+
+    message += " on line #{obj.line}"
+    if file = obj.file
+      message += " in file #{file}"
+    end
+
+    message
+  end
+
+  # Create an AST array containing a single element
+  def aryfy(arg)
+    ast AST::ASTArray, :children => [arg]
+  end
+
+  # Create an AST block containing a single element
+  def block(arg)
+    ast AST::BlockExpression, :children => [arg]
+  end
+
+  # Create an AST object, and automatically add the file and line information if
+  # available.
+  def ast(klass, hash = {})
+    klass.new ast_context(klass.use_docs, hash[:line]).merge(hash)
+  end
+
+  def ast_context(include_docs = false, ast_line = nil)
+    result = {
+      :line => ast_line || lexer.line,
+      :file => lexer.file
+    }
+    result[:doc] = lexer.getcomment(result[:line]) if include_docs
+    result
+  end
+
+  # The fully qualifed name, with the full namespace.
+  def classname(name)
+    [@lexer.namespace, name].join("::").sub(/^::/, '')
+  end
+
+  def clear
+    initvars
+  end
+
+  # Raise a Parse error.
+  def error(message, options = {})
+    if @lexer.expected
+      message += "; expected '%s'"
+    end
+    except = Puppet::ParseError.new(message)
+    except.line = options[:line] || @lexer.line
+    except.file = options[:file] || @lexer.file
+
+    raise except
+  end
+
+  def_delegators :@lexer, :file, :string=
+
+  def file=(file)
+    unless Puppet::FileSystem.exist?(file)
+      unless file =~ /\.pp$/
+        file = file + ".pp"
+      end
+    end
+    raise Puppet::AlreadyImportedError, "Import loop detected for #{file}" if known_resource_types.watching_file?(file)
+
+    watch_file(file)
+    @lexer.file = file
+  end
+
+  def_delegators :known_resource_types, :hostclass, :definition, :node, :nodes?
+  def_delegators :known_resource_types, :find_hostclass, :find_definition
+  def_delegators :known_resource_types, :watch_file, :version
+
+  def import(file)
+    deprecation_location_text =
+    if @lexer.file && @lexer.line
+      " at #{@lexer.file}:#{@lexer.line}"
+    elsif @lexer.file
+      " in file #{@lexer.file}"
+    elsif @lexer.line
+      " at #{@lexer.line}"
+    end
+
+    Puppet.deprecation_warning("The use of 'import' is deprecated#{deprecation_location_text}. See http://links.puppetlabs.com/puppet-import-deprecation")
+    if @lexer.file
+      # use a path relative to the file doing the importing
+      dir = File.dirname(@lexer.file)
+    else
+      # otherwise assume that everything needs to be from where the user is
+      # executing this command. Normally, this would be in a "puppet apply -e"
+      dir = Dir.pwd
+    end
+
+    known_resource_types.loader.import(file, dir)
+  end
+
+  def initialize(env)
+    @environment = env
+    initvars
+  end
+
+  # Initialize or reset all of our variables.
+  def initvars
+    @lexer = Puppet::Parser::Lexer.new
+  end
+
+  # Split an fq name into a namespace and name
+  def namesplit(fullname)
+    ary = fullname.split("::")
+    n = ary.pop || ""
+    ns = ary.join("::")
+    return ns, n
+  end
+
+  def on_error(token,value,stack)
+    if token == 0 # denotes end of file
+      value = 'end of file'
+    else
+      value = "'#{value[:value]}'"
+    end
+    error = "Syntax error at #{value}"
+
+    if brace = @lexer.expected
+      error += "; expected '#{brace}'"
+    end
+
+    except = Puppet::ParseError.new(error)
+    except.line = @lexer.line
+    except.file = @lexer.file if @lexer.file
+
+    raise except
+  end
+
+  # how should I do error handling here?
+  def parse(string = nil)
+    if self.file =~ /\.rb$/
+      main = parse_ruby_file
+    else
+      self.string = string if string
+      begin
+        @yydebug = false
+        main = yyparse(@lexer,:scan)
+      rescue Puppet::ParseError => except
+        except.line ||= @lexer.line
+        except.file ||= @lexer.file
+        except.pos ||= @lexer.pos
+        raise except
+      rescue => except
+        raise Puppet::ParseError.new(except.message, @lexer.file, @lexer.line, nil, except)
+      end
+    end
+    # Store the results as the top-level class.
+    return Puppet::Parser::AST::Hostclass.new('', :code => main)
+  ensure
+    @lexer.clear
+  end
+
+  def parse_ruby_file
+    Puppet.deprecation_warning("Use of the Ruby DSL is deprecated.")
+
+    # Execute the contents of the file inside its own "main" object so
+    # that it can call methods in the resource type API.
+    main_object = Puppet::DSL::ResourceTypeAPI.new
+    main_object.instance_eval(File.read(self.file))
+
+    # Then extract any types that were created.
+    Puppet::Parser::AST::BlockExpression.new :children => main_object.instance_eval { @__created_ast_objects__ }
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/relationship.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/relationship.rb
new file mode 100644
index 0000000..d226c94
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/relationship.rb
@@ -0,0 +1,77 @@
+class Puppet::Parser::Relationship
+  attr_accessor :source, :target, :type
+
+  PARAM_MAP = {:relationship => :before, :subscription => :notify}
+
+  def arrayify(resources)
+    # This if statement is needed because the 3x parser cannot load
+    # Puppet::Pops. This logic can be removed for 4.0 when the 3x AST
+    # is removed (when Pops is always used).
+    if !(Puppet.future_parser?)
+      case resources
+      when Puppet::Parser::Collector
+        resources.collected.values
+      when Array
+        resources
+      else
+        [resources]
+      end
+    else
+      require 'puppet/pops'
+      case resources
+      when Puppet::Pops::Evaluator::Collectors::AbstractCollector
+        resources.collected.values
+      when Array
+        resources
+      else
+        [resources]
+      end
+    end
+  end
+
+  def evaluate(catalog)
+    arrayify(source).each do |s|
+      arrayify(target).each do |t|
+        mk_relationship(s, t, catalog)
+      end
+    end
+  end
+
+  def initialize(source, target, type)
+    @source, @target, @type = source, target, type
+  end
+
+  def param_name
+    PARAM_MAP[type] || raise(ArgumentError, "Invalid relationship type #{type}")
+  end
+
+  def mk_relationship(source, target, catalog)
+    # REVISIT: In Ruby 1.8 we applied `to_s` to source and target, rather than
+    # `join` without an argument.  In 1.9 the behaviour of Array#to_s changed,
+    # and it gives a different representation than just concat the stringified
+    # elements.
+    #
+    # This restores the behaviour, but doesn't address the underlying question
+    # of what would happen when more than one item was passed in that array.
+    # (Hint: this will not end well.)
+    #
+    # See http://projects.puppetlabs.com/issues/12076 for the ticket tracking
+    # the fact that we should dig out the sane version of this behaviour, then
+    # implement it - where we don't risk breaking a stable release series.
+    # --daniel 2012-01-21
+    source = source.is_a?(Array) ? source.join : source.to_s
+    target = target.is_a?(Array) ? target.join : target.to_s
+
+    unless source_resource = catalog.resource(source)
+      raise ArgumentError, "Could not find resource '#{source}' for relationship on '#{target}'"
+    end
+    unless catalog.resource(target)
+      raise ArgumentError, "Could not find resource '#{target}' for relationship from '#{source}'"
+    end
+    Puppet.debug "Adding relationship from #{source} to #{target} with '#{param_name}'"
+    if source_resource[param_name].class != Array
+      source_resource[param_name] = [source_resource[param_name]].compact
+    end
+    source_resource[param_name] << target
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/resource.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/resource.rb
new file mode 100644
index 0000000..1c360dd
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/resource.rb
@@ -0,0 +1,285 @@
+require 'puppet/resource'
+
+# The primary difference between this class and its
+# parent is that this class has rules on who can set
+# parameters
+class Puppet::Parser::Resource < Puppet::Resource
+  require 'puppet/parser/resource/param'
+  require 'puppet/util/tagging'
+  require 'puppet/parser/yaml_trimmer'
+  require 'puppet/resource/type_collection_helper'
+
+  include Puppet::Resource::TypeCollectionHelper
+
+  include Puppet::Util
+  include Puppet::Util::MethodHelper
+  include Puppet::Util::Errors
+  include Puppet::Util::Logging
+  include Puppet::Parser::YamlTrimmer
+
+  attr_accessor :source, :scope, :collector_id
+  attr_accessor :virtual, :override, :translated, :catalog, :evaluated
+  attr_accessor :file, :line
+
+  attr_reader :exported, :parameters
+
+  # Determine whether the provided parameter name is a relationship parameter.
+  def self.relationship_parameter?(name)
+    @relationship_names ||= Puppet::Type.relationship_params.collect { |p| p.name }
+    @relationship_names.include?(name)
+  end
+
+  # Set up some boolean test methods
+  def translated?; !!@translated; end
+  def override?;   !!@override;   end
+  def evaluated?;  !!@evaluated;  end
+
+  def [](param)
+    param = param.intern
+    if param == :title
+      return self.title
+    end
+    if @parameters.has_key?(param)
+      @parameters[param].value
+    else
+      nil
+    end
+  end
+
+  def eachparam
+    @parameters.each do |name, param|
+      yield param
+    end
+  end
+
+  def environment
+    scope.environment
+  end
+
+  # Process the  stage metaparameter for a class.   A containment edge
+  # is drawn from  the class to the stage.   The stage for containment
+  # defaults to main, if none is specified.
+  def add_edge_to_stage
+    return unless self.class?
+
+    unless stage = catalog.resource(:stage, self[:stage] || (scope && scope.resource && scope.resource[:stage]) || :main)
+      raise ArgumentError, "Could not find stage #{self[:stage] || :main} specified by #{self}"
+    end
+
+    self[:stage] ||= stage.title unless stage.title == :main
+    catalog.add_edge(stage, self)
+  end
+
+  # Retrieve the associated definition and evaluate it.
+  def evaluate
+    return if evaluated?
+
+    Puppet::Util::Profiler.profile("Evaluated resource #{self}", [:compiler, :evaluate_resource, self]) do
+      @evaluated = true
+      if klass = resource_type and ! builtin_type?
+        finish
+        evaluated_code = klass.evaluate_code(self)
+
+        return evaluated_code
+      elsif builtin?
+        devfail "Cannot evaluate a builtin type (#{type})"
+      else
+        self.fail "Cannot find definition #{type}"
+      end
+    end
+  end
+
+  # Mark this resource as both exported and virtual,
+  # or remove the exported mark.
+  def exported=(value)
+    if value
+      @virtual = true
+      @exported = value
+    else
+      @exported = value
+    end
+  end
+
+  # Do any finishing work on this object, called before evaluation or
+  # before storage/translation.
+  def finish
+    return if finished?
+    @finished = true
+    add_defaults
+    add_scope_tags
+    validate
+  end
+
+  # Has this resource already been finished?
+  def finished?
+    @finished
+  end
+
+  def initialize(*args)
+    raise ArgumentError, "Resources require a hash as last argument" unless args.last.is_a? Hash
+    raise ArgumentError, "Resources require a scope" unless args.last[:scope]
+    super
+
+    @source ||= scope.source
+  end
+
+  # Is this resource modeling an isomorphic resource type?
+  def isomorphic?
+    if builtin_type?
+      return resource_type.isomorphic?
+    else
+      return true
+    end
+  end
+
+  # Merge an override resource in.  This will throw exceptions if
+  # any overrides aren't allowed.
+  def merge(resource)
+    # Test the resource scope, to make sure the resource is even allowed
+    # to override.
+    unless self.source.object_id == resource.source.object_id || resource.source.child_of?(self.source)
+      raise Puppet::ParseError.new("Only subclasses can override parameters", resource.line, resource.file)
+    end
+    # Some of these might fail, but they'll fail in the way we want.
+    resource.parameters.each do |name, param|
+      override_parameter(param)
+    end
+  end
+
+  # This only mattered for clients < 0.25, which we don't support any longer.
+  # ...but, since this hasn't been deprecated, and at least some functions
+  # used it, deprecate now rather than just eliminate. --daniel 2012-07-15
+  def metaparam_compatibility_mode?
+    Puppet.deprecation_warning "metaparam_compatibility_mode? is obsolete since < 0.25 clients are really, really not supported any more"
+    false
+  end
+
+  def name
+    self[:name] || self.title
+  end
+
+  # A temporary occasion, until I get paths in the scopes figured out.
+  alias path to_s
+
+  # Define a parameter in our resource.
+  # if we ever receive a parameter named 'tag', set
+  # the resource tags with its value.
+  def set_parameter(param, value = nil)
+    if ! param.is_a?(Puppet::Parser::Resource::Param)
+      param = Puppet::Parser::Resource::Param.new(
+        :name => param, :value => value, :source => self.source
+      )
+    end
+
+    tag(*param.value) if param.name == :tag
+
+    # And store it in our parameter hash.
+    @parameters[param.name] = param
+  end
+  alias []= set_parameter
+
+  def to_hash
+    @parameters.inject({}) do |hash, ary|
+      param = ary[1]
+      # Skip "undef" and nil values.
+      hash[param.name] = param.value if param.value != :undef && !param.value.nil?
+      hash
+    end
+  end
+
+  # Convert this resource to a RAL resource.
+  def to_ral
+    copy_as_resource.to_ral
+  end
+
+  # Answers if this resource is tagged with at least one of the tags given in downcased string form.
+  #
+  # The method is a faster variant of the tagged? method that does no conversion of its
+  # arguments.
+  #
+  # The match takes into account the tags that a resource will inherit from its container
+  # but have not been set yet.
+  # It does *not* take tags set via resource defaults as these will *never* be set on
+  # the resource itself since all resources always have tags that are automatically
+  # assigned.
+  #
+  # @param tag_array [Array[String]] list tags to look for
+  # @return [Boolean] true if this instance is tagged with at least one of the provided tags
+  #
+  def raw_tagged?(tag_array)
+    super || ((scope_resource = scope.resource) && !scope_resource.equal?(self) && scope_resource.raw_tagged?(tag_array))
+  end
+
+  private
+
+  # Add default values from our definition.
+  def add_defaults
+    scope.lookupdefaults(self.type).each do |name, param|
+      unless @parameters.include?(name)
+        self.debug "Adding default for #{name}"
+
+        @parameters[name] = param.dup
+      end
+    end
+  end
+
+  def add_scope_tags
+    if scope_resource = scope.resource
+      tag(*scope_resource.tags)
+    end
+  end
+
+  # Accept a parameter from an override.
+  def override_parameter(param)
+    # This can happen if the override is defining a new parameter, rather
+    # than replacing an existing one.
+    (set_parameter(param) and return) unless current = @parameters[param.name]
+
+    # The parameter is already set.  Fail if they're not allowed to override it.
+    unless param.source.child_of?(current.source)
+      msg = "Parameter '#{param.name}' is already set on #{self}"
+      msg += " by #{current.source}" if current.source.to_s != ""
+      if current.file or current.line
+        fields = []
+        fields << current.file if current.file
+        fields << current.line.to_s if current.line
+        msg += " at #{fields.join(":")}"
+      end
+      msg += "; cannot redefine"
+      raise Puppet::ParseError.new(msg, param.line, param.file)
+    end
+
+    # If we've gotten this far, we're allowed to override.
+
+    # Merge with previous value, if the parameter was generated with the +>
+    # syntax.  It's important that we use a copy of the new param instance
+    # here, not the old one, and not the original new one, so that the source
+    # is registered correctly for later overrides but the values aren't
+    # implcitly shared when multiple resources are overrriden at once (see
+    # ticket #3556).
+    if param.add
+      param = param.dup
+      param.value = [current.value, param.value].flatten
+    end
+
+    set_parameter(param)
+  end
+
+  # Make sure the resource's parameters are all valid for the type.
+  def validate
+    @parameters.each do |name, param|
+      validate_parameter(name)
+    end
+  rescue => detail
+    self.fail Puppet::ParseError, detail.to_s + " on #{self}", detail
+  end
+
+  def extract_parameters(params)
+    params.each do |param|
+      # Don't set the same parameter twice
+      self.fail Puppet::ParseError, "Duplicate parameter '#{param.name}' for on #{self}" if @parameters[param.name]
+
+      set_parameter(param)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/resource/param.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/resource/param.rb
new file mode 100644
index 0000000..cb81043
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/resource/param.rb
@@ -0,0 +1,25 @@
+require 'puppet/parser/yaml_trimmer'
+
+# The parameters we stick in Resources.
+class Puppet::Parser::Resource::Param
+  include Puppet::Util
+  include Puppet::Util::Errors
+  include Puppet::Util::MethodHelper
+  include Puppet::Parser::YamlTrimmer
+
+  attr_accessor :name, :value, :source, :add, :file, :line
+
+  def initialize(hash)
+    set_options(hash)
+    requiredopts(:name)
+    @name = @name.intern
+  end
+
+  def line_to_i
+    line ? Integer(line) : nil
+  end
+
+  def to_s
+    "#{self.name} => #{self.value}"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/scope.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/scope.rb
new file mode 100644
index 0000000..5429b04
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/scope.rb
@@ -0,0 +1,963 @@
+# The scope class, which handles storing and retrieving variables and types and
+# such.
+require 'forwardable'
+
+require 'puppet/parser'
+require 'puppet/parser/templatewrapper'
+
+require 'puppet/resource/type_collection_helper'
+require 'puppet/util/methodhelper'
+
+# This class is part of the internal parser/evaluator/compiler functionality of Puppet.
+# It is passed between the various classes that participate in evaluation.
+# None of its methods are API except those that are clearly marked as such.
+#
+# @api public
+class Puppet::Parser::Scope
+  extend Forwardable
+  include Puppet::Util::MethodHelper
+
+  include Puppet::Resource::TypeCollectionHelper
+  require 'puppet/parser/resource'
+
+  AST = Puppet::Parser::AST
+
+  # Variables that always exist with nil value even if not set
+  BUILT_IN_VARS = ['module_name'.freeze, 'caller_module_name'.freeze].freeze
+
+  Puppet::Util.logmethods(self)
+
+  include Puppet::Util::Errors
+  attr_accessor :source, :resource
+  attr_accessor :compiler
+  attr_accessor :parent
+  attr_reader :namespaces
+
+  # Hash of hashes of default values per type name
+  attr_reader :defaults
+
+  # Add some alias methods that forward to the compiler, since we reference
+  # them frequently enough to justify the extra method call.
+  def_delegators :compiler, :catalog, :environment
+
+
+  # Abstract base class for LocalScope and MatchScope
+  #
+  class Ephemeral
+
+    attr_reader :parent
+
+    def initialize(parent = nil)
+      @parent = parent
+    end
+
+    def is_local_scope?
+      false
+    end
+
+    def [](name)
+      if @parent
+        @parent[name]
+      end
+    end
+
+    def include?(name)
+      (@parent and @parent.include?(name))
+    end
+
+    def bound?(name)
+      false
+    end
+
+    def add_entries_to(target = {})
+      @parent.add_entries_to(target) unless @parent.nil?
+      # do not include match data ($0-$n)
+      target
+    end
+  end
+
+  class LocalScope < Ephemeral
+
+    def initialize(parent=nil)
+      super parent
+      @symbols = {}
+    end
+
+    def [](name)
+      if @symbols.include?(name)
+        @symbols[name]
+      else
+        super
+      end
+    end
+
+    def is_local_scope?
+      true
+    end
+
+    def []=(name, value)
+      @symbols[name] = value
+    end
+
+    def include?(name)
+      bound?(name) || super
+    end
+
+    def delete(name)
+      @symbols.delete(name)
+    end
+
+    def bound?(name)
+      @symbols.include?(name)
+    end
+
+    def add_entries_to(target = {})
+      super
+      @symbols.each do |k, v|
+        if v == :undef || v.nil?
+          target.delete(k)
+        else
+          target[ k ] = v
+        end
+      end
+      target
+    end
+  end
+
+  class MatchScope < Ephemeral
+
+    attr_accessor :match_data
+
+    def initialize(parent = nil, match_data = nil)
+      super parent
+      @match_data = match_data
+    end
+
+    def is_local_scope?
+      false
+    end
+
+    def [](name)
+      if bound?(name)
+        @match_data[name.to_i]
+      else
+        super
+      end
+    end
+
+    def include?(name)
+      bound?(name) or super
+    end
+
+    def bound?(name)
+      # A "match variables" scope reports all numeric variables to be bound if the scope has
+      # match_data. Without match data the scope is transparent.
+      #
+      @match_data && name =~ /^\d+$/
+    end
+
+    def []=(name, value)
+      # TODO: Bad choice of exception
+      raise Puppet::ParseError, "Numerical variables cannot be changed. Attempt to set $#{name}"
+    end
+
+    def delete(name)
+      # TODO: Bad choice of exception
+      raise Puppet::ParseError, "Numerical variables cannot be deleted: Attempt to delete: $#{name}"
+    end
+
+    def add_entries_to(target = {})
+      # do not include match data ($0-$n)
+      super
+    end
+
+  end
+
+  # Returns true if the variable of the given name has a non nil value.
+  # TODO: This has vague semantics - does the variable exist or not?
+  #       use ['name'] to get nil or value, and if nil check with exist?('name')
+  #       this include? is only useful because of checking against the boolean value false.
+  #
+  def include?(name)
+    ! self[name].nil?
+  end
+
+  # Returns true if the variable of the given name is set to any value (including nil)
+  #
+  # @return [Boolean] if variable exists or not
+  #
+  def exist?(name)
+    # Note !! ensure the answer is boolean
+    !! if name =~ /^(.*)::(.+)$/
+      class_name = $1
+      variable_name = $2
+      return true if class_name == '' && BUILT_IN_VARS.include?(variable_name)
+
+      # lookup class, but do not care if it is not evaluated since that will result
+      # in it not existing anyway. (Tests may run with just scopes and no evaluated classes which
+      # will result in class_scope for "" not returning topscope).
+      klass = find_hostclass(class_name)
+      other_scope = klass.nil? ? nil : class_scope(klass)
+      if other_scope.nil?
+        class_name == '' ? compiler.topscope.exist?(variable_name) : false
+      else
+        other_scope.exist?(variable_name)
+      end
+    else
+      next_scope = inherited_scope || enclosing_scope
+      effective_symtable(true).include?(name) || next_scope && next_scope.exist?(name) || BUILT_IN_VARS.include?(name)
+    end
+  end
+
+  # Returns true if the given name is bound in the current (most nested) scope for assignments.
+  #
+  def bound?(name)
+    # Do not look in ephemeral (match scope), the semantics is to answer if an assignable variable is bound
+    effective_symtable(false).bound?(name)
+  end
+
+  # Is the value true?  This allows us to control the definition of truth
+  # in one place.
+  def self.true?(value)
+    case value
+    when ''
+      false
+    when :undef
+      false
+    else
+      !!value
+    end
+  end
+
+  # Coerce value to a number, or return `nil` if it isn't one.
+  def self.number?(value)
+    case value
+    when Numeric
+      value
+    when /^-?\d+(:?\.\d+|(:?\.\d+)?e\d+)$/
+      value.to_f
+    when /^0x[0-9a-f]+$/i
+      value.to_i(16)
+    when /^0[0-7]+$/
+      value.to_i(8)
+    when /^-?\d+$/
+      value.to_i
+    else
+      nil
+    end
+  end
+
+  # Add to our list of namespaces.
+  def add_namespace(ns)
+    return false if @namespaces.include?(ns)
+    if @namespaces == [""]
+      @namespaces = [ns]
+    else
+      @namespaces << ns
+    end
+  end
+
+  def find_hostclass(name, options = {})
+    known_resource_types.find_hostclass(namespaces, name, options)
+  end
+
+  def find_definition(name)
+    known_resource_types.find_definition(namespaces, name)
+  end
+
+  def find_global_scope()
+    # walk upwards until first found node_scope or top_scope
+    if is_nodescope? || is_topscope?
+      self
+    else
+      next_scope = inherited_scope || enclosing_scope
+      if next_scope.nil?
+        # this happens when testing, and there is only a single test scope and no link to any
+        # other scopes
+        self
+      else
+        next_scope.find_global_scope()
+      end
+    end
+  end
+
+  # This just delegates directly.
+  def_delegator :compiler, :findresource
+
+  # Initialize our new scope.  Defaults to having no parent.
+  def initialize(compiler, options = {})
+    if compiler.is_a? Puppet::Parser::Compiler
+      self.compiler = compiler
+    else
+      raise Puppet::DevError, "you must pass a compiler instance to a new scope object"
+    end
+
+    if n = options.delete(:namespace)
+      @namespaces = [n]
+    else
+      @namespaces = [""]
+    end
+
+    raise Puppet::DevError, "compiler passed in options" if options.include? :compiler
+    set_options(options)
+
+    extend_with_functions_module
+
+    # The symbol table for this scope.  This is where we store variables.
+    #    @symtable = Ephemeral.new(nil, true)
+    @symtable = LocalScope.new(nil)
+
+    @ephemeral = [ MatchScope.new(@symtable, nil) ]
+
+    # All of the defaults set for types.  It's a hash of hashes,
+    # with the first key being the type, then the second key being
+    # the parameter.
+    @defaults = Hash.new { |dhash,type|
+      dhash[type] = {}
+    }
+
+    # The table for storing class singletons.  This will only actually
+    # be used by top scopes and node scopes.
+    @class_scopes = {}
+
+    @enable_immutable_data = Puppet[:immutable_node_data]
+  end
+
+  # Store the fact that we've evaluated a class, and store a reference to
+  # the scope in which it was evaluated, so that we can look it up later.
+  def class_set(name, scope)
+    if parent
+      parent.class_set(name, scope)
+    else
+      @class_scopes[name] = scope
+    end
+  end
+
+  # Return the scope associated with a class.  This is just here so
+  # that subclasses can set their parent scopes to be the scope of
+  # their parent class, and it's also used when looking up qualified
+  # variables.
+  def class_scope(klass)
+    # They might pass in either the class or class name
+    k = klass.respond_to?(:name) ? klass.name : klass
+    @class_scopes[k] || (parent && parent.class_scope(k))
+  end
+
+  # Collect all of the defaults set at any higher scopes.
+  # This is a different type of lookup because it's
+  # additive -- it collects all of the defaults, with defaults
+  # in closer scopes overriding those in later scopes.
+  #
+  # The lookupdefaults searches in the the order:
+  #
+  #   * inherited
+  #   * contained (recursive)
+  #   * self
+  #
+  def lookupdefaults(type)
+    values = {}
+
+    # first collect the values from the parents
+    if parent
+      parent.lookupdefaults(type).each { |var,value|
+        values[var] = value
+      }
+    end
+
+    # then override them with any current values
+    # this should probably be done differently
+    if @defaults.include?(type)
+      @defaults[type].each { |var,value|
+        values[var] = value
+      }
+    end
+
+    values
+  end
+
+  # Look up a defined type.
+  def lookuptype(name)
+    find_definition(name) || find_hostclass(name)
+  end
+
+  def undef_as(x,v)
+    if v.nil? or v == :undef
+      x
+    else
+      v
+    end
+  end
+
+  # Lookup a variable within this scope using the Puppet language's
+  # scoping rules. Variables can be qualified using just as in a
+  # manifest.
+  #
+  # @param [String] name the variable name to lookup
+  #
+  # @return Object the value of the variable, or nil if it's not found
+  #
+  # @api public
+  def lookupvar(name, options = {})
+    unless name.is_a? String
+      raise Puppet::ParseError, "Scope variable name #{name.inspect} is a #{name.class}, not a string"
+    end
+
+    table = @ephemeral.last
+
+    if name =~ /^(.*)::(.+)$/
+      class_name = $1
+      variable_name = $2
+      lookup_qualified_variable(class_name, variable_name, options)
+
+    # TODO: optimize with an assoc instead, this searches through scopes twice for a hit
+    elsif table.include?(name)
+      table[name]
+    else
+      next_scope = inherited_scope || enclosing_scope
+      if next_scope
+        next_scope.lookupvar(name, options)
+      else
+        variable_not_found(name)
+      end
+    end
+  end
+
+  def variable_not_found(name, reason=nil)
+    # Built in variables always exist
+    if BUILT_IN_VARS.include?(name)
+      return nil
+    end
+    if Puppet[:strict_variables]
+      if Puppet.future_parser?
+        throw :undefined_variable
+      else
+        reason_msg = reason.nil? ? '' : "; #{reason}"
+        raise Puppet::ParseError, "Undefined variable #{name.inspect}#{reason_msg}"
+      end
+    else
+      nil
+    end
+  end
+
+  # Retrieves the variable value assigned to the name given as an argument. The name must be a String,
+  # and namespace can be qualified with '::'. The value is looked up in this scope, its parent scopes,
+  # or in a specific visible named scope.
+  #
+  # @param varname [String] the name of the variable (may be a qualified name using `(ns'::')*varname`
+  # @param options [Hash] Additional options, not part of api.
+  # @return [Object] the value assigned to the given varname
+  # @see #[]=
+  # @api public
+  #
+  def [](varname, options={})
+    lookupvar(varname, options)
+  end
+
+  # The scope of the inherited thing of this scope's resource. This could
+  # either be a node that was inherited or the class.
+  #
+  # @return [Puppet::Parser::Scope] The scope or nil if there is not an inherited scope
+  def inherited_scope
+    if has_inherited_class?
+      qualified_scope(resource.resource_type.parent)
+    else
+      nil
+    end
+  end
+
+  # The enclosing scope (topscope or nodescope) of this scope.
+  # The enclosing scopes are produced when a class or define is included at
+  # some point. The parent scope of the included class or define becomes the
+  # scope in which it was included. The chain of parent scopes is followed
+  # until a node scope or the topscope is found
+  #
+  # @return [Puppet::Parser::Scope] The scope or nil if there is no enclosing scope
+  def enclosing_scope
+    if has_enclosing_scope?
+      if parent.is_topscope? or parent.is_nodescope?
+        parent
+      else
+        parent.enclosing_scope
+      end
+    else
+      nil
+    end
+  end
+
+  def is_classscope?
+    resource and resource.type == "Class"
+  end
+
+  def is_nodescope?
+    resource and resource.type == "Node"
+  end
+
+  def is_topscope?
+    compiler and self == compiler.topscope
+  end
+
+  def lookup_qualified_variable(class_name, variable_name, position)
+    begin
+      if lookup_as_local_name?(class_name, variable_name)
+        if is_topscope?
+          # This is the case where $::x is looked up from within the topscope itself, or from a local scope
+          # parented at the top scope. In this case, the lookup must ignore local and ephemeral scopes.
+          #
+          handle_not_found(class_name, variable_name, position) unless @symtable.include?(variable_name)
+          @symtable[variable_name]
+        else
+          self[variable_name]
+        end
+      else
+        qualified_scope(class_name).lookupvar(variable_name, position)
+      end
+    rescue RuntimeError => e
+      handle_not_found(class_name, variable_name, position, e.message)
+    end
+  end
+
+  def handle_not_found(class_name, variable_name, position, reason = nil)
+    unless Puppet[:strict_variables]
+      # Do not issue warning if strict variables are on, as an error will be raised by variable_not_found
+      location = if position[:lineproc]
+                   " at #{position[:lineproc].call}"
+                 elsif position[:file] && position[:line]
+                   " at #{position[:file]}:#{position[:line]}"
+                 else
+                   ""
+                 end
+      warning "Could not look up qualified variable '#{class_name}::#{variable_name}'; #{reason}#{location}"
+    end
+    variable_not_found("#{class_name}::#{variable_name}", reason)
+  end
+
+  # Handles the special case of looking up fully qualified variable in not yet evaluated top scope
+  # This is ok if the lookup request originated in topscope (this happens when evaluating
+  # bindings; using the top scope to provide the values for facts.
+  # @param class_name [String] the classname part of a variable name, may be special ""
+  # @param variable_name [String] the variable name without the absolute leading '::'
+  # @return [Boolean] true if the given variable name should be looked up directly in this scope
+  #
+  def lookup_as_local_name?(class_name, variable_name)
+    # not a local if name has more than one segment
+    return nil if variable_name =~ /::/
+    # partial only if the class for "" cannot be found
+    return nil unless class_name == "" && klass = find_hostclass(class_name) && class_scope(klass).nil?
+    is_topscope?
+  end
+
+  def has_inherited_class?
+    is_classscope? and resource.resource_type.parent
+  end
+  private :has_inherited_class?
+
+  def has_enclosing_scope?
+    not parent.nil?
+  end
+  private :has_enclosing_scope?
+
+  def qualified_scope(classname)
+    raise "class #{classname} could not be found"     unless klass = find_hostclass(classname)
+    raise "class #{classname} has not been evaluated" unless kscope = class_scope(klass)
+    kscope
+  end
+  private :qualified_scope
+
+  # Returns a Hash containing all variables and their values, optionally (and
+  # by default) including the values defined in parent. Local values
+  # shadow parent values. Ephemeral scopes for match results ($0 - $n) are not included.
+  #
+  # This is currently a wrapper for to_hash_legacy or to_hash_future.
+  #
+  # @see to_hash_future
+  #
+  # @see to_hash_legacy
+  def to_hash(recursive = true)
+    @future_parser ||= Puppet.future_parser?
+    if @future_parser
+      to_hash_future(recursive)
+    else
+      to_hash_legacy(recursive)
+    end
+  end
+
+  # Fixed version of to_hash that implements scoping correctly (i.e., with
+  # dynamic scoping disabled #28200 / PUP-1220
+  #
+  # @see to_hash
+  def to_hash_future(recursive)
+    if recursive and has_enclosing_scope?
+      target = enclosing_scope.to_hash_future(recursive)
+      if !(inherited = inherited_scope).nil?
+        target.merge!(inherited.to_hash_future(recursive))
+      end
+    else
+      target = Hash.new
+    end
+
+    # add all local scopes
+    @ephemeral.last.add_entries_to(target)
+    target
+  end
+
+  # The old broken implementation of to_hash that retains the dynamic scoping
+  # semantics
+  #
+  # @see to_hash
+  def to_hash_legacy(recursive = true)
+    if recursive and parent
+      target = parent.to_hash_legacy(recursive)
+    else
+      target = Hash.new
+    end
+
+    # add all local scopes
+    @ephemeral.last.add_entries_to(target)
+    target
+  end
+
+  def namespaces
+    @namespaces.dup
+  end
+
+  # Create a new scope and set these options.
+  def newscope(options = {})
+    compiler.newscope(self, options)
+  end
+
+  def parent_module_name
+    return nil unless @parent
+    return nil unless @parent.source
+    @parent.source.module_name
+  end
+
+  # Set defaults for a type.  The typename should already be downcased,
+  # so that the syntax is isolated.  We don't do any kind of type-checking
+  # here; instead we let the resource do it when the defaults are used.
+  def define_settings(type, params)
+    table = @defaults[type]
+
+    # if we got a single param, it'll be in its own array
+    params = [params] unless params.is_a?(Array)
+
+    params.each { |param|
+      if table.include?(param.name)
+        raise Puppet::ParseError.new("Default already defined for #{type} { #{param.name} }; cannot redefine", param.line, param.file)
+      end
+      table[param.name] = param
+    }
+  end
+
+  RESERVED_VARIABLE_NAMES = ['trusted', 'facts'].freeze
+
+  # Set a variable in the current scope.  This will override settings
+  # in scopes above, but will not allow variables in the current scope
+  # to be reassigned.
+  #   It's preferred that you use self[]= instead of this; only use this
+  # when you need to set options.
+  def setvar(name, value, options = {})
+    if name =~ /^[0-9]+$/
+      raise Puppet::ParseError.new("Cannot assign to a numeric match result variable '$#{name}'") # unless options[:ephemeral]
+    end
+    unless name.is_a? String
+      raise Puppet::ParseError, "Scope variable name #{name.inspect} is a #{name.class}, not a string"
+    end
+
+    # Check for reserved variable names
+    if @enable_immutable_data && !options[:privileged] && RESERVED_VARIABLE_NAMES.include?(name)
+      raise Puppet::ParseError, "Attempt to assign to a reserved variable name: '#{name}'"
+    end
+
+    table = effective_symtable(options[:ephemeral])
+    if table.bound?(name)
+      if options[:append]
+        error = Puppet::ParseError.new("Cannot append, variable #{name} is defined in this scope")
+      else
+        error = Puppet::ParseError.new("Cannot reassign variable #{name}")
+      end
+      error.file = options[:file] if options[:file]
+      error.line = options[:line] if options[:line]
+      raise error
+    end
+
+    if options[:append]
+      # produced result (value) is the resulting appended value, note: the table[]= does not return the value
+      table[name] = (value = append_value(undef_as('', self[name]), value))
+    else
+      table[name] = value
+    end
+    value
+  end
+
+  def set_trusted(hash)
+    setvar('trusted', deep_freeze(hash), :privileged => true)
+  end
+
+  def set_facts(hash)
+    # Remove _timestamp (it has an illegal datatype). It is not allowed to mutate the given hash
+    # since it contains the facts.
+    hash = hash.dup
+    hash.delete('_timestamp')
+    setvar('facts', deep_freeze(hash), :privileged => true)
+  end
+
+  # Deeply freezes the given object. The object and its content must be of the types:
+  # Array, Hash, Numeric, Boolean, Symbol, Regexp, NilClass, or String. All other types raises an Error.
+  # (i.e. if they are assignable to Puppet::Pops::Types::Data type).
+  #
+  def deep_freeze(object)
+    case object
+    when Array
+      object.each {|v| deep_freeze(v) }
+      object.freeze
+    when Hash
+      object.each {|k, v| deep_freeze(k); deep_freeze(v) }
+      object.freeze
+    when NilClass, Numeric, TrueClass, FalseClass
+      # do nothing
+    when String
+      object.freeze
+    else
+      raise Puppet::Error, "Unsupported data type: '#{object.class}'"
+    end
+    object
+  end
+  private :deep_freeze
+
+  # Return the effective "table" for setting variables.
+  # This method returns the first ephemeral "table" that acts as a local scope, or this
+  # scope's symtable. If the parameter `use_ephemeral` is true, the "top most" ephemeral "table"
+  # will be returned (irrespective of it being a match scope or a local scope).
+  #
+  # @param use_ephemeral [Boolean] whether the top most ephemeral (of any kind) should be used or not
+  def effective_symtable(use_ephemeral)
+    s = @ephemeral.last
+    if use_ephemeral
+      return s || @symtable
+    else
+      while s && !s.is_local_scope?()
+        s = s.parent
+      end
+      s || @symtable
+    end
+  end
+
+  # Sets the variable value of the name given as an argument to the given value. The value is
+  # set in the current scope and may shadow a variable with the same name in a visible outer scope.
+  # It is illegal to re-assign a variable in the same scope. It is illegal to set a variable in some other
+  # scope/namespace than the scope passed to a method.
+  #
+  # @param varname [String] The variable name to which the value is assigned. Must not contain `::`
+  # @param value [String] The value to assign to the given variable name.
+  # @param options [Hash] Additional options, not part of api.
+  #
+  # @api public
+  #
+  def []=(varname, value, options = {})
+    setvar(varname, value, options = {})
+  end
+
+  def append_value(bound_value, new_value)
+    case new_value
+    when Array
+      bound_value + new_value
+    when Hash
+      bound_value.merge(new_value)
+    else
+      if bound_value.is_a?(Hash)
+        raise ArgumentError, "Trying to append to a hash with something which is not a hash is unsupported"
+      end
+      bound_value + new_value
+    end
+  end
+  private :append_value
+
+  # Return the tags associated with this scope.
+  def_delegator :resource, :tags
+
+  # Used mainly for logging
+  def to_s
+    "Scope(#{@resource})"
+  end
+
+  alias_method :inspect, :to_s
+
+  # remove ephemeral scope up to level
+  # TODO: Who uses :all ? Remove ??
+  #
+  def unset_ephemeral_var(level=:all)
+    if level == :all
+      @ephemeral = [ MatchScope.new(@symtable, nil)]
+    else
+      @ephemeral.pop(@ephemeral.size - level)
+    end
+  end
+
+  def ephemeral_level
+    @ephemeral.size
+  end
+
+  # TODO: Who calls this?
+  def new_ephemeral(local_scope = false)
+    if local_scope
+      @ephemeral.push(LocalScope.new(@ephemeral.last))
+    else
+      @ephemeral.push(MatchScope.new(@ephemeral.last, nil))
+    end
+  end
+
+  # Sets match data in the most nested scope (which always is a MatchScope), it clobbers match data already set there
+  #
+  def set_match_data(match_data)
+    @ephemeral.last.match_data = match_data
+  end
+
+  # Nests a match data scope
+  def new_match_scope(match_data)
+    @ephemeral.push(MatchScope.new(@ephemeral.last, match_data))
+  end
+
+  def ephemeral_from(match, file = nil, line = nil)
+    case match
+    when Hash
+      # Create local scope ephemeral and set all values from hash
+      new_ephemeral(true)
+      match.each {|k,v| setvar(k, v, :file => file, :line => line, :ephemeral => true) }
+      # Must always have an inner match data scope (that starts out as transparent)
+      # In 3x slightly wasteful, since a new nested scope is created for a match 
+      # (TODO: Fix that problem)
+      new_ephemeral(false)
+    else
+      raise(ArgumentError,"Invalid regex match data. Got a #{match.class}") unless match.is_a?(MatchData)
+      # Create a match ephemeral and set values from match data
+      new_match_scope(match)
+    end
+  end
+
+  def find_resource_type(type)
+    # It still works fine without the type == 'class' short-cut, but it is a lot slower.
+    return nil if ["class", "node"].include? type.to_s.downcase
+    find_builtin_resource_type(type) || find_defined_resource_type(type)
+  end
+
+  def find_builtin_resource_type(type)
+    Puppet::Type.type(type.to_s.downcase.to_sym)
+  end
+
+  def find_defined_resource_type(type)
+    known_resource_types.find_definition(namespaces, type.to_s.downcase)
+  end
+
+
+  def method_missing(method, *args, &block)
+    method.to_s =~ /^function_(.*)$/
+    name = $1
+    super unless name
+    super unless Puppet::Parser::Functions.function(name)
+    # In odd circumstances, this might not end up defined by the previous
+    # method, so we might as well be certain.
+    if respond_to? method
+      send(method, *args)
+    else
+      raise Puppet::DevError, "Function #{name} not defined despite being loaded!"
+    end
+  end
+
+  def resolve_type_and_titles(type, titles)
+    raise ArgumentError, "titles must be an array" unless titles.is_a?(Array)
+
+    case type.downcase
+    when "class"
+      # resolve the titles
+      titles = titles.collect do |a_title|
+        hostclass = find_hostclass(a_title)
+        hostclass ?  hostclass.name : a_title
+      end
+    when "node"
+      # no-op
+    else
+      # resolve the type
+      resource_type = find_resource_type(type)
+      type = resource_type.name if resource_type
+    end
+
+    return [type, titles]
+  end
+
+  # Transforms references to classes to the form suitable for
+  # lookup in the compiler.
+  #
+  # Makes names passed in the names array absolute if they are relative
+  # Names are now made absolute if Puppet.future_parser? is true, this will
+  # be the default behavior in Puppet 4.0
+  #
+  # Transforms Class[] and Resource[] type referenes to class name
+  # or raises an error if a Class[] is unspecific, if a Resource is not
+  # a 'class' resource, or if unspecific (no title).
+  #
+  # TODO: Change this for 4.0 to always make names absolute
+  #
+  # @param names [Array<String>] names to (optionally) make absolute
+  # @return [Array<String>] names after transformation
+  #
+  def transform_and_assert_classnames(names)
+    if Puppet.future_parser?
+      names.map do |name|
+        case name
+        when String
+          name.sub(/^([^:]{1,2})/, '::\1')
+
+        when Puppet::Resource
+          assert_class_and_title(name.type, name.title)
+          name.title.sub(/^([^:]{1,2})/, '::\1')
+
+        when Puppet::Pops::Types::PHostClassType
+          raise ArgumentError, "Cannot use an unspecific Class[] Type" unless name.class_name
+          name.class_name.sub(/^([^:]{1,2})/, '::\1')
+
+        when Puppet::Pops::Types::PResourceType
+          assert_class_and_title(name.type_name, name.title)
+          name.title.sub(/^([^:]{1,2})/, '::\1')
+        end
+      end
+    else
+      names
+    end
+  end
+
+  # Calls a 3.x or 4.x function by name with arguments given in an array using the 4.x calling convention
+  # and returns the result.
+  # Note that it is the caller's responsibility to rescue the given ArgumentError and provide location information
+  # to aid the user find the problem. The problem is otherwise reported against the source location that
+  # invoked the function that ultimately called this method.
+  #
+  # @return [Object] the result of the called function
+  # @raise ArgumentError if the function does not exist
+  def call_function(func_name, args, &block)
+    if !Puppet.future_parser?(compiler.environment)
+      return self.send("function_#{func_name}", args, &block)
+    else
+      Puppet::Pops::Parser::EvaluatingParser.new.evaluator.external_call_function(func_name, args, self, &block)
+    end
+  end
+
+  private
+
+  def assert_class_and_title(type_name, title)
+    if type_name.nil? || type_name == ''
+      raise ArgumentError, "Cannot use an unspecific Resource[] where a Resource['class', name] is expected"
+    end
+    unless type_name =~ /^[Cc]lass$/
+      raise ArgumentError, "Cannot use a Resource[#{type_name}] where a Resource['class', name] is expected"
+    end
+    if title.nil?
+      raise ArgumentError, "Cannot use an unspecific Resource['class'] where a Resource['class', name] is expected"
+    end
+  end
+
+  def extend_with_functions_module
+    root = Puppet.lookup(:root_environment)
+    extend Puppet::Parser::Functions.environment_module(root)
+    extend Puppet::Parser::Functions.environment_module(environment) if environment != root
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/templatewrapper.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/templatewrapper.rb
new file mode 100644
index 0000000..6623955
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/templatewrapper.rb
@@ -0,0 +1,128 @@
+require 'puppet/parser/files'
+require 'erb'
+require 'puppet/file_system'
+
+# A simple wrapper for templates, so they don't have full access to
+# the scope objects.
+#
+# @api private
+class Puppet::Parser::TemplateWrapper
+  include Puppet::Util
+  Puppet::Util.logmethods(self)
+
+  def initialize(scope)
+    @__scope__ = scope
+  end
+
+  # @return [String] The full path name of the template that is being executed
+  # @api public
+  def file
+    @__file__
+  end
+
+  # @return [Puppet::Parser::Scope] The scope in which the template is evaluated
+  # @api public
+  def scope
+    @__scope__
+  end
+
+  # Find which line in the template (if any) we were called from.
+  # @return [String] the line number
+  # @api private
+  def script_line
+    identifier = Regexp.escape(@__file__ || "(erb)")
+    (caller.find { |l| l =~ /#{identifier}:/ }||"")[/:(\d+):/,1]
+  end
+  private :script_line
+
+  # Should return true if a variable is defined, false if it is not
+  # @api public
+  def has_variable?(name)
+    scope.include?(name.to_s)
+  end
+
+  # @return [Array<String>] The list of defined classes
+  # @api public
+  def classes
+    scope.catalog.classes
+  end
+
+  # @return [Array<String>] The tags defined in the current scope
+  # @api public
+  def tags
+    scope.tags
+  end
+
+  # @return [Array<String>] All the defined tags
+  # @api public
+  def all_tags
+    scope.catalog.tags
+  end
+
+  # Ruby treats variables like methods, so we used to expose variables
+  # within scope to the ERB code via method_missing.  As per RedMine #1427,
+  # though, this means that conflicts between methods in our inheritance
+  # tree (Kernel#fork) and variable names (fork => "yes/no") could arise.
+  #
+  # Worse, /new/ conflicts could pop up when a new kernel or object method
+  # was added to Ruby, causing templates to suddenly fail mysteriously when
+  # Ruby was upgraded.
+  #
+  # To ensure that legacy templates using unqualified names work we retain
+  # the missing_method definition here until we declare the syntax finally
+  # dead.
+  def method_missing(name, *args)
+    line_number = script_line
+    if scope.include?(name.to_s)
+      Puppet.deprecation_warning("Variable access via '#{name}' is deprecated. Use '@#{name}' instead. #{to_s}:#{line_number}")
+      return scope[name.to_s, { :file => @__file__, :line => line_number }]
+    else
+      # Just throw an error immediately, instead of searching for
+      # other missingmethod things or whatever.
+      raise Puppet::ParseError.new("Could not find value for '#{name}'", @__file__, line_number)
+    end
+  end
+
+  # @api private
+  def file=(filename)
+    unless @__file__ = Puppet::Parser::Files.find_template(filename, scope.compiler.environment)
+      raise Puppet::ParseError, "Could not find template '#{filename}'"
+    end
+
+    # We'll only ever not have a parser in testing, but, eh.
+    scope.known_resource_types.watch_file(@__file__)
+  end
+
+  # @api private
+  def result(string = nil)
+    if string
+      template_source = "inline template"
+    else
+      string = Puppet::FileSystem.read_preserve_line_endings(@__file__)
+      template_source = @__file__
+    end
+
+    # Expose all the variables in our scope as instance variables of the
+    # current object, making it possible to access them without conflict
+    # to the regular methods.
+    benchmark(:debug, "Bound template variables for #{template_source}") do
+      scope.to_hash.each do |name, value|
+        realname = name.gsub(/[^\w]/, "_")
+        instance_variable_set("@#{realname}", value)
+      end
+    end
+
+    result = nil
+    benchmark(:debug, "Interpolated template #{template_source}") do
+      template = ERB.new(string, 0, "-")
+      template.filename = @__file__
+      result = template.result(binding)
+    end
+
+    result
+  end
+
+  def to_s
+    "template[#{(@__file__ ? @__file__ : "inline")}]"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/type_loader.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/type_loader.rb
new file mode 100644
index 0000000..2f6c772
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/type_loader.rb
@@ -0,0 +1,152 @@
+require 'find'
+require 'forwardable'
+require 'puppet/node/environment'
+require 'puppet/parser/parser_factory'
+
+class Puppet::Parser::TypeLoader
+  extend  Forwardable
+
+  # Import manifest files that match a given file glob pattern.
+  #
+  # @param pattern [String] the file glob to apply when determining which files
+  #   to load
+  # @param dir [String] base directory to use when the file is not
+  #   found in a module
+  # @api private
+  def import(pattern, dir)
+    return if Puppet[:ignoreimport]
+
+    modname, files = Puppet::Parser::Files.find_manifests_in_modules(pattern, environment)
+    if files.empty?
+      abspat = File.expand_path(pattern, dir)
+      file_pattern = abspat + (File.extname(abspat).empty? ? '{.pp,.rb}' : '' )
+
+      files = Dir.glob(file_pattern).uniq.reject { |f| FileTest.directory?(f) }
+      modname = nil
+
+      if files.empty?
+        raise_no_files_found(pattern)
+      end
+    end
+
+    load_files(modname, files)
+  end
+
+  # Load all of the manifest files in all known modules.
+  # @api private
+  def import_all
+    # And then load all files from each module, but (relying on system
+    # behavior) only load files from the first module of a given name.  E.g.,
+    # given first/foo and second/foo, only files from first/foo will be loaded.
+    environment.modules.each do |mod|
+      load_files(mod.name, mod.all_manifests)
+    end
+  end
+
+  def_delegator :environment, :known_resource_types
+
+  def initialize(env)
+    self.environment = env
+  end
+
+  def environment
+    @environment
+  end
+
+  def environment=(env)
+    if env.is_a?(String) or env.is_a?(Symbol)
+      @environment = Puppet.lookup(:environments).get!(env)
+    else
+      @environment = env
+    end
+  end
+
+  # Try to load the object with the given fully qualified name.
+  def try_load_fqname(type, fqname)
+    return nil if fqname == "" # special-case main.
+    files_to_try_for(fqname).each do |filename|
+      begin
+        imported_types = import_from_modules(filename)
+        if result = imported_types.find { |t| t.type == type and t.name == fqname }
+          Puppet.debug "Automatically imported #{fqname} from #{filename} into #{environment}"
+          return result
+        end
+      rescue Puppet::ImportError => detail
+        # I'm not convienced we should just drop these errors, but this
+        # preserves existing behaviours.
+      end
+    end
+    # Nothing found.
+    return nil
+  end
+
+  def parse_file(file)
+    Puppet.debug("importing '#{file}' in environment #{environment}")
+    parser = Puppet::Parser::ParserFactory.parser(environment)
+    parser.file = file
+    return parser.parse
+  end
+
+  private
+
+  def import_from_modules(pattern)
+    modname, files = Puppet::Parser::Files.find_manifests_in_modules(pattern, environment)
+    if files.empty?
+      raise_no_files_found(pattern)
+    end
+
+    load_files(modname, files)
+  end
+
+  def raise_no_files_found(pattern)
+    raise Puppet::ImportError, "No file(s) found for import of '#{pattern}'"
+  end
+
+  def load_files(modname, files)
+    @loaded ||= {}
+    loaded_asts = []
+    files.reject { |file| @loaded[file] }.each do |file|
+      # NOTE: This ugly implementation will be replaced in Puppet 3.5.
+      # The implementation now makes use of a global variable because the context support is
+      # not available until Puppet 3.5.
+      # The use case is that parsing for the purpose of searching for information
+      # should not abort. There is currently one such use case in indirector/resourcetype/parser
+      #
+    if Puppet.lookup(:squelch_parse_errors) {|| false }
+        begin
+          loaded_asts << parse_file(file)
+        rescue => e
+          # Resume from errors so that all parseable files would
+          # still be parsed. Mark this file as loaded so that
+          # it would not be parsed next time (handle it as if
+          # it was successfully parsed).
+          Puppet.debug("Unable to parse '#{file}': #{e.message}")
+        end
+      else
+        loaded_asts << parse_file(file)
+      end
+
+      @loaded[file] = true
+    end
+
+    loaded_asts.collect do |ast|
+      known_resource_types.import_ast(ast, modname)
+    end.flatten
+  end
+
+  # Return a list of all file basenames that should be tried in order
+  # to load the object with the given fully qualified name.
+  def files_to_try_for(qualified_name)
+    qualified_name.split('::').inject([]) do |paths, name|
+      add_path_for_name(paths, name)
+    end
+  end
+
+  def add_path_for_name(paths, name)
+    if paths.empty?
+      [name]
+    else
+      paths.unshift(File.join(paths.first, name))
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/yaml_trimmer.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/yaml_trimmer.rb
new file mode 100644
index 0000000..657ce9d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/parser/yaml_trimmer.rb
@@ -0,0 +1,7 @@
+module Puppet::Parser::YamlTrimmer
+  REMOVE = [:@scope, :@source]
+
+  def to_yaml_properties
+    super - REMOVE
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops.rb
new file mode 100644
index 0000000..5b4fddb
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops.rb
@@ -0,0 +1,132 @@
+module Puppet
+  # The Pops language system. This includes the parser, evaluator, AST model, and
+  # Binder.
+  #
+  # @todo Explain how a user should use this to parse and evaluate the puppet
+  #   language.
+  #
+  # @note Warning: Pops is still considered experimental, as such the API may
+  #   change at any time.
+  #
+  # @api public
+  module Pops
+    require 'puppet/pops/patterns'
+    require 'puppet/pops/utils'
+
+    require 'puppet/pops/adaptable'
+    require 'puppet/pops/adapters'
+
+    require 'puppet/pops/visitable'
+    require 'puppet/pops/visitor'
+
+    require 'puppet/pops/containment'
+
+    require 'puppet/pops/issues'
+    require 'puppet/pops/semantic_error'
+    require 'puppet/pops/label_provider'
+    require 'puppet/pops/validation'
+    require 'puppet/pops/issue_reporter'
+
+    require 'puppet/pops/model/model'
+
+    # (the Types module initializes itself)
+    require 'puppet/pops/types/types'
+    require 'puppet/pops/types/type_calculator'
+    require 'puppet/pops/types/type_factory'
+    require 'puppet/pops/types/type_parser'
+    require 'puppet/pops/types/class_loader'
+    require 'puppet/pops/types/enumeration'
+
+
+    module Model
+      require 'puppet/pops/model/tree_dumper'
+      require 'puppet/pops/model/ast_transformer'
+      require 'puppet/pops/model/ast_tree_dumper'
+      require 'puppet/pops/model/factory'
+      require 'puppet/pops/model/model_tree_dumper'
+      require 'puppet/pops/model/model_label_provider'
+    end
+
+    module Binder
+      module SchemeHandler
+        # the handlers are auto loaded via bindings
+      end
+      module Producers
+        require 'puppet/pops/binder/producers'
+      end
+
+      require 'puppet/pops/binder/binder'
+      require 'puppet/pops/binder/bindings_model'
+      require 'puppet/pops/binder/binder_issues'
+      require 'puppet/pops/binder/bindings_checker'
+      require 'puppet/pops/binder/bindings_factory'
+      require 'puppet/pops/binder/bindings_label_provider'
+      require 'puppet/pops/binder/bindings_validator_factory'
+      require 'puppet/pops/binder/injector_entry'
+      require 'puppet/pops/binder/key_factory'
+      require 'puppet/pops/binder/injector'
+      require 'puppet/pops/binder/bindings_composer'
+      require 'puppet/pops/binder/bindings_model_dumper'
+      require 'puppet/pops/binder/system_bindings'
+      require 'puppet/pops/binder/bindings_loader'
+      require 'puppet/pops/binder/lookup'
+
+      module Config
+        require 'puppet/pops/binder/config/binder_config'
+        require 'puppet/pops/binder/config/binder_config_checker'
+        require 'puppet/pops/binder/config/issues'
+        require 'puppet/pops/binder/config/diagnostic_producer'
+      end
+    end
+
+    module Parser
+      require 'puppet/pops/parser/eparser'
+      require 'puppet/pops/parser/parser_support'
+      require 'puppet/pops/parser/locator'
+      require 'puppet/pops/parser/locatable'
+      require 'puppet/pops/parser/lexer2'
+      require 'puppet/pops/parser/evaluating_parser'
+      require 'puppet/pops/parser/epp_parser'
+    end
+
+    module Validation
+      require 'puppet/pops/validation/checker4_0'
+      require 'puppet/pops/validation/validator_factory_4_0'
+    end
+
+    module Evaluator
+      require 'puppet/pops/evaluator/callable_signature'
+      require 'puppet/pops/evaluator/runtime3_converter'
+      require 'puppet/pops/evaluator/runtime3_support'
+      require 'puppet/pops/evaluator/evaluator_impl'
+      require 'puppet/pops/evaluator/epp_evaluator'
+      require 'puppet/pops/evaluator/callable_mismatch_describer'
+      require 'puppet/pops/evaluator/collector_transformer'
+      require 'puppet/pops/evaluator/puppet_proc'
+      module Collectors
+        require 'puppet/pops/evaluator/collectors/abstract_collector'
+        require 'puppet/pops/evaluator/collectors/fixed_set_collector'
+        require 'puppet/pops/evaluator/collectors/catalog_collector'
+        require 'puppet/pops/evaluator/collectors/exported_collector'
+      end
+    end
+
+    # Subsystem for puppet functions defined in ruby.
+    #
+    # @api public
+    module Functions
+      require 'puppet/pops/functions/function'
+      require 'puppet/pops/functions/dispatch'
+      require 'puppet/pops/functions/dispatcher'
+    end
+
+    module Migration
+      require 'puppet/pops/migration/migration_checker'
+    end
+  end
+
+  require 'puppet/parser/ast/pops_bridge'
+  require 'puppet/bindings'
+  require 'puppet/functions'
+  require 'puppet/loaders'
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/adaptable.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/adaptable.rb
new file mode 100644
index 0000000..a7df1e4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/adaptable.rb
@@ -0,0 +1,190 @@
+# Adaptable is a mix-in module that adds adaptability to a class.
+# This means that an adapter can
+# associate itself with an instance of the class and store additional data/have behavior.
+#
+# This mechanism should be used when there is a desire to keep implementation concerns separate.
+# In Ruby it is always possible to open and modify a class or instance to teach it new tricks, but it
+# is however not possible to do this for two different versions of some service at the same time.
+# The Adaptable pattern is also good when only a few of the objects of some class needs to have extra
+# information (again possible in Ruby by adding instance variables dynamically). In fact, the implementation
+# of Adaptable does just that; it adds an instance variable named after the adapter class and keeps an
+# instance of this class in this slot.
+#
+# @note the implementation details; the fact that an instance variable is used to keep the adapter
+#   instance data should not
+#   be exploited as the implementation of _being adaptable_ may change in the future.
+# @api private
+#
+module Puppet::Pops::Adaptable
+  # Base class for an Adapter.
+  #
+  # A typical adapter just defines some accessors.
+  #
+  # A more advanced adapter may need to setup the adapter based on the object it is adapting.
+  # @example Making Duck adaptable
+  #   class Duck
+  #     include Puppet::Pops::Adaptable
+  #   end
+  # @example Giving a Duck a nick name
+  #   class NickNameAdapter < Puppet::Pops::Adaptable::Adapter
+  #     attr_accessor :nick_name
+  #   end
+  #   d = Duck.new
+  #   NickNameAdapter.adapt(d).nick_name = "Daffy"
+  #   NickNameAdapter.get(d).nick_name # => "Daffy"
+  #
+  # @example Giving a Duck a more elaborate nick name
+  #   class NickNameAdapter < Puppet::Pops::Adaptable::Adapter
+  #     attr_accessor :nick_name, :object
+  #     def initialize o
+  #       @object = o
+  #       @nick_name = "Yo"
+  #     end
+  #     def nick_name
+  #       "#{@nick_name}, the #{o.class.name}"
+  #     end
+  #     def NickNameAdapter.create_adapter(o)
+  #       x = new o
+  #       x
+  #     end
+  #   end
+  #   d = Duck.new
+  #   n = NickNameAdapter.adapt(d)
+  #   n.nick_name # => "Yo, the Duck"
+  #   n.nick_name = "Daffy"
+  #   n.nick_name # => "Daffy, the Duck"
+  # @example Using a block to set values
+  #   NickNameAdapter.adapt(o) { |a| a.nick_name = "Buddy!" }
+  #   NickNameAdapter.adapt(o) { |a, o| a.nick_name = "You're the best #{o.class.name} I met."}
+  #
+  class Adapter
+    # Returns an existing adapter for the given object, or nil, if the object is not
+    # adapted.
+    #
+    # @param o [Adaptable] object to get adapter from
+    # @return [Adapter<self>] an adapter of the same class as the receiver of #get
+    # @return [nil] if the given object o has not been adapted by the receiving adapter
+    # @raise [ArgumentError] if the object is not adaptable
+    #
+    def self.get(o)
+      attr_name = :"@#{instance_var_name(self.name)}"
+      if o.instance_variable_defined?(attr_name)
+        o.instance_variable_get(attr_name)
+      else
+        nil
+      end
+    end
+
+    # Returns an existing adapter for the given object, or creates a new adapter if the
+    # object has not been adapted, or the adapter has been cleared.
+    #
+    # @example Using a block to set values
+    #   NickNameAdapter.adapt(o) { |a| a.nick_name = "Buddy!" }
+    #   NickNameAdapter.adapt(o) { |a, o| a.nick_name = "Your the best #{o.class.name} I met."}
+    # @overload adapt(o)
+    # @overload adapt(o, {|adapter| block})
+    # @overload adapt(o, {|adapter, o| block})
+    # @param o [Adaptable] object to add adapter to
+    # @yieldparam adapter [Adapter<self>] the created adapter
+    # @yieldparam o [Adaptable] optional, the given adaptable
+    # @param block [Proc] optional, evaluated in the context of the adapter (existing or new)
+    # @return [Adapter<self>] an adapter of the same class as the receiver of the call
+    # @raise [ArgumentError] if the given object o is not adaptable
+    #
+    def self.adapt(o, &block)
+      attr_name = :"@#{instance_var_name(self.name)}"
+      adapter = if o.instance_variable_defined?(attr_name) && value = o.instance_variable_get(attr_name)
+        value
+      else
+        associate_adapter(create_adapter(o), o)
+      end
+      if block_given?
+        case block.arity
+          when 1
+            block.call(adapter)
+          else
+            block.call(adapter, o)
+        end
+      end
+      adapter
+    end
+
+    # Creates a new adapter, associates it with the given object and returns the adapter.
+    #
+    # @example Using a block to set values
+    #   NickNameAdapter.adapt_new(o) { |a| a.nick_name = "Buddy!" }
+    #   NickNameAdapter.adapt_new(o) { |a, o| a.nick_name = "Your the best #{o.class.name} I met."}
+    # This is used when a fresh adapter is wanted instead of possible returning an
+    # existing adapter as in the case of {Adapter.adapt}.
+    # @overload adapt_new(o)
+    # @overload adapt_new(o, {|adapter| block})
+    # @overload adapt_new(o, {|adapter, o| block})
+    # @yieldparam adapter [Adapter<self>] the created adapter
+    # @yieldparam o [Adaptable] optional, the given adaptable
+    # @param o [Adaptable] object to add adapter to
+    # @param block [Proc] optional, evaluated in the context of the new adapter
+    # @return [Adapter<self>] an adapter of the same class as the receiver of the call
+    # @raise [ArgumentError] if the given object o is not adaptable
+    #
+    def self.adapt_new(o, &block)
+      adapter = associate_adapter(create_adapter(o), o)
+      if block_given?
+        case block.arity
+        when 1
+          block.call(adapter)
+        else
+          block.call(adapter, o)
+        end
+      end
+      adapter
+    end
+
+    # Clears the adapter set in the given object o. Returns any set adapter or nil.
+    # @param o [Adaptable] the object where the adapter should be cleared
+    # @return [Adapter] if an adapter was set
+    # @return [nil] if the adapter has not been set
+    #
+    def self.clear(o)
+      attr_name = :"@#{instance_var_name(self.name)}"
+      if o.instance_variable_defined?(attr_name)
+        o.send(:remove_instance_variable, attr_name)
+      else
+        nil
+      end
+    end
+
+    # This base version creates an instance of the class (i.e. an instance of the concrete subclass
+    # of Adapter). A Specialization may want to create an adapter instance specialized for the given target
+    # object.
+    # @param o [Adaptable] The object to adapt. This implementation ignores this variable, but a
+    #   specialization may want to initialize itself differently depending on the object it is adapting.
+    # @return [Adapter<self>] instance of the subclass of Adapter receiving the call
+    #
+    def self.create_adapter(o)
+      new
+    end
+
+    # Associates the given adapter with the given target object
+    # @param adapter [Adapter] the adapter to associate with the given object _o_
+    # @param o [Adaptable] the object to adapt
+    # @return [adapter] the given adapter
+    #
+    def self.associate_adapter(adapter, o)
+      attr_name = :"@#{instance_var_name(adapter.class.name)}"
+      o.instance_variable_set(attr_name, adapter)
+      adapter
+    end
+
+    # Returns a suitable instance variable name given a class name.
+    # The returned string is the fully qualified name of a class with '::' replaced by '_' since
+    # '::' is not allowed in an instance variable name.
+    # @param name [String] the fully qualified name of a class
+    # @return [String] the name with all '::' replaced by '_'
+    # @api private
+    # @private
+    #
+    def self.instance_var_name(name)
+      name.split("::").join('_')
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/adapters.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/adapters.rb
new file mode 100644
index 0000000..05af117
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/adapters.rb
@@ -0,0 +1,109 @@
+# The Adapters module contains adapters for Documentation, Origin, SourcePosition, and Loader.
+#
+module Puppet::Pops::Adapters
+  # A documentation adapter adapts an object with a documentation string.
+  # (The intended use is for a source text parser to extract documentation and store this
+  # in DocumentationAdapter instances).
+  #
+  class DocumentationAdapter < Puppet::Pops::Adaptable::Adapter
+    # @return [String] The documentation associated with an object
+    attr_accessor :documentation
+  end
+
+  # A SourcePosAdapter holds a reference to  a *Positioned* object (object that has offset and length).
+  # This somewhat complex structure makes it possible to correctly refer to a source position
+  # in source that is embedded in some resource; a parser only sees the embedded snippet of source text
+  # and does not know where it was embedded. It also enables lazy evaluation of source positions (they are
+  # rarely needed - typically just when there is an error to report.
+  #
+  # @note It is relatively expensive to compute line and position on line - it is not something that
+  #   should be done for every token or model object.
+  #
+  # @see Puppet::Pops::Utils#find_adapter, Puppet::Pops::Utils#find_closest_positioned
+  #
+  class SourcePosAdapter < Puppet::Pops::Adaptable::Adapter
+    attr_accessor :locator
+
+    def self.create_adapter(o)
+      new(o)
+    end
+
+    def initialize(o)
+      @adapted = o
+    end
+
+    def locator
+      # The locator is always the parent locator, all positioned objects are positioned within their
+      # parent. If a positioned object also has a locator that locator is for its children!
+      #
+      @locator ||= find_locator(@adapted.eContainer)
+    end
+
+    def find_locator(o)
+      if o.nil?
+        raise ArgumentError, "InternalError: SourcePosAdapter for something that has no locator among parents"
+      end
+      case
+      when o.is_a?(Puppet::Pops::Model::Program)
+        return o.locator
+      # TODO_HEREDOC use case of SubLocator instead
+      when o.is_a?(Puppet::Pops::Model::SubLocatedExpression) && !(found_locator = o.locator).nil?
+        return found_locator
+      when adapter = self.class.get(o)
+        return adapter.locator
+      else
+        find_locator(o.eContainer)
+      end
+    end
+    private :find_locator
+
+    def offset
+      @adapted.offset
+    end
+
+    def length
+      @adapted.length
+    end
+
+    # Produces the line number for the given offset.
+    # @note This is an expensive operation
+    #
+    def line
+      # Optimization: manual inlining of locator accessor since this method is frequently called
+      (@locator ||= find_locator(@adapted.eContainer)).line_for_offset(offset)
+    end
+
+    # Produces the position on the line of the given offset.
+    # @note This is an expensive operation
+    #
+    def pos
+      locator.pos_on_line(offset)
+    end
+
+    # Extracts the text represented by this source position (the string is obtained from the locator)
+    def extract_text
+      locator.string.slice(offset, length)
+    end
+
+    # Produces an URI with path?line=n&pos=n. If origin is unknown the URI is string:?line=n&pos=n
+    def to_uri
+      f = locator.file
+      f = 'string:' if f.nil? || f.empty?
+      URI("#{f}?line=#{line.to_s}&pos=#{pos.to_s}")
+    end
+  end
+
+  # A LoaderAdapter adapts an object with a {Puppet::Pops::Loader}. This is used to make further loading from the
+  # perspective of the adapted object take place in the perspective of this Loader.
+  #
+  # It is typically enough to adapt the root of a model as a search is made towards the root of the model
+  # until a loader is found, but there is no harm in duplicating this information provided a contained
+  # object is adapted with the correct loader.
+  #
+  # @see Puppet::Pops::Utils#find_adapter
+  #
+  class LoaderAdapter < Puppet::Pops::Adaptable::Adapter
+    # @return [Puppet::Pops::Loader::Loader] the loader
+    attr_accessor :loader
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/binder.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/binder.rb
new file mode 100644
index 0000000..54620db
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/binder.rb
@@ -0,0 +1,393 @@
+# The Binder is responsible for processing layered bindings that can be used to setup an Injector.
+#
+# An instance should be created and a call to {#define_layers} should be made which will process the layered bindings
+# (handle overrides, abstract entries etc.).
+# The constructed hash with `key => InjectorEntry` mappings is obtained as {#injector_entries}, and is used to initialize an
+# {Puppet::Pops::Binder::Injector Injector}.
+#
+# @api public
+#
+class Puppet::Pops::Binder::Binder
+
+  # @api private
+  attr_reader :injector_entries
+
+  # @api private
+  attr :id_index
+
+  # @api private
+  attr_reader :key_factory
+
+  # A parent Binder or nil
+  # @api private
+  attr_reader :parent
+
+  # The next anonymous key to use
+  # @api private
+  attr_reader :anonymous_key
+
+  # This binder's precedence
+  # @api private
+  attr_reader :binder_precedence
+
+  # @api public
+  def initialize(layered_bindings, parent_binder=nil)
+    @parent = parent_binder
+    @id_index = Hash.new() { |k, v| [] }
+
+    @key_factory = Puppet::Pops::Binder::KeyFactory.new()
+
+    # Resulting hash of all key -> binding
+    @injector_entries = {}
+
+    if @parent.nil?
+      @anonymous_key = 0
+      @binder_precedence = 0
+    else
+      # First anonymous key is the parent's next (non incremented key). (The parent can not change, it is
+      # the final, free key).
+      @anonymous_key = @parent.anonymous_key
+      @binder_precedence = @parent.binder_precedence + 1
+    end
+    define_layers(layered_bindings)
+  end
+
+  # Binds layers from highest to lowest as defined by the given LayeredBindings.
+  # @note
+  #   The model should have been
+  #   validated to get better error messages if the model is invalid. This implementation expects the model
+  #   to be valid, and any errors raised will be more technical runtime errors.
+  #
+  # @param layered_bindings [Puppet::Pops::Binder::Bindings::LayeredBindings] the named and ordered layers
+  # @raise ArgumentError if this binder is already configured
+  # @raise ArgumentError if bindings with unresolved 'override' surfaces as an effective binding
+  # @raise ArgumentError if the given argument has the wrong type, or if model is invalid in some way
+  # @return [Puppet::Pops::Binder::Binder] self
+  # @api public
+  #
+  def define_layers(layered_bindings)
+
+    LayerProcessor.new(self, key_factory).bind(layered_bindings)
+    contribution_keys = []
+    # make one pass over entries to collect contributions, and check overrides
+    injector_entries.each do |k,v|
+      if key_factory.is_contributions_key?(k)
+        contribution_keys << [k,v]
+      elsif !v.is_resolved?()
+        raise ArgumentError, "Binding with unresolved 'override' detected: #{self.class.format_binding(v.binding)}}"
+      else
+        # if binding has an id, add it to the index
+        add_id_to_index(v.binding)
+      end
+    end
+
+    # If a lower level binder has contributions for a key also contributed to in this binder
+    # they must included in the higher shadowing contribution.
+    # If a contribution is made to an id that is defined in a parent
+    # contribute to an id that is defined in a lower binder, it must be promoted to this binder (copied) or
+    # there is risk of making the lower level injector dirty.
+    #
+    contribution_keys.each do |kv|
+      parent_contribution = lookup_in_parent(kv[0])
+      next unless parent_contribution
+      injector_entries[kv[0]] = kv[1] + parent_contributions
+
+      # key the multibind_id from the contribution key
+      multibind_id = key_factory.multibind_contribution_key_to_id(kv[0])
+      promote_matching_bindings(self, @parent, multibind_id)
+    end
+  end
+  private :define_layers
+
+  # @api private
+  def next_anonymous_key
+    tmp = @anonymous_key
+    @anonymous_key += 1
+    tmp
+  end
+
+  def add_id_to_index(binding)
+    return unless binding.is_a?(Puppet::Pops::Binder::Bindings::Multibinding) && !(id = binding.id).nil?
+    @id_index[id] = @id_index[id] << binding
+  end
+
+  def promote_matching_bindings(to_binder, from_binder, multibind_id)
+    return if from_binder.nil?
+    from_binder.id_index[ multibind_id ].each do |binding|
+      key = key_factory.binding_key(binding)
+      entry = lookup(key)
+      unless entry.precedence == @binder_precedence
+        # it is from a lower layer it must be promoted
+        injector_entries[ key ] = Puppet::Pops::Binder::InjectorEntry.new(binding, binder_precedence)
+      end
+    end
+    # recursive "up the parent chain" to promote all
+    promote_matching_bindings(to_binder, from_binder.parent, multibind_id)
+  end
+
+  def lookup_in_parent(key)
+    @parent.nil? ? nil : @parent.lookup(key)
+  end
+
+  def lookup(key)
+    if x = injector_entries[key]
+      return x
+    end
+    @parent ?  @parent.lookup(key) :  nil
+  end
+
+  # @api private
+  def self.format_binding(b)
+    type_name = Puppet::Pops::Types::TypeCalculator.new().string(b.type)
+    layer_name, bindings_name = get_named_binding_layer_and_name(b)
+    "binding: '#{type_name}/#{b.name}' in: '#{bindings_name}' in layer: '#{layer_name}'"
+  end
+
+  # @api private
+  def self.format_contribution_source(b) 
+    layer_name, bindings_name = get_named_binding_layer_and_name(b)
+    "(layer: #{layer_name}, bindings: #{bindings_name})"
+  end
+
+  # @api private
+  def self.get_named_binding_layer_and_name(b)
+    return ['<unknown>', '<unknown>'] if b.nil?
+    return [get_named_layer(b), b.name] if b.is_a?(Puppet::Pops::Binder::Bindings::NamedBindings)
+    get_named_binding_layer_and_name(b.eContainer)
+  end
+
+  # @api private
+  def self.get_named_layer(b)
+    return '<unknown>' if b.nil?
+    return b.name if b.is_a?(Puppet::Pops::Binder::Bindings::NamedLayer)
+    get_named_layer(b.eContainer)
+  end
+
+  # Processes the information in a layer, aggregating it to the injector_entries hash in its parent binder.
+  # A LayerProcessor holds the intermediate state required while processing one layer.
+  #
+  # @api private
+  #
+  class LayerProcessor
+    attr :bindings
+    attr :binder
+    attr :key_factory
+    attr :contributions
+    attr :binder_precedence
+
+    def initialize(binder, key_factory)
+      @binder = binder
+      @binder_precedence = binder.binder_precedence
+      @key_factory = key_factory
+      @bindings = []
+      @contributions = []
+      @@bind_visitor ||= Puppet::Pops::Visitor.new(nil,"bind",0,0)
+    end
+
+    # Add the binding to the list of potentially effective bindings from this layer
+    # @api private
+    #
+    def add(b)
+      bindings << Puppet::Pops::Binder::InjectorEntry.new(b, binder_precedence)
+    end
+
+    # Add a multibind contribution
+    # @api private
+    #
+    def add_contribution(b)
+      contributions << Puppet::Pops::Binder::InjectorEntry.new(b, binder_precedence)
+    end
+
+    # Bind given abstract binding
+    # @api private
+    #
+    def bind(binding)
+      @@bind_visitor.visit_this(self, binding)
+    end
+
+    # @return [Puppet::Pops::Binder::InjectorEntry] the entry with the highest precedence
+    # @api private
+    def highest(b1, b2)
+      if b1.is_abstract? != b2.is_abstract?
+        # if one is abstract and the other is not, the non abstract wins
+        b1.is_abstract? ? b2 : b1
+      else
+        case b1.precedence <=> b2.precedence
+        when 1
+          b1
+        when -1
+          b2
+        when 0
+          raise_conflicting_binding(b1, b2)
+        end
+      end
+    end
+
+    # Raises a conflicting bindings error given two InjectorEntry's with same precedence in the same layer
+    # (if they are in different layers, something is seriously wrong)
+    def raise_conflicting_binding(b1, b2)
+      b1_layer_name, b1_bindings_name = binder.class.get_named_binding_layer_and_name(b1.binding)
+      b2_layer_name, b2_bindings_name = binder.class.get_named_binding_layer_and_name(b2.binding)
+
+      finality_msg = (b1.is_final? || b2.is_final?) ? ". Override of final binding not allowed" : ''
+
+      # TODO: Use of layer_name is not very good, it is not guaranteed to be unique
+      unless b1_layer_name == b2_layer_name
+        raise ArgumentError, [
+          'Conflicting binding for',
+          "'#{b1.binding.name}'",
+          'being resolved across layers',
+          "'#{b1_layer_name}' and",
+          "'#{b2_layer_name}'"
+          ].join(' ')+finality_msg
+      end
+
+      # Conflicting bindings made from the same source
+      if b1_bindings_name == b2_bindings_name
+        raise ArgumentError, [
+          'Conflicting binding for name:',
+          "'#{b1.binding.name}'",
+          'in layer:',
+          "'#{b1_layer_name}', ",
+          'both from:',
+          "'#{b1_bindings_name}'"
+          ].join(' ')+finality_msg
+      end
+
+      # Conflicting bindings from different sources
+      raise ArgumentError, [
+        'Conflicting binding for name:',
+        "'#{b1.binding.name}'",
+        'in layer:',
+        "'#{b1_layer_name}',",
+        'from:',
+        "'#{b1_bindings_name}', and",
+        "'#{b2_bindings_name}'"
+        ].join(' ')+finality_msg
+    end
+
+
+    # Produces the key for the given Binding.
+    # @param binding [Puppet::Pops::Binder::Bindings::Binding] the binding to get a key for
+    # @return [Object] an opaque key
+    # @api private
+    #
+    def key(binding)
+      k = if is_contribution?(binding)
+        # contributions get a unique (sequential) key
+        binder.next_anonymous_key()
+      else
+        key_factory.binding_key(binding)
+      end
+    end
+
+    # @api private
+    def is_contribution?(binding)
+      ! binding.multibind_id.nil?
+    end
+
+    # @api private
+    def bind_Binding(o)
+      if is_contribution?(o)
+        add_contribution(o)
+      else
+        add(o)
+      end
+    end
+
+    # @api private
+    def bind_Bindings(o)
+      o.bindings.each {|b| bind(b) }
+    end
+
+    # @api private
+    def bind_NamedBindings(o)
+      # Name is ignored here, it should be introspected when needed (in case of errors)
+      o.bindings.each {|b| bind(b) }
+    end
+
+    # Process layered bindings from highest to lowest layer
+    # @api private
+    #
+    def bind_LayeredBindings(o)
+      o.layers.each do |layer|
+        processor = LayerProcessor.new(binder, key_factory)
+        # All except abstract (==error) are transfered to injector_entries
+
+        processor.bind(layer).each do |k, v|
+          entry = binder.injector_entries[k]
+          unless key_factory.is_contributions_key?(k)
+            if v.is_abstract?()
+              layer_name, bindings_name = Puppet::Pops::Binder::Binder.get_named_binding_layer_and_name(v.binding)
+              type_name = key_factory.type_calculator.string(v.binding.type)
+              raise ArgumentError, "The abstract binding '#{type_name}/#{v.binding.name}' in '#{bindings_name}' in layer '#{layer_name}' was not overridden"
+            end
+            raise ArgumentError, "Internal Error - redefinition of key: #{k}, (should never happen)" if entry
+            binder.injector_entries[k] = v
+          else
+            entry ? entry << v : binder.injector_entries[k] = v
+          end
+        end
+      end
+    end
+
+    # Processes one named ("top level") layer consisting of a list of NamedBindings
+    # @api private
+    #
+    def bind_NamedLayer(o)
+      o.bindings.each {|b| bind(b) }
+      this_layer = {}
+
+      # process regular bindings
+      bindings.each do |b|
+        bkey = key(b.binding)
+
+        # ignore if a higher layer defined it (unless the lower is final), but ensure override gets resolved
+        # (override is not resolved across binders)
+        if x = binder.injector_entries[bkey]
+          if b.is_final?
+            raise_conflicting_binding(x, b)
+          end
+          x.mark_override_resolved()
+          next
+        end
+
+        # If a lower (parent) binder exposes a final binding it may not be overridden
+        #
+        if (x = binder.lookup_in_parent(bkey)) && x.is_final?
+          raise_conflicting_binding(x, b)
+        end
+
+        # if already found in this layer, one wins (and resolves override), or it is an error
+        existing = this_layer[bkey]
+        winner = existing ? highest(existing, b) : b
+        this_layer[bkey] = winner
+        if existing
+          winner.mark_override_resolved()
+        end
+      end
+
+      # Process contributions
+      # - organize map multibind_id to bindings with this id
+      # - for each id, create an array with the unique anonymous keys to the contributed bindings
+      # - bind the index to a special multibind contributions key (these are aggregated)
+      #
+      c_hash = Hash.new {|hash, key| hash[ key ] = [] }
+      contributions.each {|b| c_hash[ b.binding.multibind_id ] << b }
+      # - for each id
+      c_hash.each do |k, v|
+        index = v.collect do |b|
+          bkey = key(b.binding)
+          this_layer[bkey] = b
+          bkey
+        end
+        contributions_key = key_factory.multibind_contributions(k)
+        unless this_layer[contributions_key]
+          this_layer[contributions_key] = []
+        end
+        this_layer[contributions_key] += index
+      end
+      this_layer
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/binder_issues.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/binder_issues.rb
new file mode 100644
index 0000000..98171ad
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/binder_issues.rb
@@ -0,0 +1,122 @@
+# @api public
+module Puppet::Pops::Binder::BinderIssues
+
+  # NOTE: The methods #issue and #hard_issue are done in a somewhat funny way
+  # since the Puppet::Pops::Issues is a module with these methods defined on the module-class
+  # This makes it hard to inherit them in this module. (Likewise if Issues was a class, and they
+  # need to be defined for the class, and such methods are also not inherited, it becomes more
+  # difficult to reuse these. It did not seem as a good idea to refactor Issues at this point
+  # in time - they should both probably be refactored once bindings support is finished.
+  # Meanwhile, they delegate to Issues.
+
+
+  # (see Puppet::Pops::Issues#issue)
+  def self.issue (issue_code, *args, &block)
+    Puppet::Pops::Issues.issue(issue_code, *args, &block)
+  end
+
+  # (see Puppet::Pops::Issues#hard_issue)
+  def self.hard_issue(issue_code, *args, &block)
+    Puppet::Pops::Issues.hard_issue(issue_code, *args, &block)
+  end
+
+  # Producer issues (binding identified using :binding argument)
+
+  # @api public
+  MISSING_NAME = issue :MISSING_NAME, :binding do
+    "#{label.a_an_uc(binding)} with #{label.a_an(semantic)} has no name"
+  end
+
+  # @api public
+  MISSING_KEY = issue :MISSING_KEY, :binding do
+    "#{label.a_an_uc(binding)} with #{label.a_an(semantic)} has no key"
+  end
+
+  # @api public
+  MISSING_VALUE = issue :MISSING_VALUE, :binding do
+    "#{label.a_an_uc(binding)} with #{label.a_an(semantic)} has no value"
+  end
+
+  # @api public
+  MISSING_EXPRESSION = issue :MISSING_EXPRESSION, :binding do
+    "#{label.a_an_uc(binding)} with #{label.a_an(semantic)} has no expression"
+  end
+
+  # @api public
+  MISSING_CLASS_NAME = issue :MISSING_CLASS_NAME, :binding do
+    "#{label.a_an_uc(binding)} with #{label.a_an(semantic)} has no class name"
+  end
+
+  # @api public
+  CACHED_PRODUCER_MISSING_PRODUCER = issue :PRODUCER_MISSING_PRODUCER, :binding do
+    "#{label.a_an_uc(binding)} with #{label.a_an(semantic)} has no producer"
+  end
+
+  # @api public
+  INCOMPATIBLE_TYPE = issue :INCOMPATIBLE_TYPE, :binding, :expected_type, :actual_type do
+    "#{label.a_an_uc(binding)} with #{label.a_an(semantic)} has an incompatible type: expected #{label.a_an(expected_type)}, but got #{label.a_an(actual_type)}."
+  end
+
+  # @api public
+  MULTIBIND_INCOMPATIBLE_TYPE = issue :MULTIBIND_INCOMPATIBLE_TYPE, :binding, :actual_type do
+    "#{label.a_an_uc(binding)} with #{label.a_an(semantic)} cannot bind #{label.a_an(actual_type)} value"
+  end
+
+  # @api public
+  MODEL_OBJECT_IS_UNBOUND = issue :MODEL_OBJECT_IS_UNBOUND do
+    "#{label.a_an_uc(semantic)} is not contained in a binding"
+  end
+
+  # Binding issues (binding identified using semantic)
+
+  # @api public
+  MISSING_PRODUCER = issue :MISSING_PRODUCER do
+    "#{label.a_an_uc(semantic)} has no producer"
+  end
+
+  # @api public
+  MISSING_TYPE = issue :MISSING_TYPE do
+    "#{label.a_an_uc(semantic)} has no type"
+  end
+
+  # @api public
+  MULTIBIND_NOT_COLLECTION_PRODUCER = issue :MULTIBIND_NOT_COLLECTION_PRODUCER, :actual_producer do
+    "#{label.a_an_uc(semantic)} must have a MultibindProducerDescriptor, but got: #{label.a_an(actual_producer)}"
+  end
+
+  # @api public
+  MULTIBIND_TYPE_ERROR = issue :MULTIBIND_TYPE_ERROR, :actual_type do
+    "#{label.a_an_uc(semantic)} is expected to bind a collection type, but got: #{label.a_an(actual_type)}."
+  end
+
+  # @api public
+  MISSING_BINDINGS = issue :MISSING_BINDINGS do
+    "#{label.a_an_uc(semantic)} has zero bindings"
+  end
+
+  # @api public
+  MISSING_BINDINGS_NAME = issue :MISSING_BINDINGS_NAME do
+    "#{label.a_an_uc(semantic)} has no name"
+  end
+
+  # @api public
+  MISSING_PREDICATES = issue :MISSING_PREDICATES do
+    "#{label.a_an_uc(semantic)} has zero predicates"
+  end
+
+  # @api public
+  MISSING_LAYERS = issue :MISSING_LAYERS do
+    "#{label.a_an_uc(semantic)} has zero layers"
+  end
+
+  # @api public
+  MISSING_LAYER_NAME = issue :MISSING_LAYER_NAME do
+    "#{label.a_an_uc(semantic)} has a layer without name"
+  end
+
+  # @api public
+  MISSING_BINDINGS_IN_LAYER = issue :MISSING_BINDINGS_IN_LAYER, :layer do
+    "#{label.a_an_uc(semantic)} has zero bindings in #{label.label(layer)}"
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_checker.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_checker.rb
new file mode 100644
index 0000000..11d97a6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_checker.rb
@@ -0,0 +1,197 @@
+# A validator/checker of a bindings model
+# @api public
+#
+class Puppet::Pops::Binder::BindingsChecker
+  Bindings = Puppet::Pops::Binder::Bindings
+  Issues = Puppet::Pops::Binder::BinderIssues
+  Types = Puppet::Pops::Types
+
+  attr_reader :type_calculator
+  attr_reader :acceptor
+
+  # @api public
+  def initialize(diagnostics_producer)
+    @@check_visitor     ||= Puppet::Pops::Visitor.new(nil, "check", 0, 0)
+    @type_calculator      = Puppet::Pops::Types::TypeCalculator.new()
+    @expression_validator = Puppet::Pops::Validation::ValidatorFactory_4_0.new().checker(diagnostics_producer)
+    @acceptor             = diagnostics_producer
+  end
+
+  # Validates the entire model by visiting each model element and calling `check`.
+  # The result is collected (or acted on immediately) by the configured diagnostic provider/acceptor
+  # given when creating this Checker.
+  #
+  # @api public
+  #
+  def validate(b)
+    check(b)
+    b.eAllContents.each {|c| check(c) }
+  end
+
+  # Performs binding validity check
+  # @api private
+  def check(b)
+    @@check_visitor.visit_this_0(self, b)
+  end
+
+  # Checks that a binding has a producer and a type
+  # @api private
+  def check_Binding(b)
+    # Must have a type
+    acceptor.accept(Issues::MISSING_TYPE, b) unless b.type.is_a?(Types::PAnyType)
+
+    # Must have a producer
+    acceptor.accept(Issues::MISSING_PRODUCER, b) unless b.producer.is_a?(Bindings::ProducerDescriptor)
+  end
+
+  # Checks that the producer is a Multibind producer and that the type is a PCollectionType
+  # @api private
+  def check_Multibinding(b)
+    # id is optional (empty id blocks contributions)
+
+    # A multibinding must have PCollectionType
+    acceptor.accept(Issues::MULTIBIND_TYPE_ERROR, b, {:actual_type => b.type})  unless b.type.is_a?(Types::PCollectionType)
+
+    # if the producer is nil, a suitable producer will be picked automatically
+    unless b.producer.nil? || b.producer.is_a?(Bindings::MultibindProducerDescriptor)
+      acceptor.accept(Issues::MULTIBIND_NOT_COLLECTION_PRODUCER, b, {:actual_producer => b.producer})
+    end
+  end
+
+  # Checks that the bindings object contains at least one binding. Then checks each binding in turn
+  # @api private
+  def check_Bindings(b)
+    acceptor.accept(Issues::MISSING_BINDINGS, b) unless has_entries?(b.bindings)
+  end
+
+  # Checks that a name has been associated with the bindings
+  # @api private
+  def check_NamedBindings(b)
+    acceptor.accept(Issues::MISSING_BINDINGS_NAME, b) unless has_chars?(b.name)
+    check_Bindings(b)
+  end
+
+  # Check layer has a name
+  # @api private
+  def check_NamedLayer(l)
+    acceptor.accept(Issues::MISSING_LAYER_NAME, binding_parent(l)) unless has_chars?(l.name)
+  end
+
+  # Checks that the binding has layers and that each layer has a name and at least one binding
+  # @api private
+  def check_LayeredBindings(b)
+    acceptor.accept(Issues::MISSING_LAYERS, b) unless has_entries?(b.layers)
+  end
+
+  # Checks that the non caching producer has a producer to delegate to
+  # @api private
+  def check_NonCachingProducerDescriptor(p)
+    acceptor.accept(Issues::PRODUCER_MISSING_PRODUCER, p) unless p.producer.is_a?(Bindings::ProducerDescriptor)
+  end
+
+  # Checks that a constant value has been declared in the producer and that the type
+  # of the value is compatible with the type declared in the binding
+  # @api private
+  def check_ConstantProducerDescriptor(p)
+    # the product must be of compatible type
+    # TODO: Likely to change when value becomes a typed Puppet Object
+    b = binding_parent(p)
+    if p.value.nil?
+      acceptor.accept(Issues::MISSING_VALUE, p, {:binding => b})
+    else
+      infered = type_calculator.infer(p.value)
+      unless type_calculator.assignable?(b.type, infered)
+        acceptor.accept(Issues::INCOMPATIBLE_TYPE, p, {:binding => b, :expected_type => b.type, :actual_type => infered})
+      end
+    end
+  end
+
+  # Checks that an expression has been declared in the producer
+  # @api private
+  def check_EvaluatingProducerDescriptor(p)
+    unless p.expression.is_a?(Puppet::Pops::Model::Expression)
+      acceptor.accept(Issues::MISSING_EXPRESSION, p, {:binding => binding_parent(p)})
+    end
+  end
+
+  # Checks that a class name has been declared in the producer
+  # @api private
+  def check_InstanceProducerDescriptor(p)
+    acceptor.accept(Issues::MISSING_CLASS_NAME, p, {:binding => binding_parent(p)}) unless has_chars?(p.class_name)
+  end
+
+  # Checks that a type and a name has been declared. The type must be assignable to the type
+  # declared in the binding. The name can be an empty string to denote 'no name'
+  # @api private
+  def check_LookupProducerDescriptor(p)
+    b = binding_parent(p)
+    unless type_calculator.assignable(b.type, p.type)
+      acceptor.accept(Issues::INCOMPATIBLE_TYPE, p, {:binding => b, :expected_type => b.type, :actual_type => p.type })
+    end
+    acceptor.accept(Issues::MISSING_NAME, p, {:binding => b}) if p.name.nil? # empty string is OK
+  end
+
+  # Checks that a key has been declared, then calls producer_LookupProducerDescriptor to perform
+  # checks associated with the super class
+  # @api private
+  def check_HashLookupProducerDescriptor(p)
+    acceptor.accept(Issues::MISSING_KEY, p, {:binding => binding_parent(p)}) unless has_chars?(p.key)
+    check_LookupProducerDescriptor(p)
+  end
+
+  # Checks that the type declared in the binder is a PArrayType
+  # @api private
+  def check_ArrayMultibindProducerDescriptor(p)
+    b = binding_parent(p)
+    acceptor.accept(Issues::MULTIBIND_INCOMPATIBLE_TYPE, p, {:binding => b, :actual_type => b.type}) unless b.type.is_a?(Types::PArrayType)
+  end
+
+  # Checks that the type declared in the binder is a PHashType
+  # @api private
+  def check_HashMultibindProducerDescriptor(p)
+    b = binding_parent(p)
+    acceptor.accept(Issues::MULTIBIND_INCOMPATIBLE_TYPE, p, {:binding => b, :actual_type => b.type}) unless b.type.is_a?(Types::PHashType)
+  end
+
+  # Checks that the producer that this producer delegates to is declared
+  # @api private
+  def check_ProducerProducerDescriptor(p)
+    unless p.producer.is_a?(Bindings::ProducerDescriptor)
+      acceptor.accept(Issues::PRODUCER_MISSING_PRODUCER, p, {:binding => binding_parent(p)})
+    end
+  end
+
+  # @api private
+  def check_Expression(t)
+    @expression_validator.validate(t)
+  end
+
+  # @api private
+  def check_PAnyType(t)
+    # Do nothing
+  end
+
+  # Returns true if the argument is a non empty string
+  # @api private
+  def has_chars?(s)
+    s.is_a?(String) && !s.empty?
+  end
+
+  # @api private
+  def has_entries?(s)
+    !(s.nil? || s.empty?)
+  end
+
+  # @api private
+  def binding_parent(p)
+    begin
+      x = p.eContainer
+      if x.nil?
+        acceptor.accept(Issues::MODEL_OBJECT_IS_UNBOUND, p)
+        return nil
+      end
+      p = x
+    end while !p.is_a?(Bindings::AbstractBinding)
+    p
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_composer.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_composer.rb
new file mode 100644
index 0000000..db51fbb
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_composer.rb
@@ -0,0 +1,175 @@
+# The BindingsComposer handles composition of multiple bindings sources
+# It is directed by a {Puppet::Pops::Binder::Config::BinderConfig BinderConfig} that indicates how
+# the final composition should be layered, and what should be included/excluded in each layer
+#
+# The bindings composer is intended to be used once per environment as the compiler starts its work.
+#
+# TODO: Possibly support envdir: scheme / relative to environment root (== same as confdir if there is only one environment).
+#       This is probably easier to do after ENC changes described in ARM-8 have been implemented.
+# TODO: If same config is loaded in a higher layer, skip it in the lower (since it is meaningless to load it again with lower
+#       precedence. (Optimization, or possibly an error, should produce a warning).
+#
+class Puppet::Pops::Binder::BindingsComposer
+
+  # The BindingsConfig instance holding the read and parsed, but not evaluated configuration
+  # @api public
+  #
+  attr_reader :config
+
+  # map of scheme name to handler
+  # @api private
+  attr_reader :scheme_handlers
+
+  # @return [Hash{String => Puppet::Module}] map of module name to module instance
+  # @api private
+  attr_reader :name_to_module
+
+  # @api private
+  attr_reader :confdir
+
+  # @api private
+  attr_reader :diagnostics
+
+  # Container of all warnings and errors produced while initializing and loading bindings
+  #
+  # @api public
+  attr_reader :acceptor
+
+  # @api public
+  def initialize()
+    @acceptor = Puppet::Pops::Validation::Acceptor.new()
+    @diagnostics = Puppet::Pops::Binder::Config::DiagnosticProducer.new(acceptor)
+    @config = Puppet::Pops::Binder::Config::BinderConfig.new(@diagnostics)
+    if acceptor.errors?
+      Puppet::Pops::IssueReporter.assert_and_report(acceptor, :message => 'Binding Composer: error while reading config.')
+      raise Puppet::DevError.new("Internal Error: IssueReporter did not raise exception for errors in bindings config.")
+    end
+  end
+
+  # Configures and creates the boot injector.
+  # The read config may optionally contain mapping of bindings scheme handler name to handler class, and
+  # mapping of biera2 backend symbolic name to backend class.
+  # If present, these are turned into bindings in the category 'extension' (which is only used in the boot injector) which
+  # has higher precedence than 'default'. This is done to allow users to override the default bindings for
+  # schemes and backends.
+  # @param scope [Puppet::Parser:Scope] the scope (used to find compiler and injector for the environment)
+  # @api private
+  #
+  def configure_and_create_injector(scope)
+    # create the injector (which will pick up the bindings registered above)
+    @scheme_handlers = SchemeHandlerHelper.new(scope)
+
+    # get extensions from the config
+    # ------------------------------
+    scheme_extensions = @config.scheme_extensions
+
+    # Define a named bindings that are known by the SystemBindings
+    boot_bindings = Puppet::Pops::Binder::BindingsFactory.named_bindings(Puppet::Pops::Binder::SystemBindings::ENVIRONMENT_BOOT_BINDINGS_NAME) do
+      scheme_extensions.each_pair do |scheme, class_name|
+        # turn each scheme => class_name into a binding (contribute to the buildings-schemes multibind).
+        # do this in category 'extensions' to allow them to override the 'default'
+        bind do
+          name(scheme)
+          instance_of(::Puppetx::BINDINGS_SCHEMES_TYPE)
+          in_multibind(::Puppetx::BINDINGS_SCHEMES)
+          to_instance(class_name)
+          end
+      end
+    end
+
+    @injector = scope.compiler.create_boot_injector(boot_bindings.model)
+  end
+
+  # @return [Puppet::Pops::Binder::Bindings::LayeredBindings]
+  def compose(scope)
+    # The boot injector is used to lookup scheme-handlers
+    configure_and_create_injector(scope)
+
+    # get all existing modules and their root path
+    @name_to_module = {}
+    scope.environment.modules.each {|mod| name_to_module[mod.name] = mod }
+
+    # setup the confdir
+    @confdir = Puppet.settings[:confdir]
+
+    factory = Puppet::Pops::Binder::BindingsFactory
+    contributions = []
+    configured_layers = @config.layering_config.collect do |  layer_config |
+      # get contributions
+      contribs = configure_layer(layer_config, scope, diagnostics)
+      # collect the contributions separately for later checking of category precedence
+      contributions.concat(contribs)
+      # create a named layer with all the bindings for this layer
+      factory.named_layer(layer_config['name'], *contribs.collect {|c| c.bindings }.flatten)
+    end
+
+    # Add the two system layers; the final - highest ("can not be overridden" layer), and the lowest
+    # Everything here can be overridden 'default' layer.
+    #
+    configured_layers.insert(0, Puppet::Pops::Binder::SystemBindings.final_contribution)
+    configured_layers.insert(-1, Puppet::Pops::Binder::SystemBindings.default_contribution)
+
+    # and finally... create the resulting structure
+    factory.layered_bindings(*configured_layers)
+  end
+
+  private
+
+  def configure_layer(layer_description, scope, diagnostics)
+    name = layer_description['name']
+
+    # compute effective set of uris to load (and get rid of any duplicates in the process
+    included_uris = array_of_uris(layer_description['include'])
+    excluded_uris = array_of_uris(layer_description['exclude'])
+    effective_uris = Set.new(expand_included_uris(included_uris)).subtract(Set.new(expand_excluded_uris(excluded_uris)))
+
+    # Each URI should result in a ContributedBindings
+    effective_uris.collect { |uri| scheme_handlers[uri.scheme].contributed_bindings(uri, scope, self) }
+  end
+
+  def array_of_uris(descriptions)
+    return [] unless descriptions
+    descriptions = [descriptions] unless descriptions.is_a?(Array)
+    descriptions.collect {|d| URI.parse(d) }
+  end
+
+  def expand_included_uris(uris)
+    result = []
+    uris.each do |uri|
+      unless handler = scheme_handlers[uri.scheme]
+        raise ArgumentError, "Unknown bindings provider scheme: '#{uri.scheme}'"
+      end
+      result.concat(handler.expand_included(uri, self))
+    end
+    result
+  end
+
+  def expand_excluded_uris(uris)
+    result = []
+    uris.each do |uri|
+      unless handler = scheme_handlers[uri.scheme]
+        raise ArgumentError, "Unknown bindings provider scheme: '#{uri.scheme}'"
+      end
+      result.concat(handler.expand_excluded(uri, self))
+    end
+    result
+  end
+
+  class SchemeHandlerHelper
+    T = Puppet::Pops::Types::TypeFactory
+    HASH_OF_HANDLER = T.hash_of(T.type_of('Puppetx::Puppet::BindingsSchemeHandler'))
+    def initialize(scope)
+      @scope = scope
+      @cache = nil
+    end
+    def [] (scheme)
+      load_schemes unless @cache
+      @cache[scheme]
+    end
+
+    def load_schemes
+      @cache = @scope.compiler.boot_injector.lookup(@scope, HASH_OF_HANDLER, Puppetx::BINDINGS_SCHEMES) || {}
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_factory.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_factory.rb
new file mode 100644
index 0000000..e3c4445
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_factory.rb
@@ -0,0 +1,805 @@
+# A helper class that makes it easier to construct a Bindings model.
+#
+# The Bindings Model
+# ------------------
+# The BindingsModel (defined in {Puppet::Pops::Binder::Bindings} is a model that is intended to be generally free from Ruby concerns.
+# This means that it is possible for system integrators to create and serialize such models using other technologies than
+# Ruby. This manifests itself in the model in that producers are described using instances of a `ProducerDescriptor` rather than
+# describing Ruby classes directly. This is also true of the type system where type is expressed using the {Puppet::Pops::Types} model
+# to describe all types.
+#
+# This class, the `BindingsFactory` is a concrete Ruby API for constructing instances of classes in the model.
+#
+# Named Bindings
+# --------------
+# The typical usage of the factory is to call {named_bindings} which creates a container of bindings wrapped in a *build object*
+# equipped with convenience methods to define the details of the just created named bindings.
+# The returned builder is an instance of {Puppet::Pops::Binder::BindingsFactory::BindingsContainerBuilder BindingsContainerBuilder}.
+#
+# Binding
+# -------
+# A Binding binds a type/name key to a producer of a value. A binding is conveniently created by calling `bind` on a
+# `BindingsContainerBuilder`. The call to bind, produces a binding wrapped in a build object equipped with convenience methods
+# to define the details of the just created binding. The returned builder is an instance of
+# {Puppet::Pops::Binder::BindingsFactory::BindingsBuilder BindingsBuilder}.
+#
+# Multibinding
+# ------------
+# A multibinding works like a binding, but it requires an additional ID. It also places constraints on the type of the binding;
+# it must be a collection type (Hash or Array).
+#
+# Constructing and Contributing Bindings from Ruby
+# ------------------------------------------------
+# The bindings system is used by referencing bindings symbolically; these are then specified in a Ruby file which is autoloaded
+# by Puppet. The entry point for user code that creates bindings is described in {Puppet::Bindings Bindings}.
+# That class makes use of a BindingsFactory, and the builder objects to make it easy to construct bindings.
+#
+# It is intended that a user defining bindings in Ruby should be able to use the builder object methods for the majority of tasks.
+# If something advanced is wanted, use of one of the helper class methods on the BuildingsFactory, and/or the
+# {Puppet::Pops::Types::TypeCalculator TypeCalculator} will be required to create and configure objects that are not handled by
+# the methods in the builder objects.
+#
+# Chaining of calls
+# ------------------
+# Since all the build methods return the build object it is easy to stack on additional calls. The intention is to
+# do this in an order that is readable from left to right: `bind.string.name('thename').to(42)`, but there is nothing preventing
+# making the calls in some other order e.g. `bind.to(42).name('thename').string`, the second is quite unreadable but produces
+# the same result.
+#
+# For sake of human readability, the method `name` is alsp available as `named`, with the intention that it is used after a type,
+# e.g. `bind.integer.named('the meaning of life').to(42)`
+#
+# Methods taking blocks
+# ----------------------
+# Several methods take an optional block. The block evaluates with the builder object as `self`. This means that there is no
+# need to chain the methods calls, they can instead be made in sequence - e.g.
+#
+#     bind do
+#       integer
+#       named 'the meaning of life'
+#       to 42
+#     end
+#
+# or mix the two styles
+#
+#     bind do
+#       integer.named 'the meaning of life'
+#       to 42
+#     end
+#
+# Unwrapping the result
+# ---------------------
+# The result from all methods is a builder object. Call the method `model` to unwrap the constructed bindings model object.
+#
+#     bindings = BindingsFactory.named_bindings('my named bindings') do
+#       # bind things
+#     end.model
+#
+# @example Create a NamedBinding with content
+#   result = Puppet::Pops::Binder::BindingsFactory.named_bindings("mymodule::mybindings") do
+#     bind.name("foo").to(42)
+#     bind.string.name("site url").to("http://www.example.com")
+#   end
+#   result.model()
+#
+# @api public
+#
+module Puppet::Pops::Binder::BindingsFactory
+
+  # Alias for the {Puppet::Pops::Types::TypeFactory TypeFactory}. This is also available as the method
+  # `type_factory`.
+  #
+  T = Puppet::Pops::Types::TypeFactory
+
+  # Abstract base class for bindings object builders.
+  # Supports delegation of method calls to the BindingsFactory class methods for all methods not implemented
+  # by a concrete builder.
+  #
+  # @abstract
+  #
+  class AbstractBuilder
+    # The built model object.
+    attr_reader :model
+
+    # @param binding [Puppet::Pops::Binder::Bindings::AbstractBinding] The binding to build.
+    # @api public
+    def initialize(binding)
+      @model = binding
+    end
+
+    # Provides convenient access to the Bindings Factory class methods. The intent is to provide access to the
+    # methods that return producers for the purpose of composing more elaborate things than the builder convenience
+    # methods support directly.
+    # @api private
+    #
+    def method_missing(meth, *args, &block)
+      factory = Puppet::Pops::Binder::BindingsFactory
+      if factory.respond_to?(meth)
+        factory.send(meth, *args, &block)
+      else
+        super
+      end
+    end
+  end
+
+  # A bindings builder for an AbstractBinding containing other AbstractBinding instances.
+  # @api public
+  class BindingsContainerBuilder < AbstractBuilder
+
+    # Adds an empty binding to the container, and returns a builder for it for further detailing.
+    # An optional block may be given which is evaluated using `instance_eval`.
+    # @return [BindingsBuilder] the builder for the created binding
+    # @api public
+    #
+    def bind(&block)
+      binding = Puppet::Pops::Binder::Bindings::Binding.new()
+      model.addBindings(binding)
+      builder = BindingsBuilder.new(binding)
+      builder.instance_eval(&block) if block_given?
+      builder
+    end
+
+    # Binds a multibind with the given identity where later, the looked up result contains all
+    # contributions to this key. An optional block may be given which is evaluated using `instance_eval`.
+    # @param id [String] the multibind's id used when adding contributions
+    # @return [MultibindingsBuilder] the builder for the created multibinding
+    # @api public
+    #
+    def multibind(id, &block)
+      binding = Puppet::Pops::Binder::Bindings::Multibinding.new()
+      binding.id = id
+      model.addBindings(binding)
+      builder = MultibindingsBuilder.new(binding)
+      builder.instance_eval(&block) if block_given?
+      builder
+    end
+  end
+
+  # Builds a Binding via convenience methods.
+  #
+  # @api public
+  #
+  class BindingsBuilder < AbstractBuilder
+
+    # @param binding [Puppet::Pops::Binder::Bindings::AbstractBinding] the binding to build.
+    # @api public
+    def initialize(binding)
+      super binding
+      data()
+    end
+
+    # Sets the name of the binding.
+    # @param name [String] the name to bind.
+    # @api public
+    def name(name)
+      model.name = name
+      self
+    end
+
+    # Same as {#name}, but reads better in certain combinations.
+    # @api public
+    alias_method :named, :name
+
+    # Sets the binding to be abstract (it must be overridden)
+    # @api public
+    def abstract
+      model.abstract = true
+      self
+    end
+
+    # Sets the binding to be override (it must override something)
+    # @api public
+    def override
+      model.override = true
+      self
+    end
+
+    # Sets the binding to be final (it may not be overridden)
+    # @api public
+    def final
+      model.final = true
+      self
+    end
+
+    # Makes the binding a multibind contribution to the given multibind id
+    # @param id [String] the multibind id to contribute this binding to
+    # @api public
+    def in_multibind(id)
+      model.multibind_id = id
+      self
+    end
+
+    # Sets the type of the binding to the given type.
+    # @note
+    #   This is only needed if something other than the default type `Data` is wanted, or if the wanted type is
+    #   not provided by one of the convenience methods {#array_of_data}, {#boolean}, {#float}, {#hash_of_data},
+    #   {#integer}, {#scalar}, {#pattern}, {#string}, or one of the collection methods {#array_of}, or {#hash_of}.
+    #
+    # To create a type, use the method {#type_factory}, to obtain the type.
+    # @example creating a Hash with Integer key and Array[Integer] element type
+    #     tc = type_factory
+    #     type(tc.hash(tc.array_of(tc.integer), tc.integer)
+    # @param type [Puppet::Pops::Types::PAnyType] the type to set for the binding
+    # @api public
+    #
+    def type(type)
+      model.type = type
+      self
+    end
+
+    # Sets the type of the binding to Integer.
+    # @return [Puppet::Pops::Types::PIntegerType] the type
+    # @api public
+    def integer()
+      type(T.integer())
+    end
+
+    # Sets the type of the binding to Float.
+    # @return [Puppet::Pops::Types::PFloatType] the type
+    # @api public
+    def float()
+      type(T.float())
+    end
+
+    # Sets the type of the binding to Boolean.
+    # @return [Puppet::Pops::Types::PBooleanType] the type
+    # @api public
+    def boolean()
+      type(T.boolean())
+    end
+
+    # Sets the type of the binding to String.
+    # @return [Puppet::Pops::Types::PStringType] the type
+    # @api public
+    def string()
+      type(T.string())
+    end
+
+    # Sets the type of the binding to Pattern.
+    # @return [Puppet::Pops::Types::PRegexpType] the type
+    # @api public
+    def pattern()
+      type(T.pattern())
+    end
+
+    # Sets the type of the binding to the abstract type Scalar.
+    # @return [Puppet::Pops::Types::PScalarType] the type
+    # @api public
+    def scalar()
+      type(T.scalar())
+    end
+
+    # Sets the type of the binding to the abstract type Data.
+    # @return [Puppet::Pops::Types::PDataType] the type
+    # @api public
+    def data()
+      type(T.data())
+    end
+
+    # Sets the type of the binding to Array[Data].
+    # @return [Puppet::Pops::Types::PArrayType] the type
+    # @api public
+    def array_of_data()
+      type(T.array_of_data())
+    end
+
+    # Sets the type of the binding to Array[T], where T is given.
+    # @param t [Puppet::Pops::Types::PAnyType] the type of the elements of the array
+    # @return [Puppet::Pops::Types::PArrayType] the type
+    # @api public
+    def array_of(t)
+      type(T.array_of(t))
+    end
+
+    # Sets the type of the binding to Hash[Literal, Data].
+    # @return [Puppet::Pops::Types::PHashType] the type
+    # @api public
+    def hash_of_data()
+      type(T.hash_of_data())
+    end
+
+    # Sets type of the binding to `Hash[Literal, t]`.
+    # To also limit the key type, use {#type} and give it a fully specified
+    # hash using {#type_factory} and then `hash_of(value_type, key_type)`.
+    # @return [Puppet::Pops::Types::PHashType] the type
+    # @api public
+    def hash_of(t)
+      type(T.hash_of(t))
+    end
+
+    # Sets the type of the binding based on the given argument.
+    # @overload instance_of(t)
+    #   The same as calling {#type} with `t`.
+    #   @param t [Puppet::Pops::Types::PAnyType] the type
+    # @overload instance_of(o)
+    #   Infers the type from the given Ruby object and sets that as the type - i.e. "set the type
+    #   of the binding to be that of the given data object".
+    #   @param o [Object] the object to infer the type from
+    # @overload instance_of(c)
+    #   @param c [Class] the Class to base the type on.
+    #   Sets the type based on the given ruby class. The result is one of the specific puppet types
+    #   if the class can be represented by a specific type, or the open ended PRuntimeType otherwise.
+    # @overload instance_of(s)
+    #   The same as using a class, but instead of giving a class instance, the class is expressed using its fully
+    #   qualified name. This method of specifying the type allows late binding (the class does not have to be loaded
+    #   before it can be used in a binding).
+    #   @param s [String] the fully qualified classname to base the type on.
+    # @return the resulting type
+    # @api public
+    #
+    def instance_of(t)
+      type(T.type_of(t))
+    end
+
+    # Provides convenient access to the type factory.
+    # This is intended to be used when methods taking a type as argument i.e. {#type}, {#array_of}, {#hash_of}, and {#instance_of}.
+    # @note
+    #   The type factory is also available via the constant {T}.
+    # @api public
+    def type_factory
+      Puppet::Pops::Types::TypeFactory
+    end
+
+    # Sets the binding's producer to a singleton producer, if given argument is a value, a literal producer is created for it.
+    # To create a producer producing an instance of a class with lazy loading of the class, use {#to_instance}.
+    #
+    # @overload to(a_literal)
+    #   Sets a constant producer in the binding.
+    # @overload to(a_class, *args)
+    #   Sets an Instantiating producer (producing an instance of the given class)
+    # @overload to(a_producer_descriptor)
+    #   Sets the producer from the given producer descriptor
+    # @return [BindingsBuilder] self
+    # @api public
+    #
+    def to(producer, *args)
+      case producer
+      when Class
+        producer = Puppet::Pops::Binder::BindingsFactory.instance_producer(producer.name, *args)
+      when Puppet::Pops::Model::Program
+        # program is not an expression
+        producer = Puppet::Pops::Binder::BindingsFactory.evaluating_producer(producer.body)
+      when Puppet::Pops::Model::Expression
+        producer = Puppet::Pops::Binder::BindingsFactory.evaluating_producer(producer)
+      when Puppet::Pops::Binder::Bindings::ProducerDescriptor
+      else
+      # If given producer is not a producer, create a literal producer
+        producer = Puppet::Pops::Binder::BindingsFactory.literal_producer(producer)
+      end
+      model.producer = producer
+      self
+    end
+
+    # Sets the binding's producer to a producer of an instance of given class (a String class name, or a Class instance).
+    # Use a string class name when lazy loading of the class is wanted.
+    #
+    # @overload to_instance(class_name, *args)
+    #   @param class_name [String] the name of the class to instantiate
+    #   @param args [Object] optional arguments to the constructor
+    # @overload to_instance(a_class)
+    #   @param a_class [Class] the class to instantiate
+    #   @param args [Object] optional arguments to the constructor
+    #
+    def to_instance(type, *args)
+      class_name = case type
+      when Class
+        type.name
+      when String
+        type
+      else
+        raise ArgumentError, "to_instance accepts String (a class name), or a Class.*args got: #{type.class}."
+      end
+      model.producer = Puppet::Pops::Binder::BindingsFactory.instance_producer(class_name, *args)
+    end
+
+    # Sets the binding's producer to a singleton producer
+    # @overload to_producer(a_producer)
+    #   Sets the producer to an instantiated producer. The resulting model can not be serialized as a consequence as there
+    #   is no meta-model describing the specialized producer. Use this only in exceptional cases, or where there is never the
+    #   need to serialize the model.
+    #   @param a_producer [Puppet::Pops::Binder::Producers::Producer] an instantiated producer, not serializeable !
+    #
+    # @overload to_producer(a_class, *args)
+    #   @param a_class [Class] the class to create an instance of
+    #   @param args [Object] the arguments to the given class' new
+    #
+    # @overload to_producer(a_producer_descriptor)
+    #   @param a_producer_descriptor [Puppet::Pops::Binder::Bindings::ProducerDescriptor] a descriptor
+    #      producing Puppet::Pops::Binder::Producers::Producer
+    #
+    # @api public
+    #
+    def to_producer(producer, *args)
+      case producer
+      when Class
+        producer = Puppet::Pops::Binder::BindingsFactory.instance_producer(producer.name, *args)
+      when Puppet::Pops::Binder::Bindings::ProducerDescriptor
+      when Puppet::Pops::Binder::Producers::Producer
+        # a custom producer instance
+        producer = Puppet::Pops::Binder::BindingsFactory.literal_producer(producer)
+      else
+        raise ArgumentError, "Given producer argument is none of a producer descriptor, a class, or a producer"
+      end
+      metaproducer = Puppet::Pops::Binder::BindingsFactory.producer_producer(producer)
+      model.producer = metaproducer
+      self
+    end
+
+    # Sets the binding's producer to a series of producers.
+    # Use this when you want to produce a different producer on each request for a producer
+    #
+    # @overload to_producer(a_producer)
+    #   Sets the producer to an instantiated producer. The resulting model can not be serialized as a consequence as there
+    #   is no meta-model describing the specialized producer. Use this only in exceptional cases, or where there is never the
+    #   need to serialize the model.
+    #   @param a_producer [Puppet::Pops::Binder::Producers::Producer] an instantiated producer, not serializeable !
+    #
+    # @overload to_producer(a_class, *args)
+    #   @param a_class [Class] the class to create an instance of
+    #   @param args [Object] the arguments to the given class' new
+    #
+    # @overload to_producer(a_producer_descriptor)
+    #   @param a_producer_descriptor [Puppet::Pops::Binder::Bindings::ProducerDescriptor] a descriptor
+    #      producing Puppet::Pops::Binder::Producers::Producer
+    #
+    # @api public
+    #
+    def to_producer_series(producer, *args)
+      case producer
+      when Class
+        producer = Puppet::Pops::Binder::BindingsFactory.instance_producer(producer.name, *args)
+      when Puppet::Pops::Binder::Bindings::ProducerDescriptor
+      when Puppet::Pops::Binder::Producers::Producer
+        # a custom producer instance
+        producer = Puppet::Pops::Binder::BindingsFactory.literal_producer(producer)
+      else
+        raise ArgumentError, "Given producer argument is none of a producer descriptor, a class, or a producer"
+      end
+      non_caching = Puppet::Pops::Binder::Bindings::NonCachingProducerDescriptor.new()
+      non_caching.producer = producer
+      metaproducer = Puppet::Pops::Binder::BindingsFactory.producer_producer(non_caching)
+
+      non_caching = Puppet::Pops::Binder::Bindings::NonCachingProducerDescriptor.new()
+      non_caching.producer = metaproducer
+
+      model.producer = non_caching
+      self
+    end
+
+    # Sets the binding's producer to a "non singleton" producer (each call to produce produces a new instance/copy).
+    # @overload to_series_of(a_literal)
+    #   a constant producer
+    # @overload to_series_of(a_class, *args)
+    #   Instantiating producer
+    # @overload to_series_of(a_producer_descriptor)
+    #   a given producer
+    #
+    # @api public
+    #
+    def to_series_of(producer, *args)
+      case producer
+      when Class
+        producer = Puppet::Pops::Binder::BindingsFactory.instance_producer(producer.name, *args)
+      when Puppet::Pops::Binder::Bindings::ProducerDescriptor
+      else
+      # If given producer is not a producer, create a literal producer
+        producer = Puppet::Pops::Binder::BindingsFactory.literal_producer(producer)
+      end
+      non_caching = Puppet::Pops::Binder::Bindings::NonCachingProducerDescriptor.new()
+      non_caching.producer = producer
+      model.producer = non_caching
+      self
+    end
+
+    # Sets the binding's producer to one that performs a lookup of another key
+    # @overload to_lookup_of(type, name)
+    # @overload to_lookup_of(name)
+    # @api public
+    #
+    def to_lookup_of(type, name=nil)
+      unless name
+        name = type
+        type = Puppet::Pops::Types::TypeFactory.data()
+      end
+      model.producer = Puppet::Pops::Binder::BindingsFactory.lookup_producer(type, name)
+      self
+    end
+
+    # Sets the binding's producer to a one that performs a lookup of another key and they applies hash lookup on
+    # the result.
+    #
+    # @overload to_lookup_of(type, name)
+    # @overload to_lookup_of(name)
+    # @api public
+    #
+    def to_hash_lookup_of(type, name, key)
+      model.producer = Puppet::Pops::Binder::BindingsFactory.hash_lookup_producer(type, name, key)
+      self
+    end
+
+    # Sets the binding's producer to one that produces the first found lookup of another key
+    # @param list_of_lookups [Array] array of arrays [type name], or just name (implies data)
+    # @example
+    #   binder.bind().name('foo').to_first_found('fee', 'fum', 'extended-bar')
+    #   binder.bind().name('foo').to_first_found(
+    #     [T.ruby(ThisClass), 'fee'],
+    #     [T.ruby(ThatClass), 'fum'],
+    #     'extended-bar')
+    # @api public
+    #
+    def to_first_found(*list_of_lookups)
+      producers = list_of_lookups.collect do |entry|
+        if entry.is_a?(Array)
+          case entry.size
+          when 2
+            Puppet::Pops::Binder::BindingsFactory.lookup_producer(entry[0], entry[1])
+          when 1
+            Puppet::Pops::Binder::BindingsFactory.lookup_producer(Puppet::Pops::Types::TypeFactory.data(), entry[0])
+          else
+            raise ArgumentError, "Not an array of [type, name], name, or [name]"
+          end
+        else
+          Puppet::Pops::Binder::BindingsFactory.lookup_producer(T.data(), entry)
+        end
+      end
+      model.producer = Puppet::Pops::Binder::BindingsFactory.first_found_producer(*producers)
+      self
+    end
+
+    # Sets options to the producer.
+    # See the respective producer for the options it supports. All producers supports the option `:transformer`, a
+    # puppet or ruby lambda that is evaluated with the produced result as an argument. The ruby lambda gets scope and
+    # value as arguments.
+    # @note
+    #   A Ruby lambda is not cross platform safe. Use a puppet lambda if you want a bindings model that is.
+    #
+    # @api public
+    def producer_options(options)
+      options.each do |k, v|
+        arg = Puppet::Pops::Binder::Bindings::NamedArgument.new()
+        arg.name = k.to_s
+        arg.value = v
+        model.addProducer_args(arg)
+      end
+      self
+    end
+  end
+
+  # A builder specialized for multibind - checks that type is Array or Hash based. A new builder sets the
+  # multibinding to be of type Hash[Data].
+  #
+  # @api public
+  class MultibindingsBuilder < BindingsBuilder
+    # Constraints type to be one of {Puppet::Pops::Types::PArrayType PArrayType}, or {Puppet::Pops::Types::PHashType PHashType}.
+    # @raise [ArgumentError] if type constraint is not met.
+    # @api public
+    def type(type)
+      unless type.class == Puppet::Pops::Types::PArrayType || type.class == Puppet::Pops::Types::PHashType
+        raise ArgumentError, "Wrong type; only PArrayType, or PHashType allowed, got '#{type.to_s}'"
+      end
+      model.type = type
+      self
+    end
+
+    # Overrides the default implementation that will raise an exception as a multibind requires a hash type.
+    # Thus, if nothing else is requested, a multibind will be configured as Hash[Data].
+    #
+    def data()
+      hash_of_data()
+    end
+  end
+
+  # Produces a ContributedBindings.
+  # A ContributedBindings is used by bindings providers to return a set of named bindings.
+  #
+  # @param name [String] the name of the contributed bindings (for human use in messages/logs only)
+  # @param named_bindings [Puppet::Pops::Binder::Bindings::NamedBindings, Array<Puppet::Pops::Binder::Bindings::NamedBindings>] the
+  #   named bindings to include
+  #
+  def self.contributed_bindings(name, named_bindings)
+    cb = Puppet::Pops::Binder::Bindings::ContributedBindings.new()
+    cb.name = name
+    named_bindings = [named_bindings] unless named_bindings.is_a?(Array)
+    named_bindings.each {|b| cb.addBindings(b) }
+    cb
+  end
+
+  # Creates a named binding container, the top bindings model object.
+  # A NamedBindings is typically produced by a bindings provider.
+  #
+  # The created container is wrapped in a BindingsContainerBuilder for further detailing.
+  # Unwrap the built result when done.
+  # @api public
+  #
+  def self.named_bindings(name, &block)
+    binding = Puppet::Pops::Binder::Bindings::NamedBindings.new()
+    binding.name = name
+    builder = BindingsContainerBuilder.new(binding)
+    builder.instance_eval(&block) if block_given?
+    builder
+  end
+
+  # This variant of {named_bindings} evaluates the given block as a method on an anonymous class,
+  # thus, if the block defines methods or do something with the class itself, this does not pollute
+  # the base class (BindingsContainerBuilder).
+  # @api private
+  #
+  def self.safe_named_bindings(name, scope, &block)
+    binding = Puppet::Pops::Binder::Bindings::NamedBindings.new()
+    binding.name = name
+    anon = Class.new(BindingsContainerBuilder) do
+      def initialize(b)
+        super b
+      end
+    end
+    anon.send(:define_method, :_produce, block)
+    builder = anon.new(binding)
+    case block.arity
+    when 0
+      builder._produce()
+    when 1
+      builder._produce(scope)
+    end
+    builder
+  end
+
+  # Creates a literal/constant producer
+  # @param value [Object] the value to produce
+  # @return [Puppet::Pops::Binder::Bindings::ProducerDescriptor] a producer description
+  # @api public
+  #
+  def self.literal_producer(value)
+    producer = Puppet::Pops::Binder::Bindings::ConstantProducerDescriptor.new()
+    producer.value = value
+    producer
+  end
+
+  # Creates a non caching producer
+  # @param producer [Puppet::Pops::Binder::Bindings::Producer] the producer to make non caching
+  # @return [Puppet::Pops::Binder::Bindings::ProducerDescriptor] a producer description
+  # @api public
+  #
+  def self.non_caching_producer(producer)
+    p = Puppet::Pops::Binder::Bindings::NonCachingProducerDescriptor.new()
+    p.producer = producer
+    p
+  end
+
+  # Creates a producer producer
+  # @param producer [Puppet::Pops::Binder::Bindings::Producer] a producer producing a Producer.
+  # @return [Puppet::Pops::Binder::Bindings::ProducerDescriptor] a producer description
+  # @api public
+  #
+  def self.producer_producer(producer)
+    p = Puppet::Pops::Binder::Bindings::ProducerProducerDescriptor.new()
+    p.producer = producer
+    p
+  end
+
+  # Creates an instance producer
+  # An instance producer creates a new instance of a class.
+  # If the class implements the class method `inject` this method is called instead of `new` to allow further lookups
+  # to take place. This is referred to as *assisted inject*. If the class method `inject` is missing, the regular `new` method
+  # is called.
+  #
+  # @param class_name [String] the name of the class
+  # @param args[Object] arguments to the class' `new` method.
+  # @return [Puppet::Pops::Binder::Bindings::ProducerDescriptor] a producer description
+  # @api public
+  #
+  def self.instance_producer(class_name, *args)
+    p = Puppet::Pops::Binder::Bindings::InstanceProducerDescriptor.new()
+    p.class_name = class_name
+    args.each {|a| p.addArguments(a) }
+    p
+  end
+
+  # Creates a Producer that looks up a value.
+  # @param type [Puppet::Pops::Types::PAnyType] the type to lookup
+  # @param name [String] the name to lookup
+  # @return [Puppet::Pops::Binder::Bindings::ProducerDescriptor] a producer description
+  # @api public
+  def self.lookup_producer(type, name)
+    p = Puppet::Pops::Binder::Bindings::LookupProducerDescriptor.new()
+    p.type = type
+    p.name = name
+    p
+  end
+
+  # Creates a Hash lookup producer that looks up a hash value, and then a key in the hash.
+  #
+  # @return [Puppet::Pops::Binder::Bindings::ProducerDescriptor] a producer description
+  # @param type [Puppet::Pops::Types::PAnyType] the type to lookup (i.e. a Hash of some key/value type).
+  # @param name [String] the name to lookup
+  # @param key [Object] the key to lookup in the looked up hash (type should comply with given key type).
+  # @api public
+  #
+  def self.hash_lookup_producer(type, name, key)
+    p = Puppet::Pops::Binder::Bindings::HashLookupProducerDescriptor.new()
+    p.type = type
+    p.name = name
+    p.key = key
+    p
+  end
+
+  # Creates a first-found producer that looks up from a given series of keys. The first found looked up
+  # value will be produced.
+  # @param producers [Array<Puppet::Pops::Binder::Bindings::ProducerDescriptor>] the producers to consult in given order
+  # @return [Puppet::Pops::Binder::Bindings::ProducerDescriptor] a producer descriptor
+  # @api public
+  def self.first_found_producer(*producers)
+    p = Puppet::Pops::Binder::Bindings::FirstFoundProducerDescriptor.new()
+    producers.each {|p2| p.addProducers(p2) }
+    p
+  end
+
+  # Creates an evaluating producer that evaluates a puppet expression.
+  # A puppet expression is most conveniently created by using the {Puppet::Pops::Parser::EvaluatingParser EvaluatingParser} as it performs
+  # all set up and validation of the parsed source. Two convenience methods are used to parse an expression, or parse a ruby string
+  # as a puppet string. See methods {puppet_expression}, {puppet_string} and {parser} for more information.
+  #
+  # @example producing a puppet expression
+  #     expr = puppet_string("Interpolated $fqdn", __FILE__)
+  #
+  # @param expression [Puppet::Pops::Model::Expression] a puppet DSL expression as producer by the eparser.
+  # @return [Puppet::Pops::Binder::Bindings::ProducerDescriptor] a producer descriptor
+  # @api public
+  #
+  def self.evaluating_producer(expression)
+    p = Puppet::Pops::Binder::Bindings::EvaluatingProducerDescriptor.new()
+    p.expression = expression
+    p
+  end
+
+  # Creates a NamedLayer. This is used by the bindings system to create a model of the layers.
+  #
+  # @api public
+  #
+  def self.named_layer(name, *bindings)
+    result = Puppet::Pops::Binder::Bindings::NamedLayer.new()
+    result.name = name
+    bindings.each { |b| result.addBindings(b) }
+    result
+  end
+
+  # Create a LayeredBindings. This is used by the bindings system to create a model of all given layers.
+  # @param named_layers [Puppet::Pops::Binder::Bindings::NamedLayer] one or more named layers
+  # @return [Puppet::Pops::Binder::Bindings::LayeredBindings] the constructed layered bindings.
+  # @api public
+  #
+  def self.layered_bindings(*named_layers)
+    result = Puppet::Pops::Binder::Bindings::LayeredBindings.new()
+    named_layers.each {|b| result.addLayers(b) }
+    result
+  end
+
+  # @return [Puppet::Pops::Parser::EvaluatingParser] a parser for puppet expressions
+  def self.parser
+    @parser ||= Puppet::Pops::Parser::EvaluatingParser.new()
+  end
+
+  # Parses and produces a puppet expression from the given string.
+  # @param string [String] puppet source e.g. "1 + 2"
+  # @param source_file [String] the source location, typically `__File__`
+  # @return [Puppet::Pops::Model::Expression] an expression (that can be bound)
+  # @api public
+  #
+  def self.puppet_expression(string, source_file)
+    parser.parse_string(string, source_file).current
+  end
+
+  # Parses and produces a puppet string expression from the given string.
+  # The string will automatically be quoted and special characters escaped.
+  # As an example if given the (ruby) string "Hi\nMary" it is transformed to
+  # the puppet string (illustrated with a ruby string) "\"Hi\\nMary\”" before being
+  # parsed.
+  #
+  # @param string [String] puppet source e.g. "On node $!{fqdn}"
+  # @param source_file [String] the source location, typically `__File__`
+  # @return [Puppet::Pops::Model::Expression] an expression (that can be bound)
+  # @api public
+  #
+  def self.puppet_string(string, source_file)
+    parser.parse_string(parser.quote(string), source_file).current
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_label_provider.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_label_provider.rb
new file mode 100644
index 0000000..0d531c8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_label_provider.rb
@@ -0,0 +1,43 @@
+# A provider of labels for bindings model object, producing a human name for the model object.
+# @api private
+#
+class Puppet::Pops::Binder::BindingsLabelProvider < Puppet::Pops::LabelProvider
+  def initialize
+    @@label_visitor ||= Puppet::Pops::Visitor.new(self,"label",0,0)
+  end
+
+  # Produces a label for the given object without article.
+  # @return [String] a human readable label
+  #
+  def label o
+   @@label_visitor.visit(o)
+  end
+
+  def label_PAnyType o                          ; "#{Puppet::Pops::Types::TypeFactory.label(o)}" end
+  def label_ProducerDescriptor o                ; "Producer"                                     end
+  def label_NonCachingProducerDescriptor o      ; "Non Caching Producer"                         end
+  def label_ConstantProducerDescriptor o        ; "Producer['#{o.value}']"                       end
+  def label_EvaluatingProducerDescriptor o      ; "Evaluating Producer"                          end
+  def label_InstanceProducerDescriptor o        ; "Producer[#{o.class_name}]"                    end
+  def label_LookupProducerDescriptor o          ; "Lookup Producer[#{o.name}]"                   end
+  def label_HashLookupProducerDescriptor o      ; "Hash Lookup Producer[#{o.name}][#{o.key}]"    end
+  def label_FirstFoundProducerDescriptor o      ; "First Found Producer"                         end
+  def label_ProducerProducerDescriptor o        ; "Producer[Producer]"                           end
+  def label_MultibindProducerDescriptor o       ; "Multibind Producer"                           end
+  def label_ArrayMultibindProducerDescriptor o  ; "Array Multibind Producer"                     end
+  def label_HashMultibindProducerDescriptor o   ; "Hash Multibind Producer"                      end
+  def label_Bindings o                          ; "Bindings"                                     end
+  def label_NamedBindings o                     ; "Named Bindings"                               end
+  def label_LayeredBindings o                   ; "Layered Bindings"                             end
+  def label_NamedLayer o                        ; "Layer '#{o.name}'"                            end
+  def label_ContributedBindings o               ; "Contributed Bindings"                         end
+  def label_NamedArgument o                     ; "Named Argument"                               end
+
+  def label_Binding(o)
+    'Binding' + (o.multibind_id.nil? ? '' : ' In Multibind')
+  end
+  def label_Multibinding(o)
+    'Multibinding' + (o.multibind_id.nil? ? '' : ' In Multibind')
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_loader.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_loader.rb
new file mode 100644
index 0000000..c57bb3c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_loader.rb
@@ -0,0 +1,88 @@
+require 'rgen/metamodel_builder'
+
+# The ClassLoader provides a Class instance given a class name or a meta-type.
+# If the class is not already loaded, it is loaded using the Puppet Autoloader.
+# This means it can load a class from a gem, or from puppet modules.
+#
+class Puppet::Pops::Binder::BindingsLoader
+  @confdir = Puppet.settings[:confdir]
+#  @autoloader = Puppet::Util::Autoload.new("BindingsLoader", "puppet/bindings", :wrap => false)
+
+  # Returns a XXXXX given a fully qualified class name.
+  # Lookup of class is never relative to the calling namespace.
+  # @param name [String, Array<String>, Array<Symbol>, Puppet::Pops::Types::PAnyType] A fully qualified
+  #   class name String (e.g. '::Foo::Bar', 'Foo::Bar'), a PAnyType, or a fully qualified name in Array form where each part
+  #   is either a String or a Symbol, e.g. `%w{Puppetx Puppetlabs SomeExtension}`.
+  # @return [Class, nil] the looked up class or nil if no such class is loaded
+  # @raise ArgumentError If the given argument has the wrong type
+  # @api public
+  #
+  def self.provide(scope, name)
+    case name
+    when String
+      provide_from_string(scope, name)
+
+    when Array
+      provide_from_name_path(scope, name.join('::'), name)
+
+    else
+      raise ArgumentError, "Cannot provide a bindings from a '#{name.class.name}'"
+    end
+  end
+
+  # If loadable name exists relative to a a basedir or not. Returns the loadable path as a side effect.
+  # @return [String, nil] a loadable path for the given name, or nil
+  #
+  def self.loadable?(basedir, name)
+    # note, "lib" is added by the autoloader
+    #
+    paths_for_name(name).find {|p| Puppet::FileSystem.exist?(File.join(basedir, "lib/puppet/bindings", p)+'.rb') }
+  end
+
+  private
+
+  def self.loader()
+    unless Puppet.settings[:confdir] == @confdir
+      @confdir = Puppet.settings[:confdir] == @confdir
+      @autoloader = Puppet::Util::Autoload.new("BindingsLoader", "puppet/bindings", :wrap => false)
+    end
+    @autoloader
+  end
+
+  def self.provide_from_string(scope, name)
+    name_path = name.split('::')
+    # always from the root, so remove an empty first segment
+    if name_path[0].empty?
+      name_path = name_path[1..-1]
+    end
+    provide_from_name_path(scope, name, name_path)
+  end
+
+  def self.provide_from_name_path(scope, name, name_path)
+    # If bindings is already loaded, try this first
+    result = Puppet::Bindings.resolve(scope, name)
+
+    unless result
+      # Attempt to load it using the auto loader
+      paths_for_name(name).find {|path| loader.load(path) }
+      result = Puppet::Bindings.resolve(scope, name)
+    end
+    result
+  end
+
+  def self.paths_for_name(fq_name)
+    [de_camel(fq_name), downcased_path(fq_name)]
+  end
+
+  def self.downcased_path(fq_name)
+    fq_name.to_s.gsub(/::/, '/').downcase
+  end
+
+  def self.de_camel(fq_name)
+    fq_name.to_s.gsub(/::/, '/').
+    gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
+    gsub(/([a-z\d])([A-Z])/,'\1_\2').
+    tr("-", "_").
+    downcase
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_model.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_model.rb
new file mode 100644
index 0000000..9e935ae
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_model.rb
@@ -0,0 +1,68 @@
+require 'rgen/metamodel_builder'
+
+# The Bindings model is a model of Key to Producer mappings (bindings).
+# It is composed of a meta-model part (bindings_model_meta.rb), and
+# and implementation part (this file).
+#
+# @see Puppet::Pops::Binder::BindingsFactory The BindingsFactory for more details on how to create model instances.
+# @api public
+module Puppet::Pops::Binder
+  require 'puppet/pops/binder/bindings_model_meta'
+
+  # TODO: See PUP-2978 for possible performance optimization
+
+  # Mix in implementation into the generated code
+  module Bindings
+    class BindingsModelObject
+      include Puppet::Pops::Visitable
+      include Puppet::Pops::Adaptable
+      include Puppet::Pops::Containment
+    end
+
+    class ConstantProducerDescriptor
+      module ClassModule
+        def setValue(v)
+          @value = v
+        end
+        def getValue()
+          @value
+        end
+        def value=(v)
+          @value = v
+        end
+      end
+    end
+
+    class NamedArgument
+      module ClassModule
+        def setValue(v)
+          @value = v
+        end
+        def getValue()
+          @value
+        end
+        def value=(v)
+          @value = v
+        end
+      end
+    end
+
+    class InstanceProducerDescriptor
+      module ClassModule
+        def addArguments(val, index =-1)
+          @arguments ||= []
+          @arguments.insert(index, val)
+        end
+        def removeArguments(val)
+          raise "unsupported operation"
+        end
+        def setArguments(values)
+          @arguments = []
+          values.each {|v| addArguments(v) }
+        end
+      end
+    end
+
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_model_dumper.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_model_dumper.rb
new file mode 100644
index 0000000..98b2049
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_model_dumper.rb
@@ -0,0 +1,187 @@
+
+# Dumps a Pops::Binder::Bindings model in reverse polish notation; i.e. LISP style
+# The intention is to use this for debugging output
+# TODO: BAD NAME - A DUMP is a Ruby Serialization
+# NOTE: use :break, :indent, :dedent in lists to do just that
+#
+class Puppet::Pops::Binder::BindingsModelDumper < Puppet::Pops::Model::TreeDumper
+  Bindings = Puppet::Pops::Binder::Bindings
+
+  attr_reader :type_calculator
+  attr_reader :expression_dumper
+
+  def initialize
+    super
+    @type_calculator = Puppet::Pops::Types::TypeCalculator.new()
+    @expression_dumper = Puppet::Pops::Model::ModelTreeDumper.new()
+  end
+
+  def dump_BindingsFactory o
+    do_dump(o.model)
+  end
+
+  def dump_BindingsBuilder o
+    do_dump(o.model)
+  end
+
+  def dump_BindingsContainerBuilder o
+    do_dump(o.model)
+  end
+
+  def dump_NamedLayer o
+    result = ['named-layer', (o.name.nil? ? '<no-name>': o.name), :indent]
+    if o.bindings
+      o.bindings.each do |b|
+        result << :break
+        result << do_dump(b)
+      end
+    end
+    result << :dedent
+    result
+  end
+
+
+  def dump_Array o
+    o.collect {|e| do_dump(e) }
+  end
+
+  def dump_ASTArray o
+    ["[]"] + o.children.collect {|x| do_dump(x)}
+  end
+
+  def dump_ASTHash o
+    ["{}"] + o.value.sort_by{|k,v| k.to_s}.collect {|x| [do_dump(x[0]), do_dump(x[1])]}
+  end
+
+  def dump_Integer o
+    o.to_s
+  end
+
+  # Dump a Ruby String in single quotes unless it is a number.
+  def dump_String o
+    "'#{o}'"
+  end
+
+  def dump_NilClass o
+    "()"
+  end
+
+  def dump_Object o
+    ['dev-error-no-polymorph-dump-for:', o.class.to_s, o.to_s]
+  end
+
+  def is_nop? o
+    o.nil? || o.is_a?(Model::Nop) || o.is_a?(AST::Nop)
+  end
+
+  def dump_ProducerDescriptor o
+     result = [o.class.name]
+     result << expression_dumper.dump(o.transformer) if o.transformer
+     result
+  end
+
+  def dump_NonCachingProducerDescriptor o
+    dump_ProducerDescriptor(o) + do_dump(o.producer)
+  end
+
+  def dump_ConstantProducerDescriptor o
+    ['constant', do_dump(o.value)]
+  end
+
+  def dump_EvaluatingProducerDescriptor o
+    result = dump_ProducerDescriptor(o)
+    result << expression_dumper.dump(o.expression)
+  end
+
+  def dump_InstanceProducerDescriptor o
+    # TODO: o.arguments, o. transformer
+    ['instance', o.class_name]
+  end
+
+  def dump_ProducerProducerDescriptor o
+    # skip the transformer lambda...
+    result = ['producer-producer', do_dump(o.producer)]
+    result << expression_dumper.dump(o.transformer) if o.transformer
+    result
+  end
+
+  def dump_LookupProducerDescriptor o
+    ['lookup', do_dump(o.type), o.name]
+  end
+
+  def dump_PAnyType o
+    type_calculator.string(o)
+  end
+
+  def dump_HashLookupProducerDescriptor o
+    # TODO: transformer lambda
+    result = ['hash-lookup', do_dump(o.type), o.name, "[#{do_dump(o.key)}]"]
+    result << expression_dumper.dump(o.transformer) if o.transformer
+    result
+  end
+
+  def dump_FirstFoundProducerDescriptor o
+    # TODO: transformer lambda
+    ['first-found', do_dump(o.producers)]
+  end
+
+  def dump_ArrayMultibindProducerDescriptor o
+    ['multibind-array']
+  end
+
+  def dump_HashMultibindProducerDescriptor o
+    ['multibind-hash']
+  end
+
+  def dump_NamedArgument o
+    "#{o.name} => #{do_dump(o.value)}"
+  end
+
+  def dump_Binding o
+    result = ['bind']
+    result << 'override' if o.override
+    result << 'abstract' if o.abstract
+    result.concat([do_dump(o.type), o.name])
+    result << "(in #{o.multibind_id})" if o.multibind_id
+    result << ['to', do_dump(o.producer)] + do_dump(o.producer_args)
+    result
+  end
+
+  def dump_Multibinding o
+    result = ['multibind', o.id]
+    result << 'override' if o.override
+    result << 'abstract' if o.abstract
+    result.concat([do_dump(o.type), o.name])
+    result << "(in #{o.multibind_id})" if o.multibind_id
+    result << ['to', do_dump(o.producer)] + do_dump(o.producer_args)
+    result
+  end
+
+  def dump_Bindings o
+    do_dump(o.bindings)
+  end
+
+  def dump_NamedBindings o
+    result = ['named-bindings', o.name, :indent]
+    o.bindings.each do |b|
+      result << :break
+      result << do_dump(b)
+    end
+    result << :dedent
+    result
+  end
+
+  def dump_LayeredBindings o
+    result = ['layers', :indent]
+      o.layers.each do |layer|
+        result << :break
+        result << do_dump(layer)
+      end
+    result << :dedent
+    result
+  end
+
+  def dump_ContributedBindings o
+    ['contributed', o.name, do_dump(o.bindings)]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_model_meta.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_model_meta.rb
new file mode 100644
index 0000000..a4b8749
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_model_meta.rb
@@ -0,0 +1,215 @@
+require 'rgen/metamodel_builder'
+
+# The Bindings model is a model of Key to Producer mappings (bindings).
+# The central concept is that a Bindings is a nested structure of bindings.
+# A top level Bindings should be a NamedBindings (the name is used primarily
+# in error messages). A Key is a Type/Name combination.
+#
+# TODO: In this version, references to "any object" uses the class Object,
+#       but this is only temporary. The intent is to use specific Puppet Objects
+#       that are typed using the Puppet Type System (to enable serialization).
+#
+# @see Puppet::Pops::Binder::BindingsFactory The BindingsFactory for more details on how to create model instances.
+# @api public
+module Puppet::Pops::Binder::Bindings
+  extend RGen::MetamodelBuilder::ModuleExtension
+
+  # This declaration is used to overcome bugs in RGen. What is really wanted is an Opaque Object
+  # type that does not serialize its values, but such an type does not work when recreating the
+  # meta model from a dump.
+  # Instead, after loading the model, the generated code for type validation must be patched
+  #
+  FakeObject = String
+
+  # @abstract
+  # @api public
+  class BindingsModelObject < RGen::MetamodelBuilder::MMBase
+    abstract
+  end
+
+  # @abstract
+  # @api public
+  #
+  class AbstractBinding < BindingsModelObject
+    abstract
+  end
+
+  # An abstract producer
+  # @abstract
+  # @api public
+  #
+  class ProducerDescriptor < BindingsModelObject
+    abstract
+    contains_one_uni 'transformer', Puppet::Pops::Model::LambdaExpression
+  end
+  # All producers are singleton producers unless wrapped in a non caching producer
+  # where each lookup produces a new instance. It is an error to have a nesting level > 1
+  # and to nest a NonCachingProducerDescriptor.
+  #
+  # @api public
+  #
+  class NonCachingProducerDescriptor < ProducerDescriptor
+    contains_one_uni 'producer', ProducerDescriptor
+  end
+
+  # Produces a constant value (i.e. something of {Puppet::Pops::Types::PDataType PDataType})
+  # @api public
+  #
+  class ConstantProducerDescriptor < ProducerDescriptor
+    # TODO: This should be a typed Puppet Object
+    has_attr 'value', FakeObject
+  end
+
+  # Produces a value by evaluating a Puppet DSL expression.
+  # Note that the expression is not contained as it is part of a Puppet::Pops::Model::Program.
+  # To include the expression in the serialization, the Program it is contained in must be
+  # contained in the same serialization. This can be achieved by containing it in the
+  # ContributedBindings that is the top of a BindingsModel produced and given to the Injector.
+  #
+  # @api public
+  #
+  class EvaluatingProducerDescriptor < ProducerDescriptor
+    has_one 'expression', Puppet::Pops::Model::Expression
+  end
+
+  # An InstanceProducer creates an instance of the given class
+  # Arguments are passed to the class' `new` operator in the order they are given.
+  # @api public
+  #
+  class InstanceProducerDescriptor < ProducerDescriptor
+    # TODO: This should be a typed Puppet Object ??
+    has_many_attr 'arguments', FakeObject, :upperBound => -1
+    has_attr 'class_name', String
+  end
+
+  # A ProducerProducerDescriptor, describes that the produced instance is itself a Producer
+  # that should be used to produce the value.
+  # @api public
+  #
+  class ProducerProducerDescriptor < ProducerDescriptor
+    contains_one_uni 'producer', ProducerDescriptor, :lowerBound => 1
+  end
+
+  # Produces a value by looking up another key (type/name)
+  # @api public
+  #
+  class LookupProducerDescriptor < ProducerDescriptor
+    contains_one_uni 'type', Puppet::Pops::Types::PAnyType
+    has_attr 'name', String
+  end
+
+  # Produces a value by looking up another multibound key, and then looking up
+  # the detail using a detail_key.
+  # This is used to produce a specific service of a given type (such as a SyntaxChecker for the syntax "json").
+  # @api public
+  #
+  class HashLookupProducerDescriptor < LookupProducerDescriptor
+    has_attr 'key', String
+  end
+
+  # Produces a value by looking up each producer in turn. The first existing producer wins.
+  # @api public
+  #
+  class FirstFoundProducerDescriptor < ProducerDescriptor
+    contains_many_uni 'producers', LookupProducerDescriptor
+  end
+
+  # @api public
+  # @abstract
+  class MultibindProducerDescriptor < ProducerDescriptor
+    abstract
+  end
+
+  # Used in a Multibind of Array type unless it has a producer. May explicitly be used as well.
+  # @api public
+  #
+  class ArrayMultibindProducerDescriptor < MultibindProducerDescriptor
+  end
+
+  # Used in a Multibind of Hash type unless it has a producer. May explicitly be used as well.
+  # @api public
+  #
+  class HashMultibindProducerDescriptor < MultibindProducerDescriptor
+  end
+
+  # Plays the role of "Hash[String, Object] entry" but with keys in defined order.
+  #
+  # @api public
+  #
+  class NamedArgument < BindingsModelObject
+    has_attr 'name', String, :lowerBound => 1
+    has_attr 'value', FakeObject
+  end
+
+  # Binds a type/name combination to a producer. Optionally marking the bindidng as being abstract, or being an
+  # override of another binding. Optionally, the binding defines producer arguments passed to the producer when
+  # it is created.
+  #
+  # @api public
+  class Binding < AbstractBinding
+    contains_one_uni 'type', Puppet::Pops::Types::PAnyType
+    has_attr 'name', String
+    has_attr 'override', Boolean
+    has_attr 'abstract', Boolean
+    has_attr 'final', Boolean
+    # If set is a contribution in a multibind
+    has_attr 'multibind_id', String, :lowerBound => 0
+    # Invariant: Only multibinds may have lowerBound 0, all regular Binding must have a producer.
+    contains_one_uni 'producer', ProducerDescriptor, :lowerBound => 0
+    contains_many_uni 'producer_args', NamedArgument, :lowerBound => 0
+  end
+
+
+  # A multibinding is a binding other bindings can contribute to.
+  #
+  # @api public
+  class Multibinding < Binding
+    has_attr 'id', String
+  end
+
+  # A container of Binding instances
+  # @api public
+  #
+  class Bindings < AbstractBinding
+    contains_many_uni 'bindings', AbstractBinding
+  end
+
+  # The top level container of bindings can have a name (for error messages, logging, tracing).
+  # May be nested.
+  # @api public
+  #
+  class NamedBindings < Bindings
+    has_attr 'name', String
+  end
+
+  # A named layer of bindings having the same priority.
+  # @api public
+  class NamedLayer < BindingsModelObject
+    has_attr 'name', String, :lowerBound => 1
+    contains_many_uni 'bindings', NamedBindings
+  end
+
+  # A list of layers with bindings in descending priority order.
+  # @api public
+  #
+  class LayeredBindings < BindingsModelObject
+    contains_many_uni 'layers', NamedLayer
+  end
+
+  # ContributedBindings is a named container of one or more NamedBindings.
+  # The intent is that a bindings producer returns a ContributedBindings that identifies the contributor
+  # as opposed to the names of the different set of bindings. The ContributorBindings name is typically
+  # a technical name that indicates their source (a service).
+  #
+  # When EvaluatingProducerDescriptor is used, it holds a reference to an Expression. That expression
+  # should be contained in the programs referenced in the ContributedBindings that contains that producer.
+  # While the bindings model will still work if this is not the case, it will not serialize and deserialize
+  # correctly.
+  #
+  # @api public
+  #
+  class ContributedBindings < NamedLayer
+    contains_many_uni 'programs', Puppet::Pops::Model::Program
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_validator_factory.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_validator_factory.rb
new file mode 100644
index 0000000..d22675e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/bindings_validator_factory.rb
@@ -0,0 +1,28 @@
+# Configures validation suitable for the bindings model
+# @api public
+#
+class Puppet::Pops::Binder::BindingsValidatorFactory < Puppet::Pops::Validation::Factory
+  Issues = Puppet::Pops::Binder::BinderIssues
+
+  # Produces the checker to use
+  def checker diagnostic_producer
+    Puppet::Pops::Binder::BindingsChecker.new(diagnostic_producer)
+  end
+
+  # Produces the label provider to use
+  def label_provider
+    Puppet::Pops::Binder::BindingsLabelProvider.new()
+  end
+
+  # Produces the severity producer to use
+  def severity_producer
+    p = super
+
+    # Configure each issue that should **not** be an error
+    #
+    p[Issues::MISSING_BINDINGS] = :warning
+    p[Issues::MISSING_LAYERS]   = :warning
+
+    p
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/config/binder_config.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/config/binder_config.rb
new file mode 100644
index 0000000..3e83e4a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/config/binder_config.rb
@@ -0,0 +1,107 @@
+module Puppet::Pops::Binder::Config
+  # Class holding the Binder Configuration
+  # The configuration is obtained from the file 'binder_config.yaml'
+  # that must reside in the root directory of the site
+  # @api public
+  #
+  class BinderConfig
+
+    # The layering configuration is an array of layers from most to least significant.
+    # Each layer is represented by a Hash containing :name and :include and optionally :exclude
+    #
+    # @return [Array<Hash<String, String>, Hash<String, Array<String>>]
+    # @api public
+    #
+    attr_reader :layering_config
+
+    # @return <Hash<String, String>] ({}) optional mapping of bindings-scheme to handler class name
+    attr_reader :scheme_extensions
+
+
+    # @return [String] the loaded config file
+    attr_accessor :config_file
+
+    DEFAULT_LAYERS = [
+      { 'name' => 'site',    'include' => [ 'confdir:/default?optional'] },
+      { 'name' => 'modules', 'include' => [ 'module:/*::default'] },
+    ]
+
+    DEFAULT_SCHEME_EXTENSIONS = {}
+
+    def default_config()
+      # This is hardcoded now, but may be a user supplied default configuration later
+      {'version' => 1, 'layers' => default_layers }
+    end
+
+    def confdir()
+      Puppet.settings[:confdir]
+    end
+
+    # Creates a new Config. The configuration is loaded from the file 'binder_config.yaml' which
+    # is expected to be found in confdir.
+    #
+    # @param diagnostics [DiagnosticProducer] collector of diagnostics
+    # @api public
+    #
+    def initialize(diagnostics)
+      @config_file = Puppet.settings[:binder_config]
+      # if file is stated, it must exist
+      # otherwise it is optional $confdir/binder_conf.yaml
+      # and if that fails, the default
+      case @config_file
+      when NilClass
+        # use the config file if it exists
+        rootdir = confdir
+        if rootdir.is_a?(String)
+          expanded_config_file = File.expand_path(File.join(rootdir, '/binder_config.yaml'))
+          if Puppet::FileSystem.exist?(expanded_config_file)
+            @config_file = expanded_config_file
+          end
+        else
+          raise ArgumentError, "No Puppet settings 'confdir', or it is not a String"
+        end
+      when String
+        unless Puppet::FileSystem.exist?(@config_file)
+          raise ArgumentError, "Cannot find the given binder configuration file '#{@config_file}'"
+        end
+      else
+        raise ArgumentError, "The setting binder_config is expected to be a String, got: #{@config_file.class.name}."
+      end
+      unless @config_file.is_a?(String) && Puppet::FileSystem.exist?(@config_file)
+        @config_file = nil # use defaults
+      end
+
+      validator = BinderConfigChecker.new(diagnostics)
+      begin
+        data = @config_file ? YAML.load_file(@config_file) : default_config()
+        validator.validate(data, @config_file)
+      rescue Errno::ENOENT
+        diagnostics.accept(Issues::CONFIG_FILE_NOT_FOUND, @config_file)
+      rescue Errno::ENOTDIR
+        diagnostics.accept(Issues::CONFIG_FILE_NOT_FOUND, @config_file)
+      rescue ::SyntaxError => e
+        diagnostics.accept(Issues::CONFIG_FILE_SYNTAX_ERROR, @config_file, :detail => e.message)
+      end
+
+      unless diagnostics.errors?
+        @layering_config   = data['layers'] or default_layers
+        @scheme_extensions = (data['extensions'] and data['extensions']['scheme_handlers'] or default_scheme_extensions)
+      else
+        @layering_config = []
+        @scheme_extensions = {}
+      end
+    end
+
+    # The default_xxx methods exists to make it easier to do mocking in tests.
+
+    # @api private
+    def default_layers
+      DEFAULT_LAYERS
+    end
+
+    # @api private
+    def default_scheme_extensions
+      DEFAULT_SCHEME_EXTENSIONS
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/config/binder_config_checker.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/config/binder_config_checker.rb
new file mode 100644
index 0000000..c573502
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/config/binder_config_checker.rb
@@ -0,0 +1,142 @@
+module Puppet::Pops::Binder::Config
+  # Validates the consistency of a Binder::BinderConfig
+  class BinderConfigChecker
+    # Create an instance with a diagnostic producer that will receive the result during validation
+    # @param diagnostics [DiagnosticProducer] The producer that will receive the diagnostic
+    # @api public
+    #
+    def initialize(diagnostics)
+      @diagnostics = diagnostics
+      t = Puppet::Pops::Types
+      @type_calculator = t::TypeCalculator.new()
+      @array_of_string_type = t::TypeFactory.array_of(t::TypeFactory.string())
+    end
+
+    # Validate the consistency of the given data. Diagnostics will be emitted to the DiagnosticProducer
+    # that was set when this checker was created
+    #
+    # @param data [Object] The data read from the config file
+    # @param config_file [String] The full path of the file. Used in error messages
+    # @api public
+    #
+    def validate(data, config_file)
+      @unique_layer_names = Set.new()
+
+      if data.is_a?(Hash)
+        check_top_level(data, config_file)
+      else
+        accept(Issues::CONFIG_IS_NOT_HASH, config_file)
+      end
+    end
+
+    private
+
+    def accept(issue, semantic, options = {})
+      @diagnostics.accept(issue, semantic, options)
+    end
+
+    def check_top_level(data, config_file)
+      if layers = (data['layers'] || data[:layers])
+        check_layers(layers, config_file)
+      else
+        accept(Issues::CONFIG_LAYERS_MISSING, config_file)
+      end
+
+      if version = (data['version'] or data[:version])
+        accept(Issues::CONFIG_WRONG_VERSION, config_file, {:expected => 1, :actual => version}) unless version == 1
+      else
+        accept(Issues::CONFIG_VERSION_MISSING, config_file)
+      end
+      if extensions = data['extensions']
+        check_extensions(extensions, config_file)
+      end
+    end
+
+    def check_layers(layers, config_file)
+      unless layers.is_a?(Array)
+        accept(Issues::LAYERS_IS_NOT_ARRAY, config_file, :klass => data.class)
+      else
+        layers.each {|layer| check_layer(layer, config_file) }
+      end
+    end
+
+    def check_layer(layer, config_file)
+      unless layer.is_a?(Hash)
+        accept(Issues::LAYER_IS_NOT_HASH, config_file, :klass => layer.class)
+        return
+      end
+      layer.each_pair do |k, v|
+        case k
+        when 'name'
+          unless v.is_a?(String)
+            accept(Issues::LAYER_NAME_NOT_STRING, config_file, :class_name => v.class.name)
+          end
+
+          unless @unique_layer_names.add?(v)
+            accept(Issues::DUPLICATE_LAYER_NAME, config_file, :name => v.to_s )
+          end
+
+        when 'include'
+          check_bindings_references('include', v, config_file)
+
+        when 'exclude'
+          check_bindings_references('exclude', v, config_file)
+
+        when Symbol
+          accept(Issues::LAYER_ATTRIBUTE_IS_SYMBOL, config_file, :name => k.to_s)
+
+        else
+          accept(Issues::UNKNOWN_LAYER_ATTRIBUTE, config_file, :name => k.to_s )
+        end
+      end
+    end
+
+    # references to bindings is a single String URI, or an array of String URI
+    # @param kind [String] 'include' or 'exclude' (used in issue messages)
+    # @param value [String, Array<String>] one or more String URI binding references
+    # @param config_file [String] reference to the loaded config file
+    #
+    def check_bindings_references(kind, value, config_file)
+      return check_reference(value, kind, config_file) if value.is_a?(String)
+      accept(Issues::BINDINGS_REF_NOT_STRING_OR_ARRAY, config_file, :kind => kind ) unless value.is_a?(Array)
+      value.each {|ref| check_reference(ref, kind, config_file) }
+    end
+
+    # A reference is a URI in string form having a scheme and a path (at least '/')
+    #
+    def check_reference(value, kind, config_file)
+      begin
+        uri = URI.parse(value)
+
+        unless uri.scheme
+          accept(Issues::MISSING_SCHEME, config_file, :uri => uri)
+        end
+        unless uri.path
+          accept(Issues::REF_WITHOUT_PATH, config_file, :uri => uri, :kind => kind)
+        end
+
+      rescue InvalidURIError => e
+        accept(Issues::BINDINGS_REF_INVALID_URI, config_file, :msg => e.message)
+      end
+    end
+
+    def check_extensions(extensions, config_file)
+      unless extensions.is_a?(Hash)
+        accept(Issues::EXTENSIONS_NOT_HASH, config_file, :actual => extensions.class.name)
+        return
+      end
+      # check known extensions
+      extensions.each_key do |key|
+        unless ['scheme_handlers'].include? key
+          accept(Issues::UNKNOWN_EXTENSION, config_file, :extension => key)
+        end
+      end
+
+      if binding_schemes = extensions['scheme_handlers']
+        unless binding_schemes.is_a?(Hash)
+          accept(Issues::EXTENSION_BINDING_NOT_HASH, config_file, :extension => 'scheme_handlers', :actual => binding_schemes.class.name)
+        end
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/config/diagnostic_producer.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/config/diagnostic_producer.rb
new file mode 100644
index 0000000..312dc2b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/config/diagnostic_producer.rb
@@ -0,0 +1,32 @@
+module Puppet::Pops::Binder::Config
+  # Generates validation diagnostics
+  class Puppet::Pops::Binder::Config::DiagnosticProducer
+    def initialize(acceptor)
+      @acceptor = acceptor
+      @severity_producer = Puppet::Pops::Validation::SeverityProducer.new
+    end
+
+    def accept(issue, semantic, arguments={})
+      arguments[:semantic] ||= semantic
+      severity = severity_producer.severity(issue)
+      @acceptor.accept(Puppet::Pops::Validation::Diagnostic.new(severity, issue, nil, nil, arguments))
+    end
+
+    def errors?()
+      @acceptor.errors?
+    end
+
+    def severity_producer
+      p = @severity_producer
+      # All are errors, if there is need to mark some as warnings...
+      # p[Issues::XXX] = :warning
+
+      # ignored because there is a default
+      p[Puppet::Pops::Binder::Config::Issues::CONFIG_LAYERS_MISSING] = :ignore
+
+      # ignored because there is a default
+      p[Puppet::Pops::Binder::Config::Issues::CONFIG_CATEGORIES_MISSING] = :ignore
+      p
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/config/issues.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/config/issues.rb
new file mode 100644
index 0000000..11e37fb
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/config/issues.rb
@@ -0,0 +1,86 @@
+module Puppet::Pops::Binder::Config::Issues
+  # (see Puppet::Pops::Issues#issue)
+  def self.issue (issue_code, *args, &block)
+    Puppet::Pops::Issues.issue(issue_code, *args, &block)
+  end
+
+  CONFIG_FILE_NOT_FOUND = issue :CONFIG_FILE_NOT_FOUND do
+    "The binder configuration file: #{semantic} can not be found."
+  end
+
+  CONFIG_FILE_SYNTAX_ERROR = issue :CONFIG_FILE_SYNTAX_ERROR, :detail do
+    "Syntax error in configuration file: #{detail}"
+  end
+
+  CONFIG_IS_NOT_HASH = issue :CONFIG_IS_NOT_HASH do
+    "The configuration file '#{semantic}' has no hash at the top level"
+  end
+
+  CONFIG_LAYERS_MISSING = issue :CONFIG_LAYERS_MISSING do
+    "The configuration file '#{semantic}' has no 'layers' entry in the top level hash"
+  end
+
+  CONFIG_VERSION_MISSING = issue :CONFIG_VERSION_MISSING do
+    "The configuration file '#{semantic}' has no 'version' entry in the top level hash"
+  end
+
+  LAYERS_IS_NOT_ARRAY = issue :LAYERS_IS_NOT_ARRAY, :klass do
+    "The configuration file '#{semantic}' should contain a 'layers' key with an Array value, got: #{klass.name}"
+  end
+
+  LAYER_IS_NOT_HASH = issue :LAYER_IS_NOT_HASH, :klass do
+    "The configuration file '#{semantic}' should contain one hash per layer, got #{klass.name} instead of Hash"
+  end
+
+  DUPLICATE_LAYER_NAME = issue :DUPLICATE_LAYER_NAME, :name do
+    "Duplicate layer '#{name}' in configuration file #{semantic}"
+  end
+
+  UNKNOWN_LAYER_ATTRIBUTE = issue :UNKNOWN_LAYER_ATTRIBUTE, :name do
+    "Unknown layer attribute '#{name}' in configuration file #{semantic}"
+  end
+
+  BINDINGS_REF_NOT_STRING_OR_ARRAY = issue :BINDINGS_REF_NOT_STRING_OR_ARRAY, :kind do
+    "Configuration file #{semantic} has bindings reference in '#{kind}' that is neither a String nor an Array."
+  end
+
+  MISSING_SCHEME = issue :MISSING_SCHEME, :uri do
+    "Configuration file #{semantic} contains a bindings reference: '#{uri}' without scheme."
+  end
+
+  UNKNOWN_REF_SCHEME = issue :UNKNOWN_REF_SCHEME, :uri, :kind do
+    "Configuration file #{semantic} contains a bindings reference: '#{kind}' => '#{uri}' with unknown scheme"
+  end
+
+  REF_WITHOUT_PATH = issue :REF_WITHOUT_PATH, :uri, :kind do
+    "Configuration file #{semantic} contains a bindings reference: '#{kind}' => '#{uri}' without path"
+  end
+
+  BINDINGS_REF_INVALID_URI = issue :BINDINGS_REF_INVALID_URI, :msg do
+    "Configuration file #{semantic} contains a bindings reference: '#{kind}' => invalid uri, msg: '#{msg}'"
+  end
+
+  LAYER_ATTRIBUTE_IS_SYMBOL = issue :LAYER_ATTRIBUTE_IS_SYMBOL, :name do
+    "Configuration file #{semantic} contains a layer attribute '#{name}' that is a Symbol (should be String)"
+  end
+
+  LAYER_NAME_NOT_STRING = issue :LAYER_NAME_NOT_STRING, :class_name do
+    "Configuration file #{semantic} contains a layer name that is not a String, got a: '#{class_name}'"
+  end
+
+  CONFIG_WRONG_VERSION = issue :CONFIG_WRONG_VERSION, :expected, :actual do
+    "The configuration file '#{semantic}' has unsupported 'version', expected: #{expected}, but got: #{actual}."
+  end
+
+  EXTENSIONS_NOT_HASH = issue :EXTENSIONS_NOT_HASH, :actual do
+    "The configuration file '#{semantic}' contains 'extensions', expected: Hash, but got: #{actual}."
+  end
+
+  EXTENSION_BINDING_NOT_HASH = issue :EXTENSION_BINDING_NOT_HASH, :extension, :actual do
+    "The configuration file '#{semantic}' contains '#{extension}', expected: Hash, but got: #{actual}."
+  end
+
+  UNKNOWN_EXTENSION = issue :UNKNOWN_EXTENSION, :extension do
+    "The configuration file '#{semantic}' contains the unknown extension: #{extension}."
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/injector.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/injector.rb
new file mode 100644
index 0000000..fb11c3c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/injector.rb
@@ -0,0 +1,767 @@
+# The injector is the "lookup service" class
+#
+# Initialization
+# --------------
+# The injector is initialized with a configured {Puppet::Pops::Binder::Binder Binder}. The Binder instance contains a resolved set of
+# `key => "binding information"` that is used to setup the injector.
+#
+# Lookup
+# ------
+# It is possible to lookup either the value, or a producer of the value. The {#lookup} method looks up a value, and the
+# {#lookup_producer} looks up a producer.
+# Both of these methods can be called with three different signatures; `lookup(key)`, `lookup(type, name)`, and `lookup(name)`,
+# with the corresponding calls to obtain a producer; `lookup_producer(key)`, `lookup_producer(type, name)`, and `lookup_producer(name)`.
+#
+# It is possible to pass a block to {#lookup} and {#lookup_producer}, the block is passed the result of the lookup
+# and the result of the block is returned as the value of the lookup. This is useful in order to provide a default value.
+#
+# @example Lookup with default value
+#   injector.lookup('favourite_food') {|x| x.nil? ? 'bacon' : x }
+#
+# Singleton or Not
+# ----------------
+# The lookup of a value is always based on the lookup of a producer. For *singleton producers* this means that the value is
+# determined by the first value lookup. Subsequent lookups via `lookup` or `lookup_producer` will produce the same instance.
+#
+# *Non singleton producers* will produce a new instance on each request for a value. For constant value producers this
+# means that a new deep-clone is produced for mutable objects (but not for immutable objects as this is not needed).
+# Custom producers should have non singleton behavior, or if this is not possible ensure that the produced result is
+# immutable. (The behavior if a custom producer hands out a mutable value and this is mutated is undefined).
+#
+# Custom bound producers capable of producing a series of objects when bound as a singleton means that the producer
+# is a singleton, not the value it produces. If such a producer is bound as non singleton, each `lookup` will get a new
+# producer (hence, typically, restarting the series). However, the producer returned from `lookup_producer` will not
+# recreate the producer on each call to `produce`; i.e. each `lookup_producer` returns a producer capable of returning
+# a series of objects.
+#
+# @see Puppet::Pops::Binder::Binder Binder, for details about how to bind keys to producers
+# @see Puppet::Pops::Binder::BindingsFactory BindingsFactory, for a convenient way to create a Binder and bindings
+#
+# Assisted Inject
+# ---------------
+# The injector supports lookup of instances of classes *even if the requested class is not explicitly bound*.
+# This is possible for classes that have a zero argument `initialize` method, or that has a class method called
+# `inject` that takes two arguments; `injector`, and `scope`.
+# This is useful in ruby logic as a class can then use the given injector to inject details.
+# An `inject` class method wins over a zero argument `initialize` in all cases.
+#
+# @example Using assisted inject
+#   # Class with assisted inject support
+#   class Duck
+#     attr_reader :name, :year_of_birth
+#
+#     def self.inject(injector, scope, binding, *args)
+#       # lookup default name and year of birth, and use defaults if not present
+#       name = injector.lookup(scope,'default-duck-name') {|x| x ? x : 'Donald Duck' }
+#       year_of_birth = injector.lookup(scope,'default-duck-year_of_birth') {|x| x ? x : 1934 }
+#       self.new(name, year_of_birth)
+#     end
+#
+#     def initialize(name, year_of_birth)
+#       @name = name
+#       @year_of_birth = year_of_birth
+#     end
+#   end
+#
+#   injector.lookup(scope, Duck)
+#   # Produces a Duck named 'Donald Duck' or named after the binding 'default-duck-name' (and with similar treatment of
+#   # year_of_birth).
+# @see Puppet::Pops::Binder::Producers::AssistedInjectProducer AssistedInjectProducer, for more details on assisted injection
+#
+# Access to key factory and type calculator
+# -----------------------------------------
+# It is important to use the same key factory, and type calculator as the binder. It is therefor possible to obtain
+# these with the methods {#key_factory}, and {#type_calculator}.
+#
+# Special support for producers
+# -----------------------------
+# There is one method specially designed for producers. The {#get_contributions} method returns an array of all contributions
+# to a given *contributions key*. This key is obtained from the {#key_factory} for a given multibinding. The returned set of
+# contributed bindings is sorted in descending precedence order. Any conflicts, merges, etc. is performed by the multibinding
+# producer configured for a multibinding.
+#
+# @api public
+#
+class Puppet::Pops::Binder::Injector
+
+  Producers = Puppet::Pops::Binder::Producers
+
+  def self.create_from_model(layered_bindings_model)
+    self.new(Puppet::Pops::Binder::Binder.new(layered_bindings_model))
+  end
+
+  def self.create_from_hash(name, key_value_hash)
+    factory = Puppet::Pops::Binder::BindingsFactory
+    named_bindings = factory.named_bindings(name) { key_value_hash.each {|k,v| bind.name(k).to(v) }}
+    layered_bindings = factory.layered_bindings(factory.named_layer(name+'-layer',named_bindings.model))
+    self.new(Puppet::Pops::Binder::Binder.new(layered_bindings))
+  end
+
+  # Creates an injector with a single bindings layer created with the given name, and the bindings
+  # produced by the given block. The block is evaluated with self bound to a BindingsContainerBuilder.
+  #
+  # @example
+  #   Injector.create('mysettings') do
+  #     bind('name').to(42)
+  #   end
+  #
+  # @api public
+  #
+  def self.create(name, &block)
+    factory = Puppet::Pops::Binder::BindingsFactory
+    layered_bindings = factory.layered_bindings(factory.named_layer(name+'-layer',factory.named_bindings(name, &block).model))
+    self.new(Puppet::Pops::Binder::Binder.new(layered_bindings))
+  end
+
+  # Creates an overriding injector with a single bindings layer
+  # created with the given name, and the bindings produced by the given block.
+  # The block is evaluated with self bound to a BindingsContainerBuilder.
+  #
+  # @example
+  #   an_injector.override('myoverrides') do
+  #     bind('name').to(43)
+  #   end
+  #
+  # @api public
+  #
+  def override(name, &block)
+    factory = Puppet::Pops::Binder::BindingsFactory
+    layered_bindings = factory.layered_bindings(factory.named_layer(name+'-layer',factory.named_bindings(name, &block).model))
+    self.class.new(Puppet::Pops::Binder::Binder.new(layered_bindings, @impl.binder))
+  end
+
+  # Creates an overriding injector with bindings from a bindings model (a LayeredBindings) which
+  # may consists of multiple layers of bindings.
+  #
+  # @api public
+  #
+  def override_with_model(layered_bindings)
+    unless layered_bindings.is_a?(Puppet::Pops::Binder::Bindings::LayeredBindings)
+      raise ArgumentError, "Expected a LayeredBindings model, got '#{bindings_model.class}'"
+    end
+    self.class.new(Puppet::Pops::Binder::Binder.new(layered_bindings, @impl.binder))
+  end
+
+  # Creates an overriding injector with a single bindings layer
+  # created with the given name, and the bindings given in the key_value_hash
+  # @api public
+  #
+  def override_with_hash(name, key_value_hash)
+    factory = Puppet::Pops::Binder::BindingsFactory
+    named_bindings = factory.named_bindings(name) { key_value_hash.each {|k,v| bind.name(k).to(v) }}
+    layered_bindings = factory.layered_bindings(factory.named_layer(name+'-layer',named_bindings.model))
+    self.class.new(Puppet::Pops::Binder::Binder.new(layered_bindings, @impl.binder))
+  end
+
+  # An Injector is initialized with a configured {Puppet::Pops::Binder::Binder Binder}.
+  #
+  # @param configured_binder [Puppet::Pops::Binder::Binder,nil] The configured binder containing effective bindings. A given value
+  #   of nil creates an injector that returns or yields nil on all lookup requests.
+  # @raise ArgumentError if the given binder is not fully configured
+  #
+  # @api public
+  #
+  def initialize(configured_binder, parent_injector = nil)
+    if configured_binder.nil?
+      @impl = Private::NullInjectorImpl.new()
+    else
+      @impl = Private::InjectorImpl.new(configured_binder, parent_injector)
+    end
+  end
+
+  # The KeyFactory used to produce keys in this injector.
+  # The factory is shared with the Binder to ensure consistent translation to keys.
+  # A compatible type calculator can also be obtained from the key factory.
+  # @return [Puppet::Pops::Binder::KeyFactory] the key factory in use
+  #
+  # @api public
+  #
+  def key_factory()
+    @impl.key_factory
+  end
+
+  # Returns the TypeCalculator in use for keys. The same calculator (as used for keys) should be used if there is a need
+  # to check type conformance, or infer the type of Ruby objects.
+  #
+  # @return [Puppet::Pops::Types::TypeCalculator] the type calculator that is in use for keys
+  # @api public
+  #
+  def type_calculator()
+    @impl.type_calculator()
+  end
+
+  # Lookup (a.k.a "inject") of a value given a key.
+  # The lookup may be called with different parameters. This method is a convenience method that
+  # dispatches to one of #lookup_key or #lookup_type depending on the arguments. It also provides
+  # the ability to use an optional block that is called with the looked up value, or scope and value if the
+  # block takes two parameters. This is useful to provide a default value or other transformations, calculations
+  # based on the result of the lookup.
+  #
+  # @overload lookup(scope, key)
+  #   (see #lookup_key)
+  #   @param scope [Puppet::Parser::Scope] the scope to use for evaluation
+  #   @param key [Object] an opaque object being the full key
+  #
+  # @overload lookup(scope, type, name = '')
+  #   (see #lookup_type)
+  #   @param scope [Puppet::Parser::Scope] the scope to use for evaluation
+  #   @param type [Puppet::Pops::Types::PAnyType] the type of what to lookup
+  #   @param name [String] the name to use, defaults to empty string (for unnamed)
+  #
+  # @overload lookup(scope, name)
+  #   Lookup of Data type with given name.
+  #   @see #lookup_type
+  #   @param scope [Puppet::Parser::Scope] the scope to use for evaluation
+  #   @param name [String] the Data/name to lookup
+  #
+  # @yield [value] passes the looked up value to an optional block and returns what this block returns
+  # @yield [scope, value] passes scope and value to the block and returns what this block returns
+  # @yieldparam scope [Puppet::Parser::Scope] the scope given to lookup
+  # @yieldparam value [Object, nil] the looked up value or nil if nothing was found
+  #
+  # @raise [ArgumentError] if the block has an arity that is not 1 or 2
+  #
+  # @api public
+  #
+  def lookup(scope, *args, &block)
+    @impl.lookup(scope, *args, &block)
+  end
+
+  # Looks up a (typesafe) value based on a type/name combination.
+  # Creates a key for the type/name combination using a KeyFactory. Specialization of the Data type are transformed
+  # to a Data key, and the result is type checked to conform with the given key.
+  #
+  # @param type [Puppet::Pops::Types::PAnyType] the type to lookup as defined by Puppet::Pops::Types::TypeFactory
+  # @param name [String] the (optional for non `Data` types) name of the entry to lookup.
+  #   The name may be an empty String (the default), but not nil. The name is required for lookup for subtypes of
+  #   `Data`.
+  # @return [Object, nil] the looked up bound object, or nil if not found (type conformance with given type is guaranteed)
+  # @raise [ArgumentError] if the produced value does not conform with the given type
+  #
+  # @api public
+  #
+  def lookup_type(scope, type, name='')
+    @impl.lookup_type(scope, type, name)
+  end
+
+  # Looks up the key and returns the entry, or nil if no entry is found.
+  # Produced type is checked for type conformance with its binding, but not with the lookup key.
+  # (This since all subtypes of PDataType are looked up using a key based on PDataType).
+  # Use the Puppet::Pops::Types::TypeCalculator#instance? method to check for conformance of the result
+  # if this is wanted, or use #lookup_type.
+  #
+  # @param key [Object] lookup of key as produced by the key factory
+  # @return [Object, nil] produced value of type that conforms with bound type (type conformance with key not guaranteed).
+  # @raise [ArgumentError] if the produced value does not conform with the bound type
+  #
+  # @api public
+  #
+  def lookup_key(scope, key)
+    @impl.lookup_key(scope, key)
+  end
+
+  # Lookup (a.k.a "inject") producer of a value given a key.
+  # The producer lookup may be called with different parameters. This method is a convenience method that
+  # dispatches to one of #lookup_producer_key or #lookup_producer_type depending on the arguments. It also provides
+  # the ability to use an optional block that is called with the looked up producer, or scope and producer if the
+  # block takes two parameters. This is useful to provide a default value, call a custom producer method,
+  # or other transformations, calculations based on the result of the lookup.
+  #
+  # @overload lookup_producer(scope, key)
+  #   (see #lookup_proudcer_key)
+  #   @param scope [Puppet::Parser::Scope] the scope to use for evaluation
+  #   @param key [Object] an opaque object being the full key
+  #
+  # @overload lookup_producer(scope, type, name = '')
+  #   (see #lookup_type)
+  #   @param scope [Puppet::Parser::Scope] the scope to use for evaluation
+  #   @param type [Puppet::Pops::Types::PAnyType], the type of what to lookup
+  #   @param name [String], the name to use, defaults to empty string (for unnamed)
+  #
+  # @overload lookup_producer(scope, name)
+  #   Lookup of Data type with given name.
+  #   @see #lookup_type
+  #   @param scope [Puppet::Parser::Scope] the scope to use for evaluation
+  #   @param name [String], the Data/name to lookup
+  #
+  # @return [Puppet::Pops::Binder::Producers::Producer, Object, nil] a producer, or what the optional block returns
+  #
+  # @yield [producer] passes the looked up producer to an optional block and returns what this block returns
+  # @yield [scope, producer] passes scope and producer to the block and returns what this block returns
+  # @yieldparam producer [Puppet::Pops::Binder::Producers::Producer, nil] the looked up producer or nil if nothing was bound
+  # @yieldparam scope [Puppet::Parser::Scope] the scope given to lookup
+  #
+  # @raise [ArgumentError] if the block has an arity that is not 1 or 2
+  #
+  # @api public
+  #
+  def lookup_producer(scope, *args, &block)
+    @impl.lookup_producer(scope, *args, &block)
+  end
+
+  # Looks up a Producer given an opaque binder key.
+  # @return [Puppet::Pops::Binder::Producers::Producer, nil] the bound producer, or nil if no such producer was found.
+  #
+  # @api public
+  #
+  def lookup_producer_key(scope, key)
+    @impl.lookup_producer_key(scope, key)
+  end
+
+  # Looks up a Producer given a type/name key.
+  # @note The result is not type checked (it cannot be until the producer has produced an instance).
+  # @return [Puppet::Pops::Binder::Producers::Producer, nil] the bound producer, or nil if no such producer was found
+  #
+  # @api public
+  #
+  def lookup_producer_type(scope, type, name='')
+    @impl.lookup_producer_type(scope, type, name)
+  end
+
+  # Returns the contributions to a multibind given its contribution key (as produced by the KeyFactory).
+  # This method is typically used by multibind value producers, but may be used for introspection of the injector's state.
+  #
+  # @param scope [Puppet::Parser::Scope] the scope to use
+  # @param contributions_key [Object] Opaque key as produced by KeyFactory as the contributions key for a multibinding
+  # @return [Array<Puppet::Pops::Binder::InjectorEntry>] the contributions sorted in deecending order of precedence
+  #
+  # @api public
+  #
+  def get_contributions(scope, contributions_key)
+    @impl.get_contributions(scope, contributions_key)
+  end
+
+  # Returns an Injector that returns (or yields) nil on all lookups, and produces an empty structure for contributions
+  # This method is intended for testing purposes.
+  #
+  def self.null_injector
+    self.new(nil)
+  end
+
+# The implementation of the Injector is private.
+# @see Puppet::Pops::Binder::Injector The public API this module implements.
+# @api private
+#
+module Private
+
+  # This is a mocking "Null" implementation of Injector. It never finds anything
+  # @api private
+  class NullInjectorImpl
+    attr_reader :entries
+    attr_reader :key_factory
+    attr_reader :type_calculator
+
+    def initialize
+      @entries = []
+      @key_factory = Puppet::Pops::Binder::KeyFactory.new()
+      @type_calculator = @key_factory.type_calculator
+    end
+
+    def lookup(scope, *args, &block)
+      raise ArgumentError, "lookup should be called with two or three arguments, got: #{args.size()+1}" unless args.size.between?(1,2)
+      # call block with result if given
+      if block
+        case block.arity
+        when 1
+          block.call(nil)
+        when 2
+          block.call(scope, nil)
+        else
+          raise ArgumentError, "The block should have arity 1 or 2"
+        end
+      else
+        val
+      end
+    end
+
+    # @api private
+    def binder
+      nil
+    end
+
+    # @api private
+    def lookup_key(scope, key)
+      nil
+    end
+
+    # @api private
+    def lookup_producer(scope, *args, &block)
+      lookup(scope, *args, &block)
+    end
+
+    # @api private
+    def lookup_producer_key(scope, key)
+      nil
+    end
+
+    # @api private
+    def lookup_producer_type(scope, type, name='')
+      nil
+    end
+
+    def get_contributions()
+      []
+    end
+  end
+
+  # @api private
+  #
+  class InjectorImpl
+    # Hash of key => InjectorEntry
+    # @api private
+    #
+    attr_reader :entries
+
+    attr_reader :key_factory
+
+    attr_reader :type_calculator
+
+    attr_reader :binder
+
+    def initialize(configured_binder, parent_injector = nil)
+      @binder = configured_binder
+      @parent = parent_injector
+
+      # TODO: Different error message
+      raise ArgumentError, "Given Binder is not configured" unless configured_binder #&& configured_binder.configured?()
+      @entries             = configured_binder.injector_entries()
+
+      # It is essential that the injector uses the same key factory as the binder since keys must be
+      # represented the same (but still opaque) way.
+      #
+      @key_factory         = configured_binder.key_factory()
+      @type_calculator     = key_factory.type_calculator()
+      @@transform_visitor ||= Puppet::Pops::Visitor.new(nil,"transform", 2,  2)
+      @recursion_lock = [ ]
+    end
+
+    # @api private
+    def lookup(scope, *args, &block)
+      raise ArgumentError, "lookup should be called with two or three arguments, got: #{args.size()+1}" unless args.size.between?(1,2)
+
+      val = case args[ 0 ]
+
+      when Puppet::Pops::Types::PAnyType
+        lookup_type(scope, *args)
+
+      when String
+        raise ArgumentError, "lookup of name should only pass the name" unless args.size == 1
+        lookup_key(scope, key_factory.data_key(args[ 0 ]))
+
+      else
+        raise ArgumentError, 'lookup using a key should only pass a single key' unless args.size == 1
+        lookup_key(scope, args[ 0 ])
+      end
+
+      # call block with result if given
+      if block
+        case block.arity
+        when 1
+          block.call(val)
+        when 2
+          block.call(scope, val)
+        else
+          raise ArgumentError, "The block should have arity 1 or 2"
+        end
+      else
+        val
+      end
+    end
+
+    # Produces a key for a type/name combination.
+    # @api private
+    def named_key(type, name)
+      key_factory.named_key(type, name)
+    end
+
+    # Produces a key for a PDataType/name combination
+    # @api private
+    def data_key(name)
+      key_factory.data_key(name)
+    end
+
+    # @api private
+    def lookup_type(scope, type, name='')
+      val = lookup_key(scope, named_key(type, name))
+      return nil if val.nil?
+      unless key_factory.type_calculator.instance?(type, val)
+        raise ArgumentError, "Type error: incompatible type, #{type_error_detail(type, val)}"
+      end
+      val
+    end
+
+    # @api private
+    def type_error_detail(expected, actual)
+      actual_t = type_calculator.infer(actual)
+      "expected: #{type_calculator.string(expected)}, got: #{type_calculator.string(actual_t)}"
+    end
+
+    # @api private
+    def lookup_key(scope, key)
+      if @recursion_lock.include?(key)
+        raise ArgumentError, "Lookup loop detected for key: #{key}"
+      end
+      begin
+        @recursion_lock.push(key)
+        case entry = get_entry(key)
+        when NilClass
+          @parent ? @parent.lookup_key(scope, key) : nil
+
+        when Puppet::Pops::Binder::InjectorEntry
+          val = produce(scope, entry)
+          return nil if val.nil?
+          unless key_factory.type_calculator.instance?(entry.binding.type, val)
+            raise "Type error: incompatible type returned by producer, #{type_error_detail(entry.binding.type, val)}"
+          end
+          val
+        when Producers::AssistedInjectProducer
+          entry.produce(scope)
+        else
+          # internal, direct entries
+          entry
+        end
+      ensure
+        @recursion_lock.pop()
+      end
+    end
+
+    # Should be used to get entries as it converts missing entries to NotFound entries or AssistedInject entries
+    #
+    # @api private
+    def get_entry(key)
+      case entry = entries[ key ]
+      when NilClass
+        # not found, is this an assisted inject?
+        if clazz = assistable_injected_class(key)
+          entry = Producers::AssistedInjectProducer.new(self, clazz)
+          entries[ key ] = entry
+        else
+          entries[ key ] = NotFound.new()
+          entry = nil
+        end
+      when NotFound
+        entry = nil
+      end
+      entry
+    end
+
+    # Returns contributions to a multibind in precedence order; highest first.
+    # Returns an Array on the form [ [key, entry], [key, entry]] where the key is intended to be used to lookup the value
+    # (or a producer) for that entry.
+    # @api private
+    def get_contributions(scope, contributions_key)
+      result = {}
+      return [] unless contributions = lookup_key(scope, contributions_key)
+      contributions.each { |k| result[k] = get_entry(k) }
+      result.sort {|a, b| a[0] <=> b[0] }
+      #result.sort_by {|key, entry| entry }
+    end
+
+    # Produces an injectable class given a key, or nil if key does not represent an injectable class
+    # @api private
+    #
+    def assistable_injected_class(key)
+      kt = key_factory.get_type(key)
+      return nil unless kt.is_a?(Puppet::Pops::Types::PRuntimeType) && kt.runtime == :ruby && !key_factory.is_named?(key)
+      type_calculator.injectable_class(kt)
+    end
+
+    def lookup_producer(scope, *args, &block)
+      raise ArgumentError, "lookup_producer should be called with two or three arguments, got: #{args.size()+1}" unless args.size <= 2
+
+      p = case args[ 0 ]
+      when Puppet::Pops::Types::PAnyType
+        lookup_producer_type(scope, *args)
+
+      when String
+        raise ArgumentError, "lookup_producer of name should only pass the name" unless args.size == 1
+        lookup_producer_key(scope, key_factory.data_key(args[ 0 ]))
+
+      else
+        raise ArgumentError, "lookup_producer using a key should only pass a single key" unless args.size == 1
+        lookup_producer_key(scope, args[ 0 ])
+      end
+
+      # call block with result if given
+      if block
+        case block.arity
+        when 1
+          block.call(p)
+        when 2
+          block.call(scope, p)
+        else
+          raise ArgumentError, "The block should have arity 1 or 2"
+        end
+      else
+        p
+      end
+    end
+
+    # @api private
+    def lookup_producer_key(scope, key)
+      if @recursion_lock.include?(key)
+        raise ArgumentError, "Lookup loop detected for key: #{key}"
+      end
+      begin
+        @recursion_lock.push(key)
+        producer(scope, get_entry(key), :multiple_use)
+      ensure
+        @recursion_lock.pop()
+      end
+    end
+
+    # @api private
+    def lookup_producer_type(scope, type, name='')
+      lookup_producer_key(scope, named_key(type, name))
+    end
+
+    # Returns the producer for the entry
+    # @return [Puppet::Pops::Binder::Producers::Producer] the entry's producer.
+    #
+    # @api private
+    #
+    def producer(scope, entry, use)
+      return nil unless entry # not found
+      return entry.producer(scope) if entry.is_a?(Producers::AssistedInjectProducer)
+      unless entry.cached_producer
+        entry.cached_producer = transform(entry.binding.producer, scope, entry)
+      end
+      unless entry.cached_producer
+        raise ArgumentError, "Injector entry without a producer #{format_binding(entry.binding)}"
+      end
+      entry.cached_producer.producer(scope)
+    end
+
+    # @api private
+    def transform(producer_descriptor, scope, entry)
+      @@transform_visitor.visit_this_2(self, producer_descriptor, scope, entry)
+    end
+
+    # Returns the produced instance
+    # @return [Object] the produced instance
+    # @api private
+    #
+    def produce(scope, entry)
+      return nil unless entry # not found
+      producer(scope, entry, :single_use).produce(scope)
+    end
+
+    # @api private
+    def named_arguments_to_hash(named_args)
+      nb = named_args.nil? ? [] : named_args
+      result = {}
+      nb.each {|arg| result[ :"#{arg.name}" ] = arg.value }
+      result
+    end
+
+    # @api private
+    def merge_producer_options(binding, options)
+      named_arguments_to_hash(binding.producer_args).merge(options)
+    end
+
+    # @api private
+    def format_binding(b)
+      Puppet::Pops::Binder::Binder.format_binding(b)
+    end
+
+    # Handles a  missing producer (which is valid for a Multibinding where one is selected automatically)
+    # @api private
+    #
+    def transform_NilClass(descriptor, scope, entry)
+      unless entry.binding.is_a?(Puppet::Pops::Binder::Bindings::Multibinding)
+        raise ArgumentError, "Binding without producer detected, #{format_binding(entry.binding)}"
+      end
+      case entry.binding.type
+      when Puppet::Pops::Types::PArrayType
+        transform(Puppet::Pops::Binder::Bindings::ArrayMultibindProducerDescriptor.new(), scope, entry)
+      when Puppet::Pops::Types::PHashType
+        transform(Puppet::Pops::Binder::Bindings::HashMultibindProducerDescriptor.new(), scope, entry)
+      else
+        raise ArgumentError, "Unsupported multibind type, must be an array or hash type, #{format_binding(entry.binding)}"
+      end
+    end
+
+    # @api private
+    def transform_ArrayMultibindProducerDescriptor(descriptor, scope, entry)
+      make_producer(Producers::ArrayMultibindProducer, descriptor, scope, entry, named_arguments_to_hash(entry.binding.producer_args))
+    end
+
+    # @api private
+    def transform_HashMultibindProducerDescriptor(descriptor, scope, entry)
+      make_producer(Producers::HashMultibindProducer, descriptor, scope, entry, named_arguments_to_hash(entry.binding.producer_args))
+    end
+
+    # @api private
+    def transform_ConstantProducerDescriptor(descriptor, scope, entry)
+      producer_class = singleton?(descriptor) ? Producers::SingletonProducer : Producers::DeepCloningProducer
+      producer_class.new(self, entry.binding, scope, merge_producer_options(entry.binding, {:value => descriptor.value}))
+    end
+
+    # @api private
+    def transform_InstanceProducerDescriptor(descriptor, scope, entry)
+      make_producer(Producers::InstantiatingProducer, descriptor, scope, entry,
+        merge_producer_options(entry.binding, {:class_name => descriptor.class_name, :init_args => descriptor.arguments}))
+    end
+
+    # @api private
+    def transform_EvaluatingProducerDescriptor(descriptor, scope, entry)
+      make_producer(Producers::EvaluatingProducer, descriptor, scope, entry,
+        merge_producer_options(entry.binding, {:expression => descriptor.expression}))
+    end
+
+    # @api private
+    def make_producer(clazz, descriptor, scope, entry, options)
+      singleton_wrapped(descriptor, scope, entry, clazz.new(self, entry.binding, scope, options))
+    end
+
+    # @api private
+    def singleton_wrapped(descriptor, scope, entry, producer)
+      return producer unless singleton?(descriptor)
+      Producers::SingletonProducer.new(self, entry.binding, scope,
+        merge_producer_options(entry.binding, {:value => producer.produce(scope)}))
+    end
+
+    # @api private
+    def transform_ProducerProducerDescriptor(descriptor, scope, entry)
+      p = transform(descriptor.producer, scope, entry)
+      clazz = singleton?(descriptor) ? Producers::SingletonProducerProducer : Producers::ProducerProducer
+      clazz.new(self, entry.binding, scope, merge_producer_options(entry.binding,
+        merge_producer_options(entry.binding, { :producer_producer => p })))
+    end
+
+    # @api private
+    def transform_LookupProducerDescriptor(descriptor, scope, entry)
+      make_producer(Producers::LookupProducer, descriptor, scope, entry,
+        merge_producer_options(entry.binding, {:type => descriptor.type, :name => descriptor.name}))
+    end
+
+    # @api private
+    def transform_HashLookupProducerDescriptor(descriptor, scope, entry)
+      make_producer(Producers::LookupKeyProducer, descriptor, scope,  entry,
+        merge_producer_options(entry.binding, {:type => descriptor.type, :name => descriptor.name, :key => descriptor.key}))
+    end
+
+    # @api private
+    def transform_NonCachingProducerDescriptor(descriptor, scope, entry)
+      # simply delegates to the wrapped producer
+      transform(descriptor.producer, scope, entry)
+    end
+
+    # @api private
+    def transform_FirstFoundProducerDescriptor(descriptor, scope, entry)
+      make_producer(Producers::FirstFoundProducer, descriptor, scope, entry,
+        merge_producer_options(entry.binding, {:producers => descriptor.producers.collect {|p| transform(p, scope, entry) }}))
+    end
+
+    # @api private
+    def singleton?(descriptor)
+      ! descriptor.eContainer().is_a?(Puppet::Pops::Binder::Bindings::NonCachingProducerDescriptor)
+    end
+
+    # Special marker class used in entries
+    # @api private
+    class NotFound
+    end
+  end
+end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/injector_entry.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/injector_entry.rb
new file mode 100644
index 0000000..629bc5e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/injector_entry.rb
@@ -0,0 +1,57 @@
+# Represents an entry in the injectors internal data.
+#
+# @api public
+#
+class Puppet::Pops::Binder::InjectorEntry
+  # @return [Object] An opaque (comparable) object representing the precedence
+  # @api public
+  attr_reader :precedence
+
+  # @return [Puppet::Pops::Binder::Bindings::Binding] The binding for this entry
+  # @api public
+  attr_reader :binding
+
+  # @api private
+  attr_accessor :resolved
+
+  # @api private
+  attr_accessor :cached_producer
+
+  # @api private
+  def initialize(binding, precedence = 0)
+    @precedence = precedence.freeze
+    @binding = binding
+    @cached_producer = nil
+  end
+
+  # Marks an overriding entry as resolved (if not an overriding entry, the marking has no effect).
+  # @api private
+  #
+  def mark_override_resolved()
+    @resolved = true
+  end
+
+  # The binding is resolved if it is non-override, or if the override has been resolved
+  # @api private
+  #
+  def is_resolved?()
+    !binding.override || resolved
+  end
+
+  def is_abstract?
+    binding.abstract
+  end
+
+  def is_final?
+    binding.final
+  end
+
+  # Compares against another InjectorEntry by comparing precedence.
+  # @param injector_entry [InjectorEntry] entry to compare against.
+  # @return [Integer] 1, if this entry has higher precedence, 0 if equal, and -1 if given entry has higher precedence.
+  # @api public
+  #
+  def <=> (injector_entry)
+    precedence <=> injector_entry.precedence
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/key_factory.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/key_factory.rb
new file mode 100644
index 0000000..3dccd51
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/key_factory.rb
@@ -0,0 +1,67 @@
+# The KeyFactory is responsible for creating keys used for lookup of bindings.
+# @api public
+#
+class Puppet::Pops::Binder::KeyFactory
+
+  attr_reader :type_calculator
+  # @api public
+  def initialize(type_calculator = Puppet::Pops::Types::TypeCalculator.new())
+    @type_calculator = type_calculator
+  end
+
+  # @api public
+  def binding_key(binding)
+    named_key(binding.type, binding.name)
+  end
+
+  # @api public
+  def named_key(type, name)
+    [(@type_calculator.assignable?(@type_calculator.data, type) ? @type_calculator.data : type), name]
+  end
+
+  # @api public
+  def data_key(name)
+    [@type_calculator.data, name]
+  end
+
+  # @api public
+  def is_contributions_key?(s)
+    return false unless s.is_a?(String)
+    s.start_with?('mc_')
+  end
+
+  # @api public
+  def multibind_contributions(multibind_id)
+    "mc_#{multibind_id}"
+  end
+
+  # @api public
+  def multibind_contribution_key_to_id(contributions_key)
+    # removes the leading "mc_" from the key to get the multibind_id
+    contributions_key[3..-1]
+  end
+
+  # @api public
+  def is_named?(key)
+    key.is_a?(Array) && key[1] && !key[1].empty?
+  end
+
+  # @api public
+  def is_data?(key)
+    return false unless key.is_a?(Array) && key[0].is_a?(Puppet::Pops::Types::PAnyType)
+    type_calculator.assignable?(type_calculator.data(), key[0])
+  end
+
+  # @api public
+  def is_ruby?(key)
+    key.is_a?(Array) && key[0].is_a?(Puppet::Pops::Types::PRuntimeType) && key[0].runtime == :ruby
+  end
+
+  # Returns the type of the key
+  # @api public
+  #
+  def get_type(key)
+    return nil unless key.is_a?(Array)
+    key[0]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/lookup.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/lookup.rb
new file mode 100644
index 0000000..570c8da
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/lookup.rb
@@ -0,0 +1,216 @@
+# This class is the backing implementation of the Puppet function 'lookup'.
+# See puppet/parser/functions/lookup.rb for documentation.
+#
+class Puppet::Pops::Binder::Lookup
+
+  def self.parse_lookup_args(args)
+    options = {}
+    pblock = if args[-1].respond_to?(:puppet_lambda)
+      args.pop
+    end
+
+    case args.size
+    when 1
+      # name, or all options
+      if args[ 0 ].is_a?(Hash)
+        options = to_symbolic_hash(args[ 0 ])
+      else
+        options[ :name ] = args[ 0 ]
+      end
+
+    when 2
+      # name and type, or name and options
+      if args[ 1 ].is_a?(Hash)
+        options = to_symbolic_hash(args[ 1 ])
+        options[:name] = args[ 0 ] # silently overwrite option with given name
+      else
+        options[:name] = args[ 0 ]
+        options[:type] = args[ 1 ]
+      end
+
+    when 3
+      # name, type, default (no options)
+      options[ :name ] = args[ 0 ]
+      options[ :type ] = args[ 1 ]
+      options[ :default ] = args[ 2 ]
+    else
+      raise Puppet::ParseError, "The lookup function accepts 1-3 arguments, got #{args.size}"
+    end
+    options[:pblock] = pblock
+    options
+  end
+
+  def self.to_symbolic_hash(input)
+    names = [:name, :type, :default, :accept_undef, :extra, :override]
+    options = {}
+    names.each {|n| options[n] = undef_as_nil(input[n.to_s] || input[n]) }
+    options
+  end
+  private_class_method :to_symbolic_hash
+
+  def self.type_mismatch(type_calculator, expected, got)
+    "has wrong type, expected #{type_calculator.string(expected)}, got #{type_calculator.string(got)}"
+  end
+  private_class_method :type_mismatch
+
+  def self.fail(msg)
+    raise Puppet::ParseError, "Function lookup() " + msg
+  end
+  private_class_method :fail
+
+  def self.fail_lookup(names)
+    name_part = if names.size == 1
+      "the name '#{names[0]}'"
+    else
+      "any of the names ['" + names.join(', ') + "']"
+    end
+    fail("did not find a value for #{name_part}")
+  end
+  private_class_method :fail_lookup
+
+  def self.validate_options(options, type_calculator)
+    type_parser = Puppet::Pops::Types::TypeParser.new
+    name_type = type_parser.parse('Variant[Array[String], String]')
+
+    if is_nil_or_undef?(options[:name]) || options[:name].is_a?(Array) && options[:name].empty?
+      fail ("requires a name, or array of names. Got nothing to lookup.")
+    end
+
+    t = type_calculator.infer(options[:name])
+    if ! type_calculator.assignable?(name_type, t)
+      fail("given 'name' argument, #{type_mismatch(type_calculator, name_type, t)}")
+    end
+
+    # unless a type is already given (future case), parse the type (or default 'Data'), fails if invalid type is given
+    unless options[:type].is_a?(Puppet::Pops::Types::PAnyType)
+      options[:type] = type_parser.parse(options[:type] || 'Data')
+    end
+
+    # default value must comply with the given type
+    if options[:default]
+      t = type_calculator.infer(options[:default])
+      if ! type_calculator.assignable?(options[:type], t)
+        fail("'default' value #{type_mismatch(type_calculator, options[:type], t)}")
+      end
+    end
+
+    if options[:extra] && !options[:extra].is_a?(Hash)
+      # do not perform inference here, it is enough to know that it is not a hash
+      fail("'extra' value must be a Hash, got #{options[:extra].class}")
+    end
+    options[:extra] = {} unless options[:extra]
+
+    if options[:override] && !options[:override].is_a?(Hash)
+      # do not perform inference here, it is enough to know that it is not a hash
+      fail("'override' value must be a Hash, got #{options[:extra].class}")
+    end
+    options[:override] = {} unless options[:override]
+
+  end
+  private_class_method :validate_options
+
+  def self.nil_as_undef(x)
+    x.nil? ? :undef : x
+  end
+  private_class_method :nil_as_undef
+
+  def self.undef_as_nil(x)
+    is_nil_or_undef?(x) ? nil : x
+  end
+  private_class_method :undef_as_nil
+
+  def self.is_nil_or_undef?(x)
+    x.nil? || x == :undef
+  end
+  private_class_method :is_nil_or_undef?
+
+  # This is used as a marker - a value that cannot (at least not easily) by mistake be found in
+  # hiera data.
+  #
+  class PrivateNotFoundMarker; end
+
+  def self.search_for(scope, type, name, options)
+    # search in order, override, injector, hiera, then extra
+    if !(result = options[:override][name]).nil?
+      result
+    elsif !(result = scope.compiler.injector.lookup(scope, type, name)).nil?
+      result
+   else
+     result = call_hiera_function(scope, name, PrivateNotFoundMarker)
+     if !result.nil? && result != PrivateNotFoundMarker
+       result
+     else
+       options[:extra][name]
+     end
+   end
+  end
+  private_class_method :search_for
+
+  def self.call_hiera_function(scope, name, dflt)
+    loader = scope.compiler.loaders.private_environment_loader
+    func = loader.load(:function, :hiera) unless loader.nil?
+    raise Error, 'Function not found: hiera' if func.nil?
+    func.call(scope, name, dflt)
+  end
+  private_class_method :call_hiera_function
+
+    # This is the method called from the puppet/parser/functions/lookup.rb
+  # @param args [Array] array following the puppet function call conventions
+  def self.lookup(scope, args)
+    type_calculator = Puppet::Pops::Types::TypeCalculator.new
+    options = parse_lookup_args(args)
+    validate_options(options, type_calculator)
+    names = [options[:name]].flatten
+    type = options[:type]
+
+    result_with_name = names.reduce([]) do |memo, name|
+      break memo if !memo[1].nil?
+      [name, search_for(scope, type, name, options)]
+    end
+
+    result = if result_with_name[1].nil?
+      # not found, use default (which may be nil), the default is already type checked
+      options[:default]
+    else
+      # injector.lookup is type-safe already do no need to type check the result
+      result_with_name[1]
+    end
+
+    # If a block is given it is called with :undef passed as 'nil' since the lookup function
+    # is available from 3x with --binder turned on, and the evaluation is always 4x.
+    # TODO PUPPET4: Simply pass the value
+    #
+    result = if pblock = options[:pblock]
+      result2 = case pblock.parameter_count
+      when 1
+        pblock.call(undef_as_nil(result))
+      when 2
+        pblock.call(result_with_name[ 0 ], undef_as_nil(result))
+      else
+        pblock.call(result_with_name[ 0 ], undef_as_nil(result), undef_as_nil(options[ :default ]))
+      end
+
+      # if the given result was returned, there is no need to type-check it again
+      if !result2.equal?(result)
+        t = type_calculator.infer(undef_as_nil(result2))
+        if !type_calculator.assignable?(type, t)
+          fail "the value produced by the given code block #{type_mismatch(type_calculator, type, t)}"
+        end
+      end
+      result2
+    else
+      result
+    end
+
+    # Finally, the result if nil must be acceptable or an error is raised
+    if is_nil_or_undef?(result) && !options[:accept_undef]
+      fail_lookup(names)
+    else
+      # Since the function may be used without future parser being in effect, nil is not handled in a good
+      # way, and should instead be turned into :undef.
+      # TODO PUPPET4: Simply return the result
+      #
+      Puppet.future_parser? ? result : nil_as_undef(result)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/producers.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/producers.rb
new file mode 100644
index 0000000..53a74e4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/producers.rb
@@ -0,0 +1,826 @@
+# This module contains the various producers used by Puppet Bindings.
+# The main (abstract) class is {Puppet::Pops::Binder::Producers::Producer} which documents the
+# Producer API and serves as a base class for all other producers.
+# It is required that custom producers inherit from this producer (directly or indirectly).
+#
+# The selection of a Producer is typically performed by the Innjector when it configures itself
+# from a Bindings model where a {Puppet::Pops::Binder::Bindings::ProducerDescriptor} describes
+# which producer to use. The configuration uses this to create the concrete producer.
+# It is possible to describe that a particular producer class is to be used, and also to describe that
+# a custom producer (derived from Producer) should be used. This is available for both regular
+# bindings as well as multi-bindings.
+#
+#
+# @api public
+#
+module Puppet::Pops::Binder::Producers
+  # Producer is an abstract base class representing the base contract for a bound producer.
+  # Typically, when a lookup is performed it is the value that is returned (via a producer), but
+  # it is also possible to lookup the producer, and ask it to produce the value (the producer may
+  # return a series of values, which makes this especially useful).
+  #
+  # When looking up a producer, it is of importance to only use the API of the Producer class
+  # unless it is known that a particular custom producer class has been bound.
+  #
+  # Custom Producers
+  # ----------------
+  # The intent is that this class is derived for custom producers that require additional
+  # options/arguments when producing an instance. Such a custom producer may raise an error if called
+  # with too few arguments, or may implement specific `produce` methods and always raise an
+  # error on #produce indicating that this producer requires custom calls and that it can not
+  # be used as an implicit producer.
+  #
+  # Features of Producer
+  # --------------------
+  # The Producer class is abstract, but offers the ability to transform the produced result
+  # by passing the option `:transformer` which should be a Puppet Lambda Expression taking one argument
+  # and producing the transformed (wanted) result.
+  #
+  # @abstract
+  # @api public
+  #
+  class Producer
+    # A Puppet 3 AST Lambda Expression
+    # @api public
+    #
+    attr_reader :transformer
+
+    # Creates a Producer.
+    # Derived classes should call this constructor to get support for transformer lambda.
+    #
+    # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
+    # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
+    # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
+    # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
+    # @api public
+    #
+    def initialize(injector, binding, scope, options)
+      if transformer_lambda = options[:transformer]
+        if transformer_lambda.is_a?(Proc)
+          raise ArgumentError, "Transformer Proc must take one argument; value." unless transformer_lambda.arity == 1
+          @transformer = transformer_lambda
+        else
+          raise ArgumentError, "Transformer must be a LambdaExpression" unless transformer_lambda.is_a?(Puppet::Pops::Model::LambdaExpression)
+          raise ArgumentError, "Transformer lambda must take one argument; value." unless transformer_lambda.parameters.size() == 1
+          @transformer = Puppet::Pops::Parser::EvaluatingParser.new.closure(transformer_lambda, scope)
+        end
+      end
+    end
+
+    # Produces an instance.
+    # @param scope [Puppet::Parser:Scope] the scope to use for evaluation
+    # @param args [Object] arguments to custom producers, always empty for implicit productions
+    # @return [Object] the produced instance (should never be nil).
+    # @api public
+    #
+    def produce(scope, *args)
+      do_transformation(scope, internal_produce(scope))
+    end
+
+    # Returns the producer after possibly having recreated an internal/wrapped producer.
+    # This implementation returns `self`. A derived class may want to override this method
+    # to perform initialization/refresh of its internal state. This method is called when
+    # a producer is requested.
+    # @see Puppet::Pops::Binder::ProducerProducer for an example of implementation.
+    # @param scope [Puppet::Parser:Scope] the scope to use for evaluation
+    # @return [Puppet::Pops::Binder::Producer] the producer to use
+    # @api public
+    #
+    def producer(scope)
+      self
+    end
+
+    protected
+
+    # Derived classes should implement this method to do the production of a value
+    # @param scope [Puppet::Parser::Scope] the scope to use when performing lookup and evaluation
+    # @raise [NotImplementedError] this implementation always raises an error
+    # @abstract
+    # @api private
+    #
+    def internal_produce(scope)
+      raise NotImplementedError, "Producer-class '#{self.class.name}' should implement #internal_produce(scope)"
+    end
+
+    # Transforms the produced value if a transformer has been defined.
+    # @param scope [Puppet::Parser::Scope] the scope used for evaluation
+    # @param produced_value [Object, nil] the produced value (possibly nil)
+    # @return [Object] the transformed value if a transformer is defined, else the given `produced_value`
+    # @api private
+    #
+    def do_transformation(scope, produced_value)
+      return produced_value unless transformer
+      transformer.call(produced_value)
+    end
+  end
+
+  # Abstract Producer holding a value
+  # @abstract
+  # @api public
+  #
+  class AbstractValueProducer < Producer
+
+    # @api public
+    attr_reader :value
+
+    # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
+    # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
+    # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
+    # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
+    # @option options [Puppet::Pops::Model::LambdaExpression, nil] :value (nil) the value to produce
+    # @api public
+    #
+   def initialize(injector, binding, scope, options)
+      super
+      # nil is ok here, as an abstract value producer may be used to signal "not found"
+      @value = options[:value]
+    end
+  end
+
+  # Produces the same/singleton value on each production
+  # @api public
+  #
+  class SingletonProducer < AbstractValueProducer
+    protected
+
+    # @api private
+    def internal_produce(scope)
+      value()
+    end
+  end
+
+  # Produces a deep clone of its value on each production.
+  # @api public
+  #
+  class DeepCloningProducer < AbstractValueProducer
+    protected
+
+    # @api private
+    def internal_produce(scope)
+      case value
+      when Integer, Float, TrueClass, FalseClass, Symbol
+        # These are immutable
+        return value
+      when String
+        # ok if frozen, else fall through to default
+        return value() if value.frozen?
+      end
+      # The default: serialize/deserialize to get a deep copy
+      Marshal.load(Marshal.dump(value()))
+    end
+  end
+
+  # This abstract producer class remembers the injector and binding.
+  # @abstract
+  # @api public
+  #
+  class AbstractArgumentedProducer < Producer
+
+    # @api public
+    attr_reader :injector
+
+    # @api public
+    attr_reader :binding
+
+    # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
+    # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
+    # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
+    # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
+    # @api public
+    #
+    def initialize(injector, binding, scope, options)
+      super
+      @injector = injector
+      @binding = binding
+    end
+  end
+
+  # @api public
+  class InstantiatingProducer < AbstractArgumentedProducer
+
+    # @api public
+    attr_reader :the_class
+
+    # @api public
+    attr_reader :init_args
+
+    # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
+    # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
+    # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
+    # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
+    # @option options [String] :class_name The name of the class to create instance of
+    # @option options [Array<Object>] :init_args ([]) Optional arguments to class constructor
+    # @api public
+    #
+    def initialize(injector, binding, scope, options)
+      # Better do this, even if a transformation of a created instance is kind of an odd thing to do, one can imagine
+      # sending it to a function for further detailing.
+      #
+      super
+      class_name = options[:class_name]
+      raise ArgumentError, "Option 'class_name' must be given for an InstantiatingProducer" unless class_name
+      # get class by name
+      @the_class = Puppet::Pops::Types::ClassLoader.provide(class_name)
+      @init_args = options[:init_args] || []
+      raise ArgumentError, "Can not load the class #{class_name} specified in binding named: '#{binding.name}'" unless @the_class
+    end
+
+    protected
+
+    # Performs initialization the same way as Assisted Inject does (but handle arguments to
+    # constructor)
+    # @api private
+    #
+    def internal_produce(scope)
+      result = nil
+      # A class :inject method wins over an instance :initialize if it is present, unless a more specific
+      # constructor exists. (i.e do not pick :inject from superclass if class has a constructor).
+      #
+      if the_class.respond_to?(:inject)
+        inject_method = the_class.method(:inject)
+        initialize_method = the_class.instance_method(:initialize)
+        if inject_method.owner <= initialize_method.owner
+          result = the_class.inject(injector, scope, binding, *init_args)
+        end
+      end
+      if result.nil?
+        result = the_class.new(*init_args)
+      end
+      result
+    end
+  end
+
+  # @api public
+  class FirstFoundProducer < Producer
+    # @api public
+    attr_reader :producers
+
+    # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
+    # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
+    # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
+    # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
+    # @option options [Array<Puppet::Pops::Binder::Producers::Producer>] :producers list of producers to consult. Required.
+    # @api public
+    #
+    def initialize(injector, binding, scope, options)
+      super
+      @producers = options[:producers]
+      raise ArgumentError, "Option :producers' must be set to a list of producers." if @producers.nil?
+      raise ArgumentError, "Given 'producers' option is not an Array" unless @producers.is_a?(Array)
+    end
+
+    protected
+
+    # @api private
+    def internal_produce(scope)
+      # return the first produced value that is non-nil (unfortunately there is no such enumerable method)
+      producers.reduce(nil) {|memo, p| break memo unless memo.nil?; p.produce(scope)}
+    end
+  end
+
+  # Evaluates a Puppet Expression and returns the result.
+  # This is typically used for strings with interpolated expressions.
+  # @api public
+  #
+  class EvaluatingProducer < Producer
+    # A Puppet 3 AST Expression
+    # @api public
+    #
+    attr_reader :expression
+
+    # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
+    # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
+    # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
+    # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
+    # @option options [Array<Puppet::Pops::Model::Expression>] :expression The expression to evaluate
+    # @api public
+    #
+    def initialize(injector, binding, scope, options)
+      super
+      @expression = options[:expression]
+      raise ArgumentError, "Option 'expression' must be given to an EvaluatingProducer." unless @expression
+    end
+
+    # @api private
+    def internal_produce(scope)
+      Puppet::Pops::Parser::EvaluatingParser.new.evaluate(scope, expression)
+    end
+  end
+
+  # @api public
+  class LookupProducer < AbstractArgumentedProducer
+
+    # @api public
+    attr_reader :type
+
+    # @api public
+    attr_reader :name
+
+    # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
+    # @param binder [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
+    # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
+    # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
+    # @option options [Puppet::Pops::Types::PAnyType] :type The type to lookup
+    # @option options [String] :name ('') The name to lookup
+    # @api public
+    #
+    def initialize(injector, binder, scope, options)
+      super
+      @type = options[:type]
+      @name = options[:name] || ''
+      raise ArgumentError, "Option 'type' must be given in a LookupProducer." unless @type
+    end
+
+    protected
+
+    # @api private
+    def internal_produce(scope)
+      injector.lookup_type(scope, type, name)
+    end
+  end
+
+  # @api public
+  class LookupKeyProducer < LookupProducer
+
+    # @api public
+    attr_reader :key
+
+    # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
+    # @param binder [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
+    # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
+    # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
+    # @option options [Puppet::Pops::Types::PAnyType] :type The type to lookup
+    # @option options [String] :name ('') The name to lookup
+    # @option options [Puppet::Pops::Types::PAnyType] :key The key to lookup in the hash
+    # @api public
+    #
+    def initialize(injector, binder, scope, options)
+      super
+      @key = options[:key]
+      raise ArgumentError, "Option 'key' must be given in a LookupKeyProducer." if key.nil?
+    end
+
+    protected
+
+    # @api private
+    def internal_produce(scope)
+
+      result = super
+      result.is_a?(Hash) ? result[key] : nil
+    end
+  end
+
+  # Produces the given producer, then uses that producer.
+  # @see ProducerProducer for the non singleton version
+  # @api public
+  #
+  class SingletonProducerProducer < Producer
+
+    # @api public
+    attr_reader :value_producer
+
+    # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
+    # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
+    # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
+    # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
+    # @option options [Puppet::Pops::Model::LambdaExpression] :producer_producer a producer of a value producer (required)
+    # @api public
+    #
+    def initialize(injector, binding, scope, options)
+      super
+      p = options[:producer_producer]
+      raise ArgumentError, "Option :producer_producer must be given in a SingletonProducerProducer" unless p
+      @value_producer = p.produce(scope)
+    end
+
+    protected
+
+    # @api private
+    def internal_produce(scope)
+      value_producer.produce(scope)
+    end
+  end
+
+  # A ProducerProducer creates a producer via another producer, and then uses this created producer
+  # to produce values. This is useful for custom production of series of values.
+  # On each request for a producer, this producer will reset its internal producer (i.e. restarting
+  # the series).
+  #
+  # @param producer_producer [#produce(scope)] the producer of the producer
+  #
+  # @api public
+  #
+  class ProducerProducer < Producer
+
+    # @api public
+    attr_reader :producer_producer
+
+    # @api public
+    attr_reader :value_producer
+
+    # Creates  new ProducerProducer given a producer.
+    #
+    # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
+    # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
+    # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
+    # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
+    # @option options [Puppet::Pops::Binder::Producer] :producer_producer a producer of a value producer (required)
+    #
+    # @api public
+    #
+    def initialize(injector, binding, scope, options)
+      super
+      unless producer_producer = options[:producer_producer]
+        raise ArgumentError, "The option :producer_producer must be set in a ProducerProducer"
+      end
+      raise ArgumentError, "Argument must be a Producer" unless producer_producer.is_a?(Producer)
+
+      @producer_producer = producer_producer
+      @value_producer = nil
+    end
+
+    # Updates the internal state to use a new instance of the wrapped producer.
+    # @api public
+    #
+    def producer(scope)
+      @value_producer = @producer_producer.produce(scope)
+      self
+    end
+
+    protected
+
+    # Produces a value after having created an instance of the wrapped producer (if not already created).
+    # @api private
+    #
+    def internal_produce(scope, *args)
+      producer() unless value_producer
+      value_producer.produce(scope)
+    end
+  end
+
+  # This type of producer should only be created by the Injector.
+  #
+  # @api private
+  #
+  class AssistedInjectProducer < Producer
+    # An Assisted Inject Producer is created when a lookup is made of a type that is
+    # not bound. It does not support a transformer lambda.
+    # @note This initializer has a different signature than all others. Do not use in regular logic.
+    # @api private
+    #
+    def initialize(injector, clazz)
+      raise ArgumentError, "class must be given" unless clazz.is_a?(Class)
+
+      @injector = injector
+      @clazz = clazz
+      @inst = nil
+    end
+
+    def produce(scope, *args)
+      producer(scope, *args) unless @inst
+      @inst
+    end
+
+    # @api private
+    def producer(scope, *args)
+      @inst = nil
+      # A class :inject method wins over an instance :initialize if it is present, unless a more specific zero args
+      # constructor exists. (i.e do not pick :inject from superclass if class has a zero args constructor).
+      #
+      if @clazz.respond_to?(:inject)
+        inject_method = @clazz.method(:inject)
+        initialize_method = @clazz.instance_method(:initialize)
+        if inject_method.owner <= initialize_method.owner || initialize_method.arity != 0
+          @inst = @clazz.inject(@injector, scope, nil, *args)
+        end
+      end
+      if @inst.nil?
+        unless args.empty?
+          raise ArgumentError, "Assisted Inject can not pass arguments to no-args constructor when there is no class inject method."
+        end
+        @inst = @clazz.new()
+      end
+      self
+    end
+  end
+
+  # Abstract base class for multibind producers.
+  # Is suitable as base class for custom implementations of multibind producers.
+  # @abstract
+  # @api public
+  #
+  class MultibindProducer < AbstractArgumentedProducer
+    attr_reader :contributions_key
+
+    # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
+    # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
+    # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
+    # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
+    #
+    # @api public
+    #
+    def initialize(injector, binding, scope, options)
+      super
+      @contributions_key = injector.key_factory.multibind_contributions(binding.id)
+    end
+
+    # @param expected [Array<Puppet::Pops::Types::PAnyType>, Puppet::Pops::Types::PAnyType] expected type or types
+    # @param actual [Object, Puppet::Pops::Types::PAnyType> the actual value (or its type)
+    # @return [String] a formatted string for inclusion as detail in an error message
+    # @api private
+    #
+    def type_error_detail(expected, actual)
+      tc = injector.type_calculator
+      expected = [expected] unless expected.is_a?(Array)
+      actual_t = tc.is_ptype?(actual) ? actual : tc.infer(actual)
+      expstrs = expected.collect {|t| tc.string(t) }
+      "expected: #{expstrs.join(', or ')}, got: #{tc.string(actual_t)}"
+    end
+  end
+
+  # A configurable multibind producer for Array type multibindings.
+  #
+  # This implementation collects all contributions to the multibind and then combines them using the following rules:
+  #
+  # - all *unnamed* entries are added unless the option `:priority_on_unnamed` is set to true, in which case the unnamed
+  #   contribution with the highest priority is added, and the rest are ignored (unless they have the same priority in which
+  #   case an error is raised).
+  # - all *named* entries are handled the same way as *unnamed* but the option `:priority_on_named` controls their handling.
+  # - the option `:uniq` post processes the result to only contain unique entries
+  # - the option `:flatten` post processes the result by flattening all nested arrays.
+  # - If both `:flatten` and `:uniq` are true, flattening is done first.
+  #
+  # @note
+  #   Collection accepts elements that comply with the array's element type, or the entire type (i.e. Array[element_type]).
+  #   If the type is restrictive - e.g. Array[String] and an Array[String] is contributed, the result will not be type
+  #   compliant without also using the `:flatten` option, and a type error will be raised. For an array with relaxed typing
+  #   i.e. Array[Data], it is valid to produce a result such as `['a', ['b', 'c'], 'd']` and no flattening is required
+  #   and no error is raised (but using the array needs to be aware of potential array, non-array entries.
+  #   The use of the option `:flatten` controls how the result is flattened.
+  #
+  # @api public
+  #
+  class ArrayMultibindProducer < MultibindProducer
+
+    # @return [Boolean] whether the result should be made contain unique (non-equal) entries or not
+    # @api public
+    attr_reader :uniq
+
+    # @return [Boolean, Integer] If result should be flattened (true), or not (false), or flattened to given level (0 = none, -1 = all)
+    # @api public
+    attr_reader :flatten
+
+    # @return [Boolean] whether priority should be considered for named contributions
+    # @api public
+    attr_reader :priority_on_named
+
+    # @return [Boolean] whether priority should be considered for unnamed contributions
+    # @api public
+    attr_reader :priority_on_unnamed
+
+    # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
+    # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
+    # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
+    # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
+    # @option options [Boolean] :uniq (false) if collected result should be post-processed to contain only unique entries
+    # @option options [Boolean, Integer] :flatten (false) if collected result should be post-processed so all contained arrays
+    #   are flattened. May be set to an Integer value to indicate the level of recursion (-1 is endless, 0 is none).
+    # @option options [Boolean] :priority_on_named (true) if highest precedented named element should win or if all should be included
+    # @option options [Boolean] :priority_on_unnamed (false) if highest precedented unnamed element should win or if all should be included
+    # @api public
+    #
+    def initialize(injector, binding, scope, options)
+      super
+      @uniq = !!options[:uniq]
+      @flatten = options[:flatten]
+      @priority_on_named = options[:priority_on_named].nil? ? true : options[:priority_on_name]
+      @priority_on_unnamed = !!options[:priority_on_unnamed]
+
+      case @flatten
+      when Integer
+      when true
+        @flatten = -1
+      when false
+        @flatten = nil
+      when NilClass
+        @flatten = nil
+      else
+        raise ArgumentError, "Option :flatten must be nil, Boolean, or an integer value" unless @flatten.is_a?(Integer)
+      end
+    end
+
+    protected
+
+    # @api private
+    def internal_produce(scope)
+      seen = {}
+      included_keys = []
+
+      injector.get_contributions(scope, contributions_key).each do |element|
+        key = element[0]
+        entry = element[1]
+
+        name = entry.binding.name
+        existing = seen[name]
+        empty_name = name.nil? || name.empty?
+        if existing
+          if empty_name && priority_on_unnamed
+            if (seen[name] <=> entry) >= 0
+              raise ArgumentError, "Duplicate key (same priority) contributed to Array Multibinding '#{binding.name}' with unnamed entry."
+            end
+            next
+          elsif !empty_name && priority_on_named
+            if (seen[name] <=> entry) >= 0
+              raise ArgumentError, "Duplicate key (same priority) contributed to Array Multibinding '#{binding.name}', key: '#{name}'."
+            end
+            next
+          end
+        else
+          seen[name] = entry
+        end
+        included_keys << key
+      end
+      result = included_keys.collect do |k|
+        x = injector.lookup_key(scope, k)
+        assert_type(binding(), injector.type_calculator(), x)
+        x
+      end
+
+      result.flatten!(flatten) if flatten
+      result.uniq! if uniq
+      result
+    end
+
+    # @api private
+    def assert_type(binding, tc, value)
+      infered = tc.infer(value)
+      unless tc.assignable?(binding.type.element_type, infered) || tc.assignable?(binding.type, infered)
+        raise ArgumentError, ["Type Error: contribution to '#{binding.name}' does not match type of multibind, ",
+          "#{type_error_detail([binding.type.element_type, binding.type], value)}"].join()
+      end
+    end
+  end
+
+  # @api public
+  class HashMultibindProducer < MultibindProducer
+
+    # @return [Symbol] One of `:error`, `:merge`, `:append`, `:priority`, `:ignore`
+    # @api public
+    attr_reader :conflict_resolution
+
+    # @return [Boolean]
+    # @api public
+    attr_reader :uniq
+
+    # @return [Boolean, Integer] Flatten all if true, or none if false, or to given level (0 = none, -1 = all)
+    # @api public
+    attr_reader :flatten
+
+    # The hash multibind producer provides options to control conflict resolution.
+    # By default, the hash is produced using `:priority` resolution - the highest entry is selected, the rest are
+    # ignored unless they have the same priority which is an error.
+    #
+    # @param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates
+    # @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer
+    # @param scope [Puppet::Parser::Scope] The scope to use for evaluation
+    # @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value
+    # @option options [Symbol, String] :conflict_resolution (:priority) One of `:error`, `:merge`, `:append`, `:priority`, `:ignore`
+    #   <ul><li> `ignore` the first found highest priority contribution is used, the rest are ignored</li>
+    #   <li>`error` any duplicate key is an error</li>
+    #   <li>`append` element type must be compatible with Array, makes elements be arrays and appends all found</li>
+    #   <li>`merge` element type must be compatible with hash, merges hashes with retention of highest priority hash content</li>
+    #   <li>`priority` the first found highest priority contribution is used, duplicates with same priority raises and error, the rest are
+    #     ignored.</li></ul>
+    # @option options [Boolean, Integer] :flatten (false) If appended should be flattened. Also see {#flatten}.
+    # @option options [Boolean] :uniq (false) If appended result should be made unique.
+    #
+    # @api public
+    #
+  def initialize(injector, binding, scope, options)
+      super
+      @conflict_resolution = options[:conflict_resolution].nil? ? :priority : options[:conflict_resolution]
+      @uniq = !!options[:uniq]
+      @flatten = options[:flatten]
+
+      unless [:error, :merge, :append, :priority, :ignore].include?(@conflict_resolution)
+        raise ArgumentError, "Unknown conflict_resolution for Multibind Hash: '#{@conflict_resolution}."
+      end
+
+      case @flatten
+      when Integer
+      when true
+        @flatten = -1
+      when false
+        @flatten = nil
+      when NilClass
+        @flatten = nil
+      else
+        raise ArgumentError, "Option :flatten must be nil, Boolean, or an integer value" unless @flatten.is_a?(Integer)
+      end
+
+      if uniq || flatten || conflict_resolution.to_s == 'append'
+        etype = binding.type.element_type
+        unless etype.class == Puppet::Pops::Types::PDataType || etype.is_a?(Puppet::Pops::Types::PArrayType)
+          detail = []
+          detail << ":uniq" if uniq
+          detail << ":flatten" if flatten
+          detail << ":conflict_resolution => :append" if conflict_resolution.to_s == 'append'
+          raise ArgumentError, ["Options #{detail.join(', and ')} cannot be used with a Multibind ",
+            "of type #{injector.type_calculator.string(binding.type)}"].join()
+        end
+      end
+    end
+
+    protected
+
+    # @api private
+    def internal_produce(scope)
+      seen = {}
+      included_entries = []
+
+      injector.get_contributions(scope, contributions_key).each do |element|
+        key = element[0]
+        entry = element[1]
+
+        name = entry.binding.name
+        raise ArgumentError, "A Hash Multibind contribution to '#{binding.name}' must have a name." if name.nil? || name.empty?
+
+        existing = seen[name]
+        if existing
+          case conflict_resolution.to_s
+          when 'priority'
+            # skip if duplicate has lower prio
+            if (comparison = (seen[name] <=> entry)) <= 0
+              raise ArgumentError, "Internal Error: contributions not given in decreasing precedence order" unless comparison == 0
+              raise ArgumentError, "Duplicate key (same priority) contributed to Hash Multibinding '#{binding.name}', key: '#{name}'."
+            end
+            next
+
+          when 'ignore'
+            # skip, ignore conflict if prio is the same
+            next
+
+          when 'error'
+            raise ArgumentError, "Duplicate key contributed to Hash Multibinding '#{binding.name}', key: '#{name}'."
+
+          end
+        else
+          seen[name] = entry
+        end
+        included_entries << [key, entry]
+      end
+      result = {}
+      included_entries.each do |element|
+        k = element[ 0 ]
+        entry = element[ 1 ]
+        x = injector.lookup_key(scope, k)
+        name = entry.binding.name
+        assert_type(binding(), injector.type_calculator(), name, x)
+        if result[ name ]
+          merge(result, name, result[ name ], x)
+        else
+          result[ name ] = conflict_resolution().to_s == 'append' ? [x] : x
+        end
+      end
+      result
+    end
+
+    # @api private
+    def merge(result, name, higher, lower)
+      case conflict_resolution.to_s
+      when 'append'
+        unless higher.is_a?(Array)
+          higher = [higher]
+        end
+        tmp = higher + [lower]
+        tmp.flatten!(flatten) if flatten
+        tmp.uniq! if uniq
+        result[name] = tmp
+
+      when 'merge'
+        result[name] = lower.merge(higher)
+
+      end
+    end
+
+    # @api private
+    def assert_type(binding, tc, key, value)
+      unless tc.instance?(binding.type.key_type, key)
+        raise ArgumentError, ["Type Error: key contribution to #{binding.name}['#{key}'] ",
+          "is incompatible with key type: #{tc.label(binding.type)}, ",
+          type_error_detail(binding.type.key_type, key)].join()
+      end
+
+      if key.nil? || !key.is_a?(String) || key.empty?
+        raise ArgumentError, "Entry contributing to multibind hash with id '#{binding.id}' must have a name."
+      end
+
+      unless tc.instance?(binding.type.element_type, value)
+        raise ArgumentError, ["Type Error: value contribution to #{binding.name}['#{key}'] ",
+          "is incompatible, ",
+          type_error_detail(binding.type.element_type, value)].join()
+      end
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/scheme_handler/confdir_scheme.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/scheme_handler/confdir_scheme.rb
new file mode 100644
index 0000000..aafbf71
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/scheme_handler/confdir_scheme.rb
@@ -0,0 +1,34 @@
+require 'puppet/pops/binder/scheme_handler/symbolic_scheme'
+
+# Similar to {Puppet::Pops::Binder::SchemeHandler::ModuleScheme ModuleScheme}, but relative to the config root.
+# Does not support wildcard expansion.
+#
+# URI
+# ---
+# The URI scheme is `confdir:/[<FQN>]['?' | [?optional]` where FQN is the fully qualified name of the bindings to load.
+# The referecence is made optional by using a URI query of `?` or `?optional`.
+#
+# @todo
+#   If the file to load is outside of the file system rooted at $confdir (in a gem, or just on the Ruby path), it can not
+#   be marked as optional as it will always be ignored.
+#
+class Puppet::Pops::Binder::SchemeHandler::ConfdirScheme < Puppet::Pops::Binder::SchemeHandler::SymbolicScheme
+
+  def expand_included(uri, composer)
+    fqn = fqn_from_path(uri)[1]
+    if is_optional?(uri)
+      if Puppet::Pops::Binder::BindingsLoader.loadable?(composer.confdir, fqn)
+        [URI.parse('confdir:/' + fqn)]
+      else
+        []
+      end
+    else
+      # assume it exists (do not give error if not, since it may be excluded later)
+      [URI.parse('confdir:/' + fqn)]
+    end
+  end
+
+  def expand_excluded(uri, composer)
+    [URI.parse("confdir:/#{fqn_from_path(uri)[1]}")]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/scheme_handler/module_scheme.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/scheme_handler/module_scheme.rb
new file mode 100644
index 0000000..b409f8a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/scheme_handler/module_scheme.rb
@@ -0,0 +1,84 @@
+require 'puppet/pops/binder/scheme_handler/symbolic_scheme'
+
+# The module scheme allows loading bindings using the Puppet autoloader.
+# Optional uris are handled by checking if the symbolic name can be resolved to a loadable file
+# from modules.
+# 
+# URI
+# ---
+# The uri is on the format: `module:/[fqn][? | ?optional]` where `fqn` is a fully qualified bindings name
+# starting with the module name or '*' to denote 'any module'. A URI query of `?` or `?optional` makes the
+# request optional; if no loadable file is found, it is simply skipped.
+#
+#
+# @todo
+#   Does currently only support checking of optionality against files under a module. If the result should be loaded
+#   from any other location it can not be marked as optional as it will be ignored.
+#
+class Puppet::Pops::Binder::SchemeHandler::ModuleScheme < Puppet::Pops::Binder::SchemeHandler::SymbolicScheme
+
+  # Expands URIs with wildcards and checks optionality.
+  # @param uri [URI] the uri to possibly expand
+  # @return [Array<URI>] the URIs to include
+  # @api public
+  #
+  def expand_included(uri, composer)
+    result = []
+    split_name, fqn = fqn_from_path(uri)
+
+    # supports wild card in the module name
+    case split_name[0]
+    when '*'
+      # create new URIs, one per module name that has a corresponding .rb file relative to its
+      # '<root>/lib/puppet/bindings/'
+      #
+      composer.name_to_module.each_pair do | mod_name, mod |
+        expanded_name_parts = [mod_name] + split_name[1..-1]
+        expanded_name = expanded_name_parts.join('::')
+        if Puppet::Pops::Binder::BindingsLoader.loadable?(mod.path, expanded_name)
+          result << URI.parse('module:/' + expanded_name)
+        end
+      end
+    when nil
+      raise ArgumentError, "Bad bindings uri, the #{uri} has neither module name or wildcard '*' in its first path position"
+    else
+      joined_name = split_name.join('::')
+      # skip optional uri if it does not exist
+      if is_optional?(uri)
+        mod = composer.name_to_module[split_name[0]]
+        if mod && Puppet::Binder::BindingsLoader.loadable?(mod.path, joined_name)
+          result << URI.parse('module:/' + joined_name)
+        end
+      else
+        # assume it exists (do not give error if not, since it may be excluded later)
+        result << URI.parse('module:/' + joined_name)
+      end
+    end
+    result
+  end
+
+  # Expands URIs with wildcards
+  # @param uri [URI] the uri to possibly expand
+  # @return [Array<URI>] the URIs to exclude
+  # @api public
+  #
+  def expand_excluded(uri, composer)
+    result = []
+    split_name, fqn = fqn_from_path(uri)
+
+    case split_name[ 0 ]
+    when '*'
+      # create new URIs, one per module name
+      composer.name_to_module.each_pair do | name, mod |
+        result << URI.parse('module:/' + ([name] + split_name).join('::'))
+      end
+
+    when nil
+      raise ArgumentError, "Bad bindings uri, the #{uri} has neither module name or wildcard '*' in its first path position"
+    else
+      # create a clean copy (get rid of optional, fragments etc. and any trailing stuff
+      result << URI.parse('module:/' + split_name.join('::'))
+    end
+    result
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/scheme_handler/symbolic_scheme.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/scheme_handler/symbolic_scheme.rb
new file mode 100644
index 0000000..dc25811
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/scheme_handler/symbolic_scheme.rb
@@ -0,0 +1,53 @@
+# Abstract base class for schemes based on symbolic names of bindings.
+# This class helps resolve symbolic names by computing a path from a fully qualified name (fqn).
+# There are also helper methods do determine if the symbolic name contains a wild-card ('*') in the first
+# portion of the fqn (with the convention that '*' means 'any module').
+#
+# @abstract
+# @api public
+#
+class Puppet::Pops::Binder::SchemeHandler::SymbolicScheme < Puppetx::Puppet::BindingsSchemeHandler
+
+  # Shared implementation for module: and confdir: since the distinction is only in checks if a symbolic name
+  # exists as a loadable file or not. Once this method is called it is assumed that the name is relative
+  # and that it should exist relative to some loadable ruby location.
+  #
+  # TODO: this needs to be changed once ARM-8 Puppet DSL concrete syntax is also supported.
+  # @api public
+  #
+  def contributed_bindings(uri, scope, composer)
+    fqn = fqn_from_path(uri)[1]
+    bindings = Puppet::Pops::Binder::BindingsLoader.provide(scope, fqn)
+    raise ArgumentError, "Cannot load bindings '#{uri}' - no bindings found." unless bindings
+    # Must clone as the rest mutates the model
+    cloned_bindings = Marshal.load(Marshal.dump(bindings))
+    Puppet::Pops::Binder::BindingsFactory.contributed_bindings(fqn, cloned_bindings)
+  end
+
+  # @api private
+  def fqn_from_path(uri)
+    split_path = uri.path.split('/')
+    if split_path.size > 1 && split_path[-1].empty?
+      split_path.delete_at(-1)
+    end
+
+    fqn = split_path[ 1 ]
+    raise ArgumentError, "Module scheme binding reference has no name." unless fqn
+    split_name = fqn.split('::')
+    # drop leading '::'
+    split_name.shift if split_name[0] && split_name[0].empty?
+    [split_name, split_name.join('::')]
+  end
+
+  # True if super thinks it is optional or if it contains a wildcard.
+  # @return [Boolean] true if the uri represents an optional set of bindings.
+  # @api public
+  def is_optional?(uri)
+    super(uri) || has_wildcard?(uri)
+  end
+
+  # @api private
+  def has_wildcard?(uri)
+    (path = uri.path) && path.split('/')[1].start_with?('*::')
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/system_bindings.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/system_bindings.rb
new file mode 100644
index 0000000..33bbd71
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/binder/system_bindings.rb
@@ -0,0 +1,60 @@
+class Puppet::Pops::Binder::SystemBindings
+  # Constant with name used for bindings used during initialization of injector
+  ENVIRONMENT_BOOT_BINDINGS_NAME = 'puppet::env::injector::boot'
+
+  Factory = Puppet::Pops::Binder::BindingsFactory
+  @extension_bindings = Factory.named_bindings("puppet::extensions")
+  @default_bindings   = Factory.named_bindings("puppet::default")
+  # Bindings in effect when real injector is created
+  @injector_boot_bindings   = Factory.named_bindings("puppet::injector_boot")
+
+  def self.extensions()
+    @extension_bindings
+  end
+
+  def self.default_bindings()
+    @default_bindings
+  end
+
+  def self.injector_boot_bindings()
+    @injector_boot_bindings
+  end
+
+  def self.final_contribution
+    Factory.contributed_bindings("puppet-final", [deep_clone(@extension_bindings.model)])
+  end
+
+  def self.default_contribution
+    Factory.contributed_bindings("puppet-default", [deep_clone(@default_bindings.model)])
+  end
+
+  def self.injector_boot_contribution(env_boot_bindings)
+    # Compose the injector_boot_bindings contributed from the puppet runtime book (i.e. defaults for
+    # extensions that should be active in the boot injector - see Puppetx initialization.
+    #
+    bindings = [deep_clone(@injector_boot_bindings.model), deep_clone(@injector_default_bindings)]
+
+    # Add the bindings that come from the bindings_composer as it may define custom extensions added in the bindings
+    # configuration. (i.e. bindings required to be able to lookup using bindings schemes and backends when
+    # configuring the real injector).
+    #
+    bindings << env_boot_bindings unless env_boot_bindings.nil?
+
+    # return the composition
+    Factory.contributed_bindings("puppet-injector-boot", bindings)
+  end
+
+  def self.factory()
+    Puppet::Pops::Binder::BindingsFactory
+  end
+
+  def self.type_factory()
+    Puppet::Pops::Types::TypeFactory
+  end
+
+  private
+
+  def self.deep_clone(o)
+    Marshal.load(Marshal.dump(o))
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/containment.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/containment.rb
new file mode 100644
index 0000000..6f38f0c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/containment.rb
@@ -0,0 +1,104 @@
+# FIXME: This module should be updated when a newer version of RGen (>0.6.2) adds required meta model "e-method" supports.
+#
+require 'rgen/ecore/ecore'
+module Puppet::Pops::Containment
+  # Returns Enumerable, thus allowing
+  # some_element.eAllContents each {|contained| }
+  # This is a depth first enumeration where parent appears before children.
+  # @note the top-most object itself is not included in the enumeration, only what it contains.
+  def eAllContents
+    EAllContentsEnumerator.new(self)
+  end
+
+  def eAllContainers
+    EAllContainersEnumerator.new(self)
+  end
+
+  class EAllContainersEnumerator
+    include Enumerable
+
+    def initialize o
+      @element = o
+    end
+
+    def each &block
+      if block_given?
+        eAllContainers(@element, &block)
+      else
+        self
+      end
+    end
+
+    def eAllContainers(element, &block)
+      x = element.eContainer
+      while !x.nil? do
+        yield x
+        x = x.eContainer
+      end
+    end
+
+  end
+
+  class EAllContentsEnumerator
+    include Enumerable
+    def initialize o
+      @element = o
+      @@cache ||= {}
+    end
+
+    def each &block
+      if block_given?
+        eAllContents(@element, &block)
+        @element
+      else
+        self
+      end
+    end
+
+    def eAllContents(element, &block)
+      # This method is performance critical and code has been manually in-lined.
+      # Resist the urge to make this pretty.
+      # The slow way is element.eAllContainments.each {|c| element.getGenericsAsArray(c.name) }
+      #
+      (@@cache[element.class] || all_containment_getters(element)).each do |r|
+        children = element.send(r)
+        if children.is_a?(Array)
+          children.each do |c|
+            yield c
+            eAllContents(c, &block)
+          end
+        elsif !children.nil?
+          yield children
+          eAllContents(children, &block)
+        end
+      end
+    end
+
+    private
+
+    def all_containment_getters(element)
+      elem_class = element.class
+      containments = []
+      collect_getters(elem_class.ecore, containments)
+      @@cache[elem_class] = containments
+    end
+
+    def collect_getters(eclass, containments)
+        eclass.eStructuralFeatures.select {|r| r.is_a?(RGen::ECore::EReference) && r.containment}.each do |r|
+          n = r.name
+          containments << :"get#{n[0..0].upcase + ( n[1..-1] || "" )}"
+        end
+        eclass.eSuperTypes.each do |t|
+          if cached = @@cache[ t.instanceClass ]
+            containments.concat(cached)
+          else
+            super_containments = []
+            collect_getters(t, super_containments)
+            @@cache[ t.instanceClass ] = super_containments
+            containments.concat(super_containments)
+          end
+      end
+    end
+
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/access_operator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/access_operator.rb
new file mode 100644
index 0000000..edd366f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/access_operator.rb
@@ -0,0 +1,620 @@
+# AccessOperator handles operator []
+# This operator is part of evaluation.
+#
+class Puppet::Pops::Evaluator::AccessOperator
+  # Provides access to the Puppet 3.x runtime (scope, etc.)
+  # This separation has been made to make it easier to later migrate the evaluator to an improved runtime.
+  #
+  include Puppet::Pops::Evaluator::Runtime3Support
+
+  Issues = Puppet::Pops::Issues
+  TYPEFACTORY = Puppet::Pops::Types::TypeFactory
+  EMPTY_STRING = ''.freeze
+
+  attr_reader :semantic
+
+  # Initialize with AccessExpression to enable reporting issues
+  # @param access_expression [Puppet::Pops::Model::AccessExpression] the semantic object being evaluated
+  # @return [void]
+  #
+  def initialize(access_expression)
+    @@access_visitor ||= Puppet::Pops::Visitor.new(self, "access", 2, nil)
+    @semantic = access_expression
+  end
+
+  def access (o, scope, *keys)
+    @@access_visitor.visit_this_2(self, o, scope, keys)
+  end
+
+  protected
+
+  def access_Object(o, scope, keys)
+    fail(Issues::OPERATOR_NOT_APPLICABLE, @semantic.left_expr, :operator=>'[]', :left_value => o)
+  end
+
+  def access_String(o, scope, keys)
+    keys.flatten!
+    result = case keys.size
+    when 0
+      fail(Puppet::Pops::Issues::BAD_STRING_SLICE_ARITY, @semantic.left_expr, {:actual => keys.size})
+    when 1
+      # Note that Ruby 1.8.7 requires a length of 1 to produce a String
+      k1 = coerce_numeric(keys[0], @semantic.keys[0], scope)
+      bad_access_key_type(o, 0, k1, Integer) unless k1.is_a?(Integer)
+      k2 = 1
+      k1 = k1 < 0 ? o.length + k1 : k1           # abs pos
+      # if k1 is outside, a length of 1 always produces an empty string
+      if k1 < 0
+        EMPTY_STRING
+      else
+        o[ k1, k2 ]
+      end
+    when 2
+      k1 = coerce_numeric(keys[0], @semantic.keys[0], scope)
+      k2 = coerce_numeric(keys[1], @semantic.keys[1], scope)
+      [k1, k2].each_with_index { |k,i| bad_access_key_type(o, i, k, Integer) unless k.is_a?(Integer) }
+
+      k1 = k1 < 0 ? o.length + k1 : k1           # abs pos (negative is count from end)
+      k2 = k2 < 0 ? o.length - k1 + k2 + 1 : k2  # abs length (negative k2 is length from pos to end count)
+      # if k1 is outside, adjust to first position, and adjust length
+      if k1 < 0
+        k2 = k2 + k1
+        k1 = 0
+      end
+      o[ k1, k2 ]
+    else
+      fail(Puppet::Pops::Issues::BAD_STRING_SLICE_ARITY, @semantic.left_expr, {:actual => keys.size})
+    end
+    # Specified as: an index outside of range, or empty result == empty string
+    (result.nil? || result.empty?) ? EMPTY_STRING : result
+  end
+
+  # Parameterizes a PRegexp Type with a pattern string or r ruby egexp
+  #
+  def access_PRegexpType(o, scope, keys)
+    keys.flatten!
+    unless keys.size == 1
+      blamed = keys.size == 0 ? @semantic : @semantic.keys[1]
+      fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_ARITY, blamed, :base_type => o, :min=>1, :actual => keys.size)
+    end
+    assert_keys(keys, o, 1, 1, String, Regexp)
+    Puppet::Pops::Types::TypeFactory.regexp(*keys)
+  end
+
+  # Evaluates <ary>[] with 1 or 2 arguments. One argument is an index lookup, two arguments is a slice from/to.
+  #
+  def access_Array(o, scope, keys)
+    keys.flatten!
+    case keys.size
+    when 0
+      fail(Puppet::Pops::Issues::BAD_ARRAY_SLICE_ARITY, @semantic.left_expr, {:actual => keys.size})
+    when 1
+      k = coerce_numeric(keys[0], @semantic.keys[0], scope)
+      unless k.is_a?(Integer)
+        bad_access_key_type(o, 0, k, Integer)
+      end
+      o[k]
+    when 2
+      # A slice [from, to] with support for -1 to mean start, or end respectively.
+      k1 = coerce_numeric(keys[0], @semantic.keys[0], scope)
+      k2 = coerce_numeric(keys[1], @semantic.keys[1], scope)
+
+      [k1, k2].each_with_index { |k,i| bad_access_key_type(o, i, k, Integer) unless k.is_a?(Integer) }
+
+      # Help confused Ruby do the right thing (it truncates to the right, but negative index + length can never overlap
+      # the available range.
+      k1 = k1 < 0 ? o.length + k1 : k1           # abs pos (negative is count from end)
+      k2 = k2 < 0 ? o.length - k1 + k2 + 1 : k2  # abs length (negative k2 is length from pos to end count)
+      # if k1 is outside, adjust to first position, and adjust length
+      if k1 < 0
+        k2 = k2 + k1
+        k1 = 0
+      end
+      # Help ruby always return empty array when asking for a sub array
+      result = o[ k1, k2 ]
+      result.nil? ? [] : result
+    else
+      fail(Puppet::Pops::Issues::BAD_ARRAY_SLICE_ARITY, @semantic.left_expr, {:actual => keys.size})
+    end
+  end
+
+
+  # Evaluates <hsh>[] with support for one or more arguments. If more than one argument is used, the result
+  # is an array with each lookup.
+  # @note
+  #   Does not flatten its keys to enable looking up with a structure
+  #
+  def access_Hash(o, scope, keys)
+    # Look up key in hash, if key is nil, try alternate form (:undef) before giving up.
+    # This is done because the hash may have been produced by 3x logic and may thus contain :undef.
+    result = keys.collect do |k|
+      o.fetch(k) { |key| key.nil? ? o[:undef] : nil }
+    end
+    case result.size
+    when 0
+      fail(Puppet::Pops::Issues::BAD_HASH_SLICE_ARITY, @semantic.left_expr, {:actual => keys.size})
+    when 1
+      result.pop
+    else
+      # remove nil elements and return
+      result.compact!
+      result
+    end
+  end
+
+  # Ruby does not have an infinity constant.  TODO: Consider having one constant in Puppet. Now it is in several places.
+  INFINITY = 1.0 / 0.0
+
+  def access_PEnumType(o, scope, keys)
+    keys.flatten!
+    assert_keys(keys, o, 1, INFINITY, String)
+    Puppet::Pops::Types::TypeFactory.enum(*keys)
+  end
+
+  def access_PVariantType(o, scope, keys)
+    keys.flatten!
+    assert_keys(keys, o, 1, INFINITY, Puppet::Pops::Types::PAnyType)
+    Puppet::Pops::Types::TypeFactory.variant(*keys)
+  end
+
+  def access_PTupleType(o, scope, keys)
+    keys.flatten!
+    if TYPEFACTORY.is_range_parameter?(keys[-2]) && TYPEFACTORY.is_range_parameter?(keys[-1])
+      size_type = TYPEFACTORY.range(keys[-2], keys[-1])
+      keys = keys[0, keys.size - 2]
+    elsif TYPEFACTORY.is_range_parameter?(keys[-1])
+      size_type = TYPEFACTORY.range(keys[-1], :default)
+      keys = keys[0, keys.size - 1]
+    end
+    assert_keys(keys, o, 1, INFINITY, Puppet::Pops::Types::PAnyType)
+    t = Puppet::Pops::Types::TypeFactory.tuple(*keys)
+    # set size type, or nil for default (exactly 1)
+    t.size_type = size_type
+    t
+  end
+
+  def access_PCallableType(o, scope, keys)
+    TYPEFACTORY.callable(*keys)
+  end
+
+  def access_PStructType(o, scope, keys)
+    assert_keys(keys, o, 1, 1, Hash)
+    TYPEFACTORY.struct(keys[0])
+  end
+
+  def access_PStringType(o, scope, keys)
+    keys.flatten!
+    case keys.size
+    when 1
+      size_t = collection_size_t(0, keys[0])
+    when 2
+      size_t = collection_size_t(0, keys[0], keys[1])
+    else
+      fail(Puppet::Pops::Issues::BAD_STRING_SLICE_ARITY, @semantic, {:actual => keys.size})
+    end
+    string_t = Puppet::Pops::Types::TypeFactory.string()
+    string_t.size_type = size_t
+    string_t
+  end
+
+  # Asserts type of each key and calls fail with BAD_TYPE_SPECIFICATION
+  # @param keys [Array<Object>] the evaluated keys
+  # @param o [Object] evaluated LHS reported as :base_type
+  # @param min [Integer] the minimum number of keys (typically 1)
+  # @param max [Numeric] the maximum number of keys (use same as min, specific number, or INFINITY)
+  # @param allowed_classes [Class] a variable number of classes that each key must be an instance of (any)
+  # @api private
+  #
+  def assert_keys(keys, o, min, max, *allowed_classes)
+    size = keys.size
+    unless size.between?(min, max || INFINITY)
+      fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_ARITY, @semantic, :base_type => o, :min=>1, :max => max, :actual => keys.size)
+    end
+    keys.each_with_index do |k, i|
+      unless allowed_classes.any? {|clazz| k.is_a?(clazz) }
+        bad_type_specialization_key_type(o, i, k, *allowed_classes)
+      end
+    end
+  end
+
+  def bad_access_key_type(lhs, key_index, actual, *expected_classes)
+    fail(Puppet::Pops::Issues::BAD_SLICE_KEY_TYPE, @semantic.keys[key_index], {
+      :left_value => lhs,
+      :actual => bad_key_type_name(actual),
+      :expected_classes => expected_classes
+    })
+  end
+
+  def bad_key_type_name(actual)
+    case actual
+    when nil
+      'Undef'
+    when :default
+      'Default'
+    else
+      Puppet::Pops::Types::TypeCalculator.generalize!(Puppet::Pops::Types::TypeCalculator.infer(actual)).to_s
+    end
+  end
+
+  def bad_type_specialization_key_type(type, key_index, actual, *expected_classes)
+    label_provider = Puppet::Pops::Model::ModelLabelProvider.new()
+    expected = expected_classes.map {|c| label_provider.label(c) }.join(' or ')
+    fail(Puppet::Pops::Issues::BAD_TYPE_SPECIALIZATION, @semantic.keys[key_index], {
+      :type => type,
+      :message => "Cannot use #{bad_key_type_name(actual)} where #{expected} is expected"
+    })
+  end
+
+  def access_PPatternType(o, scope, keys)
+    keys.flatten!
+    assert_keys(keys, o, 1, INFINITY, String, Regexp, Puppet::Pops::Types::PPatternType, Puppet::Pops::Types::PRegexpType)
+    Puppet::Pops::Types::TypeFactory.pattern(*keys)
+  end
+
+  def access_POptionalType(o, scope, keys)
+    keys.flatten!
+    if keys.size == 1
+      type = keys[0]
+      unless type.is_a?(Puppet::Pops::Types::PAnyType) || type.is_a?(String)
+        fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_TYPE, @semantic.keys[0], {:base_type => 'Optional-Type', :actual => type.class})
+      end
+      TYPEFACTORY.optional(type)
+    else
+      fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_ARITY, @semantic, {:base_type => 'Optional-Type', :min => 1, :actual => keys.size})
+    end
+  end
+
+  def access_PNotUndefType(o, scope, keys)
+    keys.flatten!
+    case keys.size
+    when 0
+      TYPEFACTORY.not_undef
+    when 1
+      type = keys[0]
+      case type
+      when String
+        type = TYPEFACTORY.string(type)
+      when Puppet::Pops::Types::PAnyType
+        type = nil if type.class == Puppet::Pops::Types::PAnyType
+      else
+        fail(Puppet::Pops::Issues::BAD_NOT_UNDEF_SLICE_TYPE, @semantic.keys[0], {:base_type => 'NotUndef-Type', :actual => type.class})
+      end
+      TYPEFACTORY.not_undef(type)
+    else
+      fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_ARITY, @semantic, {:base_type => 'NotUndef-Type', :min => 0, :max => 1, :actual => keys.size})
+    end
+  end
+
+  def access_PType(o, scope, keys)
+    keys.flatten!
+    if keys.size == 1
+      unless keys[0].is_a?(Puppet::Pops::Types::PAnyType)
+        fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_TYPE, @semantic.keys[0], {:base_type => 'Type-Type', :actual => keys[0].class})
+      end
+      result = Puppet::Pops::Types::PType.new()
+      result.type = keys[0]
+      result
+    else
+      fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_ARITY, @semantic, {:base_type => 'Type-Type', :min => 1, :actual => keys.size})
+    end
+  end
+
+  def access_PRuntimeType(o, scope, keys)
+    keys.flatten!
+    assert_keys(keys, o, 2, 2, String, String)
+    # create runtime type based on runtime and name of class, (not inference of key's type)
+    Puppet::Pops::Types::TypeFactory.runtime(*keys)
+  end
+
+  def access_PIntegerType(o, scope, keys)
+    keys.flatten!
+    unless keys.size.between?(1, 2)
+      fail(Puppet::Pops::Issues::BAD_INTEGER_SLICE_ARITY, @semantic, {:actual => keys.size})
+    end
+    keys.each_with_index do |x, index|
+      fail(Puppet::Pops::Issues::BAD_INTEGER_SLICE_TYPE, @semantic.keys[index],
+        {:actual => x.class}) unless (x.is_a?(Integer) || x == :default)
+    end
+    ranged_integer = Puppet::Pops::Types::PIntegerType.new()
+    from, to = keys
+    # NOTE! Do not merge the following line to 4.x. It has the same check in the initialize method
+    raise ArgumentError, "'from' must be less or equal to 'to'. Got (#{from}, #{to}" if from.is_a?(Numeric) && to.is_a?(Numeric) && from > to
+
+    ranged_integer.from = from == :default ? nil : from
+    ranged_integer.to = to == :default ? nil : to
+    ranged_integer
+  end
+
+  def access_PFloatType(o, scope, keys)
+    keys.flatten!
+    unless keys.size.between?(1, 2)
+      fail(Puppet::Pops::Issues::BAD_FLOAT_SLICE_ARITY, @semantic, {:actual => keys.size})
+    end
+    keys.each_with_index do |x, index|
+      fail(Puppet::Pops::Issues::BAD_FLOAT_SLICE_TYPE, @semantic.keys[index],
+        {:actual => x.class}) unless (x.is_a?(Float) || x.is_a?(Integer) || x == :default)
+    end
+    ranged_float = Puppet::Pops::Types::PFloatType.new()
+    from, to = keys
+    # NOTE! Do not merge the following line to 4.x. It has the same check in the initialize method
+    raise ArgumentError, "'from' must be less or equal to 'to'. Got (#{from}, #{to}" if from.is_a?(Numeric) && to.is_a?(Numeric) && from > to
+
+    ranged_float.from = from == :default || from.nil? ? nil : Float(from)
+    ranged_float.to = to == :default || to.nil? ? nil : Float(to)
+    ranged_float
+  end
+
+  # A Hash can create a new Hash type, one arg sets value type, two args sets key and value type in new type.
+  # With 3 or 4 arguments, these are used to create a size constraint.
+  # It is not possible to create a collection of Hash types directly.
+  #
+  def access_PHashType(o, scope, keys)
+    keys.flatten!
+    keys[0,2].each_with_index do |k, index|
+      unless k.is_a?(Puppet::Pops::Types::PAnyType)
+        fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_TYPE, @semantic.keys[index], {:base_type => 'Hash-Type', :actual => k.class})
+      end
+    end
+    case keys.size
+    when 2
+      result = Puppet::Pops::Types::PHashType.new()
+      result.key_type = keys[0]
+      result.element_type = keys[1]
+      result
+    when 3
+      result = Puppet::Pops::Types::PHashType.new()
+      result.key_type = keys[0]
+      result.element_type = keys[1]
+      size_t = collection_size_t(1, keys[2])
+      result
+    when 4
+      result = Puppet::Pops::Types::PHashType.new()
+      result.key_type = keys[0]
+      result.element_type = keys[1]
+      size_t = collection_size_t(1, keys[2], keys[3])
+      result
+    else
+      fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_ARITY, @semantic, {
+        :base_type => 'Hash-Type', :min => 2, :max => 4, :actual => keys.size
+      })
+    end
+    result.size_type = size_t if size_t
+    result
+  end
+
+  # CollectionType is parameterized with a range
+  def access_PCollectionType(o, scope, keys)
+    keys.flatten!
+    case keys.size
+    when 1
+      size_t = collection_size_t(1, keys[0])
+    when 2
+      size_t = collection_size_t(1, keys[0], keys[1])
+    else
+      fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_ARITY, @semantic,
+        {:base_type => 'Collection-Type', :min => 1, :max => 2, :actual => keys.size})
+    end
+    result = Puppet::Pops::Types::PCollectionType.new()
+    result.size_type = size_t
+    result
+  end
+
+  # An Array can create a new Array type. It is not possible to create a collection of Array types.
+  #
+  def access_PArrayType(o, scope, keys)
+    keys.flatten!
+    case keys.size
+    when 1
+      size_t = nil
+    when 2
+      size_t = collection_size_t(1, keys[1])
+    when 3
+      size_t = collection_size_t(1, keys[1], keys[2])
+    else
+      fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_ARITY, @semantic,
+        {:base_type => 'Array-Type', :min => 1, :max => 3, :actual => keys.size})
+    end
+    unless keys[0].is_a?(Puppet::Pops::Types::PAnyType)
+      fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_TYPE, @semantic.keys[0], {:base_type => 'Array-Type', :actual => keys[0].class})
+    end
+    result = Puppet::Pops::Types::PArrayType.new()
+    result.element_type = keys[0]
+    result.size_type = size_t
+    result
+  end
+
+  # Produces an PIntegerType (range) given one or two keys.
+  def collection_size_t(start_index, *keys)
+    if keys.size == 1 && keys[0].is_a?(Puppet::Pops::Types::PIntegerType)
+      keys[0].copy
+    else
+      keys.each_with_index do |x, index|
+        fail(Puppet::Pops::Issues::BAD_COLLECTION_SLICE_TYPE, @semantic.keys[start_index + index],
+          {:actual => x.class}) unless (x.is_a?(Integer) || x == :default)
+      end
+      ranged_integer = Puppet::Pops::Types::PIntegerType.new()
+      from, to = keys
+      # NOTE! Do not merge the following line to 4.x. It has the same check in the initialize method
+      raise ArgumentError, "'from' must be less or equal to 'to'. Got (#{from}, #{to}" if from.is_a?(Numeric) && to.is_a?(Numeric) && from > to
+
+      ranged_integer.from = from == :default ? nil : from
+      ranged_integer.to = to == :default ? nil : to
+      ranged_integer
+    end
+  end
+
+  # A Puppet::Resource represents either just a type (no title), or is a fully qualified type/title.
+  #
+  def access_Resource(o, scope, keys)
+    # To access a Puppet::Resource as if it was a PResourceType, simply infer it, and take the type of
+    # the parameterized meta type (i.e. Type[Resource[the_resource_type, the_resource_title]])
+    t = Puppet::Pops::Types::TypeCalculator.infer(o).type
+    # must map "undefined title" from resource to nil
+    t.title = nil if t.title == EMPTY_STRING
+    access(t, scope, *keys)
+  end
+
+  # A Resource can create a new more specific Resource type, and/or an array of resource types
+  # If the given type has title set, it can not be specified further.
+  # @example
+  #   Resource[File]               # => File
+  #   Resource[File, 'foo']        # => File[foo]
+  #   Resource[File. 'foo', 'bar'] # => [File[foo], File[bar]]
+  #   File['foo', 'bar']           # => [File[foo], File[bar]]
+  #   File['foo']['bar']           # => Value of the 'bar' parameter in the File['foo'] resource
+  #   Resource[File]['foo', 'bar'] # => [File[Foo], File[bar]]
+  #   Resource[File, 'foo', 'bar'] # => [File[foo], File[bar]]
+  #   Resource[File, 'foo']['bar'] # => Value of the 'bar' parameter in the File['foo'] resource
+  #
+  def access_PResourceType(o, scope, keys)
+    blamed = keys.size == 0 ? @semantic : @semantic.keys[0]
+
+    if keys.size == 0
+      fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_ARITY, blamed,
+        :base_type => Puppet::Pops::Types::TypeCalculator.new().string(o), :min => 1, :max => -1, :actual => 0)
+    end
+
+    # Must know which concrete resource type to operate on in all cases.
+    # It is not allowed to specify the type in an array arg - e.g. Resource[[File, 'foo']]
+    # type_name is LHS type_name if set, else the first given arg
+    type_name = o.type_name || keys.shift
+    type_name = case type_name
+    when Puppet::Pops::Types::PResourceType
+      type_name.type_name
+    when String
+      type_name.downcase
+    else
+      # blame given left expression if it defined the type, else the first given key expression
+      blame = o.type_name.nil? ? @semantic.keys[0] : @semantic.left_expr
+      fail(Puppet::Pops::Issues::ILLEGAL_RESOURCE_SPECIALIZATION, blame, {:actual => bad_key_type_name(type_name)})
+    end
+
+    # type name must conform
+    if type_name !~ Puppet::Pops::Patterns::CLASSREF
+      fail(Puppet::Pops::Issues::ILLEGAL_CLASSREF, blamed, {:name=>type_name})
+    end
+
+    # The result is an array if multiple titles are given, or if titles are specified with an array
+    # (possibly multiple arrays, and nested arrays).
+    result_type_array = keys.size > 1 || keys[0].is_a?(Array)
+    keys_orig_size = keys.size
+
+    keys.flatten!
+    keys.compact!
+
+    # If given keys  that were just a mix of empty/nil with empty array as a result.
+    # As opposed to calling the function the wrong way (without any arguments), (configurable issue),
+    # Return an empty array
+    #
+    if keys.empty? && keys_orig_size > 0
+      optionally_fail(Puppet::Pops::Issues::EMPTY_RESOURCE_SPECIALIZATION, blamed)
+      return result_type_array ? [] : nil
+    end
+
+    if !o.title.nil?
+      # lookup resource and return one or more parameter values
+      resource = find_resource(scope, o.type_name, o.title)
+      unless resource
+        fail(Puppet::Pops::Issues::UNKNOWN_RESOURCE, @semantic, {:type_name => o.type_name, :title => o.title})
+      end
+
+      result = keys.map do |k|
+        unless is_parameter_of_resource?(scope, resource, k)
+          fail(Puppet::Pops::Issues::UNKNOWN_RESOURCE_PARAMETER, @semantic,
+            {:type_name => o.type_name, :title => o.title, :param_name=>k})
+        end
+        get_resource_parameter_value(scope, resource, k)
+      end
+      return result_type_array ? result : result.pop
+    end
+
+
+    keys = [:no_title] if keys.size < 1 # if there was only a type_name and it was consumed
+    result = keys.each_with_index.map do |t, i|
+      unless t.is_a?(String) || t == :no_title
+        index = keys_orig_size != keys.size ? i+1 : i
+        fail(Puppet::Pops::Issues::BAD_TYPE_SPECIALIZATION, @semantic.keys[index], {
+          :type => o,
+          :message => "Cannot use #{bad_key_type_name(t)} where a resource title String is expected"
+        })
+      end
+
+      rtype = Puppet::Pops::Types::PResourceType.new()
+      rtype.type_name = type_name
+      rtype.title = (t == :no_title ? nil : t)
+      rtype
+    end
+    # returns single type if request was for a single entity, else an array of types (possibly empty)
+    return result_type_array ? result : result.pop
+  end
+
+  def access_PHostClassType(o, scope, keys)
+    blamed = keys.size == 0 ? @semantic : @semantic.keys[0]
+    keys_orig_size = keys.size
+
+    if keys_orig_size == 0
+      fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_ARITY, blamed,
+        :base_type => Puppet::Pops::Types::TypeCalculator.new().string(o), :min => 1, :max => -1, :actual => 0)
+    end
+
+    # The result is an array if multiple classnames are given, or if classnames are specified with an array
+    # (possibly multiple arrays, and nested arrays).
+    result_type_array = keys.size > 1 || keys[0].is_a?(Array)
+
+    keys.flatten!
+    keys.compact!
+
+    # If given keys  that were just a mix of empty/nil with empty array as a result.
+    # As opposed to calling the function the wrong way (without any arguments), (configurable issue),
+    # Return an empty array
+    #
+    if keys.empty? && keys_orig_size > 0
+      optionally_fail(Puppet::Pops::Issues::EMPTY_RESOURCE_SPECIALIZATION, blamed)
+      return result_type_array ? [] : nil
+    end
+
+    if o.class_name.nil?
+      # The type argument may be a Resource Type - the Puppet Language allows a reference such as
+      # Class[Foo], and this is interpreted as Class[Resource[Foo]] - which is ok as long as the resource
+      # does not have a title. This should probably be deprecated.
+      #
+      result = keys.each_with_index.map do |c, i|
+        name = if c.is_a?(Puppet::Pops::Types::PResourceType) && !c.type_name.nil? && c.title.nil?
+                 # type_name is already downcase. Don't waste time trying to downcase again
+                 c.type_name
+               elsif c.is_a?(String)
+                 c.downcase
+               else
+                 fail(Puppet::Pops::Issues::ILLEGAL_HOSTCLASS_NAME, @semantic.keys[i], {:name => c})
+               end
+
+        if name =~ Puppet::Pops::Patterns::NAME
+          ctype = Puppet::Pops::Types::PHostClassType.new()
+          # Remove leading '::' since all references are global, and 3x runtime does the wrong thing
+          ctype.class_name = name.sub(/^::/, EMPTY_STRING)
+          ctype
+        else
+          fail(Issues::ILLEGAL_NAME, @semantic.keys[i], {:name=>c})
+        end
+      end
+    else
+      # lookup class resource and return one or more parameter values
+      resource = find_resource(scope, 'class', o.class_name)
+      if resource
+        result = keys.map do |k|
+          if is_parameter_of_resource?(scope, resource, k)
+            get_resource_parameter_value(scope, resource, k)
+          else
+            fail(Puppet::Pops::Issues::UNKNOWN_RESOURCE_PARAMETER, @semantic,
+              {:type_name => 'Class', :title => o.class_name, :param_name=>k})
+          end
+        end
+      else
+        fail(Puppet::Pops::Issues::UNKNOWN_RESOURCE, @semantic, {:type_name => 'Class', :title => o.class_name})
+      end
+    end
+
+    # returns single type as type, else an array of types
+    return result_type_array ? result : result.pop
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/callable_mismatch_describer.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/callable_mismatch_describer.rb
new file mode 100644
index 0000000..9d1108f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/callable_mismatch_describer.rb
@@ -0,0 +1,175 @@
+# @api private
+module Puppet::Pops::Evaluator::CallableMismatchDescriber
+  # Produces a string with the difference between the given arguments and support signature(s).
+  #
+  # @param name [String] The name of the callable to describe
+  # @param args_type [Puppet::Pops::Types::Tuple] The tuple of argument types.
+  # @param supported_signatures [Array<Puppet::Pops::Types::Callable>] The available signatures that were available for calling.
+  #
+  # @api private
+  def self.diff_string(name, args_type, supported_signatures)
+    result = [ ]
+    if supported_signatures.size == 1
+      signature = supported_signatures[0]
+      params_type  = signature.type.param_types
+      block_type   = signature.type.block_type
+      params_names = signature.parameter_names
+      result << "expected:\n  #{name}(#{signature_string(signature)}) - #{arg_count_string(signature.type)}"
+    else
+      result << "expected one of:\n"
+      result << supported_signatures.map do |signature|
+        params_type = signature.type.param_types
+        "  #{name}(#{signature_string(signature)}) - #{arg_count_string(signature.type)}"
+      end.join("\n")
+    end
+
+    result << "\nactual:\n  #{name}(#{arg_types_string(args_type)}) - #{arg_count_string(args_type)}"
+
+    result.join('')
+  end
+
+  private
+
+  # Produces a string for the signature(s)
+  #
+  # @api private
+  def self.signature_string(signature)
+    param_types  = signature.type.param_types
+    block_type   = signature.type.block_type
+    param_names = signature.parameter_names
+
+    from, to = param_types.size_range
+    if from == 0 && to == 0
+      # No parameters function
+      return ''
+    end
+
+    required_count = from
+    # there may be more names than there are types, and count needs to be subtracted from the count
+    # to make it correct for the last named element
+    adjust = max(0, param_names.size() -1)
+    last_range = [max(0, (from - adjust)), (to - adjust)]
+
+    types =
+    case param_types
+    when Puppet::Pops::Types::PTupleType
+      param_types.types
+    when Puppet::Pops::Types::PArrayType
+      [ param_types.element_type ]
+    end
+    tc = Puppet::Pops::Types::TypeCalculator
+
+    # join type with names (types are always present, names are optional)
+    # separate entries with comma
+    #
+    result =
+    if param_names.empty?
+      types.each_with_index.map {|t, index| tc.string(t) + opt_value_indicator(index, required_count, 0) }
+    else
+      limit = param_names.size
+      result = param_names.each_with_index.map do |name, index|
+        [tc.string(types[index] || types[-1]), name].join(' ') + opt_value_indicator(index, required_count, limit)
+      end
+    end.join(', ')
+
+    # Add {from, to} for the last type
+    # This works for both Array and Tuple since it describes the allowed count of the "last" type element
+    # for both. It does not show anything when the range is {1,1}.
+    #
+    result += range_string(last_range)
+
+    # If there is a block, include it with its own optional count {0,1}
+    case signature.type.block_type
+    when Puppet::Pops::Types::POptionalType
+      result << ', ' unless result == ''
+      result << "#{tc.string(signature.type.block_type.optional_type)} #{signature.block_name} {0,1}"
+    when Puppet::Pops::Types::PCallableType
+      result << ', ' unless result == ''
+      result << "#{tc.string(signature.type.block_type)} #{signature.block_name}"
+    when NilClass
+      # nothing
+    end
+    result
+  end
+
+  # Why oh why Ruby do you not have a standard Math.max ?
+  # @api private
+  def self.max(a, b)
+    a >= b ? a : b
+  end
+
+  # @api private
+  def self.opt_value_indicator(index, required_count, limit)
+    count = index + 1
+    (count > required_count && count < limit) ? '?' : ''
+  end
+
+  # @api private
+  def self.arg_count_string(args_type)
+    if args_type.is_a?(Puppet::Pops::Types::PCallableType)
+      size_range = args_type.param_types.size_range # regular parameters
+      adjust_range=
+      case args_type.block_type
+      when Puppet::Pops::Types::POptionalType
+        size_range[1] += 1
+      when Puppet::Pops::Types::PCallableType
+        size_range[0] += 1
+        size_range[1] += 1
+      when NilClass
+        # nothing
+      else
+        raise ArgumentError, "Internal Error, only nil, Callable, and Optional[Callable] supported by Callable block type"
+      end
+    else
+      size_range = args_type.size_range
+    end
+    "arg count #{range_string(size_range, false)}"
+  end
+
+  # @api private
+  def self.arg_types_string(args_type)
+    types =
+    case args_type
+    when Puppet::Pops::Types::PTupleType
+      last_range = args_type.repeat_last_range
+      args_type.types
+    when Puppet::Pops::Types::PArrayType
+      last_range = args_type.size_range
+      [ args_type.element_type ]
+    end
+    # stringify generalized versions or it will display Integer[10,10] for "10", String['the content'] etc.
+    # note that type must be copied since generalize is a mutating operation
+    tc = Puppet::Pops::Types::TypeCalculator
+    result = types.map { |t| tc.string(tc.generalize!(t.copy)) }.join(', ')
+
+    # Add {from, to} for the last type
+    # This works for both Array and Tuple since it describes the allowed count of the "last" type element
+    # for both. It does not show anything when the range is {1,1}.
+    #
+    result += range_string(last_range)
+    result
+  end
+
+  # Formats a range into a string of the form: `{from, to}`
+  #
+  # The following cases are optimized:
+  #
+  #   * from and to are equal => `{from}`
+  #   * from and to are both and 1 and squelch_one == true => `''`
+  #   * from is 0 and to is 1 => `'?'`
+  #   * to is INFINITY => `{from, }`
+  #
+  # @api private
+  def self.range_string(size_range, squelch_one = true)
+    from, to = size_range
+    if from == to
+      (squelch_one && from == 1) ? '' : "{#{from}}"
+    elsif to == Puppet::Pops::Types::INFINITY
+      "{#{from},}"
+    elsif from == 0 && to == 1
+      '?'
+    else
+      "{#{from},#{to}}"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/callable_signature.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/callable_signature.rb
new file mode 100644
index 0000000..044fc53
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/callable_signature.rb
@@ -0,0 +1,100 @@
+# CallableSignature
+# ===
+# A CallableSignature describes how something callable expects to be called.
+# Different implementation of this class are used for different types of callables.
+#
+# @api public
+#
+class Puppet::Pops::Evaluator::CallableSignature
+
+  # Returns the names of the parameters as an array of strings. This does not include the name
+  # of an optional block parameter.
+  #
+  # All implementations are not required to supply names for parameters. They may be used if present,
+  # to provide user feedback in errors etc. but they are not authoritative about the number of
+  # required arguments, optional arguments, etc.
+  #
+  # A derived class must implement this method.
+  #
+  # @return [Array<String>] - an array of names (that may be empty if names are unavailable)
+  #
+  # @api public
+  #
+  def parameter_names
+    raise NotImplementedError.new
+  end
+
+  # Returns a PCallableType with the type information, required and optional count, and type information about
+  # an optional block.
+  #
+  # A derived class must implement this method.
+  #
+  # @return [Puppet::Pops::Types::PCallableType]
+  # @api public
+  #
+  def type
+    raise NotImplementedError.new
+  end
+
+  # Returns the expected type for an optional block. The type may be nil, which means that the callable does
+  # not accept a block. If a type is returned it is one of Callable, Optional[Callable], Variant[Callable,...],
+  # or Optional[Variant[Callable, ...]]. The Variant type is used when multiple signatures are acceptable.
+  # The Optional type is used when the block is optional.
+  #
+  # @return [Puppet::Pops::Types::PAnyType, nil] the expected type of a block given as the last parameter in a call.
+  #
+  # @api public
+  #
+  def block_type
+    type.block_type
+  end
+
+  # Returns the name of the block parameter if the callable accepts a block.
+  # @return [String] the name of the block parameter
+  # A derived class must implement this method.
+  # @api public
+  #
+  def block_name
+    raise NotImplementedError.new
+  end
+
+  # Returns a range indicating the optionality of a block. One of [0,0] (does not accept block), [0,1] (optional
+  # block), and [1,1] (block required)
+  #
+  # @return [Array(Integer, Integer)] the range of the block parameter
+  #
+  def block_range
+    type.block_range
+  end
+
+  # Returns the range of required/optional argument values as an array of [min, max], where an infinite
+  # end is given as INFINITY. To test against infinity, use the infinity? method.
+  #
+  # @return [Array[Integer, Numeric]] - an Array with [min, max]
+  #
+  # @api public
+  #
+  def args_range
+    type.size_range
+  end
+
+  # Returns true if the last parameter captures the rest of the arguments, with a possible cap, as indicated
+  # by the `args_range` method.
+  # A derived class must implement this method.
+  #
+  # @return [Boolean] true if last parameter captures the rest of the given arguments (up to a possible cap)
+  # @api public
+  #
+  def last_captures_rest?
+    raise NotImplementedError.new
+  end
+
+  # Returns true if the given x is infinity
+  # @return [Boolean] true, if given value represents infinity
+  #
+  # @api public
+  #
+  def infinity?(x)
+    x == Puppet::Pops::Types::INFINITY
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/closure.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/closure.rb
new file mode 100644
index 0000000..644bbd0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/closure.rb
@@ -0,0 +1,228 @@
+
+# A Closure represents logic bound to a particular scope.
+# As long as the runtime (basically the scope implementation) has the behaviour of Puppet 3x it is not
+# safe to use this closure when the scope given to it when initialized goes "out of scope".
+#
+# Note that the implementation is backwards compatible in that the call method accepts a scope, but this
+# scope is not used.
+#
+# Note that this class is a CallableSignature, and the methods defined there should be used
+# as the API for obtaining information in a callable implementation agnostic way.
+#
+class Puppet::Pops::Evaluator::Closure < Puppet::Pops::Evaluator::CallableSignature
+  attr_reader :evaluator
+  attr_reader :model
+  attr_reader :enclosing_scope
+
+  def initialize(evaluator, model, scope)
+    @evaluator = evaluator
+    @model = model
+    @enclosing_scope = scope
+  end
+
+  # marker method checked with respond_to :puppet_lambda
+  # @api private
+  # @deprecated Use the type system to query if an object is of Callable type, then use its signatures method for info
+  def puppet_lambda()
+    true
+  end
+
+  # compatible with 3x AST::Lambda
+  # @api public
+  def call(*args)
+    variable_bindings = combine_values_with_parameters(args)
+
+    tc = Puppet::Pops::Types::TypeCalculator
+    final_args = tc.infer_set(parameters.inject([]) do |final_args, param|
+      if param.captures_rest
+        final_args.concat(variable_bindings[param.name])
+      else
+        final_args << variable_bindings[param.name]
+      end
+    end)
+
+    if tc.callable?(type, final_args)
+      @evaluator.evaluate_block_with_bindings(@enclosing_scope, variable_bindings, @model.body)
+    else
+      raise ArgumentError, "lambda called with mis-matched arguments\n#{Puppet::Pops::Evaluator::CallableMismatchDescriber.diff_string('lambda', final_args, [self])}"
+    end
+  end
+
+  # Call closure with argument assignment by name
+  def call_by_name(scope, args_hash, enforce_parameters)
+    if enforce_parameters
+      if args_hash.size > parameters.size
+        raise ArgumentError, "Too many arguments: #{args_hash.size} for #{parameters.size}"
+      end
+
+      # associate values with parameters
+      scope_hash = {}
+      parameters.each do |p|
+        name = p.name
+        if (arg_value = args_hash[name]).nil?
+          # only set result of default expr if it is defined (it is otherwise not possible to differentiate
+          # between explicit undef and no default expression
+          unless p.value.nil?
+            scope_hash[name] = @evaluator.evaluate(p.value, @enclosing_scope)
+          end
+        else
+          scope_hash[name] = arg_value
+        end
+      end
+
+      missing = parameters.select { |p| !scope_hash.include?(p.name) }
+      if missing.any?
+        raise ArgumentError, "Too few arguments; no value given for required parameters #{missing.collect(&:name).join(" ,")}"
+      end
+
+      tc = Puppet::Pops::Types::TypeCalculator
+      final_args = tc.infer_set(parameter_names.collect { |param| scope_hash[param] })
+      if !tc.callable?(type, final_args)
+        raise ArgumentError, "lambda called with mis-matched arguments\n#{Puppet::Pops::Evaluator::CallableMismatchDescriber.diff_string('lambda', final_args, [self])}"
+      end
+    else
+      scope_hash = args_hash
+    end
+
+    @evaluator.evaluate_block_with_bindings(@enclosing_scope, scope_hash, @model.body)
+  end
+
+  def parameters
+    @model.parameters
+  end
+
+  # Returns the number of parameters (required and optional)
+  # @return [Integer] the total number of accepted parameters
+  def parameter_count
+    # yes, this is duplication of code, but it saves a method call
+    @model.parameters.size
+  end
+
+  # @api public
+  def parameter_names
+    @model.parameters.collect(&:name)
+  end
+
+  # @api public
+  def type
+    @callable ||= create_callable_type
+  end
+
+  # @api public
+  def last_captures_rest?
+    last = @model.parameters[-1]
+    last && last.captures_rest
+  end
+
+  # @api public
+  def block_name
+    # TODO: Lambda's does not support blocks yet. This is a placeholder
+    'unsupported_block'
+  end
+
+  private
+
+  def combine_values_with_parameters(args)
+    variable_bindings = {}
+
+    parameters.each_with_index do |parameter, index|
+      param_captures     = parameter.captures_rest
+      default_expression = parameter.value
+
+      if index >= args.size
+        if default_expression
+          # not given, has default
+          value = @evaluator.evaluate(default_expression, @enclosing_scope)
+          if param_captures && !value.is_a?(Array)
+            # correct non array default value
+            value = [value]
+          end
+        else
+          # not given, does not have default
+          if param_captures
+            # default for captures rest is an empty array
+            value = []
+          else
+            @evaluator.fail(Puppet::Pops::Issues::MISSING_REQUIRED_PARAMETER, parameter, { :param_name => parameter.name })
+          end
+        end
+      else
+        given_argument = args[index]
+        if param_captures
+          # get excess arguments
+          value = args[(parameter_count-1)..-1]
+          # If the input was a single nil, or undef, and there is a default, use the default
+          # This supports :undef in case it was used in a 3x data structure and it is passed as an arg
+          #
+          if value.size == 1 && (given_argument.nil? || given_argument == :undef) && default_expression
+            value = @evaluator.evaluate(default_expression, scope)
+            # and ensure it is an array
+            value = [value] unless value.is_a?(Array)
+          end
+        else
+          value = given_argument
+        end
+      end
+
+      variable_bindings[parameter.name] = value
+    end
+
+    variable_bindings
+  end
+
+  def create_callable_type()
+    types = []
+    range = [0, 0]
+    in_optional_parameters = false
+    parameters.each do |param|
+      type = if param.type_expr
+               @evaluator.evaluate(param.type_expr, @enclosing_scope)
+             else
+               Puppet::Pops::Types::TypeFactory.any()
+             end
+
+      if param.captures_rest && type.is_a?(Puppet::Pops::Types::PArrayType)
+        # An array on a slurp parameter is how a size range is defined for a
+        # slurp (Array[Integer, 1, 3] *$param). However, the callable that is
+        # created can't have the array in that position or else type checking
+        # will require the parameters to be arrays, which isn't what is
+        # intended. The array type contains the intended information and needs
+        # to be unpacked.
+        param_range = type.size_range
+        type = type.element_type
+      elsif param.captures_rest && !type.is_a?(Puppet::Pops::Types::PArrayType)
+        param_range = ANY_NUMBER_RANGE
+      elsif param.value
+        param_range = OPTIONAL_SINGLE_RANGE
+      else
+        param_range = REQUIRED_SINGLE_RANGE
+      end
+
+      types << type
+
+      if param_range[0] == 0
+        in_optional_parameters = true
+      elsif param_range[0] != 0 && in_optional_parameters
+        @evaluator.fail(Puppet::Pops::Issues::REQUIRED_PARAMETER_AFTER_OPTIONAL, param, { :param_name => param.name })
+      end
+
+      range[0] += param_range[0]
+      range[1] += param_range[1]
+    end
+
+    if range[1] == Puppet::Pops::Types::INFINITY
+      range[1] = :default
+    end
+
+    Puppet::Pops::Types::TypeFactory.callable(*(types + range))
+  end
+
+  # Produces information about parameters compatible with a 4x Function (which can have multiple signatures)
+  def signatures
+    [ self ]
+  end
+
+  ANY_NUMBER_RANGE = [0, Puppet::Pops::Types::INFINITY]
+  OPTIONAL_SINGLE_RANGE = [0, 1]
+  REQUIRED_SINGLE_RANGE = [1, 1]
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/collector_transformer.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/collector_transformer.rb
new file mode 100644
index 0000000..70ad4f8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/collector_transformer.rb
@@ -0,0 +1,209 @@
+class Puppet::Pops::Evaluator::CollectorTransformer
+
+  def initialize
+    @@query_visitor    ||= Puppet::Pops::Visitor.new(nil, "query", 1, 1)
+    @@match_visitor    ||= Puppet::Pops::Visitor.new(nil, "match", 1, 1)
+    @@evaluator        ||= Puppet::Pops::Evaluator::EvaluatorImpl.new
+    @@compare_operator ||= Puppet::Pops::Evaluator::CompareOperator.new()
+  end
+
+  def transform(o, scope)
+    raise ArgumentError, "Expected CollectExpression" unless o.is_a? Puppet::Pops::Model::CollectExpression
+
+    raise "LHS is not a type" unless o.type_expr.is_a? Puppet::Pops::Model::QualifiedReference
+    type = o.type_expr.value().downcase()
+
+    if type == 'class'
+      fail "Classes cannot be collected"
+    end
+
+    resource_type = scope.find_resource_type(type)
+    fail "Resource type #{type} doesn't exist" unless resource_type
+
+    adapter = Puppet::Pops::Adapters::SourcePosAdapter.adapt(o)
+    line_num = adapter.line
+    position = adapter.pos
+    file_path = adapter.locator.file
+
+    if !o.operations.empty?
+      overrides = {
+        :parameters => o.operations.map{ |x| @@evaluator.evaluate(x, scope)}.flatten,
+        :file       => file_path,
+        :line       => [line_num, position],
+        :source     => scope.source,
+        :scope      => scope
+      }
+    end
+
+    code = query_unless_nop(o.query, scope)
+
+    case o.query
+    when Puppet::Pops::Model::VirtualQuery
+      newcoll = Puppet::Pops::Evaluator::Collectors::CatalogCollector.new(scope, resource_type.name, code, overrides)
+    when Puppet::Pops::Model::ExportedQuery
+      match = match_unless_nop(o.query, scope)
+      newcoll = Puppet::Pops::Evaluator::Collectors::ExportedCollector.new(scope, resource_type.name, match, code, overrides)
+    end
+
+    scope.compiler.add_collection(newcoll)
+
+    newcoll
+  end
+
+protected
+
+  def query(o, scope)
+    @@query_visitor.visit_this_1(self, o, scope)
+  end
+
+  def match(o, scope)
+    @@match_visitor.visit_this_1(self, o, scope)
+  end
+
+  def query_unless_nop(query, scope)
+    unless query.expr.nil? || query.expr.is_a?(Puppet::Pops::Model::Nop)
+      query(query.expr, scope)
+    end
+  end
+
+  def match_unless_nop(query, scope)
+    unless query.expr.nil? || query.expr.is_a?(Puppet::Pops::Model::Nop)
+      match(query.expr, scope)
+    end
+  end
+
+  def query_AndExpression(o, scope)
+    left_code = query(o.left_expr, scope)
+    right_code = query(o.right_expr, scope)
+    proc do |resource|
+      left_code.call(resource) && right_code.call(resource)
+    end
+  end
+
+  def query_OrExpression(o, scope)
+    left_code = query(o.left_expr, scope)
+    right_code = query(o.right_expr, scope)
+    proc do |resource|
+      left_code.call(resource) || right_code.call(resource)
+    end
+  end
+
+  def query_ComparisonExpression(o, scope)
+    left_code = query(o.left_expr, scope)
+    right_code = query(o.right_expr, scope)
+
+    case o.operator
+    when :'=='
+      if left_code == "tag"
+        # Ensure that to_s and downcase is done once, i.e. outside the proc block and
+        # then use raw_tagged? instead of tagged?
+        if right_code.is_a?(Array)
+          tags = right_code
+        else
+          tags = [ right_code ]
+        end
+        tags = tags.collect do |t|
+          raise ArgumentError, 'Cannot transform a number to a tag' if t.is_a?(Numeric)
+          t.to_s.downcase
+        end
+        proc do |resource|
+          resource.raw_tagged?(tags)
+        end
+      else
+        proc do |resource|
+          if (tmp = resource[left_code]).is_a?(Array)
+            @@compare_operator.include?(tmp, right_code, scope)
+          else
+            @@compare_operator.equals(tmp, right_code)
+          end
+        end
+      end
+    when :'!='
+      proc do |resource|
+        !@@compare_operator.equals(resource[left_code], right_code)
+      end
+    end
+  end
+
+  def query_VariableExpression(o, scope)
+    @@evaluator.evaluate(o, scope)
+  end
+
+  def query_LiteralBoolean(o, scope)
+    @@evaluator.evaluate(o, scope)
+  end
+
+  def query_LiteralString(o, scope)
+    @@evaluator.evaluate(o, scope)
+  end
+
+  def query_ConcatenatedString(o, scope)
+    @@evaluator.evaluate(o, scope)
+  end
+
+  def query_LiteralNumber(o, scope)
+    @@evaluator.evaluate(o, scope)
+  end
+
+  def query_QualifiedName(o, scope)
+    @@evaluator.evaluate(o, scope)
+  end
+
+  def query_ParenthesizedExpression(o, scope)
+   query(o.expr, scope)
+  end
+
+  def query_Object(o, scope)
+    raise ArgumentError, "Cannot transform object of class #{o.class}"
+  end
+
+  def match_AndExpression(o, scope)
+    left_match = match(o.left_expr, scope)
+    right_match = match(o.right_expr, scope)
+    return [left_match, 'and', right_match]
+  end
+
+  def match_OrExpression(o, scope)
+    left_match = match(o.left_expr, scope)
+    right_match = match(o.right_expr, scope)
+    return [left_match, 'or', right_match]
+  end
+
+  def match_ComparisonExpression(o, scope)
+    left_match = match(o.left_expr, scope)
+    right_match = match(o.right_expr, scope)
+    return [left_match, o.operator.to_s, right_match]
+  end
+
+  def match_VariableExpression(o, scope)
+    @@evaluator.evaluate(o, scope)
+  end
+
+  def match_LiteralBoolean(o, scope)
+    @@evaluator.evaluate(o, scope)
+  end
+
+  def match_LiteralString(o, scope)
+    @@evaluator.evaluate(o, scope)
+  end
+
+  def match_ConcatenatedString(o, scope)
+    @@evaluator.evaluate(o, scope)
+  end
+
+  def match_LiteralNumber(o, scope)
+    @@evaluator.evaluate(o, scope)
+  end
+
+  def match_QualifiedName(o, scope)
+    @@evaluator.evaluate(o, scope)
+  end
+
+  def match_ParenthesizedExpression(o, scope)
+   match(o.expr, scope)
+  end
+
+  def match_Object(o, scope)
+    raise ArgumentError, "Cannot transform object of class #{o.class}"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/collectors/abstract_collector.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/collectors/abstract_collector.rb
new file mode 100644
index 0000000..f5abe5e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/collectors/abstract_collector.rb
@@ -0,0 +1,86 @@
+class Puppet::Pops::Evaluator::Collectors::AbstractCollector
+  attr_reader :scope
+
+  # The collector's hash of overrides {:parameters => params}
+  attr_reader :overrides
+
+  # The set of collected resources
+  attr_reader :collected
+
+  # An empty array which will be returned by the unresolved_resources
+  # method unless we have a FixSetCollector
+  EMPTY_RESOURCES = [].freeze
+
+  # Initialized the instance variables needed by the base
+  # collector class to perform evaluation
+  #
+  # @param [Puppet::Parser::Scope] scope
+  #
+  # @param [Hash] overrides a hash of optional overrides
+  # @options opts [Array] :parameters
+  # @options opts [String] :file
+  # @options opts [Array] :line
+  # @options opts [Puppet::Resource::Type] :source
+  # @options opts [Puppet::Parser::Scope] :scope
+  def initialize(scope, overrides = nil)
+    @collected = {}
+    @scope = scope
+
+    if !(overrides.nil? || overrides[:parameters])
+      raise ArgumentError, "Exported resource try to override without parameters"
+    end
+
+    @overrides = overrides
+  end
+
+  # Collects resources and marks collected objects as non-virtual. Also
+  # handles overrides.
+  #
+  # @return [Array] the resources we have collected
+  def evaluate
+    objects = collect.each do |obj|
+      obj.virtual = false
+    end
+
+    return false if objects.empty?
+
+    if @overrides and !objects.empty?
+      overrides[:source].meta_def(:child_of?) do |klass|
+        true
+      end
+
+      objects.each do |res|
+        unless @collected.include?(res.ref)
+          newres = Puppet::Parser::Resource.new(res.type, res.title, @overrides)
+          scope.compiler.add_override(newres)
+        end
+      end
+    end
+
+    objects.reject! { |o| @collected.include?(o.ref) }
+
+    return false if objects.empty?
+
+    objects.inject(@collected) { |c,o| c[o.ref]=o; c }
+
+    objects
+  end
+
+  # This should only return an empty array unless we have
+  # an FixedSetCollector, in which case it will return the
+  # resources that have not yet been realized
+  #
+  # @return [Array] the resources that have not been resolved
+  def unresolved_resources
+    EMPTY_RESOURCES
+  end
+
+  # Collect the specified resources. The way this is done depends on which type
+  # of collector we are dealing with. This method is implemented differently in
+  # each of the three child classes
+  #
+  # @return [Array] the collected resources
+  def collect
+    raise NotImplementedError, "This method must be implemented by the child class"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/collectors/catalog_collector.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/collectors/catalog_collector.rb
new file mode 100644
index 0000000..c684e49
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/collectors/catalog_collector.rb
@@ -0,0 +1,25 @@
+class Puppet::Pops::Evaluator::Collectors::CatalogCollector < Puppet::Pops::Evaluator::Collectors::AbstractCollector
+
+  # Creates a CatalogCollector using the AbstractCollector's 
+  # constructor to set the scope and overrides
+  #
+  # param [Symbol] type the resource type to be collected
+  # param [Proc] query the query which defines which resources to match
+  def initialize(scope, type, query, overrides = nil)
+    super(scope, overrides)
+
+    @query = query
+
+    @type = Puppet::Resource.new(type, "whatever").type
+  end
+
+  # Collects virtual resources based off a collection in a manifest
+  def collect
+    t = @type
+    q = @query
+
+    scope.compiler.resources.find_all do |resource|
+      resource.type == t && (q ?  q.call(resource) : true)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/collectors/exported_collector.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/collectors/exported_collector.rb
new file mode 100644
index 0000000..a59e787
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/collectors/exported_collector.rb
@@ -0,0 +1,66 @@
+class Puppet::Pops::Evaluator::Collectors::ExportedCollector < Puppet::Pops::Evaluator::Collectors::AbstractCollector
+
+  # Creates an ExportedCollector using the AbstractCollector's
+  # constructor to set the scope and overrides
+  #
+  # param [Symbol] type the resource type to be collected
+  # param [Array] equery an array representation of the query (exported query)
+  # param [Proc] cquery a proc representation of the query (catalog query)
+  def initialize(scope, type, equery, cquery, overrides = nil)
+    super(scope, overrides)
+
+    @equery = equery
+    @cquery = cquery
+
+    @type = Puppet::Resource.new(type, "whatever").type
+  end
+
+  # Ensures that storeconfigs is present before calling AbstractCollector's
+  # evaluate method
+  def evaluate
+    if Puppet[:storeconfigs] != true
+      Puppet.warning "Not collecting exported resources without storeconfigs"
+      return false
+    end
+
+    super
+  end
+
+  # Collect exported resources as defined by an exported
+  # collection. Used with PuppetDB
+  def collect
+    resources = []
+
+    time = Puppet::Util.thinmark do
+      t = @type
+      q = @cquery
+
+      resources = scope.compiler.resources.find_all do |resource|
+        resource.type == t && resource.exported? && (q.nil? || q.call(resource))
+      end
+
+      found = Puppet::Resource.indirection.
+        search(@type, :host => @scope.compiler.node.name, :filter => @equery, :scope => @scope)
+
+      found_resources = found.map {|x| x.is_a?(Puppet::Parser::Resource) ? x : x.to_resource(@scope)}
+
+      found_resources.each do |item|
+        if existing = @scope.findresource(item.type, item.title)
+          unless existing.collector_id == item.collector_id
+            raise Puppet::ParseError,
+              "A duplicate resource was found while collecting exported resources, with the type and title #{item.ref}"
+          end
+        else
+          item.exported = false
+          @scope.compiler.add_resource(@scope, item)
+          resources << item
+        end
+      end
+    end
+
+    scope.debug("Collected %s %s resource%s in %.2f seconds" %
+                [resources.length, @type, resources.length == 1 ? "" : "s", time])
+
+    resources
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/collectors/fixed_set_collector.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/collectors/fixed_set_collector.rb
new file mode 100644
index 0000000..8627245
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/collectors/fixed_set_collector.rb
@@ -0,0 +1,37 @@
+class Puppet::Pops::Evaluator::Collectors::FixedSetCollector < Puppet::Pops::Evaluator::Collectors::AbstractCollector
+
+  # Creates a FixedSetCollector using the AbstractCollector constructor
+  # to set the scope. It is not possible for a collection to have
+  # overrides in this case, since we have a fixed set of resources that
+  # can be different types.
+  #
+  # @param [Array] resources the fixed set of resources we want to realize
+  def initialize(scope, resources)
+    super(scope)
+    @resources = resources.is_a?(Array)? resources.dup : [resources]
+  end
+
+  # Collects a fixed set of resources and realizes them. Used
+  # by the realize function
+  def collect
+    resolved = []
+    result = @resources.reduce([]) do |memo, ref|
+      if res = @scope.findresource(ref.to_s)
+        res.virtual = false
+        memo << res
+        resolved << ref
+      end
+      memo
+    end
+
+    @resources = @resources - resolved
+
+    @scope.compiler.delete_collection(self) if @resources.empty?
+
+    result
+  end
+
+  def unresolved_resources
+    @resources
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/compare_operator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/compare_operator.rb
new file mode 100644
index 0000000..b5a6874
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/compare_operator.rb
@@ -0,0 +1,195 @@
+# Compares the puppet DSL way
+#
+# ==Equality
+# All string vs. numeric equalities check for numeric equality first, then string equality
+# Arrays are equal to arrays if they have the same length, and each element #equals
+# Hashes  are equal to hashes if they have the same size and keys and values #equals.
+# All other objects are equal if they are ruby #== equal
+#
+class Puppet::Pops::Evaluator::CompareOperator
+  include Puppet::Pops::Utils
+
+  # Provides access to the Puppet 3.x runtime (scope, etc.)
+  # This separation has been made to make it easier to later migrate the evaluator to an improved runtime.
+  #
+  include Puppet::Pops::Evaluator::Runtime3Support
+
+  def initialize
+    @@equals_visitor  ||= Puppet::Pops::Visitor.new(self, "equals", 1, 1)
+    @@compare_visitor ||= Puppet::Pops::Visitor.new(self, "cmp", 1, 1)
+    @@match_visitor ||= Puppet::Pops::Visitor.new(self, "match", 2, 2)
+    @@include_visitor ||= Puppet::Pops::Visitor.new(self, "include", 2, 2)
+    @type_calculator = Puppet::Pops::Types::TypeCalculator.new()
+  end
+
+  def equals (a, b)
+    @@equals_visitor.visit_this_1(self, a, b)
+  end
+
+  # Performs a comparison of a and b, and return > 0 if a is bigger, 0 if equal, and < 0 if b is bigger.
+  # Comparison of String vs. Numeric always compares using numeric.
+  def compare(a, b)
+    @@compare_visitor.visit_this_1(self, a, b)
+  end
+
+  # Performs a match of a and b, and returns true if b matches a
+  def match(a, b, scope)
+    @@match_visitor.visit_this_2(self, b, a, scope)
+  end
+
+  # Answers is b included in a
+  def include?(a, b, scope)
+    @@include_visitor.visit_this_2(self, a, b, scope)
+  end
+
+  protected
+
+  def cmp_String(a, b)
+    return a.casecmp(b) if b.is_a?(String)
+    raise ArgumentError.new("A String is not comparable to a non String")
+  end
+
+  # Equality is case independent.
+  def equals_String(a, b)
+    return false unless b.is_a?(String)
+    a.casecmp(b) == 0
+  end
+
+  def cmp_Numeric(a, b)
+    if b.is_a?(Numeric)
+      a <=> b
+    else
+      raise ArgumentError.new("A Numeric is not comparable to non Numeric")
+    end
+  end
+
+  def equals_Numeric(a, b)
+    if b.is_a?(Numeric)
+      a == b
+    else
+      false
+    end
+  end
+
+  def equals_Array(a, b)
+    return false unless b.is_a?(Array) && a.size == b.size
+    a.each_index {|i| return false unless equals(a.slice(i), b.slice(i)) }
+    true
+  end
+
+  def equals_Hash(a, b)
+    return false unless b.is_a?(Hash) && a.size == b.size
+    a.each {|ak, av| return false unless equals(b[ak], av)}
+    true
+  end
+
+  def cmp_Symbol(a, b)
+    if b.is_a?(Symbol)
+      a <=> b
+    else
+      raise ArgumentError.new("Symbol not comparable to non Symbol")
+    end
+  end
+
+  def cmp_Object(a, b)
+    raise ArgumentError.new("Only Strings and Numbers are comparable")
+  end
+
+
+  def equals_Object(a, b)
+    a == b
+  end
+
+  def equals_NilClass(a, b)
+    # :undef supported in case it is passed from a 3x data structure
+    b.nil? || b == :undef
+  end
+
+  def equals_Symbol(a, b)
+    # :undef supported in case it is passed from a 3x data structure
+    a == b || a == :undef && b.nil?
+  end
+
+  def include_Object(a, b, scope)
+    false
+  end
+
+  def include_String(a, b, scope)
+    case b
+    when String
+      # subsstring search downcased
+      a.downcase.include?(b.downcase)
+    when Regexp
+      matched = a.match(b)           # nil, or MatchData
+      set_match_data(matched, scope) # creates ephemeral
+      !!matched                      # match (convert to boolean)
+    when Numeric
+      # convert string to number, true if ==
+      equals(a, b)
+    else
+      false
+    end
+  end
+
+  def include_Array(a, b, scope)
+    case b
+    when Regexp
+      matched = nil
+      a.each do |element|
+        next unless element.is_a? String
+        matched = element.match(b) # nil, or MatchData
+        break if matched
+      end
+      # Always set match data, a "not found" should not keep old match data visible
+      set_match_data(matched, scope) # creates ephemeral
+      return !!matched
+    when Puppet::Pops::Types::PAnyType
+      a.each {|element| return true if @type_calculator.instance?(b, element) }
+      return false
+    else
+      a.each {|element| return true if equals(element, b) }
+      return false
+    end
+  end
+
+  def include_Hash(a, b, scope)
+    include?(a.keys, b, scope)
+  end
+
+  # Matches in general by using == operator
+  def match_Object(pattern, a, scope)
+    equals(a, pattern)
+  end
+
+  # Matches only against strings
+  def match_Regexp(regexp, left, scope)
+    return false unless left.is_a? String
+    matched = regexp.match(left)
+    set_match_data(matched, scope) # creates or clears ephemeral
+    !!matched # convert to boolean
+  end
+
+  def match_PAnyType(any_type, left, scope)
+    # right is a type and left is not - check if left is an instance of the given type
+    # (The reverse is not terribly meaningful - computing which of the case options that first produces
+    # an instance of a given type).
+    #
+    @type_calculator.instance?(any_type, left)
+  end
+
+  def match_Array(array, left, scope)
+    return false unless left.is_a?(Array)
+    return false unless left.length == array.length
+    array.each_with_index.all? { | pattern, index| match(left[index], pattern, scope) }
+  end
+
+  def match_Hash(hash, left, scope)
+    return false unless left.is_a?(Hash)
+    hash.all? {|x,y| match(left[x], y, scope) }
+  end
+
+  def match_Symbol(symbol, left, scope)
+    return true if symbol == :default
+    equals(left, default, scope)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/epp_evaluator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/epp_evaluator.rb
new file mode 100644
index 0000000..57a95bc
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/epp_evaluator.rb
@@ -0,0 +1,88 @@
+# Handler of Epp call/evaluation from the epp and inline_epp functions
+#
+class Puppet::Pops::Evaluator::EppEvaluator
+
+  def self.inline_epp(scope, epp_source, template_args = nil)
+    unless epp_source.is_a?(String)
+      raise ArgumentError, "inline_epp(): the first argument must be a String with the epp source text, got a #{epp_source.class}"
+    end
+
+    # Parse and validate the source
+    parser = Puppet::Pops::Parser::EvaluatingParser::EvaluatingEppParser.new
+    begin
+      result = parser.parse_string(epp_source, 'inlined-epp-text')
+    rescue Puppet::ParseError => e
+      raise ArgumentError, "inline_epp(): Invalid EPP: #{e.message}"
+    end
+
+    # Evaluate (and check template_args)
+    evaluate(parser, 'inline_epp', scope, false, result, template_args)
+  end
+
+  def self.epp(scope, file, env_name, template_args = nil)
+    unless file.is_a?(String)
+      raise ArgumentError, "epp(): the first argument must be a String with the filename, got a #{file.class}"
+    end
+
+    file = file + ".epp" unless file =~ /\.epp$/
+    scope.debug "Retrieving epp template #{file}"
+    template_file = Puppet::Parser::Files.find_template(file, env_name)
+    unless template_file
+      raise Puppet::ParseError, "Could not find template '#{file}'"
+    end
+
+    # Parse and validate the source
+    parser = Puppet::Pops::Parser::EvaluatingParser::EvaluatingEppParser.new
+    begin
+      result = parser.parse_file(template_file)
+    rescue Puppet::ParseError => e
+      raise ArgumentError, "epp(): Invalid EPP: #{e.message}"
+    end
+
+    # Evaluate (and check template_args)
+    evaluate(parser, 'epp', scope, true, result, template_args)
+  end
+
+  private
+
+  def self.evaluate(parser, func_name, scope, use_global_scope_only, parse_result, template_args)
+    template_args, template_args_set = handle_template_args(func_name, template_args)
+
+    body = parse_result.body
+    unless body.is_a?(Puppet::Pops::Model::LambdaExpression)
+      raise ArgumentError, "#{func_name}(): the parser did not produce a LambdaExpression, got '#{body.class}'"
+    end
+    unless body.body.is_a?(Puppet::Pops::Model::EppExpression)
+      raise ArgumentError, "#{func_name}(): the parser did not produce an EppExpression, got '#{body.body.class}'"
+    end
+    unless parse_result.definitions.empty?
+      raise ArgumentError, "#{func_name}(): The EPP template contains illegal expressions (definitions)"
+    end
+
+    parameters_specified = body.body.parameters_specified
+    if parameters_specified || template_args_set
+      # no epp params or user provided arguments in a hash, epp() logic
+      # only sees global + what was given
+      closure_scope = scope.find_global_scope
+      enforce_parameters = parameters_specified
+    else
+      # no epp params and no arguments were given => inline_epp() logic
+      # sees all local variables, epp() all global
+      closure_scope =  use_global_scope_only ? scope.find_global_scope : scope
+      enforce_parameters = true
+    end
+    evaluated_result = parser.closure(body, closure_scope).call_by_name(scope, template_args, enforce_parameters)
+    evaluated_result
+  end
+
+  def self.handle_template_args(func_name, template_args)
+    if template_args.nil?
+      [{}, false]
+    else
+      unless template_args.is_a?(Hash)
+        raise ArgumentError, "#{func_name}(): the template_args must be a Hash, got a #{template_args.class}"
+      end
+      [template_args, true]
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/evaluator_impl.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/evaluator_impl.rb
new file mode 100644
index 0000000..1565a5d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/evaluator_impl.rb
@@ -0,0 +1,1212 @@
+require 'rgen/ecore/ecore'
+require 'puppet/pops/evaluator/compare_operator'
+require 'puppet/pops/evaluator/relationship_operator'
+require 'puppet/pops/evaluator/access_operator'
+require 'puppet/pops/evaluator/closure'
+require 'puppet/pops/evaluator/external_syntax_support'
+
+# This implementation of {Puppet::Pops::Evaluator} performs evaluation using the puppet 3.x runtime system
+# in a manner largely compatible with Puppet 3.x, but adds new features and introduces constraints.
+#
+# The evaluation uses _polymorphic dispatch_ which works by dispatching to the first found method named after
+# the class or one of its super-classes. The EvaluatorImpl itself mainly deals with evaluation (it currently
+# also handles assignment), and it uses a delegation pattern to more specialized handlers of some operators
+# that in turn use polymorphic dispatch; this to not clutter EvaluatorImpl with too much responsibility).
+#
+# Since a pattern is used, only the main entry points are fully documented. The parameters _o_ and _scope_ are
+# the same in all the polymorphic methods, (the type of the parameter _o_ is reflected in the method's name;
+# either the actual class, or one of its super classes). The _scope_ parameter is always the scope in which
+# the evaluation takes place. If nothing else is mentioned, the return is always the result of evaluation.
+#
+# See {Puppet::Pops::Visitable} and {Puppet::Pops::Visitor} for more information about
+# polymorphic calling.
+#
+class Puppet::Pops::Evaluator::EvaluatorImpl
+  include Puppet::Pops::Utils
+
+  # Provides access to the Puppet 3.x runtime (scope, etc.)
+  # This separation has been made to make it easier to later migrate the evaluator to an improved runtime.
+  #
+  include Puppet::Pops::Evaluator::Runtime3Support
+  include Puppet::Pops::Evaluator::ExternalSyntaxSupport
+
+  # This constant is not defined as Float::INFINITY in Ruby 1.8.7 (but is available in later version
+  # Refactor when support is dropped for Ruby 1.8.7.
+  #
+  INFINITY = 1.0 / 0.0
+  EMPTY_STRING = ''.freeze
+  COMMA_SEPARATOR = ', '.freeze
+
+  # Reference to Issues name space makes it easier to refer to issues
+  # (Issues are shared with the validator).
+  #
+  Issues = Puppet::Pops::Issues
+
+  def initialize
+    @@eval_visitor     ||= Puppet::Pops::Visitor.new(self, "eval", 1, 1)
+    @@lvalue_visitor   ||= Puppet::Pops::Visitor.new(self, "lvalue", 1, 1)
+    @@assign_visitor   ||= Puppet::Pops::Visitor.new(self, "assign", 3, 3)
+    @@string_visitor   ||= Puppet::Pops::Visitor.new(self, "string", 1, 1)
+
+    @@type_calculator  ||= Puppet::Pops::Types::TypeCalculator.new()
+    @@type_parser      ||= Puppet::Pops::Types::TypeParser.new()
+
+    @@compare_operator     ||= Puppet::Pops::Evaluator::CompareOperator.new()
+    @@relationship_operator ||= Puppet::Pops::Evaluator::RelationshipOperator.new()
+
+    # Use null migration checker unless given in context
+    @migration_checker = (Puppet.lookup(:migration_checker) { Puppet::Pops::Migration::MigrationChecker.new() })
+  end
+
+  # @api private
+  def type_calculator
+    @@type_calculator
+  end
+
+  # Evaluates the given _target_ object in the given scope.
+  #
+  # @overload evaluate(target, scope)
+  # @param target [Object] evaluation target - see methods on the pattern assign_TYPE for actual supported types.
+  # @param scope [Object] the runtime specific scope class where evaluation should take place
+  # @return [Object] the result of the evaluation
+  #
+  # @api public
+  #
+  def evaluate(target, scope)
+    begin
+      @@eval_visitor.visit_this_1(self, target, scope)
+
+    rescue Puppet::Pops::SemanticError => e
+      # A raised issue may not know the semantic target, use errors call stack, but fill in the 
+      # rest from a supplied semantic object, or the target instruction if there is not semantic
+      # object.
+      #
+      fail(e.issue, e.semantic || target, e.options, e)
+
+    rescue Puppet::PreformattedError => e
+      # Already formatted with location information, and with the wanted call stack.
+      # Note this is currently a specialized ParseError, so rescue-order is important
+      #
+      raise e
+
+    rescue Puppet::ParseError => e
+      # ParseError may be raised in ruby code without knowing the location
+      # in puppet code.
+      # Accept a ParseError that has file or line information available
+      # as an error that should be used verbatim. (Tests typically run without
+      # setting a file name).
+      # ParseError can supply an original - it is impossible to determine which
+      # call stack that should be propagated, using the ParseError's backtrace.
+      #
+      if e.file || e.line
+        raise e
+      else
+        # Since it had no location information, treat it as user intended a general purpose
+        # error. Pass on its call stack.
+        fail(Issues::RUNTIME_ERROR, target, {:detail => e.message}, e)
+      end
+
+
+    rescue Puppet::Error => e
+      # PuppetError has the ability to wrap an exception, if so, use the wrapped exception's
+      # call stack instead
+      fail(Issues::RUNTIME_ERROR, target, {:detail => e.message}, e.original || e)
+
+    rescue StandardError => e
+      # All other errors, use its message and call stack
+      fail(Issues::RUNTIME_ERROR, target, {:detail => e.message}, e)
+    end
+  end
+
+  # Assigns the given _value_ to the given _target_. The additional argument _o_ is the instruction that
+  # produced the target/value tuple and it is used to set the origin of the result.
+  #
+  # @param target [Object] assignment target - see methods on the pattern assign_TYPE for actual supported types.
+  # @param value [Object] the value to assign to `target`
+  # @param o [Puppet::Pops::Model::PopsObject] originating instruction
+  # @param scope [Object] the runtime specific scope where evaluation should take place
+  #
+  # @api private
+  #
+  def assign(target, value, o, scope)
+    @@assign_visitor.visit_this_3(self, target, value, o, scope)
+  end
+
+  # Computes a value that can be used as the LHS in an assignment.
+  # @param o [Object] the expression to evaluate as a left (assignable) entity
+  # @param scope [Object] the runtime specific scope where evaluation should take place
+  #
+  # @api private
+  #
+  def lvalue(o, scope)
+    @@lvalue_visitor.visit_this_1(self, o, scope)
+  end
+
+  # Produces a String representation of the given object _o_ as used in interpolation.
+  # @param o [Object] the expression of which a string representation is wanted
+  # @param scope [Object] the runtime specific scope where evaluation should take place
+  #
+  # @api public
+  #
+  def string(o, scope)
+    @@string_visitor.visit_this_1(self, o, scope)
+  end
+
+  # Evaluate a BlockExpression in a new scope with variables bound to the
+  # given values.
+  #
+  # @param scope [Puppet::Parser::Scope] the parent scope
+  # @param variable_bindings [Hash{String => Object}] the variable names and values to bind (names are keys, bound values are values)
+  # @param block [Puppet::Pops::Model::BlockExpression] the sequence of expressions to evaluate in the new scope
+  #
+  # @api private
+  #
+  def evaluate_block_with_bindings(scope, variable_bindings, block_expr)
+    with_guarded_scope(scope) do
+      # change to create local scope_from - cannot give it file and line -
+      # that is the place of the call, not "here"
+      create_local_scope_from(variable_bindings, scope)
+      evaluate(block_expr, scope)
+    end
+  end
+
+  protected
+
+  def lvalue_VariableExpression(o, scope)
+    # evaluate the name
+    evaluate(o.expr, scope)
+  end
+
+  # Catches all illegal lvalues
+  #
+  def lvalue_Object(o, scope)
+    fail(Issues::ILLEGAL_ASSIGNMENT, o)
+  end
+
+  # Assign value to named variable.
+  # The '$' sign is never part of the name.
+  # @example In Puppet DSL
+  #   $name = value
+  # @param name [String] name of variable without $
+  # @param value [Object] value to assign to the variable
+  # @param o [Puppet::Pops::Model::PopsObject] originating instruction
+  # @param scope [Object] the runtime specific scope where evaluation should take place
+  # @return [value<Object>]
+  #
+  def assign_String(name, value, o, scope)
+    if name =~ /::/
+      fail(Issues::CROSS_SCOPE_ASSIGNMENT, o.left_expr, {:name => name})
+    end
+    set_variable(name, value, o, scope)
+    value
+  end
+
+  def assign_Numeric(n, value, o, scope)
+    fail(Issues::ILLEGAL_NUMERIC_ASSIGNMENT, o.left_expr, {:varname => n.to_s})
+  end
+
+  # Catches all illegal assignment (e.g. 1 = 2, {'a'=>1} = 2, etc)
+  #
+  def assign_Object(name, value, o, scope)
+    fail(Issues::ILLEGAL_ASSIGNMENT, o)
+  end
+
+  def eval_Factory(o, scope)
+    evaluate(o.current, scope)
+  end
+
+  # Evaluates any object not evaluated to something else to itself.
+  def eval_Object o, scope
+    o
+  end
+
+  # Allows nil to be used as a Nop, Evaluates to nil
+  def eval_NilClass(o, scope)
+    nil
+  end
+
+  # Evaluates Nop to nil.
+  def eval_Nop(o, scope)
+    nil
+  end
+
+  # Captures all LiteralValues not handled elsewhere.
+  #
+  def eval_LiteralValue(o, scope)
+    o.value
+  end
+
+  # Reserved Words fail to evaluate
+  #
+  def eval_ReservedWord(o, scope)
+    if !o.future
+      fail(Puppet::Pops::Issues::RESERVED_WORD, o, {:word => o.word})
+    else
+      o.word
+    end
+  end
+
+  def eval_LiteralDefault(o, scope)
+    :default
+  end
+
+  def eval_LiteralUndef(o, scope)
+    nil
+  end
+
+  # A QualifiedReference (i.e. a  capitalized qualified name such as Foo, or Foo::Bar) evaluates to a PType
+  #
+  def eval_QualifiedReference(o, scope)
+    @@type_parser.interpret(o)
+  end
+
+  def eval_NotExpression(o, scope)
+    ! is_true?(evaluate(o.expr, scope), o.expr)
+  end
+
+  def eval_UnaryMinusExpression(o, scope)
+    - coerce_numeric(evaluate(o.expr, scope), o, scope)
+  end
+
+  def eval_UnfoldExpression(o, scope)
+    candidate = evaluate(o.expr, scope)
+    case candidate
+    when nil
+      []
+    when Array
+      candidate
+    when Hash
+      candidate.to_a
+    else
+      # turns anything else into an array (so result can be unfolded)
+      [candidate]
+    end
+  end
+
+  # Abstract evaluation, returns array [left, right] with the evaluated result of left_expr and
+  # right_expr
+  # @return <Array<Object, Object>> array with result of evaluating left and right expressions
+  #
+  def eval_BinaryExpression o, scope
+    [ evaluate(o.left_expr, scope), evaluate(o.right_expr, scope) ]
+  end
+
+  # Evaluates assignment with operators =, +=, -= and
+  #
+  # @example Puppet DSL
+  #   $a = 1
+  #   $a += 1
+  #   $a -= 1
+  #
+  def eval_AssignmentExpression(o, scope)
+    name = lvalue(o.left_expr, scope)
+    value = evaluate(o.right_expr, scope)
+
+    if o.operator == :'='
+      assign(name, value, o, scope)
+    else
+      fail(Issues::UNSUPPORTED_OPERATOR, o, {:operator => o.operator})
+    end
+    value
+  end
+
+  ARITHMETIC_OPERATORS = [:'+', :'-', :'*', :'/', :'%', :'<<', :'>>']
+  COLLECTION_OPERATORS = [:'+', :'-', :'<<']
+
+  # Handles binary expression where lhs and rhs are array/hash or numeric and operator is +, - , *, % / << >>
+  #
+  def eval_ArithmeticExpression(o, scope)
+    left = evaluate(o.left_expr, scope)
+    right = evaluate(o.right_expr, scope)
+
+    begin
+      result = calculate(left, right, o.operator, o.left_expr, o.right_expr, scope)
+    rescue ArgumentError => e
+      fail(Issues::RUNTIME_ERROR, o, {:detail => e.message}, e)
+    end
+    result
+  end
+
+
+  # Handles binary expression where lhs and rhs are array/hash or numeric and operator is +, - , *, % / << >>
+  #
+  def calculate(left, right, operator, left_o, right_o, scope)
+    unless ARITHMETIC_OPERATORS.include?(operator)
+      fail(Issues::UNSUPPORTED_OPERATOR, left_o.eContainer, {:operator => o.operator})
+    end
+
+    if (left.is_a?(Array) || left.is_a?(Hash)) && COLLECTION_OPERATORS.include?(operator)
+      # Handle operation on collections
+      case operator
+      when :'+'
+        concatenate(left, right)
+      when :'-'
+        delete(left, right)
+      when :'<<'
+        unless left.is_a?(Array)
+          fail(Issues::OPERATOR_NOT_APPLICABLE, left_o, {:operator => operator, :left_value => left})
+        end
+        left + [right]
+      end
+    else
+      # Handle operation on numeric
+      left = coerce_numeric(left, left_o, scope)
+      right = coerce_numeric(right, right_o, scope)
+      begin
+        if operator == :'%' && (left.is_a?(Float) || right.is_a?(Float))
+          # Deny users the fun of seeing severe rounding errors and confusing results
+          fail(Issues::OPERATOR_NOT_APPLICABLE, left_o, {:operator => operator, :left_value => left})
+        end
+        result = left.send(operator, right)
+      rescue NoMethodError => e
+        fail(Issues::OPERATOR_NOT_APPLICABLE, left_o, {:operator => operator, :left_value => left})
+      rescue ZeroDivisionError => e
+        fail(Issues::DIV_BY_ZERO, right_o)
+      end
+      if result == INFINITY || result == -INFINITY
+        fail(Issues::RESULT_IS_INFINITY, left_o, {:operator => operator})
+      end
+      result
+    end
+  end
+
+  def eval_EppExpression(o, scope)
+    scope["@epp"] = []
+    evaluate(o.body, scope)
+    result = scope["@epp"].join
+    result
+  end
+
+  def eval_RenderStringExpression(o, scope)
+    scope["@epp"] << o.value.dup
+    nil
+  end
+
+  def eval_RenderExpression(o, scope)
+    scope["@epp"] << string(evaluate(o.expr, scope), scope)
+    nil
+  end
+
+  # Evaluates Puppet DSL ->, ~>, <-, and <~
+  def eval_RelationshipExpression(o, scope)
+    # First level evaluation, reduction to basic data types or puppet types, the relationship operator then translates this
+    # to the final set of references (turning strings into references, which can not naturally be done by the main evaluator since
+    # all strings should not be turned into references.
+    #
+    real = eval_BinaryExpression(o, scope)
+    @@relationship_operator.evaluate(real, o, scope)
+  end
+
+  # Evaluates x[key, key, ...]
+  #
+  def eval_AccessExpression(o, scope)
+    left = evaluate(o.left_expr, scope)
+    keys = o.keys.nil? ? [] : o.keys.collect {|key| evaluate(key, scope) }
+    Puppet::Pops::Evaluator::AccessOperator.new(o).access(left, scope, *keys)
+  end
+
+  # Evaluates <, <=, >, >=, and ==
+  #
+  def eval_ComparisonExpression o, scope
+    left = evaluate(o.left_expr, scope)
+    right = evaluate(o.right_expr, scope)
+
+    @migration_checker.report_uc_bareword_type(left, o.left_expr)
+    @migration_checker.report_uc_bareword_type(right, o.right_expr)
+
+    begin
+    # Left is a type
+    if left.is_a?(Puppet::Pops::Types::PAnyType)
+      case o.operator
+      when :'=='
+        @migration_checker.report_equality_type_mismatch(left, right, o)
+        @@type_calculator.equals(left,right)
+
+      when :'!='
+        @migration_checker.report_equality_type_mismatch(left, right, o)
+        !@@type_calculator.equals(left,right)
+
+      when :'<'
+        # left can be assigned to right, but they are not equal
+        @@type_calculator.assignable?(right, left) && ! @@type_calculator.equals(left,right)
+      when :'<='
+        # left can be assigned to right
+        @@type_calculator.assignable?(right, left)
+      when :'>'
+        # right can be assigned to left, but they are not equal
+        @@type_calculator.assignable?(left,right) && ! @@type_calculator.equals(left,right)
+      when :'>='
+        # right can be assigned to left
+        @@type_calculator.assignable?(left, right)
+      else
+        fail(Issues::UNSUPPORTED_OPERATOR, o, {:operator => o.operator})
+      end
+    else
+      case o.operator
+      when :'=='
+        @migration_checker.report_equality_type_mismatch(left, right, o)
+        @@compare_operator.equals(left,right)
+      when :'!='
+        @migration_checker.report_equality_type_mismatch(left, right, o)
+        ! @@compare_operator.equals(left,right)
+      when :'<'
+        @@compare_operator.compare(left,right) < 0
+      when :'<='
+        @@compare_operator.compare(left,right) <= 0
+      when :'>'
+        @@compare_operator.compare(left,right) > 0
+      when :'>='
+        @@compare_operator.compare(left,right) >= 0
+      else
+        fail(Issues::UNSUPPORTED_OPERATOR, o, {:operator => o.operator})
+      end
+    end
+    rescue ArgumentError => e
+      fail(Issues::COMPARISON_NOT_POSSIBLE, o, {
+        :operator => o.operator,
+        :left_value => left,
+        :right_value => right,
+        :detail => e.message}, e)
+    end
+  end
+
+  # Evaluates matching expressions with type, string or regexp rhs expression.
+  # If RHS is a type, the =~ matches compatible (instance? of) type.
+  #
+  # @example
+  #   x =~ /abc.*/
+  # @example
+  #   x =~ "abc.*/"
+  # @example
+  #   y = "abc"
+  #   x =~ "${y}.*"
+  # @example
+  #   [1,2,3] =~ Array[Integer[1,10]]
+  #
+  # Note that a string is not instance? of Regexp, only Regular expressions are.
+  # The Pattern type should instead be used as it is specified as subtype of String.
+  #
+  # @return [Boolean] if a match was made or not. Also sets $0..$n to matchdata in current scope.
+  #
+  def eval_MatchExpression o, scope
+    left = evaluate(o.left_expr, scope)
+    pattern = evaluate(o.right_expr, scope)
+
+    @migration_checker.report_uc_bareword_type(left, o.left_expr)
+
+    # matches RHS types as instance of for all types except a parameterized Regexp[R]
+    if pattern.is_a?(Puppet::Pops::Types::PAnyType)
+      # evaluate as instance? of type check
+      matched = @@type_calculator.instance?(pattern, left)
+      # convert match result to Boolean true, or false
+      return o.operator == :'=~' ? !!matched : !matched
+    end
+
+    begin
+      pattern = Regexp.new(pattern) unless pattern.is_a?(Regexp)
+    rescue StandardError => e
+      fail(Issues::MATCH_NOT_REGEXP, o.right_expr, {:detail => e.message}, e)
+    end
+    unless left.is_a?(String)
+      fail(Issues::MATCH_NOT_STRING, o.left_expr, {:left_value => left})
+    end
+
+    matched = pattern.match(left) # nil, or MatchData
+    set_match_data(matched,scope) # creates ephemeral
+
+    # convert match result to Boolean true, or false
+    o.operator == :'=~' ? !!matched : !matched
+  end
+
+  # Evaluates Puppet DSL `in` expression
+  #
+  def eval_InExpression o, scope
+    left = evaluate(o.left_expr, scope)
+    right = evaluate(o.right_expr, scope)
+    @migration_checker.report_uc_bareword_type(left, o.left_expr)
+    @migration_checker.report_in_expression(o)
+    @@compare_operator.include?(right, left, scope)
+  end
+
+  # @example
+  #   $a and $b
+  # b is only evaluated if a is true
+  #
+  def eval_AndExpression o, scope
+    is_true?(evaluate(o.left_expr, scope), o.left_expr) ? is_true?(evaluate(o.right_expr, scope), o.right_expr) : false
+  end
+
+  # @example
+  #   a or b
+  # b is only evaluated if a is false
+  #
+  def eval_OrExpression o, scope
+    is_true?(evaluate(o.left_expr, scope), o.left_expr) ? true : is_true?(evaluate(o.right_expr, scope), o.right_expr)
+  end
+
+  # Evaluates each entry of the literal list and creates a new Array
+  # Supports unfolding of entries
+  # @return [Array] with the evaluated content
+  #
+  def eval_LiteralList o, scope
+    unfold([], o.values, scope)
+  end
+
+  # Evaluates each entry of the literal hash and creates a new Hash.
+  # @return [Hash] with the evaluated content
+  #
+  def eval_LiteralHash o, scope
+    # optimized
+    o.entries.reduce({}) {|h,entry| h[evaluate(entry.key, scope)] = evaluate(entry.value, scope); h }
+  end
+
+  # Evaluates all statements and produces the last evaluated value
+  #
+  def eval_BlockExpression o, scope
+    r = nil
+    o.statements.each {|s| r = evaluate(s, scope)}
+    r
+  end
+
+  # Performs optimized search over case option values, lazily evaluating each
+  # until there is a match. If no match is found, the case expression's default expression
+  # is evaluated (it may be nil or Nop if there is no default, thus producing nil).
+  # If an option matches, the result of evaluating that option is returned.
+  # @return [Object, nil] what a matched option returns, or nil if nothing matched.
+  #
+  def eval_CaseExpression(o, scope)
+    # memo scope level before evaluating test - don't want a match in the case test to leak $n match vars
+    # to expressions after the case expression.
+    #
+    with_guarded_scope(scope) do
+      test = evaluate(o.test, scope)
+      @migration_checker.report_uc_bareword_type(test, o.test)
+
+      result = nil
+      the_default = nil
+      if o.options.find do |co|
+        # the first case option that matches
+        if co.values.find do |c|
+          c = unwind_parentheses(c)
+          case c
+          when Puppet::Pops::Model::LiteralDefault
+            the_default = co.then_expr
+            next false
+          when Puppet::Pops::Model::UnfoldExpression
+            # not ideal for error reporting, since it is not known which unfolded result
+            # that caused an error - the entire unfold expression is blamed (i.e. the var c, passed to is_match?)
+            evaluate(c, scope).any? {|v| is_match?(test, v, c, co, scope) }
+          else
+            is_match?(test, evaluate(c, scope), c, co, scope)
+          end
+        end
+        result = evaluate(co.then_expr, scope)
+        true # the option was picked
+        end
+      end
+        result # an option was picked, and produced a result
+      else
+        evaluate(the_default, scope) # evaluate the default (should be a nop/nil) if there is no default).
+      end
+    end
+  end
+
+  # Evaluates a CollectExpression by creating a collector transformer. The transformer
+  # will evaulate the collection, create the appropriate collector, and hand it off
+  # to the compiler to collect the resources specified by the query.
+  #
+  def eval_CollectExpression o, scope
+    Puppet::Pops::Evaluator::CollectorTransformer.new().transform(o,scope)
+  end
+
+  def eval_ParenthesizedExpression(o, scope)
+    evaluate(o.expr, scope)
+  end
+
+  # This evaluates classes, nodes and resource type definitions to nil, since 3x:
+  # instantiates them, and evaluates their parameters and body. This is achieved by
+  # providing bridge AST classes in Puppet::Parser::AST::PopsBridge that bridges a
+  # Pops Program and a Pops Expression.
+  #
+  # Since all Definitions are handled "out of band", they are treated as a no-op when
+  # evaluated.
+  #
+  def eval_Definition(o, scope)
+    nil
+  end
+
+  def eval_Program(o, scope)
+    evaluate(o.body, scope)
+  end
+
+  # Produces Array[PAnyType], an array of resource references
+  #
+  def eval_ResourceExpression(o, scope)
+    exported = o.exported
+    virtual = o.virtual
+
+    # Get the type name
+    type_name =
+    if (tmp_name = o.type_name).is_a?(Puppet::Pops::Model::QualifiedName)
+      tmp_name.value # already validated as a name
+    else
+      type_name_acceptable =
+      case o.type_name
+      when Puppet::Pops::Model::QualifiedReference
+        true
+      when Puppet::Pops::Model::AccessExpression
+        o.type_name.left_expr.is_a?(Puppet::Pops::Model::QualifiedReference)
+      end
+
+      evaluated_name = evaluate(tmp_name, scope)
+      unless type_name_acceptable
+        actual = type_calculator.generalize!(type_calculator.infer(evaluated_name)).to_s
+        fail(Puppet::Pops::Issues::ILLEGAL_RESOURCE_TYPE, o.type_name, {:actual => actual})
+      end
+
+      # must be a CatalogEntry subtype
+      case evaluated_name
+      when Puppet::Pops::Types::PHostClassType
+        unless evaluated_name.class_name.nil?
+          fail(Puppet::Pops::Issues::ILLEGAL_RESOURCE_TYPE, o.type_name, {:actual=> evaluated_name.to_s})
+        end
+        'class'
+
+      when Puppet::Pops::Types::PResourceType
+        unless evaluated_name.title().nil?
+          fail(Puppet::Pops::Issues::ILLEGAL_RESOURCE_TYPE, o.type_name, {:actual=> evaluated_name.to_s})
+        end
+        evaluated_name.type_name # assume validated
+
+      else
+        actual = type_calculator.generalize!(type_calculator.infer(evaluated_name)).to_s
+        fail(Puppet::Pops::Issues::ILLEGAL_RESOURCE_TYPE, o.type_name, {:actual=>actual})
+      end
+    end
+
+    # This is a runtime check - the model is valid, but will have runtime issues when evaluated
+    # and storeconfigs is not set.
+    if(o.exported)
+      optionally_fail(Puppet::Pops::Issues::RT_NO_STORECONFIGS_EXPORT, o);
+    end
+
+    titles_to_body = {}
+    body_to_titles = {}
+    body_to_params = {}
+
+    # titles are evaluated before attribute operations
+    o.bodies.map do | body |
+      titles = evaluate(body.title, scope)
+
+      # Title may not be nil
+      # Titles may be given as an array, it is ok if it is empty, but not if it contains nil entries
+      # Titles may not be an empty String
+      # Titles must be unique in the same resource expression
+      # There may be a :default entry, its entries apply with lower precedence
+      #
+      if titles.nil?
+        fail(Puppet::Pops::Issues::MISSING_TITLE, body.title)
+      end
+      titles = [titles].flatten
+
+      # Check types of evaluated titles and duplicate entries
+      titles.each_with_index do |title, index|
+        if title.nil?
+          fail(Puppet::Pops::Issues::MISSING_TITLE_AT, body.title, {:index => index})
+
+        elsif !title.is_a?(String) && title != :default
+          actual = type_calculator.generalize!(type_calculator.infer(title)).to_s
+          fail(Puppet::Pops::Issues::ILLEGAL_TITLE_TYPE_AT, body.title, {:index => index, :actual => actual})
+
+        elsif title == EMPTY_STRING
+         fail(Puppet::Pops::Issues::EMPTY_STRING_TITLE_AT, body.title, {:index => index})
+
+        elsif titles_to_body[title]
+          fail(Puppet::Pops::Issues::DUPLICATE_TITLE, o, {:title => title})
+        end
+        titles_to_body[title] = body
+      end
+
+      # Do not create a real instance from the :default case
+      titles.delete(:default)
+
+      body_to_titles[body] = titles
+
+      # Store evaluated parameters in a hash associated with the body, but do not yet create resource
+      # since the entry containing :defaults may appear later
+      body_to_params[body] = body.operations.reduce({}) do |param_memo, op|
+        params = evaluate(op, scope)
+        params = [params] unless params.is_a?(Array)
+        params.each do |p|
+          if param_memo.include? p.name
+            fail(Puppet::Pops::Issues::DUPLICATE_ATTRIBUTE, o, {:attribute => p.name})
+          end
+          param_memo[p.name] = p
+        end
+        param_memo
+      end
+    end
+
+    # Titles and Operations have now been evaluated and resources can be created
+    # Each production is a PResource, and an array of all is produced as the result of
+    # evaluating the ResourceExpression.
+    #
+    defaults_hash = body_to_params[titles_to_body[:default]] || {}
+    o.bodies.map do | body |
+      titles = body_to_titles[body]
+      params = defaults_hash.merge(body_to_params[body] || {})
+      create_resources(o, scope, virtual, exported, type_name, titles, params.values)
+    end.flatten.compact
+  end
+
+  def eval_ResourceOverrideExpression(o, scope)
+    evaluated_resources = evaluate(o.resources, scope)
+    evaluated_parameters = o.operations.map { |op| evaluate(op, scope) }
+    create_resource_overrides(o, scope, [evaluated_resources].flatten, evaluated_parameters)
+    evaluated_resources
+  end
+
+  # Produces 3x parameter
+  def eval_AttributeOperation(o, scope)
+    create_resource_parameter(o, scope, o.attribute_name, evaluate(o.value_expr, scope), o.operator)
+  end
+
+  def eval_AttributesOperation(o, scope)
+    hashed_params = evaluate(o.expr, scope)
+    unless hashed_params.is_a?(Hash)
+      actual = type_calculator.generalize!(type_calculator.infer(hashed_params)).to_s
+      fail(Puppet::Pops::Issues::TYPE_MISMATCH, o.expr, {:expected => 'Hash', :actual => actual})
+    end
+    hashed_params.map { |k,v| create_resource_parameter(o, scope, k, v, :'=>') }
+  end
+
+  # Sets default parameter values for a type, produces the type
+  #
+  def eval_ResourceDefaultsExpression(o, scope)
+    type = evaluate(o.type_ref, scope)
+    type_name =
+    if type.is_a?(Puppet::Pops::Types::PResourceType) && !type.type_name.nil? && type.title.nil?
+      type.type_name # assume it is a valid name
+    else
+      actual = type_calculator.generalize!(type_calculator.infer(type))
+      fail(Issues::ILLEGAL_RESOURCE_TYPE, o.type_ref, {:actual => actual})
+    end
+    evaluated_parameters = o.operations.map {|op| evaluate(op, scope) }
+    create_resource_defaults(o, scope, type_name, evaluated_parameters)
+    # Produce the type
+    type
+  end
+
+  # Evaluates function call by name.
+  #
+  def eval_CallNamedFunctionExpression(o, scope)
+    # The functor expression is not evaluated, it is not possible to select the function to call
+    # via an expression like $a()
+    case o.functor_expr
+    when Puppet::Pops::Model::QualifiedName
+      # ok
+    when Puppet::Pops::Model::RenderStringExpression
+      # helpful to point out this easy to make Epp error
+      fail(Issues::ILLEGAL_EPP_PARAMETERS, o)
+    else
+      fail(Issues::ILLEGAL_EXPRESSION, o.functor_expr, {:feature=>'function name', :container => o})
+    end
+    name = o.functor_expr.value
+    call_function_with_block(name, unfold([], o.arguments, scope), o, scope)
+  end
+
+  # Evaluation of CallMethodExpression handles a NamedAccessExpression functor (receiver.function_name)
+  #
+  def eval_CallMethodExpression(o, scope)
+    unless o.functor_expr.is_a? Puppet::Pops::Model::NamedAccessExpression
+      fail(Issues::ILLEGAL_EXPRESSION, o.functor_expr, {:feature=>'function accessor', :container => o})
+    end
+    receiver = unfold([], [o.functor_expr.left_expr], scope)
+    name = o.functor_expr.right_expr
+    unless name.is_a? Puppet::Pops::Model::QualifiedName
+      fail(Issues::ILLEGAL_EXPRESSION, o.functor_expr, {:feature=>'function name', :container => o})
+    end 
+    name = name.value # the string function name
+    call_function_with_block(name, unfold(receiver, o.arguments || [], scope), o, scope)
+  end
+
+  def call_function_with_block(name, evaluated_arguments, o, scope)
+    if o.lambda.nil?
+      call_function(name, evaluated_arguments, o, scope)
+    else
+      closure = Puppet::Pops::Evaluator::Closure.new(self, o.lambda, scope)
+      call_function(name, evaluated_arguments, o, scope, &proc_from_closure(closure))
+    end
+  end
+  private :call_function_with_block
+
+  # Creates a Proc with an arity count that matches the parameters of the given closure. The arity will
+  # be correct up to 10 parameters and then default to varargs (-1)
+  #
+  def proc_from_closure(closure)
+    return Puppet::Pops::Evaluator::PuppetProc.new(closure) { |*args| closure.call(*args) } unless RUBY_VERSION[0,3] == '1.8'
+
+    # This code is required since a Proc isn't propagated by reference in Ruby 1.8.x. It produces a standard
+    # Proc that has correct arity as a replacement for the otherwise used PuppetProc
+    # TODO: Remove when Ruby 1.8.x support is dropped
+    arity = closure.parameters.reduce(0) do |memo, param|
+      count = memo + 1
+      break -count if param.captures_rest || !param.value.nil?
+      count
+    end
+
+    case arity
+    when 0
+      proc { || closure.call }
+    when 1
+      proc { |a| closure.call(a) }
+    when 2
+      proc { |a, b| closure.call(a, b) }
+    when 3
+      proc { |a, b, c| closure.call(a, b, c) }
+    when 4
+      proc { |a, b, c, d| closure.call(a, b, c, d) }
+    when 5
+      proc { |a, b, c, d, e| closure.call(a, b, c, d, e) }
+    when 6
+      proc { |a, b, c, d, e, f| closure.call(a, b, c, d, e, f) }
+    when 7
+      proc { |a, b, c, d, e, f, g| closure.call(a, b, c, d, e, f, g) }
+    when 8
+      proc { |a, b, c, d, e, f, g, h| closure.call(a, b, c, d, e, f, g, h) }
+    when 9
+      proc { |a, b, c, d, e, f, g, h, i| closure.call(a, b, c, d, e, f, g, h, i) }
+    when 10
+      proc { |a, b, c, d, e, f, g, h, i, j| closure.call(a, b, c, d, e, f, g, h, i, j) }
+    when -1
+      proc { |*v| closure.call(*v) }
+    when -2
+      proc { |a, *v| closure.call(a, *v) }
+    when -3
+      proc { |a, b, *v| closure.call(a, b, *v) }
+    when -4
+      proc { |a, b, c, *v| closure.call(a, b, c, *v) }
+    when -5
+      proc { |a, b, c, d, *v| closure.call(a, b, c, d, *v) }
+    when -6
+      proc { |a, b, c, d, e, *v| closure.call(a, b, c, d, e, *v) }
+    when -7
+      proc { |a, b, c, d, e, f, *v| closure.call(a, b, c, d, e, f, *v) }
+    when -8
+      proc { |a, b, c, d, e, f, g, *v| closure.call(a, b, c, d, e, f, g, *v) }
+    when -9
+      proc { |a, b, c, d, e, f, g, h, *v| closure.call(a, b, c, d, e, f,g, h, *v) }
+    when -10
+      proc { |a, b, c, d, e, f, g, h, i, *v| closure.call(a, b, c, d, e, f,g, h, i, *v) }
+    else
+      proc { |*a| closure.call(*a) }
+    end
+  end
+  private :proc_from_closure
+
+  # @example
+  #   $x ? { 10 => true, 20 => false, default => 0 }
+  #
+  def eval_SelectorExpression o, scope
+    # memo scope level before evaluating test - don't want a match in the case test to leak $n match vars
+    # to expressions after the selector expression.
+    #
+    with_guarded_scope(scope) do
+      test = evaluate(o.left_expr, scope)
+      @migration_checker.report_uc_bareword_type(test, o.left_expr)
+
+      the_default = nil
+      selected = o.selectors.find do |s|
+        me = unwind_parentheses(s.matching_expr)
+        case me
+        when Puppet::Pops::Model::LiteralDefault
+          the_default = s.value_expr
+          false
+        when Puppet::Pops::Model::UnfoldExpression
+          # not ideal for error reporting, since it is not known which unfolded result
+          # that caused an error - the entire unfold expression is blamed (i.e. the var c, passed to is_match?)
+          evaluate(me, scope).any? {|v| is_match?(test, v, me, s, scope) }
+        else
+          is_match?(test, evaluate(me, scope), me, s, scope)
+        end
+      end
+      if selected
+        evaluate(selected.value_expr, scope)
+      elsif the_default
+        evaluate(the_default, scope)
+      else
+        fail(Issues::UNMATCHED_SELECTOR, o.left_expr, :param_value => test)
+      end
+    end
+  end
+
+  # SubLocatable is simply an expression that holds location information
+  def eval_SubLocatedExpression o, scope
+    evaluate(o.expr, scope)
+  end
+
+  # Evaluates Puppet DSL Heredoc
+  def eval_HeredocExpression o, scope
+    result = evaluate(o.text_expr, scope)
+    assert_external_syntax(scope, result, o.syntax, o.text_expr)
+    result
+  end
+
+  # Evaluates Puppet DSL `if`
+  def eval_IfExpression o, scope
+    with_guarded_scope(scope) do
+      if is_true?(evaluate(o.test, scope), o.test)
+        evaluate(o.then_expr, scope)
+      else
+        evaluate(o.else_expr, scope)
+      end
+    end
+  end
+
+  # Evaluates Puppet DSL `unless`
+  def eval_UnlessExpression o, scope
+    with_guarded_scope(scope) do
+      unless is_true?(evaluate(o.test, scope), o.test)
+        evaluate(o.then_expr, scope)
+      else
+        evaluate(o.else_expr, scope)
+      end
+    end
+  end
+
+  # Evaluates a variable (getting its value)
+  # The evaluator is lenient; any expression producing a String is used as a name
+  # of a variable.
+  #
+  def eval_VariableExpression o, scope
+    # Evaluator is not too fussy about what constitutes a name as long as the result
+    # is a String and a valid variable name
+    #
+    name = evaluate(o.expr, scope)
+
+    # Should be caught by validation, but make this explicit here as well, or mysterious evaluation issues
+    # may occur for some evaluation use cases.
+    case name
+    when String
+    when Numeric
+    else
+      fail(Issues::ILLEGAL_VARIABLE_EXPRESSION, o.expr)
+    end
+    get_variable_value(name, o, scope)
+  end
+
+  # Evaluates double quoted strings that may contain interpolation
+  #
+  def eval_ConcatenatedString o, scope
+    o.segments.collect {|expr| string(evaluate(expr, scope), scope)}.join
+  end
+
+
+  # If the wrapped expression is a QualifiedName, it is taken as the name of a variable in scope.
+  # Note that this is different from the 3.x implementation, where an initial qualified name
+  # is accepted. (e.g. `"---${var + 1}---"` is legal. This implementation requires such concrete
+  # syntax to be expressed in a model as `(TextExpression (+ (Variable var) 1)` - i.e. moving the decision to
+  # the parser.
+  #
+  # Semantics; the result of an expression is turned into a string, nil is silently transformed to empty
+  # string.
+  # @return [String] the interpolated result
+  #
+  def eval_TextExpression o, scope
+    if o.expr.is_a?(Puppet::Pops::Model::QualifiedName)
+      string(get_variable_value(o.expr.value, o, scope), scope)
+    else
+      string(evaluate(o.expr, scope), scope)
+    end
+  end
+
+  def string_Object(o, scope)
+    o.to_s
+  end
+
+  def string_Symbol(o, scope)
+    if :undef == o  # optimized comparison 1.44 vs 1.95
+      EMPTY_STRING
+    else
+      o.to_s
+    end
+  end
+
+  def string_Array(o, scope)
+    "[#{o.map {|e| string(e, scope)}.join(COMMA_SEPARATOR)}]"
+  end
+
+  def string_Hash(o, scope)
+    "{#{o.map {|k,v| "#{string(k, scope)} => #{string(v, scope)}"}.join(COMMA_SEPARATOR)}}"
+  end
+
+  def string_Regexp(o, scope)
+    "/#{o.source}/"
+  end
+
+  def string_PAnyType(o, scope)
+    @@type_calculator.string(o)
+  end
+
+  # Produces concatenation / merge of x and y.
+  #
+  # When x is an Array, y of type produces:
+  #
+  # * Array => concatenation `[1,2], [3,4] => [1,2,3,4]`
+  # * Hash => concatenation of hash as array `[key, value, key, value, ...]`
+  # * any other => concatenation of single value
+  #
+  # When x is a Hash, y of type produces:
+  #
+  # * Array => merge of array interpreted as `[key, value, key, value,...]`
+  # * Hash => a merge, where entries in `y` overrides
+  # * any other => error
+  #
+  # When x is something else, wrap it in an array first.
+  #
+  # When x is nil, an empty array is used instead.
+  #
+  # @note to concatenate an Array, nest the array - i.e. `[1,2], [[2,3]]`
+  #
+  # @overload concatenate(obj_x, obj_y)
+  #   @param obj_x [Object] object to wrap in an array and concatenate to; see other overloaded methods for return type
+  #   @param ary_y [Object] array to concatenate at end of `ary_x`
+  #   @return [Object] wraps obj_x in array before using other overloaded option based on type of obj_y
+  # @overload concatenate(ary_x, ary_y)
+  #   @param ary_x [Array] array to concatenate to
+  #   @param ary_y [Array] array to concatenate at end of `ary_x`
+  #   @return [Array] new array with `ary_x` + `ary_y`
+  # @overload concatenate(ary_x, hsh_y)
+  #   @param ary_x [Array] array to concatenate to
+  #   @param hsh_y [Hash] converted to array form, and concatenated to array
+  #   @return [Array] new array with `ary_x` + `hsh_y` converted to array
+  # @overload concatenate (ary_x, obj_y)
+  #   @param ary_x [Array] array to concatenate to
+  #   @param obj_y [Object] non array or hash object to add to array
+  #   @return [Array] new array with `ary_x` + `obj_y` added as last entry
+  # @overload concatenate(hsh_x, ary_y)
+  #   @param hsh_x [Hash] the hash to merge with
+  #   @param ary_y [Array] array interpreted as even numbered sequence of key, value merged with `hsh_x`
+  #   @return [Hash] new hash with `hsh_x` merged with `ary_y` interpreted as hash in array form
+  # @overload concatenate(hsh_x, hsh_y)
+  #   @param hsh_x [Hash] the hash to merge to
+  #   @param hsh_y [Hash] hash merged with `hsh_x`
+  #   @return [Hash] new hash with `hsh_x` merged with `hsh_y`
+  # @raise [ArgumentError] when `xxx_x` is neither an Array nor a Hash
+  # @raise [ArgumentError] when `xxx_x` is a Hash, and `xxx_y` is neither Array nor Hash.
+  #
+  def concatenate(x, y)
+    x = [x] unless x.is_a?(Array) || x.is_a?(Hash)
+    case x
+    when Array
+      y = case y
+      when Array then y
+      when Hash  then y.to_a
+      else
+        [y]
+      end
+      x + y # new array with concatenation
+    when Hash
+      y = case y
+      when Hash then y
+      when Array
+        # Hash[[a, 1, b, 2]] => {}
+        # Hash[a,1,b,2] => {a => 1, b => 2}
+        # Hash[[a,1], [b,2]] => {[a,1] => [b,2]}
+        # Hash[[[a,1], [b,2]]] => {a => 1, b => 2}
+        # Use type calcultor to determine if array is Array[Array[?]], and if so use second form
+        # of call
+        t = @@type_calculator.infer(y)
+        if t.element_type.is_a? Puppet::Pops::Types::PArrayType
+          Hash[y]
+        else
+          Hash[*y]
+        end
+      else
+        raise ArgumentError.new("Can only append Array or Hash to a Hash")
+      end
+      x.merge y # new hash with overwrite
+    else
+      raise ArgumentError.new("Can only append to an Array or a Hash.")
+    end
+  end
+
+  # Produces the result x \ y (set difference)
+  # When `x` is an Array, `y` is transformed to an array and then all matching elements removed from x.
+  # When `x` is a Hash, all contained keys are removed from x as listed in `y` if it is an Array, or all its keys if it is a Hash.
+  # The difference is returned. The given `x` and `y` are not modified by this operation.
+  # @raise [ArgumentError] when `x` is neither an Array nor a Hash
+  #
+  def delete(x, y)
+    result = x.dup
+    case x
+    when Array
+      y = case y
+      when Array then y
+      when Hash then y.to_a
+      else
+        [y]
+      end
+      y.each {|e| result.delete(e) }
+    when Hash
+      y = case y
+      when Array then y
+      when Hash then y.keys
+      else
+        [y]
+      end
+      y.each {|e| result.delete(e) }
+    else
+      raise ArgumentError.new("Can only delete from an Array or Hash.")
+    end
+    result
+  end
+
+  # Implementation of case option matching.
+  #
+  # This is the type of matching performed in a case option, using == for every type
+  # of value except regular expression where a match is performed.
+  #
+  def is_match?(left, right, o, option_expr, scope)
+    @migration_checker.report_option_type_mismatch(left, right, option_expr, o)
+    if right.is_a?(Puppet::Pops::Types::PAnyType)
+      @migration_checker.report_uc_bareword_type(right, o)
+    end
+    @@compare_operator.match(left, right, scope)
+  end
+
+  def with_guarded_scope(scope)
+    scope_memo = get_scope_nesting_level(scope)
+    begin
+      yield
+    ensure
+      set_scope_nesting_level(scope, scope_memo)
+    end
+  end
+
+  # Maps the expression in the given array to their product except for UnfoldExpressions which are first unfolded.
+  # The result is added to the given result Array.
+  # @param result [Array] Where to add the result (may contain information to add to)
+  # @param array [Array[Puppet::Pops::Model::Expression] the expressions to map
+  # @param scope [Puppet::Parser::Scope] the scope to evaluate in
+  # @return [Array] the given result array with content added from the operation
+  #
+  def unfold(result, array, scope)
+    array.each do |x|
+      x = unwind_parentheses(x)
+      if x.is_a?(Puppet::Pops::Model::UnfoldExpression)
+        result.concat(evaluate(x, scope))
+      else
+        result << evaluate(x, scope)
+      end
+    end
+    result
+  end
+  private :unfold
+
+  def unwind_parentheses(o)
+    return o unless o.is_a?(Puppet::Pops::Model::ParenthesizedExpression)
+    unwind_parentheses(o.expr)
+  end
+  private :unwind_parentheses
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/external_syntax_support.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/external_syntax_support.rb
new file mode 100644
index 0000000..9ee96a8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/external_syntax_support.rb
@@ -0,0 +1,49 @@
+# This module is an integral part of the evaluator. It deals with the concern of validating
+# external syntax in text produced by heredoc and templates.
+#
+module Puppet::Pops::Evaluator::ExternalSyntaxSupport
+  # TODO: This can be simplified if the Factory directly supporteded hash_of/type_of
+  TYPES = Puppet::Pops::Types::TypeFactory
+
+  def assert_external_syntax(scope, result, syntax, reference_expr)
+    @@HASH_OF_SYNTAX_CHECKERS ||= TYPES.hash_of(TYPES.type_of(::Puppetx::SYNTAX_CHECKERS_TYPE))
+    # ignore 'unspecified syntax'
+    return if syntax.nil? || syntax == ''
+
+    checker = checker_for_syntax(scope, syntax)
+    # ignore syntax with no matching checker
+    return unless checker
+
+    # Call checker and give it the location information from the expression
+    # (as opposed to where the heredoc tag is (somewhere on the line above)).
+    acceptor = Puppet::Pops::Validation::Acceptor.new()
+    source_pos = find_closest_positioned(reference_expr)
+    checker.check(result, syntax, acceptor, source_pos)
+
+    if acceptor.error_count > 0
+      checker_message = "Invalid produced text having syntax: '#{syntax}'."
+      Puppet::Pops::IssueReporter.assert_and_report(acceptor, :message => checker_message)
+      raise ArgumentError, "Internal Error: Configuration of runtime error handling wrong: should have raised exception"
+    end
+  end
+
+  # Finds the most significant checker for the given syntax (most significant is to the right).
+  # Returns nil if there is no registered checker.
+  #
+  def checker_for_syntax(scope, syntax)
+    checkers_hash = scope.compiler.injector.lookup(scope, @@HASH_OF_SYNTAX_CHECKERS, ::Puppetx::SYNTAX_CHECKERS) || {}
+    checkers_hash[lookup_keys_for_syntax(syntax).find {|x| checkers_hash[x] }]
+  end
+
+  # Returns an array of possible syntax names
+  def lookup_keys_for_syntax(syntax)
+    segments = syntax.split(/\+/)
+    result = []
+    begin
+      result << segments.join("+")
+      segments.shift
+    end until segments.empty?
+    result
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/puppet_proc.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/puppet_proc.rb
new file mode 100644
index 0000000..33e71db
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/puppet_proc.rb
@@ -0,0 +1,69 @@
+# Complies with Proc API by mapping a Puppet::Pops::Evaluator::Closure to a ruby Proc.
+# Creating and passing an instance of this class instead of just a plain block makes
+# it possible to inherit the parameter info and arity from the closure. Advanced users
+# may also access the closure itself. The Puppet::Pops::Functions::Dispatcher uses this
+# when it needs to get the Callable type of the closure.
+#
+# The class is part of the Puppet Function API for Ruby and thus public API but a user
+# should never create an instance of this class.
+#
+# @api public
+class Puppet::Pops::Evaluator::PuppetProc < Proc
+  # Creates a new instance from a closure and a block that will dispatch
+  # all parameters to the closure. The block must be similar to:
+  #
+  #   { |*args| closure.call(*args) }
+  #
+  # @param closure [Puppet::Pops::Evaluator::Closure] The closure to map
+  # @param &block [Block] The varargs block that invokes the closure.call method
+  #
+  # @api private
+  def self.new(closure, &block)
+    proc = super(&block)
+    proc.instance_variable_set(:@closure, closure)
+    proc
+  end
+
+  # @return  [Puppet::Pops::Evaluator::Closure] the mapped closure
+  # @api public
+  attr_reader :closure
+
+  # @overrides Block.lambda?
+  # @return [Boolean] always false since this proc doesn't do the Ruby lambda magic
+  # @api public
+  def lambda?
+    false
+  end
+
+  # Maps the closure parameters to standard Block parameter info where each
+  # parameter is represented as a two element Array where the first
+  # element is :req, :opt, or :rest and the second element is the name
+  # of the parameter.
+  #
+  # @return [Array<Array<Symbol>>] array of parameter info pairs
+  # @overrides Block.parameters
+  # @api public
+  def parameters
+    @closure.parameters.map do |param|
+      sym = param.name.to_sym
+      if param.captures_rest
+        [ :rest, sym ]
+      elsif param.value
+        [ :opt, sym ]
+      else
+        [ :req, sym ]
+      end
+    end
+  end
+
+  # @return [Fixnum] the arity of the block
+  # @overrides Block.arity
+  # @api public
+  def arity
+    parameters.reduce(0) do |memo, param|
+      count = memo + 1
+      break -count unless param[0] == :req
+      count
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/relationship_operator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/relationship_operator.rb
new file mode 100644
index 0000000..1731870
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/relationship_operator.rb
@@ -0,0 +1,161 @@
+# The RelationshipOperator implements the semantics of the -> <- ~> <~ operators creating relationships or notification
+# relationships between the left and right hand side's references to resources.
+#
+# This is separate class since a second level of evaluation is required that transforms string in left or right hand
+# to type references. The task of "making a relationship" is delegated to the "runtime support" class that is included.
+# This is done to separate the concerns of the new evaluator from the 3x runtime; messy logic goes into the runtime support
+# module. Later when more is cleaned up this can be simplified further.
+#
+class Puppet::Pops::Evaluator::RelationshipOperator
+
+  # Provides access to the Puppet 3.x runtime (scope, etc.)
+  # This separation has been made to make it easier to later migrate the evaluator to an improved runtime.
+  #
+  include Puppet::Pops::Evaluator::Runtime3Support
+
+  Issues = Puppet::Pops::Issues
+
+  class IllegalRelationshipOperandError < RuntimeError
+    attr_reader :operand
+    def initialize operand
+      @operand = operand
+    end
+  end
+
+  class NotCatalogTypeError < RuntimeError
+    attr_reader :type
+    def initialize type
+      @type = type
+    end
+  end
+
+  def initialize
+    @type_transformer_visitor = Puppet::Pops::Visitor.new(self, "transform", 1, 1)
+    @type_calculator = Puppet::Pops::Types::TypeCalculator.new()
+    @type_parser = Puppet::Pops::Types::TypeParser.new()
+
+    tf = Puppet::Pops::Types::TypeFactory
+    @catalog_type = tf.variant(tf.catalog_entry, tf.type_type(tf.catalog_entry))
+  end
+
+  def transform(o, scope)
+    @type_transformer_visitor.visit_this_1(self, o, scope)
+  end
+
+  # Catch all non transformable objects
+  # @api private
+  def transform_Object(o, scope)
+    raise IllegalRelationshipOperandError.new(o)
+  end
+
+  # A string must be a type reference in string format
+  # @api private
+  def transform_String(o, scope)
+    assert_catalog_type(@type_parser.parse(o), scope)
+  end
+
+  # A qualified name is short hand for a class with this name
+  # @api private
+  def transform_QualifiedName(o, scope)
+    Puppet::Pops::Types::TypeFactory.host_class(o.value)
+  end
+
+  # Types are what they are, just check the type
+  # @api private
+  def transform_PAnyType(o, scope)
+    assert_catalog_type(o, scope)
+  end
+
+  # This transforms a 3x Collector (the result of evaluating a 3x AST::Collection).
+  # It is passed through verbatim since it is evaluated late by the compiler. At the point
+  # where the relationship is evaluated, it is simply recorded with the compiler for later evaluation.
+  # If one of the sides of the relationship is a Collector it is evaluated before the actual
+  # relationship is formed. (All of this happens at a later point in time.
+  #
+  def transform_Collector(o, scope)
+    o
+  end
+
+  def transform_AbstractCollector(o, scope)
+    o
+  end
+
+  # Array content needs to be transformed
+  def transform_Array(o, scope)
+    o.map{|x| transform(x, scope) }
+  end
+
+  # Asserts (and returns) the type if it is a PCatalogEntryType
+  # (A PCatalogEntryType is the base class of PHostClassType, and PResourceType).
+  #
+  def assert_catalog_type(o, scope)
+    unless @type_calculator.assignable?(@catalog_type, o)
+      raise NotCatalogTypeError.new(o)
+    end
+    # TODO must check if this is an abstract PResourceType (i.e. without a type_name) - which should fail ?
+    # e.g. File -> File (and other similar constructs) - maybe the catalog protects against this since references
+    # may be to future objects...
+    o
+  end
+
+  RELATIONSHIP_OPERATORS = [:'->', :'~>', :'<-', :'<~']
+  REVERSE_OPERATORS      = [:'<-', :'<~']
+  RELATION_TYPE = {
+    :'->' => :relationship,
+    :'<-' => :relationship,
+    :'~>' => :subscription,
+    :'<~' => :subscription
+  }
+
+  # Evaluate a relationship.
+  # TODO: The error reporting is not fine grained since evaluation has already taken place
+  # There is no references to the original source expressions at this point, only the overall
+  # relationship expression. (e.g.. the expression may be ['string', func_call(), etc.] -> func_call())
+  # To implement this, the general evaluator needs to be able to track each evaluation result and associate
+  # it with a corresponding expression. This structure should then be passed to the relationship operator.
+  #
+  def evaluate (left_right_evaluated, relationship_expression, scope)
+    # assert operator (should have been validated, but this logic makes assumptions which would
+    # screw things up royally). Better safe than sorry.
+    unless RELATIONSHIP_OPERATORS.include?(relationship_expression.operator)
+      fail(Issues::UNSUPPORTED_OPERATOR, relationship_expression, {:operator => relationship_expression.operator})
+    end
+
+    begin
+      # Turn each side into an array of types (this also asserts their type)
+      # (note wrap in array first if value is not already an array)
+      #
+      # TODO: Later when objects are Puppet Runtime Objects and know their type, it will be more efficient to check/infer
+      # the type first since a chained operation then does not have to visit each element again. This is not meaningful now
+      # since inference needs to visit each object each time, and this is what the transformation does anyway).
+      #
+      # real is [left, right], and both the left and right may be a single value or an array. In each case all content
+      # should be flattened, and then transformed to a type. left or right may also be a value that is transformed
+      # into an array, and thus the resulting left and right must be flattened individually
+      # Once flattened, the operands should be sets (to remove duplicate entries)
+      #
+      real = left_right_evaluated.collect {|x| [x].flatten.collect {|x| transform(x, scope) }}
+      real[0].flatten!
+      real[1].flatten!
+      real[0].uniq!
+      real[1].uniq!
+
+      # reverse order if operator is Right to Left
+      source, target = reverse_operator?(relationship_expression) ? real.reverse : real
+
+      # Add the relationships to the catalog
+      source.each {|s| target.each {|t| add_relationship(s, t, RELATION_TYPE[relationship_expression.operator], scope) }}
+
+      # Produce the transformed source RHS (if this is a chain, this does not need to be done again)
+      real.slice(1)
+    rescue NotCatalogTypeError => e
+      fail(Issues::ILLEGAL_RELATIONSHIP_OPERAND_TYPE, relationship_expression, {:type => @type_calculator.string(e.type)})
+    rescue IllegalRelationshipOperandError => e
+      fail(Issues::ILLEGAL_RELATIONSHIP_OPERAND_TYPE, relationship_expression, {:operand => e.operand})
+    end
+  end
+
+  def reverse_operator?(o)
+    REVERSE_OPERATORS.include?(o.operator)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/runtime3_converter.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/runtime3_converter.rb
new file mode 100644
index 0000000..f759743
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/runtime3_converter.rb
@@ -0,0 +1,175 @@
+module Puppet::Pops::Evaluator
+# Converts nested 4x supported values to 3x values. This is required because
+# resources and other objects do not know about the new type system, and does not support
+# regular expressions. Unfortunately this has to be done for array and hash as well.
+# A complication is that catalog types needs to be resolved against the scope.
+#
+# Users should not create instances of this class. Instead the class methods {Runtime3Converter.convert},
+# {Runtime3Converter.map_args}, or {Runtime3Converter.instance} should be used
+class Runtime3Converter
+  # Converts 4x supported values to a 3x values. Same as calling Runtime3Converter.instance.map_args(...)
+  #
+  # @param args [Array] Array of values to convert
+  # @param scope [Puppet::Parser::Scope] The scope to use when converting
+  # @param undef_value [Object] The value that nil is converted to
+  # @return [Array] The converted values
+  #
+  def self.map_args(args, scope, undef_value)
+    @@instance.map_args(args, scope, undef_value)
+  end
+
+  # Converts 4x supported values to a 3x values. Same as calling Runtime3Converter.instance.convert(...)
+  #
+  # @param o [Object]The value to convert
+  # @param scope [Puppet::Parser::Scope] The scope to use when converting
+  # @param undef_value [Object] The value that nil is converted to
+  # @return [Object] The converted value
+  #
+  def self.convert(o, scope, undef_value)
+    @@instance.convert(o, scope, undef_value)
+  end
+
+  # Returns the singleton instance of this class.
+  # @return [Runtime3Converter] The singleton instance
+  def self.instance
+    @@instance
+  end
+
+  # Converts 4x supported values to a 3x values.
+  #
+  # @param args [Array] Array of values to convert
+  # @param scope [Puppet::Parser::Scope] The scope to use when converting
+  # @param undef_value [Object] The value that nil is converted to
+  # @return [Array] The converted values
+  #
+  def map_args(args, scope, undef_value)
+    args.map {|a| convert(a, scope, undef_value) }
+  end
+
+  # Converts a 4x supported value to a 3x value.
+  #
+  # @param o [Object]The value to convert
+  # @param scope [Puppet::Parser::Scope] The scope to use when converting
+  # @param undef_value [Object] The value that nil is converted to
+  # @return [Object] The converted value
+  #
+  def convert(o, scope, undef_value)
+    @convert_visitor.visit_this_2(self, o, scope, undef_value)
+  end
+
+  def convert_NilClass(o, scope, undef_value)
+    undef_value
+  end
+
+  def convert2_NilClass(o, scope, undef_value)
+    :undef
+  end
+
+  def convert_String(o, scope, undef_value)
+    # although wasteful, needed because user code may mutate these strings in Resources
+    o.frozen? ? o.dup : o
+  end
+  alias convert2_String :convert_String
+
+  def convert_Object(o, scope, undef_value)
+    o
+  end
+  alias :convert2_Object :convert_Object
+
+  def convert_Array(o, scope, undef_value)
+    o.map {|x| convert2(x, scope, undef_value) }
+  end
+  alias :convert2_Array :convert_Array
+
+  def convert_Hash(o, scope, undef_value)
+    result = {}
+    o.each {|k,v| result[convert2(k, scope, undef_value)] = convert2(v, scope, undef_value) }
+    result
+  end
+  alias :convert2_Hash :convert_Hash
+
+  def convert_Regexp(o, scope, undef_value)
+    # Puppet 3x cannot handle parameter values that are reqular expressions. Turn into regexp string in
+    # source form
+    o.inspect
+  end
+  alias :convert2_Regexp :convert_Regexp
+
+  def convert_Symbol(o, scope, undef_value)
+    case o
+      # Support :undef since it may come from a 3x structure
+      when :undef
+        undef_value  # 3x wants undef as either empty string or :undef
+      else
+        o   # :default, and all others are verbatim since they are new in future evaluator
+    end
+  end
+
+  # The :undef symbol should not be converted when nested in arrays or hashes
+  def convert2_Symbol(o, scope, undef_value)
+    o
+  end
+
+  def convert_PAnyType(o, scope, undef_value)
+    o
+  end
+  alias :convert2_PAnyType :convert_PAnyType
+
+  def convert_PCatalogEntryType(o, scope, undef_value)
+    # Since 4x does not support dynamic scoping, all names are absolute and can be
+    # used as is (with some check/transformation/mangling between absolute/relative form
+    # due to Puppet::Resource's idiosyncratic behavior where some references must be
+    # absolute and others cannot be.
+    # Thus there is no need to call scope.resolve_type_and_titles to do dynamic lookup.
+
+    Puppet::Resource.new(*catalog_type_to_split_type_title(o))
+  end
+  alias :convert2_PCatalogEntryType :convert_PCatalogEntryType
+
+  # Produces an array with [type, title] from a PCatalogEntryType
+  # This method is used to produce the arguments for creation of reference resource instances
+  # (used when 3x is operating on a resource).
+  # Ensures that resources are *not* absolute.
+  #
+  def catalog_type_to_split_type_title(catalog_type)
+    split_type = catalog_type.is_a?(Puppet::Pops::Types::PType) ? catalog_type.type : catalog_type
+    case split_type
+      when Puppet::Pops::Types::PHostClassType
+        class_name = split_type.class_name
+        ['class', class_name.nil? ? nil : class_name.sub(/^::/, '')]
+      when Puppet::Pops::Types::PResourceType
+        type_name = split_type.type_name
+        title = split_type.title
+        if type_name =~ /^(::)?[Cc]lass$/
+          ['class', title.nil? ? nil : title.sub(/^::/, '')]
+        else
+          # Ensure that title is '' if nil
+          # Resources with absolute name always results in error because tagging does not support leading ::
+          [type_name.nil? ? nil : type_name.sub(/^::/, ''), title.nil? ? '' : title]
+        end
+      else
+        raise ArgumentError, "Cannot split the type #{catalog_type.class}, it represents neither a PHostClassType, nor a PResourceType."
+    end
+  end
+
+  private
+
+  def initialize
+    @convert_visitor  = Puppet::Pops::Visitor.new(self, 'convert', 2, 2)
+    @convert2_visitor = Puppet::Pops::Visitor.new(self, 'convert2', 2, 2)
+  end
+
+  @@instance = self.new
+
+  # Converts a nested 4x supported value to a 3x value.
+  #
+  # @param o [Object]The value to convert
+  # @param scope [Puppet::Parser::Scope] The scope to use when converting
+  # @param undef_value [Object] The value that nil is converted to
+  # @return [Object] The converted value
+  #
+  def convert2(o, scope, undef_value)
+    @convert2_visitor.visit_this_2(self, o, scope, undef_value)
+  end
+end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/runtime3_support.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/runtime3_support.rb
new file mode 100644
index 0000000..d02657f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/evaluator/runtime3_support.rb
@@ -0,0 +1,521 @@
+# A module with bindings between the new evaluator and the 3x runtime.
+# The intention is to separate all calls into scope, compiler, resource, etc. in this module
+# to make it easier to later refactor the evaluator for better implementations of the 3x classes.
+#
+# @api private
+module Puppet::Pops::Evaluator::Runtime3Support
+
+  NAME_SPACE_SEPARATOR = '::'.freeze
+
+  # Fails the evaluation of _semantic_ with a given issue.
+  #
+  # @param issue [Puppet::Pops::Issue] the issue to report
+  # @param semantic [Puppet::Pops::ModelPopsObject] the object for which evaluation failed in some way. Used to determine origin.
+  # @param options [Hash] hash of optional named data elements for the given issue
+  # @return [!] this method does not return
+  # @raise [Puppet::ParseError] an evaluation error initialized from the arguments (TODO: Change to EvaluationError?)
+  #
+  def fail(issue, semantic, options={}, except=nil)
+    optionally_fail(issue, semantic, options, except)
+    # an error should have been raised since fail always fails
+    raise ArgumentError, "Internal Error: Configuration of runtime error handling wrong: should have raised exception"
+  end
+
+  # Optionally (based on severity) Fails the evaluation of _semantic_ with a given issue
+  # If the given issue is configured to be of severity < :error it is only reported, and the function returns.
+  #
+  # @param issue [Puppet::Pops::Issue] the issue to report
+  # @param semantic [Puppet::Pops::ModelPopsObject] the object for which evaluation failed in some way. Used to determine origin.
+  # @param options [Hash] hash of optional named data elements for the given issue
+  # @return [!] this method does not return
+  # @raise [Puppet::ParseError] an evaluation error initialized from the arguments (TODO: Change to EvaluationError?)
+  #
+  def optionally_fail(issue, semantic, options={}, except=nil)
+    if except.nil?
+      # Want a stacktrace, and it must be passed as an exception
+      begin
+       raise EvaluationError.new()
+      rescue EvaluationError => e
+        except = e
+      end
+    end
+    diagnostic_producer.accept(issue, semantic, options, except)
+  end
+
+  # Binds the given variable name to the given value in the given scope.
+  # The reference object `o` is intended to be used for origin information - the 3x scope implementation
+  # only makes use of location when there is an error. This is now handled by other mechanisms; first a check
+  # is made if a variable exists and an error is raised if attempting to change an immutable value. Errors
+  # in name, numeric variable assignment etc. have also been validated prior to this call. In the event the
+  # scope.setvar still raises an error, the general exception handling for evaluation of the assignment
+  # expression knows about its location. Because of this, there is no need to extract the location for each
+  # setting (extraction is somewhat expensive since 3x requires line instead of offset).
+  #
+  def set_variable(name, value, o, scope)
+    # Scope also checks this but requires that location information are passed as options.
+    # Those are expensive to calculate and a test is instead made here to enable failing with better information.
+    # The error is not specific enough to allow catching it - need to check the actual message text.
+    # TODO: Improve the messy implementation in Scope.
+    #
+    if scope.bound?(name)
+      if Puppet::Parser::Scope::RESERVED_VARIABLE_NAMES.include?(name)
+        fail(Puppet::Pops::Issues::ILLEGAL_RESERVED_ASSIGNMENT, o, {:name => name} )
+      else
+        fail(Puppet::Pops::Issues::ILLEGAL_REASSIGNMENT, o, {:name => name} )
+      end
+    end
+    scope.setvar(name, value)
+  end
+
+  # Returns the value of the variable (nil is returned if variable has no value, or if variable does not exist)
+  #
+  def get_variable_value(name, o, scope)
+    # Puppet 3x stores all variables as strings (then converts them back to numeric with a regexp... to see if it is a match variable)
+    # Not ideal, scope should support numeric lookup directly instead.
+    # TODO: consider fixing scope
+    catch(:undefined_variable) {
+      x = scope.lookupvar(name.to_s)
+      # Must convert :undef back to nil - this can happen when an undefined variable is used in a
+      # parameter's default value expression - there nil must be :undef to work with the rest of 3x.
+      # Now that the value comes back to 4x it is changed to nil.
+      return (x == :undef) ? nil : x
+    }
+    # It is always ok to reference numeric variables even if they are not assigned. They are always undef
+    # if not set by a match expression.
+    #
+    unless name =~ Puppet::Pops::Patterns::NUMERIC_VAR_NAME
+      fail(Puppet::Pops::Issues::UNKNOWN_VARIABLE, o, {:name => name})
+    end
+  end
+
+  # Returns true if the variable of the given name is set in the given most nested scope. True is returned even if
+  # variable is bound to nil.
+  #
+  def variable_bound?(name, scope)
+    scope.bound?(name.to_s)
+  end
+
+  # Returns true if the variable is bound to a value or nil, in the scope or it's parent scopes.
+  #
+  def variable_exists?(name, scope)
+    scope.exist?(name.to_s)
+  end
+
+  def set_match_data(match_data, scope)
+    # See set_variable for rationale for not passing file and line to ephemeral_from.
+    # NOTE: The 3x scope adds one ephemeral(match) to its internal stack per match that succeeds ! It never
+    # clears anything. Thus a context that performs many matches will get very deep (there simply is no way to
+    # clear the match variables without rolling back the ephemeral stack.)
+    # This implementation does not attempt to fix this, it behaves the same bad way.
+    unless match_data.nil?
+      scope.ephemeral_from(match_data)
+    end
+  end
+
+  # Creates a local scope with vairalbes set from a hash of variable name to value
+  #
+  def create_local_scope_from(hash, scope)
+    # two dummy values are needed since the scope tries to give an error message (can not happen in this
+    # case - it is just wrong, the error should be reported by the caller who knows in more detail where it
+    # is in the source.
+    #
+    raise ArgumentError, "Internal error - attempt to create a local scope without a hash" unless hash.is_a?(Hash)
+    scope.ephemeral_from(hash)
+  end
+
+  # Creates a nested match scope
+  def create_match_scope_from(scope)
+    # Create a transparent match scope (for future matches)
+    scope.new_match_scope(nil)
+  end
+
+  def get_scope_nesting_level(scope)
+    scope.ephemeral_level
+  end
+
+  def set_scope_nesting_level(scope, level)
+    # Yup, 3x uses this method to reset the level, it also supports passing :all to destroy all 
+    # ephemeral/local scopes - which is a sure way to create havoc.
+    #
+    scope.unset_ephemeral_var(level)
+  end
+
+  # Adds a relationship between the given `source` and `target` of the given `relationship_type`
+  # @param source [Puppet:Pops::Types::PCatalogEntryType] the source end of the relationship (from)
+  # @param target [Puppet:Pops::Types::PCatalogEntryType] the target end of the relationship (to)
+  # @param relationship_type [:relationship, :subscription] the type of the relationship
+  #
+  def add_relationship(source, target, relationship_type, scope)
+    # The 3x way is to record a Puppet::Parser::Relationship that is evaluated at the end of the compilation.
+    # This means it is not possible to detect any duplicates at this point (and signal where an attempt is made to
+    # add a duplicate. There is also no location information to signal the original place in the logic. The user will have
+    # to go fish.
+    # The 3.x implementation is based on Strings :-o, so the source and target must be transformed. The resolution is
+    # done by Catalog#resource(type, title). To do that, it creates a Puppet::Resource since it is responsible for
+    # translating the name/type/title and create index-keys used by the catalog. The Puppet::Resource has bizarre parsing of
+    # the type and title (scan for [] that is interpreted as type/title (but it gets it wrong).
+    # Moreover if the type is "" or "component", the type is Class, and if the type is :main, it is :main, all other cases
+    # undergo capitalization of name-segments (foo::bar becomes Foo::Bar). (This was earlier done in the reverse by the parser).
+    # Further, the title undergoes the same munging !!!
+    #
+    # That bug infested nest of messy logic needs serious Exorcism!
+    #
+    # Unfortunately it is not easy to simply call more intelligent methods at a lower level as the compiler evaluates the recorded
+    # Relationship object at a much later point, and it is responsible for invoking all the messy logic.
+    #
+    # TODO: Revisit the below logic when there is a sane implementation of the catalog, compiler and resource. For now
+    # concentrate on transforming the type references to what is expected by the wacky logic.
+    #
+    # HOWEVER, the Compiler only records the Relationships, and the only method it calls is @relationships.each{|x| x.evaluate(catalog) }
+    # Which means a smarter Relationship class could do this right. Instead of obtaining the resource from the catalog using
+    # the borked resource(type, title) which creates a resource for the purpose of looking it up, it needs to instead
+    # scan the catalog's resources
+    #
+    # GAAAH, it is even worse!
+    # It starts in the parser, which parses "File['foo']" into an AST::ResourceReference with type = File, and title = foo
+    # This AST is evaluated by looking up the type/title in the scope - causing it to be loaded if it exists, and if not, the given
+    # type name/title is used. It does not search for resource instances, only classes and types. It returns symbolic information
+    # [type, [title, title]]. From this, instances of Puppet::Resource are created and returned. These only have type/title information
+    # filled out. One or an array of resources are returned.
+    # This set of evaluated (empty reference) Resource instances are then passed to the relationship operator. It creates a
+    # Puppet::Parser::Relationship giving it a source and a target that are (empty reference) Resource instances. These are then remembered
+    # until the relationship is evaluated by the compiler (at the end). When evaluation takes place, the (empty reference) Resource instances
+    # are converted to String (!?! WTF) on the simple format "#{type}[#{title}]", and the catalog is told to find a resource, by giving
+    # it this string. If it cannot find the resource it fails, else the before/notify parameter is appended with the target.
+    # The search for the resource begin with (you guessed it) again creating an (empty reference) resource from type and title (WTF?!?!).
+    # The catalog now uses the reference resource to compute a key [r.type, r.title.to_s] and also gets a uniqueness key from the
+    # resource (This is only a reference type created from title and type). If it cannot find it with the first key, it uses the
+    # uniqueness key to lookup.
+    #
+    # This is probably done to allow a resource type to munge/translate the title in some way (but it is quite unclear from the long
+    # and convoluted path of evaluation.
+    # In order to do this in a way that is similar to 3.x two resources are created to be used as keys.
+    #
+    # And if that is not enough, a source/target may be a Collector (a baked query that will be evaluated by the
+    # compiler - it is simply passed through here for processing by the compiler at the right time).
+    #
+    if source.is_a?(Puppet::Parser::Collector) || source.is_a?(Puppet::Pops::Evaluator::Collectors::AbstractCollector)
+      # use verbatim - behavior defined by 3x
+      source_resource = source
+    else
+      # transform into the wonderful String representation in 3x
+      type, title = Puppet::Pops::Evaluator::Runtime3Converter.instance.catalog_type_to_split_type_title(source)
+      source_resource = Puppet::Resource.new(type, title)
+    end
+    if target.is_a?(Puppet::Parser::Collector) || target.is_a?(Puppet::Pops::Evaluator::Collectors::AbstractCollector)
+      # use verbatim - behavior defined by 3x
+      target_resource = target
+    else
+      # transform into the wonderful String representation in 3x
+      type, title = Puppet::Pops::Evaluator::Runtime3Converter.instance.catalog_type_to_split_type_title(target)
+      target_resource = Puppet::Resource.new(type, title)
+    end
+    # Add the relationship to the compiler for later evaluation.
+    scope.compiler.add_relationship(Puppet::Parser::Relationship.new(source_resource, target_resource, relationship_type))
+  end
+
+  # Coerce value `v` to numeric or fails.
+  # The given value `v` is coerced to Numeric, and if that fails the operation
+  # calls {#fail}.
+  # @param v [Object] the value to convert
+  # @param o [Object] originating instruction
+  # @param scope [Object] the (runtime specific) scope where evaluation of o takes place
+  # @return [Numeric] value `v` converted to Numeric.
+  #
+  def coerce_numeric(v, o, scope)
+    unless n = Puppet::Pops::Utils.to_n(v)
+      fail(Puppet::Pops::Issues::NOT_NUMERIC, o, {:value => v})
+    end
+    n
+  end
+
+  # Provides the ability to call a 3.x or 4.x function from the perspective of a 3.x function or ERB template.
+  # The arguments to the function must be an Array containing values compliant with the 4.x calling convention.
+  # If the targeted function is a 3.x function, the values will be transformed.
+  # @param name [String] the name of the function (without the 'function_' prefix used by scope)
+  # @param args [Array] arguments, may be empty
+  # @param scope [Object] the (runtime specific) scope where evaluation takes place
+  # @raise ArgumentError 'unknown function' if the function does not exist
+  #
+  def external_call_function(name, args, scope, &block)
+    # Call via 4x API if the function exists there
+    loaders = scope.compiler.loaders
+    # Since this is a call from non puppet code, it is not possible to relate it to a module loader
+    # It is known where the call originates by using the scope associated module - but this is the calling scope
+    # and it does not defined the visibility of functions from a ruby function's perspective. Instead,
+    # this is done from the perspective of the environment.
+    loader = loaders.private_environment_loader
+    if loader && func = loader.load(:function, name)
+      return func.call(scope, *args, &block)
+    end
+
+    # Call via 3x API if function exists there
+    raise ArgumentError, "Unknown function '#{name}'" unless Puppet::Parser::Functions.function(name)
+
+    # Arguments must be mapped since functions are unaware of the new and magical creatures in 4x.
+    # NOTE: Passing an empty string last converts nil/:undef to empty string
+    mapped_args = Puppet::Pops::Evaluator::Runtime3Converter.map_args(args, scope, '')
+    result = scope.send("function_#{name}", mapped_args, &block)
+    # Prevent non r-value functions from leaking their result (they are not written to care about this)
+    Puppet::Parser::Functions.rvalue?(name) ? result : nil
+  end
+
+  def call_function(name, args, o, scope, &block)
+    # Call via 4x API if the function exists there
+    loaders = scope.compiler.loaders
+    # find the loader that loaded the code, or use the private_environment_loader (sees env + all modules)
+    adapter = Puppet::Pops::Utils.find_adapter(o, Puppet::Pops::Adapters::LoaderAdapter)
+    loader = adapter.nil? ? loaders.private_environment_loader : adapter.loader
+    if loader && func = loader.load(:function, name)
+      return func.call(scope, *args, &block)
+    end
+
+    # Call via 3x API if function exists there
+    fail(Puppet::Pops::Issues::UNKNOWN_FUNCTION, o, {:name => name}) unless Puppet::Parser::Functions.function(name)
+
+    # Arguments must be mapped since functions are unaware of the new and magical creatures in 4x.
+    # NOTE: Passing an empty string last converts nil/:undef to empty string
+    mapped_args = Puppet::Pops::Evaluator::Runtime3Converter.map_args(args, scope, '')
+    result = scope.send("function_#{name}", mapped_args, &block)
+    # Prevent non r-value functions from leaking their result (they are not written to care about this)
+    Puppet::Parser::Functions.rvalue?(name) ? result : nil
+  end
+
+  # The o is used for source reference
+  def create_resource_parameter(o, scope, name, value, operator)
+    file, line = extract_file_line(o)
+    Puppet::Parser::Resource::Param.new(
+      :name   => name,
+      :value  => convert(value, scope, nil), # converted to 3x since 4x supports additional objects / types
+      :source => scope.source, :line => line, :file => file,
+      :add    => operator == :'+>'
+    )
+  end
+
+  def convert(value, scope, undef_value)
+    Puppet::Pops::Evaluator::Runtime3Converter.convert(value, scope, undef_value)
+  end
+
+  CLASS_STRING = 'class'.freeze
+
+  def create_resources(o, scope, virtual, exported, type_name, resource_titles, evaluated_parameters)
+
+    # TODO: Unknown resource causes creation of Resource to fail with ArgumentError, should give
+    # a proper Issue. Now the result is "Error while evaluating a Resource Statement" with the message
+    # from the raised exception. (It may be good enough).
+
+    # resolve in scope.
+    fully_qualified_type, resource_titles = scope.resolve_type_and_titles(type_name, resource_titles)
+
+    # Not 100% accurate as this is the resource expression location and each title is processed separately
+    # The titles are however the result of evaluation and they have no location at this point (an array
+    # of positions for the source expressions are required for this to work).
+    # TODO: Revisit and possible improve the accuracy.
+    #
+    file, line = extract_file_line(o)
+    # Build a resource for each title
+    resource_titles.map do |resource_title|
+        resource = Puppet::Parser::Resource.new(
+          fully_qualified_type, resource_title,
+          :parameters => evaluated_parameters,
+          :file => file,
+          :line => line,
+          :exported => exported,
+          :virtual => virtual,
+          # WTF is this? Which source is this? The file? The name of the context ?
+          :source => scope.source,
+          :scope => scope,
+          :strict => true
+        )
+
+        if resource.resource_type.is_a? Puppet::Resource::Type
+          resource.resource_type.instantiate_resource(scope, resource)
+        end
+        scope.compiler.add_resource(scope, resource)
+        scope.compiler.evaluate_classes([resource_title], scope, false, true) if fully_qualified_type == CLASS_STRING
+        # Turn the resource into a PType (a reference to a resource type)
+        # weed out nil's
+        resource_to_ptype(resource)
+    end
+  end
+
+  # Defines default parameters for a type with the given name.
+  #
+  def create_resource_defaults(o, scope, type_name, evaluated_parameters)
+    # Note that name must be capitalized in this 3x call
+    # The 3x impl creates a Resource instance with a bogus title and then asks the created resource
+    # for the type of the name.
+    # Note, locations are available per parameter.
+    #
+    scope.define_settings(capitalize_qualified_name(type_name), evaluated_parameters.flatten)
+  end
+
+  # Capitalizes each segment of a qualified name
+  #
+  def capitalize_qualified_name(name)
+    name.split(/::/).map(&:capitalize).join(NAME_SPACE_SEPARATOR)
+  end
+
+  # Creates resource overrides for all resource type objects in evaluated_resources. The same set of
+  # evaluated parameters are applied to all.
+  #
+  def create_resource_overrides(o, scope, evaluated_resources, evaluated_parameters)
+    # Not 100% accurate as this is the resource expression location and each title is processed separately
+    # The titles are however the result of evaluation and they have no location at this point (an array
+    # of positions for the source expressions are required for this to work.
+    # TODO: Revisit and possible improve the accuracy.
+    #
+    file, line = extract_file_line(o)
+    # A *=> results in an array of arrays
+    evaluated_parameters = evaluated_parameters.flatten
+    evaluated_resources.each do |r|
+      unless r.is_a?(Puppet::Pops::Types::PResourceType) && r.type_name != 'class'
+        fail(Puppet::Pops::Issues::ILLEGAL_OVERRIDEN_TYPE, o, {:actual => r} )
+      end
+      resource = Puppet::Parser::Resource.new(
+      r.type_name, r.title,
+        :parameters => evaluated_parameters,
+        :file => file,
+        :line => line,
+        # WTF is this? Which source is this? The file? The name of the context ?
+        :source => scope.source,
+        :scope => scope
+      )
+
+      scope.compiler.add_override(resource)
+    end
+  end
+
+  # Finds a resource given a type and a title.
+  #
+  def find_resource(scope, type_name, title)
+    scope.compiler.findresource(type_name, title)
+  end
+
+  # Returns the value of a resource's parameter by first looking up the parameter in the resource
+  # and then in the defaults for the resource. Since the resource exists (it must in order to look up its
+  # parameters, any overrides have already been applied). Defaults are not applied to a resource until it
+  # has been finished (which typically has not taken place when this is evaluated; hence the dual lookup).
+  #
+  def get_resource_parameter_value(scope, resource, parameter_name)
+    # This gets the parameter value, or nil (for both valid parameters and parameters that do not exist).
+    val = resource[parameter_name]
+
+    # Sometimes the resource is a Puppet::Parser::Resource and sometimes it is
+    # a Puppet::Resource. The Puppet::Resource case occurs when puppet language
+    # is evaluated against an already completed catalog (where all instances of
+    # Puppet::Parser::Resource are converted to Puppet::Resource instances).
+    # Evaluating against an already completed catalog is really only found in
+    # the language specification tests, where the puppet language is used to
+    # test itself.
+    if resource.is_a?(Puppet::Parser::Resource)
+      # The defaults must be looked up in the scope where the resource was created (not in the given
+      # scope where the lookup takes place.
+      resource_scope = resource.scope
+      if val.nil? && resource_scope && defaults = resource_scope.lookupdefaults(resource.type)
+        # NOTE: 3x resource keeps defaults as hash using symbol for name as key to Parameter which (again) holds
+        # name and value.
+        # NOTE: meta parameters that are unset ends up here, and there are no defaults for those encoded
+        # in the defaults, they may receive hardcoded defaults later (e.g. 'tag').
+        param = defaults[parameter_name.to_sym]
+        # Some parameters (meta parameters like 'tag') does not return a param from which the value can be obtained
+        # at all times. Instead, they return a nil param until a value has been set.
+        val = param.nil? ? nil : param.value
+      end
+    end
+    val
+  end
+
+  # Returns true, if the given name is the name of a resource parameter.
+  #
+  def is_parameter_of_resource?(scope, resource, name)
+    return false unless name.is_a?(String)
+    resource.valid_parameter?(name)
+  end
+
+  def resource_to_ptype(resource)
+    nil if resource.nil?
+    # inference returns the meta type since the 3x Resource is an alternate way to describe a type
+    type_calculator.infer(resource).type
+  end
+
+  # This is the same type of "truth" as used in the current Puppet DSL.
+  #
+  def is_true?(value, o)
+    # Is the value true?  This allows us to control the definition of truth
+    # in one place.
+    case value
+    # Support :undef since it may come from a 3x structure
+    when :undef
+      false
+    when String
+      @migration_checker.report_empty_string_true(value, o)
+      true
+    else
+      !!value
+    end
+  end
+
+  # Utility method for TrueClass || FalseClass
+  # @param x [Object] the object to test if it is instance of TrueClass or FalseClass
+  def is_boolean? x
+    x.is_a?(TrueClass) || x.is_a?(FalseClass)
+  end
+
+  def extract_file_line(o)
+    source_pos = Puppet::Pops::Utils.find_closest_positioned(o)
+    return [nil, -1] unless source_pos
+    [source_pos.locator.file, source_pos.line]
+  end
+
+  def find_closest_positioned(o)
+    return nil if o.nil? || o.is_a?(Puppet::Pops::Model::Program)
+    o.offset.nil? ? find_closest_positioned(o.eContainer) : Puppet::Pops::Adapters::SourcePosAdapter.adapt(o)
+  end
+
+  # Creates a diagnostic producer
+  def diagnostic_producer
+    Puppet::Pops::Validation::DiagnosticProducer.new(
+      ExceptionRaisingAcceptor.new(),                   # Raises exception on all issues
+      SeverityProducer.new(), # All issues are errors
+      Puppet::Pops::Model::ModelLabelProvider.new())
+  end
+
+  # Configure the severity of failures
+  class SeverityProducer < Puppet::Pops::Validation::SeverityProducer
+    Issues = Puppet::Pops::Issues
+
+    def initialize
+      super
+      p = self
+      # Issues triggering warning only if --debug is on
+      if Puppet[:debug]
+        p[Issues::EMPTY_RESOURCE_SPECIALIZATION] = :warning
+      else
+        p[Issues::EMPTY_RESOURCE_SPECIALIZATION] = :ignore
+      end
+
+      # Store config issues, ignore or warning
+      p[Issues::RT_NO_STORECONFIGS_EXPORT]    = Puppet[:storeconfigs] ? :ignore : :warning
+      p[Issues::RT_NO_STORECONFIGS]           = Puppet[:storeconfigs] ? :ignore : :warning
+    end
+  end
+
+  # An acceptor of diagnostics that immediately raises an exception.
+  class ExceptionRaisingAcceptor < Puppet::Pops::Validation::Acceptor
+    def accept(diagnostic)
+      super
+      Puppet::Pops::IssueReporter.assert_and_report(self, {
+        :message => "Evaluation Error:", 
+        :emit_warnings => true,  # log warnings
+        :exception_class => Puppet::PreformattedError
+      })
+      if errors?
+        raise ArgumentError, "Internal Error: Configuration of runtime error handling wrong: should have raised exception"
+      end
+    end
+  end
+
+  class EvaluationError < StandardError
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/functions/dispatch.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/functions/dispatch.rb
new file mode 100644
index 0000000..8a5eafa
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/functions/dispatch.rb
@@ -0,0 +1,85 @@
+# Defines a connection between a implementation method and the signature that
+# the method will handle.
+#
+# This interface should not be used directly. Instead dispatches should be
+# constructed using the DSL defined in {Puppet::Functions}.
+#
+# @api private
+class Puppet::Pops::Functions::Dispatch < Puppet::Pops::Evaluator::CallableSignature
+  # @api public
+  attr_reader :type
+  # TODO: refactor to parameter_names since that makes it API
+  attr_reader :param_names
+  attr_reader :injections
+
+  # Describes how arguments are woven if there are injections, a regular argument is a given arg index, an array
+  # an injection description.
+  #
+  attr_reader :weaving
+  # @api public
+  attr_reader :block_name
+
+  # @api private
+  def initialize(type, method_name, param_names, block_name, injections, weaving, last_captures)
+    @type = type
+    @method_name = method_name
+    @param_names = param_names || []
+    @block_name = block_name
+    @injections = injections || []
+    @weaving = weaving
+    @last_captures = last_captures
+  end
+
+  # @api private
+  def parameter_names
+    @param_names
+  end
+
+  # @api private
+  def last_captures_rest?
+    !! @last_captures
+  end
+
+  # @api private
+  def invoke(instance, calling_scope, args, &block)
+    instance.send(@method_name, *weave(calling_scope, args), &block)
+  end
+
+  # @api private
+  def weave(scope, args)
+    # no need to weave if there are no injections
+    if @injections.empty?
+      args
+    else
+      injector = nil # lazy lookup of injector Puppet.lookup(:injector)
+      new_args = []
+      @weaving.each do |knit|
+        if knit.is_a?(Array)
+          injection_data = @injections[knit[0]]
+          new_args <<
+            case injection_data[3]
+            when :dispatcher_internal
+              # currently only supports :scope injection
+              scope
+            when :producer
+              injector ||= Puppet.lookup(:injector)
+              injector.lookup_producer(scope, injection_data[0], injection_data[2])
+            else
+              injector ||= Puppet.lookup(:injector)
+              injector.lookup(scope, injection_data[0], injection_data[2])
+            end
+        else
+          # Careful so no new nil arguments are added since they would override default
+          # parameter values in the received
+          if knit < 0
+            idx = -knit - 1
+            new_args += args[idx..-1] if idx < args.size
+          else
+            new_args << args[knit] if knit < args.size
+          end
+        end
+      end
+      new_args
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/functions/dispatcher.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/functions/dispatcher.rb
new file mode 100644
index 0000000..45ea403
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/functions/dispatcher.rb
@@ -0,0 +1,70 @@
+# Evaluate the dispatches defined as {Puppet::Pops::Functions::Dispatch}
+# instances to call the appropriate method on the
+# {Puppet::Pops::Functions::Function} instance.
+#
+# @api private
+class Puppet::Pops::Functions::Dispatcher
+  attr_reader :dispatchers
+
+  # @api private
+  def initialize()
+    @dispatchers = [ ]
+  end
+
+  # Answers if dispatching has been defined
+  # @return [Boolean] true if dispatching has been defined
+  #
+  # @api private
+  def empty?
+    @dispatchers.empty?
+  end
+
+  # Dispatches the call to the first found signature (entry with matching type).
+  #
+  # @param instance [Puppet::Functions::Function] - the function to call
+  # @param calling_scope [T.B.D::Scope] - the scope of the caller
+  # @param args [Array<Object>] - the given arguments in the form of an Array
+  # @return [Object] - what the called function produced
+  #
+  # @api private
+  def dispatch(instance, calling_scope, args, &block)
+    tc = Puppet::Pops::Types::TypeCalculator
+    actual = tc.infer_set(block_given? ? args + [block] : args)
+    found = @dispatchers.find { |d| tc.callable?(d.type, actual) }
+    if found
+      found.invoke(instance, calling_scope, args, &block)
+    else
+      raise ArgumentError, "function '#{instance.class.name}' called with mis-matched arguments\n#{Puppet::Pops::Evaluator::CallableMismatchDescriber.diff_string(instance.class.name, actual, @dispatchers)}"
+    end
+  end
+
+  # Adds a regular dispatch for one method name
+  #
+  # @param type [Puppet::Pops::Types::PArrayType, Puppet::Pops::Types::PTupleType] - type describing signature
+  # @param method_name [String] - the name of the method that will be called when type matches given arguments
+  # @param names [Array<String>] - array with names matching the number of parameters specified by type (or empty array)
+  #
+  # @api private
+  def add_dispatch(type, method_name, param_names, block_name, injections, weaving, last_captures)
+    @dispatchers << Puppet::Pops::Functions::Dispatch.new(type, method_name, param_names, block_name, injections, weaving, last_captures)
+  end
+
+  # Produces a CallableType for a single signature, and a Variant[<callables>] otherwise
+  #
+  # @api private
+  def to_type()
+    # make a copy to make sure it can be contained by someone else (even if it is not contained here, it
+    # should be treated as immutable).
+    #
+    callables = dispatchers.map { | dispatch | dispatch.type.copy }
+
+    # multiple signatures, produce a Variant type of Callable1-n (must copy them)
+    # single signature, produce single Callable
+    callables.size > 1 ?  Puppet::Pops::Types::TypeFactory.variant(*callables) : callables.pop
+  end
+
+  # @api private
+  def signatures
+    @dispatchers
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/functions/function.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/functions/function.rb
new file mode 100644
index 0000000..b16d43a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/functions/function.rb
@@ -0,0 +1,109 @@
+# @note WARNING: This new function API is still under development and may change at
+#   any time
+#
+# A function in the puppet evaluator.
+#
+# Functions are normally defined by another system, which produces subclasses
+# of this class as well as constructing delegations to call the appropriate methods.
+#
+# This class should rarely be used directly. Instead functions should be
+# constructed using {Puppet::Functions.create_function}.
+#
+# @api public
+class Puppet::Pops::Functions::Function
+  # The scope where the function was defined
+  attr_reader :closure_scope
+
+  # The loader that loaded this function.
+  # Should be used if function wants to load other things.
+  #
+  attr_reader :loader
+
+  def initialize(closure_scope, loader)
+    @closure_scope = closure_scope
+    @loader = loader
+  end
+
+  # Invokes the function via the dispatching logic that performs type check and weaving.
+  # A specialized function may override this method to do its own dispatching and checking of
+  # the raw arguments. A specialized implementation can rearrange arguments, add or remove
+  # arguments and then delegate to the dispatching logic by calling:
+  #
+  # @example Delegating to the dispatcher
+  #     def call(scope, *args)
+  #       manipulated_args = args + ['easter_egg']
+  #       self.class.dispatcher.dispatch(self, scope, manipulated_args)
+  #     end
+  #
+  # System functions that must have access to the calling scope can use this technique. Functions
+  # in general should not need the calling scope. (The closure scope; what is visible where the function
+  # is defined) is available via the method `closure_scope`).
+  #
+  # @api public
+  def call(scope, *args, &block)
+    self.class.dispatcher.dispatch(self, scope, args, &block)
+  end
+
+  # Allows the implementation of a function to call other functions by name. The callable functions
+  # are those visible to the same loader that loaded this function (the calling function). The
+  # referenced function is called with the calling functions closure scope as the caller's scope.
+  #
+  # @param function_name [String] The name of the function
+  # @param *args [Object] splat of arguments
+  # @return [Object] The result returned by the called function
+  #
+  # @api public
+  def call_function(function_name, *args, &block)
+    internal_call_function(closure_scope, function_name, args, &block)
+  end
+
+  # The dispatcher for the function
+  #
+  # @api private
+  def self.dispatcher
+    @dispatcher ||= Puppet::Pops::Functions::Dispatcher.new
+  end
+
+  # Produces information about parameters in a way that is compatible with Closure
+  #
+  # @api private
+  def self.signatures
+    @dispatcher.signatures
+  end
+
+  protected
+
+  # Allows the implementation of a function to call other functions by name and pass the caller
+  # scope. The callable functions are those visible to the same loader that loaded this function
+  # (the calling function).
+  #
+  # @param scope [Puppet::Parser::Scope] The caller scope
+  # @param function_name [String] The name of the function
+  # @param args [Array] array of arguments
+  # @return [Object] The result returned by the called function
+  #
+  # @api public
+  def internal_call_function(scope, function_name, args, &block)
+
+    the_loader = loader
+    raise ArgumentError, "Function #{self.class.name}(): cannot call function '#{function_name}' - no loader specified" unless the_loader
+
+    func = the_loader.load(:function, function_name)
+    return func.call(scope, *args, &block) if func
+
+    # Check if a 3x function is present. Raise a generic error if it's not to allow upper layers to fill in the details
+    # about where in a puppet manifest this error originates. (Such information is not available here).
+    loader_scope = closure_scope
+    func_3x = Puppet::Parser::Functions.function(function_name, loader_scope.environment) if loader_scope.is_a?(Puppet::Parser::Scope)
+    raise ArgumentError, "Function #{self.class.name}(): cannot call function '#{function_name}' - not found" unless func_3x
+
+    # Call via 3x API
+    # Arguments must be mapped since functions are unaware of the new and magical creatures in 4x.
+    # NOTE: Passing an empty string last converts nil/:undef to empty string
+    result = scope.send(func_3x, Puppet::Pops::Evaluator::Runtime3Converter.map_args(args, loader_scope, ''), &block)
+
+    # Prevent non r-value functions from leaking their result (they are not written to care about this)
+    Puppet::Parser::Functions.rvalue?(function_name) ? result : nil
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/issue_reporter.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/issue_reporter.rb
new file mode 100644
index 0000000..895160d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/issue_reporter.rb
@@ -0,0 +1,113 @@
+class Puppet::Pops::IssueReporter
+
+  # @param acceptor [Puppet::Pops::Validation::Acceptor] the acceptor containing reported issues
+  # @option options [String] :message (nil) A message text to use as prefix in
+  #   a single Error message
+  # @option options [Boolean] :emit_warnings (false) whether warnings should be emitted
+  # @option options [Boolean] :emit_errors (true) whether errors should be
+  #   emitted or only the given message
+  # @option options [Exception] :exception_class (Puppet::ParseError) The exception to raise
+  #
+  def self.assert_and_report(acceptor, options)
+    return unless acceptor
+
+    max_errors       = options[:max_errors]   || Puppet[:max_errors]
+    max_warnings     = options[:max_warnings] || Puppet[:max_warnings]
+    max_deprecations = options[:max_deprecations] || (Puppet[:disable_warnings].include?('deprecations') ? 0 : Puppet[:max_deprecations])
+
+    emit_warnings    = options[:emit_warnings] || false
+    emit_errors      = options[:emit_errors].nil? ? true : !!options[:emit_errors]
+    emit_message     = options[:message]
+    emit_exception   = options[:exception_class] || Puppet::ParseErrorWithIssue
+
+    # If there are warnings output them
+    warnings = acceptor.warnings
+    if emit_warnings && warnings.size > 0
+      formatter = Puppet::Pops::Validation::DiagnosticFormatterPuppetStyle.new
+      emitted_w = 0
+      emitted_dw = 0
+      acceptor.warnings.each do |w|
+        if w.severity == :deprecation
+          # Do *not* call Puppet.deprecation_warning it is for internal deprecation, not
+          # deprecation of constructs in manifests! (It is not designed for that purpose even if
+          # used throughout the code base).
+          #
+          log_message(:warning, formatter, w) if emitted_dw < max_deprecations
+          emitted_dw += 1
+        else
+          log_message(:warning, formatter, w) if emitted_w < max_warnings
+          emitted_w += 1
+        end
+        break if emitted_w >= max_warnings && emitted_dw >= max_deprecations # but only then
+      end
+    end
+
+    # If there were errors, report the first found. Use a puppet style formatter.
+    errors = acceptor.errors
+    if errors.size > 0
+      unless emit_errors
+        raise emit_exception.new(emit_message)
+      end
+      formatter = Puppet::Pops::Validation::DiagnosticFormatterPuppetStyle.new
+      if errors.size == 1 || max_errors <= 1
+        # raise immediately
+        exception = create_exception(emit_exception, emit_message, formatter, errors[0])
+        # if an exception was given as cause, use it's backtrace instead of the one indicating "here"
+        if errors[0].exception
+          exception.set_backtrace(errors[0].exception.backtrace)
+        end
+        raise exception
+      end
+      emitted = 0
+      if emit_message
+        Puppet.err(emit_message)
+      end
+      errors.each do |e|
+        log_message(:err, formatter, e)
+        emitted += 1
+        break if emitted >= max_errors
+      end
+      warnings_message = (emit_warnings && warnings.size > 0) ? ", and #{warnings.size} warnings" : ""
+      giving_up_message = "Found #{errors.size} errors#{warnings_message}. Giving up"
+      exception = emit_exception.new(giving_up_message)
+      exception.file = errors[0].file
+      raise exception
+    end
+  end
+
+  def self.format_with_prefix(prefix, message)
+    return message unless prefix
+    [prefix, message].join(' ')
+  end
+
+  def self.create_exception(exception_class, emit_message, formatter, diagnostic)
+    file = diagnostic.file
+    file = (file.is_a?(String) && file.empty?) ? nil : file
+    line = pos = nil
+    if diagnostic.source_pos
+      line = diagnostic.source_pos.line
+      pos = diagnostic.source_pos.pos
+    end
+    exception_class.new(format_with_prefix(emit_message, formatter.format_message(diagnostic)), file, line, pos, nil, diagnostic.issue.issue_code)
+  end
+  private_class_method :create_exception
+
+  def self.log_message(severity, formatter, diagnostic)
+    file = diagnostic.file
+    file = (file.is_a?(String) && file.empty?) ? nil : file
+    line = pos = nil
+    if diagnostic.source_pos
+      line = diagnostic.source_pos.line
+      pos = diagnostic.source_pos.pos
+    end
+    Puppet::Util::Log.create({
+        :level => severity,
+        :message => formatter.format_message(diagnostic),
+        :issue_code => diagnostic.issue.issue_code,
+        :file => file,
+        :line => line,
+        :pos => pos,
+      })
+  end
+  private_class_method :log_message
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/issues.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/issues.rb
new file mode 100644
index 0000000..e3a4058
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/issues.rb
@@ -0,0 +1,656 @@
+# Defines classes to deal with issues, and message formatting and defines constants with Issues.
+# @api public
+#
+module Puppet::Pops::Issues
+  # Describes an issue, and can produce a message for an occurrence of the issue.
+  #
+  class Issue
+    # The issue code
+    # @return [Symbol]
+    attr_reader :issue_code
+
+    # A block producing the message
+    # @return [Proc]
+    attr_reader :message_block
+
+    # Names that must be bound in an occurrence of the issue to be able to produce a message.
+    # These are the names in addition to requirements stipulated by the Issue formatter contract; i.e. :label`,
+    # and `:semantic`.
+    #
+    attr_reader :arg_names
+
+    # If this issue can have its severity lowered to :warning, :deprecation, or :ignored
+    attr_writer :demotable
+    # Configures the Issue with required arguments (bound by occurrence), and a block producing a message.
+    def initialize issue_code, *args, &block
+      @issue_code = issue_code
+      @message_block = block
+      @arg_names = args
+      @demotable = true
+    end
+
+    # Returns true if it is allowed to demote this issue
+    def demotable?
+      @demotable
+    end
+
+    # Formats a message for an occurrence of the issue with argument bindings passed in a hash.
+    # The hash must contain a LabelProvider bound to the key `label` and the semantic model element
+    # bound to the key `semantic`. All required arguments as specified by `arg_names` must be bound
+    # in the given `hash`.
+    # @api public
+    #
+    def format(hash ={})
+      # Create a Message Data where all hash keys become methods for convenient interpolation
+      # in issue text.
+      msgdata = MessageData.new(*arg_names)
+      begin
+        # Evaluate the message block in the msg data's binding
+        msgdata.format(hash, &message_block)
+      rescue StandardError => e
+        Puppet::Pops::Issues::MessageData
+        raise RuntimeError, "Error while reporting issue: #{issue_code}. #{e.message}", caller
+      end
+    end
+  end
+
+  # Provides a binding of arguments passed to Issue.format to method names available
+  # in the issue's message producing block.
+  # @api private
+  #
+  class MessageData
+    def initialize *argnames
+      singleton = class << self; self end
+      argnames.each do |name|
+        singleton.send(:define_method, name) do
+          @data[name]
+        end
+      end
+    end
+
+    def format(hash, &block)
+      @data = hash
+      instance_eval &block
+    end
+
+    # Returns the label provider given as a key in the hash passed to #format.
+    # If given an argument, calls #label on the label provider (caller would otherwise have to
+    # call label.label(it)
+    #
+    def label(it = nil)
+      raise "Label provider key :label must be set to produce the text of the message!" unless @data[:label]
+      it.nil? ? @data[:label] : @data[:label].label(it)
+    end
+
+    # Returns the label provider given as a key in the hash passed to #format.
+    #
+    def semantic
+      raise "Label provider key :semantic must be set to produce the text of the message!" unless @data[:semantic]
+      @data[:semantic]
+    end
+  end
+
+  # Defines an issue with the given `issue_code`, additional required parameters, and a block producing a message.
+  # The block is evaluated in the context of a MessageData which provides convenient access to all required arguments
+  # via accessor methods. In addition to accessors for specified arguments, these are also available:
+  # * `label` - a `LabelProvider` that provides human understandable names for model elements and production of article (a/an/the).
+  # * `semantic` - the model element for which the issue is reported
+  #
+  # @param issue_code [Symbol] the issue code for the issue used as an identifier, should be the same as the constant
+  #   the issue is bound to.
+  # @param args [Symbol] required arguments that must be passed when formatting the message, may be empty
+  # @param block [Proc] a block producing the message string, evaluated in a MessageData scope. The produced string
+  #   should not end with a period as additional information may be appended.
+  #
+  # @see MessageData
+  # @api public
+  #
+  def self.issue (issue_code, *args, &block)
+    Issue.new(issue_code, *args, &block)
+  end
+
+  # Creates a non demotable issue.
+  # @see Issue.issue
+  #
+  def self.hard_issue(issue_code, *args, &block)
+    result = Issue.new(issue_code, *args, &block)
+    result.demotable = false
+    result
+  end
+
+  # @comment Here follows definitions of issues. The intent is to provide a list from which yardoc can be generated
+  #   containing more detailed information / explanation of the issue.
+  #   These issues are set as constants, but it is unfortunately not possible for the created object to easily know which
+  #   name it is bound to. Instead the constant has to be repeated. (Alternatively, it could be done by instead calling
+  #   #const_set on the module, but the extra work required to get yardoc output vs. the extra effort to repeat the name
+  #   twice makes it not worth it (if doable at all, since there is no tag to artificially construct a constant, and
+  #   the parse tag does not produce any result for a constant assignment).
+
+  # This is allowed (3.1) and has not yet been deprecated.
+  # @todo configuration
+  #
+  NAME_WITH_HYPHEN = issue :NAME_WITH_HYPHEN, :name do
+    "#{label.a_an_uc(semantic)} may not have a name containing a hyphen. The name '#{name}' is not legal"
+  end
+
+  # When a variable name contains a hyphen and these are illegal.
+  # It is possible to control if a hyphen is legal in a name or not using the setting TODO
+  # @todo describe the setting
+  # @api public
+  # @todo configuration if this is error or warning
+  #
+  VAR_WITH_HYPHEN = issue :VAR_WITH_HYPHEN, :name do
+    "A variable name may not contain a hyphen. The name '#{name}' is not legal"
+  end
+
+  # A class, definition, or node may only appear at top level or inside other classes
+  # @todo Is this really true for nodes? Can they be inside classes? Isn't that too late?
+  # @api public
+  #
+  NOT_TOP_LEVEL = hard_issue :NOT_TOP_LEVEL do
+    "Classes, definitions, and nodes may only appear at toplevel or inside other classes"
+  end
+
+  CROSS_SCOPE_ASSIGNMENT = hard_issue :CROSS_SCOPE_ASSIGNMENT, :name do
+    "Illegal attempt to assign to '#{name}'. Cannot assign to variables in other namespaces"
+  end
+
+  # Assignment can only be made to certain types of left hand expressions such as variables.
+  ILLEGAL_ASSIGNMENT = hard_issue :ILLEGAL_ASSIGNMENT do
+    "Illegal attempt to assign to '#{label.a_an(semantic)}'. Not an assignable reference"
+  end
+
+  # Variables are immutable, cannot reassign in the same assignment scope
+  ILLEGAL_REASSIGNMENT = hard_issue :ILLEGAL_REASSIGNMENT, :name do
+    "Cannot reassign variable #{name}"
+  end
+
+  ILLEGAL_RESERVED_ASSIGNMENT = hard_issue :ILLEGAL_RESERVED_ASSIGNMENT, :name do
+    "Attempt to assign to a reserved variable name: '#{name}'"
+  end
+
+  # Assignment cannot be made to numeric match result variables
+  ILLEGAL_NUMERIC_ASSIGNMENT = issue :ILLEGAL_NUMERIC_ASSIGNMENT, :varname do
+    "Illegal attempt to assign to the numeric match result variable '$#{varname}'. Numeric variables are not assignable"
+  end
+
+  # parameters cannot have numeric names, clashes with match result variables
+  ILLEGAL_NUMERIC_PARAMETER = issue :ILLEGAL_NUMERIC_PARAMETER, :name do
+    "The numeric parameter name '$#{name}' cannot be used (clashes with numeric match result variables)"
+  end
+
+  # In certain versions of Puppet it may be allowed to assign to a not already assigned key
+  # in an array or a hash. This is an optional validation that may be turned on to prevent accidental
+  # mutation.
+  #
+  ILLEGAL_INDEXED_ASSIGNMENT = issue :ILLEGAL_INDEXED_ASSIGNMENT do
+    "Illegal attempt to assign via [index/key]. Not an assignable reference"
+  end
+
+  # When indexed assignment ($x[]=) is allowed, the leftmost expression must be
+  # a variable expression.
+  #
+  ILLEGAL_ASSIGNMENT_VIA_INDEX = hard_issue :ILLEGAL_ASSIGNMENT_VIA_INDEX do
+    "Illegal attempt to assign to #{label.a_an(semantic)} via [index/key]. Not an assignable reference"
+  end
+
+  APPENDS_DELETES_NO_LONGER_SUPPORTED = hard_issue :APPENDS_DELETES_NO_LONGER_SUPPORTED, :operator do
+    "The operator '#{operator}' is no longer supported. See http://links.puppetlabs.com/remove-plus-equals"
+  end
+
+  # For unsupported operators (e.g. += and -= in puppet 4).
+  #
+  UNSUPPORTED_OPERATOR = hard_issue :UNSUPPORTED_OPERATOR, :operator do
+    "The operator '#{operator}' is not supported."
+  end
+
+  # For operators that are not supported in specific contexts (e.g. '* =>' in
+  # resource defaults)
+  #
+  UNSUPPORTED_OPERATOR_IN_CONTEXT = hard_issue :UNSUPPORTED_OPERATOR_IN_CONTEXT, :operator do
+    "The operator '#{operator}' in #{label.a_an(semantic)} is not supported."
+  end
+
+  # For non applicable operators (e.g. << on Hash).
+  #
+  OPERATOR_NOT_APPLICABLE = hard_issue :OPERATOR_NOT_APPLICABLE, :operator, :left_value do
+    "Operator '#{operator}' is not applicable to #{label.a_an(left_value)}."
+  end
+
+  COMPARISON_NOT_POSSIBLE = hard_issue :COMPARISON_NOT_POSSIBLE, :operator, :left_value, :right_value, :detail do
+    "Comparison of: #{label(left_value)} #{operator} #{label(right_value)}, is not possible. Caused by '#{detail}'."
+  end
+
+  MATCH_NOT_REGEXP = hard_issue :MATCH_NOT_REGEXP, :detail do
+    "Can not convert right match operand to a regular expression. Caused by '#{detail}'."
+  end
+
+  MATCH_NOT_STRING = hard_issue :MATCH_NOT_STRING, :left_value do
+    "Left match operand must result in a String value. Got #{label.a_an(left_value)}."
+  end
+
+  # Some expressions/statements may not produce a value (known as right-value, or rvalue).
+  # This may vary between puppet versions.
+  #
+  NOT_RVALUE = issue :NOT_RVALUE do
+    "Invalid use of expression. #{label.a_an_uc(semantic)} does not produce a value"
+  end
+
+  # Appending to attributes is only allowed in certain types of resource expressions.
+  #
+  ILLEGAL_ATTRIBUTE_APPEND = hard_issue :ILLEGAL_ATTRIBUTE_APPEND, :name, :parent do
+    "Illegal +> operation on attribute #{name}. This operator can not be used in #{label.a_an(parent)}"
+  end
+
+  ILLEGAL_NAME = hard_issue :ILLEGAL_NAME, :name do
+    "Illegal name. The given name '#{name}' does not conform to the naming rule /^((::)?[a-z_]\w*)(::[a-z]\\w*)*$/"
+  end
+
+  ILLEGAL_PARAM_NAME = hard_issue :ILLEGAL_PARAM_NAME, :name do
+    "Illegal parameter name. The given name '#{name}' does not conform to the naming rule /^[a-z_]\\w*$/"
+  end
+
+  ILLEGAL_VAR_NAME = hard_issue :ILLEGAL_VAR_NAME, :name do
+    "Illegal variable name, The given name '#{name}' does not conform to the naming rule /^((::)?[a-z]\\w*)*((::)?[a-z_]\\w*)$/"
+  end
+
+  ILLEGAL_NUMERIC_VAR_NAME = hard_issue :ILLEGAL_NUMERIC_VAR_NAME, :name do
+    "Illegal numeric variable name, The given name '#{name}' must be a decimal value if it starts with a digit 0-9"
+  end
+
+  # In case a model is constructed programmatically, it must create valid type references.
+  #
+  ILLEGAL_CLASSREF = hard_issue :ILLEGAL_CLASSREF, :name do
+    "Illegal type reference. The given name '#{name}' does not conform to the naming rule"
+  end
+
+  # This is a runtime issue - storeconfigs must be on in order to collect exported. This issue should be
+  # set to :ignore when just checking syntax.
+  # @todo should be a :warning by default
+  #
+  RT_NO_STORECONFIGS = issue :RT_NO_STORECONFIGS do
+    "You cannot collect exported resources without storeconfigs being set; the collection will be ignored"
+  end
+
+  # This is a runtime issue - storeconfigs must be on in order to export a resource. This issue should be
+  # set to :ignore when just checking syntax.
+  # @todo should be a :warning by default
+  #
+  RT_NO_STORECONFIGS_EXPORT = issue :RT_NO_STORECONFIGS_EXPORT do
+    "You cannot collect exported resources without storeconfigs being set; the export is ignored"
+  end
+
+  # A hostname may only contain letters, digits, '_', '-', and '.'.
+  #
+  ILLEGAL_HOSTNAME_CHARS = hard_issue :ILLEGAL_HOSTNAME_CHARS, :hostname do
+    "The hostname '#{hostname}' contains illegal characters (only letters, digits, '_', '-', and '.' are allowed)"
+  end
+
+  # A hostname may only contain letters, digits, '_', '-', and '.'.
+  #
+  ILLEGAL_HOSTNAME_INTERPOLATION = hard_issue :ILLEGAL_HOSTNAME_INTERPOLATION do
+    "An interpolated expression is not allowed in a hostname of a node"
+  end
+
+  # Issues when an expression is used where it is not legal.
+  # E.g. an arithmetic expression where a hostname is expected.
+  #
+  ILLEGAL_EXPRESSION = hard_issue :ILLEGAL_EXPRESSION, :feature, :container do
+    "Illegal expression. #{label.a_an_uc(semantic)} is unacceptable as #{feature} in #{label.a_an(container)}"
+  end
+
+  # Issues when a variable is not a NAME
+  #
+  ILLEGAL_VARIABLE_EXPRESSION = hard_issue :ILLEGAL_VARIABLE_EXPRESSION do
+    "Illegal variable expression. #{label.a_an_uc(semantic)} did not produce a variable name (String or Numeric)."
+  end
+
+  # Issues when an expression is used illegaly in a query.
+  # query only supports == and !=, and not <, > etc.
+  #
+  ILLEGAL_QUERY_EXPRESSION = hard_issue :ILLEGAL_QUERY_EXPRESSION do
+    "Illegal query expression. #{label.a_an_uc(semantic)} cannot be used in a query"
+  end
+
+  # If an attempt is made to make a resource default virtual or exported.
+  #
+  NOT_VIRTUALIZEABLE = hard_issue :NOT_VIRTUALIZEABLE do
+    "Resource Defaults are not virtualizable"
+  end
+
+  # When an attempt is made to use multiple keys (to produce a range in Ruby - e.g. $arr[2,-1]).
+  # This is not supported in 3x, but it allowed in 4x.
+  #
+  UNSUPPORTED_RANGE = issue :UNSUPPORTED_RANGE, :count do
+    "Attempt to use unsupported range in #{label.a_an(semantic)}, #{count} values given for max 1"
+  end
+
+  ILLEGAL_RELATIONSHIP_OPERAND_TYPE = issue :ILLEGAL_RELATIONSHIP_OPERAND_TYPE, :operand do
+    "Illegal relationship operand, can not form a relationship with #{label.a_an(operand)}. A Catalog type is required."
+  end
+
+  NOT_CATALOG_TYPE = issue :NOT_CATALOG_TYPE, :type do
+    "Illegal relationship operand, can not form a relationship with something of type #{type}. A Catalog type is required."
+  end
+
+  BAD_STRING_SLICE_ARITY = issue :BAD_STRING_SLICE_ARITY, :actual do
+    "String supports [] with one or two arguments. Got #{actual}"
+  end
+
+  BAD_STRING_SLICE_TYPE = issue :BAD_STRING_SLICE_TYPE, :actual do
+    "String-Type [] requires all arguments to be integers (or default). Got #{actual}"
+  end
+
+  BAD_ARRAY_SLICE_ARITY = issue :BAD_ARRAY_SLICE_ARITY, :actual do
+    "Array supports [] with one or two arguments. Got #{actual}"
+  end
+
+  BAD_HASH_SLICE_ARITY = issue :BAD_HASH_SLICE_ARITY, :actual do
+    "Hash supports [] with one or more arguments. Got #{actual}"
+  end
+
+  BAD_INTEGER_SLICE_ARITY = issue :BAD_INTEGER_SLICE_ARITY, :actual do
+    "Integer-Type supports [] with one or two arguments (from, to). Got #{actual}"
+  end
+
+  BAD_INTEGER_SLICE_TYPE = issue :BAD_INTEGER_SLICE_TYPE, :actual do
+    "Integer-Type [] requires all arguments to be integers (or default). Got #{actual}"
+  end
+
+  BAD_COLLECTION_SLICE_TYPE = issue :BAD_COLLECTION_SLICE_TYPE, :actual do
+    "A Type's size constraint arguments must be a single Integer type, or 1-2 integers (or default). Got #{label.a_an(actual)}"
+  end
+
+  BAD_FLOAT_SLICE_ARITY = issue :BAD_INTEGER_SLICE_ARITY, :actual do
+    "Float-Type supports [] with one or two arguments (from, to). Got #{actual}"
+  end
+
+  BAD_FLOAT_SLICE_TYPE = issue :BAD_INTEGER_SLICE_TYPE, :actual do
+    "Float-Type [] requires all arguments to be floats, or integers (or default). Got #{actual}"
+  end
+
+  BAD_SLICE_KEY_TYPE = issue :BAD_SLICE_KEY_TYPE, :left_value, :expected_classes, :actual do
+    expected_text = if expected_classes.size > 1
+      "one of #{expected_classes.join(', ')} are"
+    else
+      "#{expected_classes[0]} is"
+    end
+    "#{label.a_an_uc(left_value)}[] cannot use #{actual} where #{expected_text} expected"
+  end
+
+  BAD_NOT_UNDEF_SLICE_TYPE = issue :BAD_NOT_UNDEF_SLICE_TYPE, :base_type, :actual do
+    "#{base_type}[] argument must be a Type or a String. Got #{actual}"
+  end
+
+  BAD_TYPE_SLICE_TYPE = issue :BAD_TYPE_SLICE_TYPE, :base_type, :actual do
+    "#{base_type}[] arguments must be types. Got #{actual}"
+  end
+
+  BAD_TYPE_SLICE_ARITY = issue :BAD_TYPE_SLICE_ARITY, :base_type, :min, :max, :actual do
+    base_type_label = base_type.is_a?(String) ? base_type : label.a_an_uc(base_type)
+    if max == -1 || max == 1.0 / 0.0 # Infinity
+      "#{base_type_label}[] accepts #{min} or more arguments. Got #{actual}"
+    elsif max && max != min
+      "#{base_type_label}[] accepts #{min} to #{max} arguments. Got #{actual}"
+    else
+      "#{base_type_label}[] accepts #{min} #{label.plural_s(min, 'argument')}. Got #{actual}"
+    end
+  end
+
+  BAD_TYPE_SPECIALIZATION = hard_issue :BAD_TYPE_SPECIALIZATION, :type, :message do
+    "Error creating type specialization of #{label.a_an(type)}, #{message}"
+  end
+
+  ILLEGAL_TYPE_SPECIALIZATION = issue :ILLEGAL_TYPE_SPECIALIZATION, :kind do
+    "Cannot specialize an already specialized #{kind} type"
+  end
+
+  ILLEGAL_RESOURCE_SPECIALIZATION = issue :ILLEGAL_RESOURCE_SPECIALIZATION, :actual do
+    "First argument to Resource[] must be a resource type or a String. Got #{actual}."
+  end
+
+  EMPTY_RESOURCE_SPECIALIZATION = issue :EMPTY_RESOURCE_SPECIALIZATION do
+    "Arguments to Resource[] are all empty/undefined"
+  end
+
+  ILLEGAL_HOSTCLASS_NAME = hard_issue :ILLEGAL_HOSTCLASS_NAME, :name do
+    "Illegal Class name in class reference. #{label.a_an_uc(name)} cannot be used where a String is expected"
+  end
+
+  ILLEGAL_DEFINITION_NAME = hard_issue :ILLEGAL_DEFINTION_NAME, :name do
+    "Unacceptable name. The name '#{name}' is unacceptable as the name of #{label.a_an(semantic)}"
+  end
+
+  CAPTURES_REST_NOT_LAST = hard_issue :CAPTURES_REST_NOT_LAST, :param_name do
+    "Parameter $#{param_name} is not last, and has 'captures rest'"
+  end
+
+  CAPTURES_REST_NOT_SUPPORTED = hard_issue :CAPTURES_REST_NOT_SUPPORTED, :container, :param_name do
+    "Parameter $#{param_name} has 'captures rest' - not supported in #{label.a_an(container)}"
+  end
+
+  REQUIRED_PARAMETER_AFTER_OPTIONAL = hard_issue :REQUIRED_PARAMETER_AFTER_OPTIONAL, :param_name do
+    "Parameter $#{param_name} is required but appears after optional parameters"
+  end
+
+  MISSING_REQUIRED_PARAMETER = hard_issue :MISSING_REQUIRED_PARAMETER, :param_name do
+    "Parameter $#{param_name} is required but no value was given"
+  end
+
+  NOT_NUMERIC = issue :NOT_NUMERIC, :value do
+    "The value '#{value}' cannot be converted to Numeric."
+  end
+
+  UNKNOWN_FUNCTION = issue :UNKNOWN_FUNCTION, :name do
+    "Unknown function: '#{name}'."
+  end
+
+  UNKNOWN_VARIABLE = issue :UNKNOWN_VARIABLE, :name do
+    "Unknown variable: '#{name}'."
+  end
+
+  RUNTIME_ERROR = issue :RUNTIME_ERROR, :detail do
+    "Error while evaluating #{label.a_an(semantic)}, #{detail}"
+  end
+
+  UNKNOWN_RESOURCE_TYPE = issue :UNKNOWN_RESOURCE_TYPE, :type_name do
+    "Resource type not found: #{type_name.capitalize}"
+  end
+
+  ILLEGAL_RESOURCE_TYPE = hard_issue :ILLEGAL_RESOURCE_TYPE, :actual do
+    "Illegal Resource Type expression, expected result to be a type name, or untitled Resource, got #{actual}"
+  end
+
+  DUPLICATE_TITLE = issue :DUPLICATE_TITLE, :title  do
+    "The title '#{title}' has already been used in this resource expression"
+  end
+
+  DUPLICATE_ATTRIBUTE = issue :DUPLICATE_ATTRIBUE, :attribute  do
+    "The attribute '#{attribute}' has already been set in this resource body"
+  end
+
+  MISSING_TITLE = hard_issue :MISSING_TITLE do
+    "Missing title. The title expression resulted in undef"
+  end
+
+  MISSING_TITLE_AT = hard_issue :MISSING_TITLE_AT, :index do
+    "Missing title at index #{index}. The title expression resulted in an undef title"
+  end
+
+  ILLEGAL_TITLE_TYPE_AT = hard_issue :ILLEGAL_TITLE_TYPE_AT, :index, :actual do
+    "Illegal title type at index #{index}. Expected String, got #{actual}"
+  end
+
+  EMPTY_STRING_TITLE_AT = hard_issue :EMPTY_STRING_TITLE_AT, :index do
+    "Empty string title at #{index}. Title strings must have a length greater than zero."
+  end
+
+  UNKNOWN_RESOURCE = issue :UNKNOWN_RESOURCE, :type_name, :title do
+    "Resource not found: #{type_name.capitalize}['#{title}']"
+  end
+
+  UNKNOWN_RESOURCE_PARAMETER = issue :UNKNOWN_RESOURCE_PARAMETER, :type_name, :title, :param_name do
+    "The resource #{type_name.capitalize}['#{title}'] does not have a parameter called '#{param_name}'"
+  end
+
+  DIV_BY_ZERO = hard_issue :DIV_BY_ZERO do
+    "Division by 0"
+  end
+
+  RESULT_IS_INFINITY = hard_issue :RESULT_IS_INFINITY, :operator do
+    "The result of the #{operator} expression is Infinity"
+  end
+
+  # TODO_HEREDOC
+  EMPTY_HEREDOC_SYNTAX_SEGMENT = issue :EMPTY_HEREDOC_SYNTAX_SEGMENT, :syntax do
+    "Heredoc syntax specification has empty segment between '+' : '#{syntax}'"
+  end
+
+  ILLEGAL_EPP_PARAMETERS = issue :ILLEGAL_EPP_PARAMETERS do
+    "Ambiguous EPP parameter expression. Probably missing '<%-' before parameters to remove leading whitespace"
+  end
+
+  DISCONTINUED_IMPORT = hard_issue :DISCONTINUED_IMPORT do
+    "Use of 'import' has been discontinued in favor of a manifest directory. See http://links.puppetlabs.com/puppet-import-deprecation"
+  end
+
+  IDEM_EXPRESSION_NOT_LAST = issue :IDEM_EXPRESSION_NOT_LAST do
+    "This #{label.label(semantic)} has no effect. A value-producing expression without other effect may only be placed last in a block/sequence"
+  end
+
+  IDEM_NOT_ALLOWED_LAST = hard_issue :IDEM_NOT_ALLOWED_LAST, :container do
+    "This #{label.label(semantic)} has no effect. #{label.a_an_uc(container)} can not end with a value-producing expression without other effect"
+  end
+
+  RESERVED_WORD = hard_issue :RESERVED_WORD, :word do
+    "Use of reserved word: #{word}, must be quoted if intended to be a String value"
+  end
+
+  FUTURE_RESERVED_WORD = issue :FUTURE_RESERVED_WORD, :word do
+    "Use of future reserved word: '#{word}'"
+  end
+
+  RESERVED_TYPE_NAME = hard_issue :RESERVED_TYPE_NAME, :name do
+    "The name: '#{name}' is already defined by Puppet and can not be used as the name of #{label.a_an(semantic)}."
+  end
+
+  UNMATCHED_SELECTOR = hard_issue :UNMATCHED_SELECTOR, :param_value do
+    "No matching entry for selector parameter with value '#{param_value}'"
+  end
+
+  ILLEGAL_NODE_INHERITANCE = issue :ILLEGAL_NODE_INHERITANCE do
+    "Node inheritance is not supported in Puppet >= 4.0.0. See http://links.puppetlabs.com/puppet-node-inheritance-deprecation"
+  end
+
+  ILLEGAL_OVERRIDEN_TYPE = issue :ILLEGAL_OVERRIDEN_TYPE, :actual do
+    "Resource Override can only operate on resources, got: #{label.label(actual)}"
+  end
+
+  DUPLICATE_PARAMETER = hard_issue :DUPLICATE_PARAMETER, :param_name do
+    "The parameter '#{param_name}' is declared more than once in the parameter list"
+  end
+
+  RESERVED_PARAMETER = hard_issue :RESERVED_PARAMETER, :container, :param_name do
+    "The parameter $#{param_name} redefines a built in parameter in #{label.the(container)}"
+  end
+
+  TYPE_MISMATCH = hard_issue :TYPE_MISMATCH, :expected, :actual do
+    "Expected value of type #{expected}, got #{actual}"
+  end
+
+  MULTIPLE_ATTRIBUTES_UNFOLD = hard_issue :MULTIPLE_ATTRIBUTES_UNFOLD do
+    "Unfolding of attributes from Hash can only be used once per resource body"
+  end
+
+  SYNTAX_ERROR = hard_issue :SYNTAX_ERROR, :where do
+    "Syntax error at #{where}"
+  end
+
+  ILLEGAL_CLASS_REFERENCE = hard_issue :ILLEGAL_CLASS_REFERENCE do
+    'Illegal class reference'
+  end
+
+  ILLEGAL_FULLY_QUALIFIED_CLASS_REFERENCE = hard_issue :ILLEGAL_FULLY_QUALIFIED_CLASS_REFERENCE do
+    'Illegal fully qualified class reference'
+  end
+
+  ILLEGAL_FULLY_QUALIFIED_NAME = hard_issue :ILLEGAL_FULLY_QUALIFIED_NAME do
+    'Illegal fully qualified name'
+  end
+
+  ILLEGAL_NAME_OR_BARE_WORD = hard_issue :ILLEGAL_NAME_OR_BARE_WORD do
+    'Illegal name or bare word'
+  end
+
+  ILLEGAL_NUMBER = hard_issue :ILLEGAL_NUMBER do
+    'Illegal number'
+  end
+
+  ILLEGAL_UNICODE_ESCAPE = issue :ILLEGAL_UNICODE_ESCAPE do
+    "Unicode escape '\\u' was not followed by 4 hex digits or 1-6 hex digits in {} or was > 10ffff"
+  end
+
+  INVALID_HEX_NUMBER = hard_issue :INVALID_HEX_NUMBER, :value do
+    "Not a valid hex number #{value}"
+  end
+
+  INVALID_OCTAL_NUMBER = hard_issue :INVALID_OCTAL_NUMBER, :value do
+    "Not a valid octal number #{value}"
+  end
+
+  INVALID_DECIMAL_NUMBER = hard_issue :INVALID_DECIMAL_NUMBER, :value do
+    "Not a valid decimal number #{value}"
+  end
+
+  NO_INPUT_TO_LEXER = hard_issue :NO_INPUT_TO_LEXER do
+    "Internal Error: No string or file given to lexer to process."
+  end
+
+  UNRECOGNIZED_ESCAPE = issue :UNRECOGNIZED_ESCAPE, :ch do
+    "Unrecognized escape sequence '\\#{ch}'"
+  end
+
+  UNCLOSED_QUOTE = hard_issue :UNCLOSED_QUOTE, :after, :followed_by do
+    "Unclosed quote after #{after} followed by '#{followed_by}'"
+  end
+
+  EPP_INTERNAL_ERROR = hard_issue :EPP_INTERNAL_ERROR, :error do
+    "Internal error: #{error}"
+  end
+
+  EPP_UNBALANCED_TAG = hard_issue :EPP_UNBALANCED_TAG do
+    'Unbalanced epp tag, reached <eof> without closing tag.'
+  end
+
+  EPP_UNBALANCED_COMMENT = hard_issue :EPP_UNBALANCED_COMMENT do
+    'Reaching end after opening <%# without seeing %>'
+  end
+
+  EPP_UNBALANCED_EXPRESSION = hard_issue :EPP_UNBALANCED_EXPRESSION do
+    'Unbalanced embedded expression - opening <% and reaching end of input'
+  end
+
+  HEREDOC_UNCLOSED_PARENTHESIS = hard_issue :HEREDOC_UNCLOSED_PARENTHESIS, :followed_by do
+    "Unclosed parenthesis after '@(' followed by '#{followed_by}'"
+  end
+
+  HEREDOC_WITHOUT_END_TAGGED_LINE = hard_issue :HEREDOC_WITHOUT_END_TAGGED_LINE do
+    'Heredoc without end-tagged line'
+  end
+
+  HEREDOC_INVALID_ESCAPE = hard_issue :HEREDOC_INVALID_ESCAPE, :actual do
+    "Invalid heredoc escape char. Only t, r, n, s,  u, L, $ allowed. Got '#{actual}'"
+  end
+
+  HEREDOC_INVALID_SYNTAX = hard_issue :HEREDOC_INVALID_SYNTAX do
+    'Invalid syntax in heredoc expected @(endtag[:syntax][/escapes])'
+  end
+
+  HEREDOC_WITHOUT_TEXT = hard_issue :HEREDOC_WITHOUT_TEXT do
+    'Heredoc without any following lines of text'
+  end
+
+  HEREDOC_MULTIPLE_AT_ESCAPES = hard_issue :HEREDOC_MULTIPLE_AT_ESCAPES, :escapes do
+    "An escape char for @() may only appear once. Got '#{escapes.join(', ')}'"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/label_provider.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/label_provider.rb
new file mode 100644
index 0000000..3581c61
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/label_provider.rb
@@ -0,0 +1,76 @@
+# Provides a label for an object.
+# This simple implementation calls #to_s on the given object, and handles articles 'a/an/the'.
+#
+class Puppet::Pops::LabelProvider
+  VOWELS = %w{a e i o u y}
+  SKIPPED_CHARACTERS = %w{" '}
+  A = "a"
+  AN = "an"
+
+  # Provides a label for the given object by calling `to_s` on the object.
+  # The intent is for this method to be overridden in concrete label providers.
+  def label o
+    o.to_s
+  end
+
+  # Produces a label for the given text with indefinite article (a/an)
+  def a_an o
+    text = label(o)
+    "#{article(text)} #{text}"
+  end
+
+  # Produces a label for the given text with indefinite article (A/An)
+  def a_an_uc o
+    text = label(o)
+    "#{article(text).capitalize} #{text}"
+  end
+
+  # Produces a label for the given text with *definitie article* (the).
+  def the o
+    "the #{label(o)}"
+  end
+
+  # Produces a label for the given text with *definitie article* (The).
+  def the_uc o
+    "The #{label(o)}"
+  end
+
+  # Appends 's' to (optional) text if count != 1 else an empty string
+  def plural_s(count, text = '')
+    count == 1 ? text : "#{text}s"
+  end
+
+  private
+
+  # Produces an *indefinite article* (a/an) for the given text ('a' if
+  # it starts with a vowel) This is obviously flawed in the general
+  # sense as may labels have punctuation at the start and this method
+  # does not translate punctuation to English words. Also, if a vowel is
+  # pronounced as a consonant, the article should not be "an".
+  #
+  def article s
+    article_for_letter(first_letter_of(s))
+  end
+
+  def first_letter_of(string)
+    char = string[0,1]
+    if SKIPPED_CHARACTERS.include? char
+      char = string[1,1]
+    end
+
+    if char == ""
+      raise Puppet::DevError, "<#{string}> does not appear to contain a word"
+    end
+
+    char
+  end
+
+  def article_for_letter(letter)
+    downcased = letter.downcase
+    if VOWELS.include? downcased
+      AN
+    else
+      A
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/base_loader.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/base_loader.rb
new file mode 100644
index 0000000..cd91686
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/base_loader.rb
@@ -0,0 +1,102 @@
+# BaseLoader
+# ===
+# An abstract implementation of Puppet::Pops::Loader::Loader
+#
+# A derived class should implement `find(typed_name)` and set entries, and possible handle "miss caching".
+#
+# @api private
+#
+class Puppet::Pops::Loader::BaseLoader < Puppet::Pops::Loader::Loader
+
+  # The parent loader
+  attr_reader :parent
+
+  # An internal name used for debugging and error message purposes
+  attr_reader :loader_name
+
+  def initialize(parent_loader, loader_name)
+    @parent = parent_loader # the higher priority loader to consult
+    @named_values = {}      # hash name => NamedEntry
+    @last_name = nil        # the last name asked for (optimization)
+    @last_result = nil      # the value of the last name (optimization)
+    @loader_name = loader_name # the name of the loader (not the name-space it is a loader for)
+  end
+
+  # @api public
+  #
+  def load_typed(typed_name)
+    # The check for "last queried name" is an optimization when a module searches. First it checks up its parent
+    # chain, then itself, and then delegates to modules it depends on.
+    # These modules are typically parented by the same
+    # loader as the one initiating the search. It is inefficient to again try to search the same loader for
+    # the same name.
+    if typed_name == @last_name
+      @last_result
+    else
+      @last_name = typed_name
+      @last_result = internal_load(typed_name)
+    end
+  end
+
+  # This method is final (subclasses should not override it)
+  #
+  # @api private
+  #
+  def get_entry(typed_name)
+    @named_values[typed_name]
+  end
+
+  # @api private
+  #
+  def set_entry(typed_name, value, origin = nil)
+    if entry = @named_values[typed_name] then fail_redefined(entry); end
+    @named_values[typed_name] = Puppet::Pops::Loader::Loader::NamedEntry.new(typed_name, value, origin)
+  end
+
+  # @api private
+  #
+  def add_entry(type, name, value, origin)
+    set_entry(Puppet::Pops::Loader::Loader::TypedName.new(type, name), value, origin)
+  end
+
+  # Promotes an already created entry (typically from another loader) to this loader
+  #
+  # @api private
+  #
+  def promote_entry(named_entry)
+    typed_name = named_entry.typed_name
+    if entry = @named_values[typed_name] then fail_redefine(entry); end
+    @named_values[typed_name] = named_entry
+  end
+
+  private
+
+  def fail_redefine(entry)
+    origin_info = entry.origin ? " Originally set at #{origin_label(entry.origin)}." : "unknown location"
+    raise ArgumentError, "Attempt to redefine entity '#{entry.typed_name}' originally set at #{origin_info}"
+  end
+
+  # TODO: Should not really be here?? - TODO: A Label provider ? semantics for the URI?
+  #
+  def origin_label(origin)
+    if origin && origin.is_a?(URI)
+      origin.to_s
+    elsif origin.respond_to?(:uri)
+      origin.uri.to_s
+    else
+      origin
+    end
+  end
+
+  # loads in priority order:
+  # 1. already loaded here
+  # 2. load from parent
+  # 3. find it here
+  # 4. give up
+  #
+  def internal_load(typed_name)
+    # avoid calling get_entry, by looking it up
+    @named_values[typed_name] || parent.load_typed(typed_name) || find(typed_name)
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/dependency_loader.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/dependency_loader.rb
new file mode 100644
index 0000000..dbeda41
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/dependency_loader.rb
@@ -0,0 +1,60 @@
+# =DependencyLoader
+# This loader provides visibility into a set of other loaders. It is used as a child of a ModuleLoader (or other
+# loader) to make its direct dependencies visible for loading from contexts that have access to this dependency loader.
+# Access is typically given to logic that resides inside of the module, but not to those that just depend on the module.
+#
+# It is instantiated with a name, and with a set of dependency_loaders.
+#
+# @api private
+#
+class Puppet::Pops::Loader::DependencyLoader < Puppet::Pops::Loader::BaseLoader
+
+  # An index of module_name to module loader used to speed up lookup of qualified names
+  attr_reader :index
+
+  # Creates a DependencyLoader for one parent loader
+  #
+  # @param parent_loader [Puppet::Pops::Loader] typically a module loader for the root
+  # @param name [String] the name of the dependency-loader (used for debugging and tracing only)
+  # @param dependency_loaders [Array<Puppet::Pops::Loader>] array of loaders for modules this module depends on
+  #
+  def initialize(parent_loader, name, dependency_loaders)
+    super parent_loader, name
+    @dependency_loaders = dependency_loaders
+  end
+
+  # Finds name in a loader this loader depends on / can see
+  #
+  def find(typed_name)
+    if typed_name.qualified
+      if loader = index()[typed_name.name_parts[0]]
+        loader.load_typed(typed_name)
+      else
+        # no module entered as dependency with name matching first segment of wanted name
+        nil
+      end
+    else
+      # a non name-spaced name, have to search since it can be anywhere.
+      # (Note: superclass caches the result in this loader as it would have to repeat this search for every
+      # lookup otherwise).
+      loaded = @dependency_loaders.reduce(nil) do |previous, loader|
+        break previous if !previous.nil?
+        loader.load_typed(typed_name)
+      end
+      if loaded
+        promote_entry(loaded)
+      end
+      loaded
+    end
+  end
+
+  def to_s()
+    "(DependencyLoader '#{@loader_name}' [" + @dependency_loaders.map {|loader| loader.to_s }.join(' ,') + "])"
+  end
+
+  private
+
+  def index()
+    @index ||= @dependency_loaders.reduce({}) { |index, loader| index[loader.module_name] = loader; index }
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/gem_support.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/gem_support.rb
new file mode 100644
index 0000000..bf58244
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/gem_support.rb
@@ -0,0 +1,49 @@
+# GemSupport offers methods to find a gem's location by name or gem://gemname URI.
+#
+# TODO: The Puppet 3x, uses Puppet::Util::RubyGems to do this, and obtain paths, and avoids using ::Gems
+# when ::Bundler is in effect. A quick check what happens on Ruby 1.8.7 and Ruby 1.9.3 with current
+# version of bundler seems to work just fine without jumping through any hoops. Hopefully the Puppet::Utils::RubyGems is
+# just dealing with arcane things prior to RubyGems 1.8 that are not needed any more. To verify there is
+# the need to set up a scenario where additional bundles than what Bundler allows for a given configuration are available
+# and then trying to access those.
+#
+module Puppet::Pops::Loader::GemSupport
+
+  # Produces the root directory of a gem given as an URI (gem://gemname/optional/path), or just the
+  # gemname as a string.
+  #
+  def gem_dir(uri_or_string)
+    case uri_or_string
+    when URI
+      gem_dir_from_uri(uri_or_string)
+    when String
+      gem_dir_from_name(uri_or_string)
+    end
+  end
+
+  # Produces the root directory of a gem given as an uri, where hostname is the gemname, and an optional
+  # path is appended to the root of the gem (i.e. if the reference is given to a sub-location within a gem.
+  # TODO: FIND by name raises exception Gem::LoadError with list of all gems on the path
+  #
+  def gem_dir_from_uri(uri)
+    unless spec = Gem::Specification.find_by_name(uri.hostname)
+      raise ArgumentError, "Gem not found #{uri}"
+    end
+    # if path given append that, else append given subdir
+    if uri.path.empty?
+      spec.gem_dir
+    else
+      File.join(spec.full_gem_path, uri.path)
+    end
+  end
+
+  # Produces the root directory of a gem given as a string with the gem's name.
+  # TODO: FIND by name raises exception Gem::LoadError with list of all gems on the path
+  #
+  def gem_dir_from_name(gem_name)
+    unless spec = Gem::Specification.find_by_name(gem_name)
+      raise ArgumentError, "Gem not found '#{gem_name}'"
+    end
+    spec.full_gem_path
+  end
+end
\ No newline at end of file
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/loader.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/loader.rb
new file mode 100644
index 0000000..37c912c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/loader.rb
@@ -0,0 +1,180 @@
+# Loader
+# ===
+# A Loader is responsible for loading "entities" ("instantiable and executable objects in the puppet language" which
+# are type, hostclass, definition, function, and bindings.
+#
+# The main method for users of a Loader is the `load` or `load_typed methods`, which returns a previously loaded entity
+# of a given type/name, and searches and loads the entity if not already loaded.
+#
+# private entities
+# ---
+# TODO: handle loading of entities that are private. Suggest that all calls pass an origin_loader (the loader
+# where request originated (or symbol :public). A module loader has one (or possibly a list) of what is
+# considered to represent private loader - i.e. the dependency loader for a module. If an entity is private
+# it should be stored with this status, and an error should be raised if the origin_loader is not on the list
+# of accepted "private" loaders.
+# The private loaders can not be given at creation time (they are parented by the loader in question). Another
+# alternative is to check if the origin_loader is a child loader, but this requires bidirectional links
+# between loaders or a search if loader with private entity is a parent of the origin_loader).
+#
+# @api public
+#
+class Puppet::Pops::Loader::Loader
+
+  # Produces the value associated with the given name if already loaded, or available for loading
+  # by this loader, one of its parents, or other loaders visible to this loader.
+  # This is the method an external party should use to "get" the named element.
+  #
+  # An implementor of this method should first check if the given name is already loaded by self, or a parent
+  # loader, and if so return that result. If not, it should call `find` to perform the loading.
+  #
+  # @param type [:Symbol] the type to load
+  # @param name [String, Symbol]  the name of the entity to load
+  # @return [Object, nil] the value or nil if not found
+  #
+  # @api public
+  #
+  def load(type, name)
+    if result = load_typed(TypedName.new(type, name.to_s))
+      result.value
+    end
+  end
+
+  # Loads the given typed name, and returns a NamedEntry if found, else returns nil.
+  # This the same a `load`, but returns a NamedEntry with origin/value information.
+  #
+  # @param typed_name [TypedName] - the type, name combination to lookup
+  # @return [NamedEntry, nil] the entry containing the loaded value, or nil if not found
+  #
+  # @api public
+  #
+  def load_typed(typed_name)
+    raise NotImplementedError.new
+  end
+
+  # Produces the value associated with the given name if defined **in this loader**, or nil if not defined.
+  # This lookup does not trigger any loading, or search of the given name.
+  # An implementor of this method may not search or look up in any other loader, and it may not
+  # define the name.
+  #
+  # @param typed_name [TypedName] - the type, name combination to lookup
+  #
+  # @api private
+  #
+  def [] (typed_name)
+    if found = get_entry(typed_name)
+      found.value
+    else
+      nil
+    end
+  end
+
+  # Searches for the given name in this loader's context (parents should already have searched their context(s) without
+  # producing a result when this method is called).
+  # An implementation of find typically caches the result.
+  #
+  # @param typed_name [TypedName] the type, name combination to lookup
+  # @return [NamedEntry, nil] the entry for the loaded entry, or nil if not found
+  #
+  # @api private
+  #
+  def find(typed_name)
+    raise NotImplementedError.new
+  end
+
+  # Returns the parent of the loader, or nil, if this is the top most loader. This implementation returns nil.
+  def parent
+    nil
+  end
+
+  # Produces the private loader for loaders that have a one (the visibility given to loaded entities).
+  # For loaders that does not provide a private loader, self is returned.
+  #
+  # @api private
+  def private_loader
+    self
+  end
+
+  # Binds a value to a name. The name should not start with '::', but may contain multiple segments.
+  #
+  # @param type [:Symbol] the type of the entity being set
+  # @param name [String, Symbol] the name of the entity being set
+  # @param origin [URI, #uri, String] the origin of the set entity, a URI, or provider of URI, or URI in string form
+  # @return [NamedEntry, nil] the created entry
+  #
+  # @api private
+  #
+  def set_entry(type, name, value, origin = nil)
+    raise NotImplementedError.new
+  end
+
+  # Produces a NamedEntry if a value is bound to the given name, or nil if nothing is bound.
+  #
+  # @param typed_name [TypedName] the type, name combination to lookup
+  # @return [NamedEntry, nil] the value bound in an entry
+  #
+  # @api private
+  #
+  def get_entry(typed_name)
+    raise NotImplementedError.new
+  end
+
+  # An entry for one entity loaded by the loader.
+  #
+  class NamedEntry
+    attr_reader :typed_name
+    attr_reader :value
+    attr_reader :origin
+
+    def initialize(typed_name, value, origin)
+      @typed_name = typed_name
+      @value = value
+      @origin = origin
+      freeze()
+    end
+  end
+
+  # A name/type combination that can be used as a compound hash key
+  #
+  class TypedName
+    attr_reader :type
+    attr_reader :name
+    attr_reader :name_parts
+
+    # True if name is qualified (more than a single segment)
+    attr_reader :qualified
+
+    def initialize(type, name)
+      @type = type
+      # relativize the name (get rid of leading ::), and make the split string available
+      @name_parts = name.to_s.split(/::/)
+      @name_parts.shift if name_parts[0].empty?
+      @name = name_parts.join('::')
+      @qualified = name_parts.size > 1
+      # precompute hash - the name is frozen, so this is safe to do
+      @hash = [self.class, type, @name].hash
+
+      # Not allowed to have numeric names - 0, 010, 0x10, 1.2 etc
+      if Puppet::Pops::Utils.is_numeric?(@name)
+        raise ArgumentError, "Illegal attempt to use a numeric name '#{name}' at #{origin_label(origin)}."
+      end
+
+      freeze()
+    end
+
+    def hash
+      @hash
+    end
+
+    def ==(o)
+      o.class == self.class && type == o.type && name == o.name
+    end
+
+    alias eql? ==
+
+    def to_s
+      "#{type}/#{name}"
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/loader_paths.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/loader_paths.rb
new file mode 100644
index 0000000..5058879
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/loader_paths.rb
@@ -0,0 +1,118 @@
+
+# LoaderPaths
+# ===
+# The central loader knowledge about paths, what they represent and how to instantiate from them.
+# Contains helpers (*smart paths*) to deal with lazy resolution of paths.
+#
+# TODO: Currently only supports loading of functions (3 kinds)
+#
+module Puppet::Pops::Loader::LoaderPaths
+  # Returns an array of SmartPath, each instantiated with a reference to the given loader (for root path resolution
+  # and existence checks). The smart paths in the array appear in precedence order. The returned array may be
+  # mutated.
+  #
+  def self.relative_paths_for_type(type, loader)
+    result =
+    case type
+    when :function
+        [FunctionPath4x.new(loader)]
+    else
+      # unknown types, simply produce an empty result; no paths to check, nothing to find... move along...
+      []
+    end
+    result
+  end
+
+#  # DO NOT REMOVE YET. needed later? when there is the need to decamel a classname
+#  def de_camel(fq_name)
+#    fq_name.to_s.gsub(/::/, '/').
+#    gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
+#    gsub(/([a-z\d])([A-Z])/,'\1_\2').
+#    tr("-", "_").
+#    downcase
+#  end
+
+  class SmartPath
+    # Generic path, in the sense of "if there are any entities of this kind to load, where are they?"
+    attr_reader :generic_path
+
+    # Creates SmartPath for the given loader (loader knows how to check for existence etc.)
+    def initialize(loader)
+      @loader = loader
+    end
+
+    def generic_path()
+      return @generic_path unless @generic_path.nil?
+
+      root_path = @loader.path
+      @generic_path = (root_path.nil? ? relative_path : File.join(root_path, relative_path))
+    end
+
+    # Effective path is the generic path + the name part(s) + extension.
+    #
+    def effective_path(typed_name, start_index_in_name)
+      "#{File.join(generic_path, typed_name.name_parts)}#{extension}"
+    end
+
+    def relative_path()
+      raise NotImplementedError.new
+    end
+
+    def instantiator()
+      raise NotImplementedError.new
+    end
+  end
+
+  class RubySmartPath < SmartPath
+    def extension
+      ".rb"
+    end
+
+    # Duplication of extension information, but avoids one call
+    def effective_path(typed_name, start_index_in_name)
+      "#{File.join(generic_path, typed_name.name_parts)}.rb"
+    end
+  end
+
+  class FunctionPath4x < RubySmartPath
+    FUNCTION_PATH_4X = File.join('puppet', 'functions')
+
+    def relative_path
+      FUNCTION_PATH_4X
+    end
+
+    def instantiator()
+      Puppet::Pops::Loader::RubyFunctionInstantiator
+    end
+  end
+
+  # SmartPaths
+  # ===
+  # Holds effective SmartPath instances per type
+  #
+  class SmartPaths
+    def initialize(path_based_loader)
+      @loader = path_based_loader
+      @smart_paths = {}
+    end
+
+    # Ensures that the paths for the type have been probed and pruned to what is existing relative to
+    # the given root.
+    #
+    # @param type [Symbol] the entity type to load
+    # @return [Array<SmartPath>] array of effective paths for type (may be empty)
+    #
+    def effective_paths(type)
+      smart_paths = @smart_paths
+      loader = @loader
+      unless effective_paths = smart_paths[type]
+        # type not yet processed, does the various directories for the type exist ?
+        # Get the relative dirs for the type
+        paths_for_type = Puppet::Pops::Loader::LoaderPaths.relative_paths_for_type(type, loader)
+        # Check which directories exist in the loader's content/index
+        effective_paths = smart_paths[type] = paths_for_type.select { |sp| loader.meaningful_to_search?(sp) }
+      end
+      effective_paths
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/module_loaders.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/module_loaders.rb
new file mode 100644
index 0000000..3bfa196
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/module_loaders.rb
@@ -0,0 +1,258 @@
+
+# =ModuleLoaders
+# A ModuleLoader loads items from a single module.
+# The ModuleLoaders (ruby) module contains various such loaders. There is currently one concrete
+# implementation, ModuleLoaders::FileBased that loads content from the file system.
+# Other implementations can be created - if they are based on name to path mapping where the path
+# is relative to a root path, they can derive the base behavior from the ModuleLoaders::AbstractPathBasedModuleLoader class.
+#
+# Examples of such extensions could be a zip/jar/compressed file base loader.
+#
+# Notably, a ModuleLoader does not configure itself - it is given the information it needs (the root, its name etc.)
+# Logic higher up in the loader hierarchy of things makes decisions based on the "shape of modules", and "available
+# modules" to determine which module loader to use for each individual module. (There could be differences in
+# internal layout etc.)
+#
+# A module loader is also not aware of the mapping of name to relative paths - this is performed by the
+# included module Puppet::Pops::Loader::PathBasedInstantatorConfig which knows about the map from type/name to
+# relative path, and the logic that can instantiate what is expected to be found in the content of that path.
+#
+# @api private
+#
+module Puppet::Pops::Loader::ModuleLoaders
+  def self.system_loader_from(parent_loader, loaders)
+    # Puppet system may be installed in a fixed location via RPM, installed as a Gem, via source etc.
+    # The only way to find this across the different ways puppet can be installed is
+    # to search up the path from this source file's __FILE__ location until it finds the base of
+    # puppet.
+    #
+    puppet_lib = File.join(File.dirname(__FILE__), '../../..')
+    Puppet::Pops::Loader::ModuleLoaders::FileBased.new(parent_loader,
+                                                       loaders,
+                                                       nil,
+                                                       puppet_lib,
+                                                       'puppet_system')
+  end
+
+  def self.module_loader_from(parent_loader, loaders, module_name, module_path)
+    Puppet::Pops::Loader::ModuleLoaders::FileBased.new(parent_loader,
+                                                       loaders,
+                                                       module_name,
+                                                       File.join(module_path, 'lib'),
+                                                       module_name)
+  end
+
+  class AbstractPathBasedModuleLoader < Puppet::Pops::Loader::BaseLoader
+
+    # The name of the module, or nil, if this is a global "component"
+    attr_reader :module_name
+
+    # The path to the location of the module/component - semantics determined by subclass
+    attr_reader :path
+
+    # A map of type to smart-paths that help with minimizing the number of paths to scan
+    attr_reader :smart_paths
+
+    # A Module Loader has a private loader, it is lazily obtained on request to provide the visibility
+    # for entities contained in the module. Since a ModuleLoader also represents an environment and it is
+    # created a different way, this loader can be set explicitly by the loaders bootstrap logic.
+    #
+    # @api private
+    attr_accessor :private_loader
+
+    # Initialize a kind of ModuleLoader for one module
+    # @param parent_loader [Puppet::Pops::Loader] loader with higher priority
+    # @param module_name [String] the name of the module (non qualified name), may be nil for a global "component"
+    # @param path [String] the path to the root of the module (semantics defined by subclass)
+    # @param loader_name [String] a name that is used for human identification (useful when module_name is nil)
+    #
+    def initialize(parent_loader, loaders, module_name, path, loader_name)
+      super parent_loader, loader_name
+
+      @module_name = module_name
+      @path = path
+      @smart_paths = Puppet::Pops::Loader::LoaderPaths::SmartPaths.new(self)
+      @loaders = loaders
+    end
+
+    # Finds typed/named entity in this module
+    # @param typed_name [Puppet::Pops::Loader::TypedName] the type/name to find
+    # @return [Puppet::Pops::Loader::Loader::NamedEntry, nil found/created entry, or nil if not found
+    #
+    def find(typed_name)
+      # Assume it is a global name, and that all parts of the name should be used when looking up
+      name_part_index = 0
+      name_parts = typed_name.name_parts
+
+      # Certain types and names can be disqualified up front
+      if name_parts.size > 1
+        # The name is in a name space.
+
+        # Then entity cannot possible be in this module unless the name starts with the module name.
+        # Note: If "module" represents a "global component", the module_name is nil and cannot match which is
+        # ok since such a "module" cannot have namespaced content).
+        #
+        return nil unless name_parts[0] == module_name
+
+        # Skip the first part of the name when computing the path since the path already contains the name of the
+        # module
+        name_part_index = 1
+      else
+        # The name is in the global name space.
+
+        # The only globally name-spaced elements that may be loaded from modules are functions and resource types
+        case typed_name.type
+        when :function
+        when :resource_type
+        else
+          # anything else cannot possibly be in this module
+          # TODO: should not be allowed anyway... may have to revisit this decision
+          return nil
+        end
+      end
+
+      # Get the paths that actually exist in this module (they are lazily processed once and cached).
+      # The result is an array (that may be empty).
+      # Find the file to instantiate, and instantiate the entity if file is found
+      origin = nil
+      if (smart_path = smart_paths.effective_paths(typed_name.type).find do |sp|
+          origin = sp.effective_path(typed_name, name_part_index)
+          existing_path(origin)
+        end)
+        value = smart_path.instantiator.create(self, typed_name, origin, get_contents(origin))
+        # cache the entry and return it
+        set_entry(typed_name, value, origin)
+      else
+        nil
+      end
+    end
+
+    # Abstract method that subclasses override that checks if it is meaningful to search using a generic smart path.
+    # This optimization is performed to not be tricked into searching an empty directory over and over again.
+    # The implementation may perform a deep search for file content other than directories and cache this in
+    # and index. It is guaranteed that a call to meaningful_to_search? takes place before checking any other
+    # path with relative_path_exists?.
+    #
+    # This optimization exists because many modules have been created from a template and they have
+    # empty directories for functions, types, etc. (It is also the place to create a cached index of the content).
+    #
+    # @param smart_path [String] a path relative to the module's root
+    # @return [Boolean] true if there is content in the directory appointed by the relative path
+    #
+    def meaningful_to_search?(smart_path)
+      raise NotImplementedError.new
+    end
+
+    # Abstract method that subclasses override to answer if the given relative path exists, and if so returns that path
+    #
+    # @param resolved_path [String] a path resolved by a smart path against the loader's root (if it has one)
+    # @return [Boolean] true if the file exists
+    #
+    def existing_path(resolved_path)
+      raise NotImplementedError.new
+    end
+
+    # Abstract method that subclasses override to produce the content of the effective path.
+    # It should either succeed and return a String or fail with an exception.
+    #
+    # @param effective_path [String] a path as resolved by a smart path
+    # @return [String] the content of the file
+    #
+    def get_contents(effective_path)
+      raise NotImplementedError.new
+    end
+
+    # Abstract method that subclasses override to produce a source reference String used to identify the
+    # system resource (resource in the URI sense).
+    #
+    # @param relative_path [String] a path relative to the module's root
+    # @return [String] a reference to the source file (in file system, zip file, or elsewhere).
+    #
+    def get_source_ref(relative_path)
+      raise NotImplementedError.new
+    end
+
+    # Produces the private loader for the module. If this module is not already resolved, this will trigger resolution
+    #
+    def private_loader
+      # The system loader has a nil module_name and it does not have a private_loader as there are no functions
+      # that can only by called by puppet runtime - if so, it acts as the privuate loader directly.
+      @private_loader ||= ((module_name.nil? && self) || @loaders.private_loader_for_module(module_name))
+    end
+  end
+
+  # @api private
+  #
+  class FileBased < AbstractPathBasedModuleLoader
+
+    attr_reader :smart_paths
+    attr_reader :path_index
+
+    # Create a kind of ModuleLoader for one module (Puppet Module, or module like)
+    #
+    # @param parent_loader [Puppet::Pops::Loader::Loader] typically the loader for the environment or root
+    # @param module_name [String] the name of the module (non qualified name), may be nil for "modules" only containing globals
+    # @param path [String] the path to the root of the module (semantics defined by subclass)
+    # @param loader_name [String] a name that identifies the loader
+    #
+    def initialize(parent_loader, loaders, module_name, path, loader_name)
+      super
+      @path_index = Set.new()
+    end
+
+    def existing_path(effective_path)
+      # Optimized, checks index instead of visiting file system
+      @path_index.include?(effective_path) ? effective_path : nil
+    end
+
+    def meaningful_to_search?(smart_path)
+      ! add_to_index(smart_path).empty?
+    end
+
+    def to_s()
+      "(ModuleLoader::FileBased '#{loader_name()}' '#{module_name()}')"
+    end
+
+    def add_to_index(smart_path)
+      found = Dir.glob(File.join(smart_path.generic_path, '**', "*#{smart_path.extension}"))
+      @path_index.merge(found)
+      found
+    end
+
+    def get_contents(effective_path)
+      Puppet::FileSystem.read(effective_path)
+    end
+  end
+
+  # Loads from a gem specified as a URI, gem://gemname/optional/path/in/gem, or just a String gemname.
+  # The source reference (shown in errors etc.) is the expanded path of the gem as this is believed to be more
+  # helpful - given the location it should be quite obvious which gem it is, without the location, the user would
+  # need to go on a hunt for where the file actually is located.
+  #
+  # TODO: How does this get instantiated? Does the gemname refelect the name of the module (the namespace)
+  #   or is that specified a different way? Can a gem be the container of multiple modules?
+  #
+  # @api private
+  #
+  class GemBased < FileBased
+    include Puppet::Pops::Loader::GemSupport
+
+    attr_reader :gem_ref
+
+    # Create a kind of ModuleLoader for one module
+    # The parameters are:
+    # * parent_loader - typically the loader for the root
+    # * module_name - the name of the module (non qualified name)
+    # * gem_ref - [URI, String] gem reference to the root of the module (URI, gem://gemname/optional/path/in/gem), or
+    #     just the gem's name as a String.
+    #
+    def initialize(parent_loader, loaders, module_name, gem_ref, loader_name)
+      @gem_ref = gem_ref
+      super parent_loader, loaders, module_name, gem_dir(gem_ref), loader_name
+    end
+
+    def to_s()
+      "(ModuleLoader::GemBased '#{loader_name()}' '#{@gem_ref}' [#{module_name()}])"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/null_loader.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/null_loader.rb
new file mode 100644
index 0000000..22076e3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/null_loader.rb
@@ -0,0 +1,44 @@
+# The null loader is empty and delegates everything to its parent if it has one.
+#
+class Puppet::Pops::Loader::NullLoader < Puppet::Pops::Loader::Loader
+  attr_reader :loader_name
+
+  # Construct a NullLoader, optionally with a parent loader
+  #
+  def initialize(parent_loader=nil, loader_name = "null-loader")
+    @loader_name = loader_name
+    @parent = parent_loader
+  end
+
+  # Has parent if one was set when constructed
+  def parent
+    @parent
+  end
+
+  def load_typed(typed_name)
+    if @parent.nil?
+      nil
+    else
+      @parent.load_typed(typed_name)
+    end
+  end
+
+  # Has no entries on its own - always nil
+  def get_entry(typed_name)
+    nil
+  end
+
+  # Finds nothing, there are no entries
+  def find(name)
+    nil
+  end
+
+  # Cannot store anything
+  def set_entry(typed_name, value, origin = nil)
+    nil
+  end
+
+  def to_s()
+    "(NullLoader '#{loader_name}')"
+  end
+end
\ No newline at end of file
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/ruby_function_instantiator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/ruby_function_instantiator.rb
new file mode 100644
index 0000000..de372ab
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/ruby_function_instantiator.rb
@@ -0,0 +1,34 @@
+# The RubyFunctionInstantiator instantiates a Puppet::Functions::Function given the ruby source
+# that calls Puppet::Functions.create_function.
+#
+class Puppet::Pops::Loader::RubyFunctionInstantiator
+  # Produces an instance of the Function class with the given typed_name, or fails with an error if the
+  # given ruby source does not produce this instance when evaluated.
+  #
+  # @param loader [Puppet::Pops::Loader::Loader] The loader the function is associated with
+  # @param typed_name [Puppet::Pops::Loader::TypedName] the type / name of the function to load
+  # @param source_ref [URI, String] a reference to the source / origin of the ruby code to evaluate
+  # @param ruby_code_string [String] ruby code in a string
+  #
+  # @return [Puppet::Pops::Functions.Function] - an instantiated function with global scope closure associated with the given loader
+  #
+  def self.create(loader, typed_name, source_ref, ruby_code_string)
+    unless ruby_code_string.is_a?(String) && ruby_code_string =~ /Puppet\:\:Functions\.create_function/
+      raise ArgumentError, "The code loaded from #{source_ref} does not seem to be a Puppet 4x API function - no create_function call."
+    end
+    created = eval(ruby_code_string, nil, source_ref, 1)
+    unless created.is_a?(Class)
+      raise ArgumentError, "The code loaded from #{source_ref} did not produce a Function class when evaluated. Got '#{created.class}'"
+    end
+    unless created.name.to_s == typed_name.name()
+      raise ArgumentError, "The code loaded from #{source_ref} produced mis-matched name, expected '#{typed_name.name}', got #{created.name}"
+    end
+    # create the function instance - it needs closure (scope), and loader (i.e. where it should start searching for things
+    # when calling functions etc.
+    # It should be bound to global scope
+
+    # TODO: Cheating wrt. scope - assuming it is found in the context
+    closure_scope = Puppet.lookup(:global_scope) { {} }
+    created.new(closure_scope, loader.private_loader)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/simple_environment_loader.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/simple_environment_loader.rb
new file mode 100644
index 0000000..43e7a6f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/simple_environment_loader.rb
@@ -0,0 +1,20 @@
+# SimpleEnvironmentLoader
+# ===
+# This loader does not load anything and it is populated by the bootstrapping logic that loads
+# the site.pp or equivalent for an environment. It does not restrict the names of what it may contain,
+# and what is loaded here overrides any child loaders (modules).
+#
+class Puppet::Pops::Loader::SimpleEnvironmentLoader < Puppet::Pops::Loader::BaseLoader
+
+  attr_accessor :private_loader
+
+  # Never finds anything, everything "loaded" is set externally
+  def find(typed_name)
+    nil
+  end
+
+  def to_s()
+    "(SimpleEnvironmentLoader '#{loader_name}')"
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/static_loader.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/static_loader.rb
new file mode 100644
index 0000000..50b6a15
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/static_loader.rb
@@ -0,0 +1,79 @@
+  # Static Loader contains constants, basic data types and other types required for the system
+  # to boot.
+  #
+class Puppet::Pops::Loader::StaticLoader < Puppet::Pops::Loader::Loader
+
+  attr_reader :loaded
+  def initialize
+    @loaded = {}
+    create_logging_functions()
+  end
+
+  def load_typed(typed_name)
+    load_constant(typed_name)
+  end
+
+  def get_entry(typed_name)
+    load_constant(typed_name)
+  end
+
+  def find(name)
+    # There is nothing to search for, everything this loader knows about is already available
+    nil
+  end
+
+  def parent
+    nil # at top of the hierarchy
+  end
+
+  def to_s()
+    "(StaticLoader)"
+  end
+  private
+
+  def load_constant(typed_name)
+    @loaded[typed_name]
+  end
+
+  private
+
+  # Creates a function for each of the specified log levels
+  #
+  def create_logging_functions()
+    Puppet::Util::Log.levels.each do |level|
+
+      fc = Puppet::Functions.create_function(level) do
+        # create empty dispatcher to stop it from complaining about missing method since
+        # an override of :call is made instead of using dispatch.
+        dispatch(:log) { }
+
+        # Logs per the specified level, outputs formatted information for arrays, hashes etc.
+        # Overrides the implementation in Function that uses dispatching. This is not needed here
+        # since it accepts 0-n Object.
+        #
+        define_method(:call) do |scope, *vals|
+          # NOTE: 3x, does this: vals.join(" ")
+          # New implementation uses the evaluator to get proper formatting per type
+          # TODO: uses a fake scope (nil) - fix when :scopes are available via settings
+          mapped = vals.map {|v| Puppet::Pops::Evaluator::EvaluatorImpl.new.string(v, nil) }
+
+          # Bypass Puppet.<level> call since it picks up source from "self" which is not applicable in the 4x
+          # Function API.
+          # TODO: When a function can obtain the file, line, pos of the call merge those in (3x supports
+          #       options :file, :line. (These were never output when calling the 3x logging functions since
+          #       3x scope does not know about the calling location at that detailed level, nor do they
+          #       appear in a report to stdout/error when included). Now, the output simply uses scope (like 3x)
+          #       as this is good enough, but does not reflect the true call-stack, but is a rough estimate
+          #       of where the logging call originates from).
+          #
+          Puppet::Util::Log.create({:level => level, :source => scope, :message => mapped.join(" ")})
+        end
+      end
+
+      typed_name = Puppet::Pops::Loader::Loader::TypedName.new(:function, level)
+      # TODO:closure scope is fake (an empty hash) - waiting for new global scope to be available via lookup of :scopes
+      func = fc.new({},self)
+      @loaded[ typed_name ] = Puppet::Pops::Loader::Loader::NamedEntry.new(typed_name, func, __FILE__)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/uri_helper.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/uri_helper.rb
new file mode 100644
index 0000000..ff42a60
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loader/uri_helper.rb
@@ -0,0 +1,22 @@
+module Puppet::Pops::Loader::UriHelper
+  # Raises an exception if specified gem can not be located
+  #
+  def path_for_uri(uri, subdir='lib')
+    case uri.scheme
+    when "gem"
+      begin
+        spec = Gem::Specification.find_by_name(uri.hostname)
+        # if path given append that, else append given subdir
+        File.join(spec.gem_dir, uri.path.empty?() ? subdir : uri.path)
+      rescue StandardError => e
+        raise "TODO TYPE: Failed to located gem #{uri}. #{e.message}"
+      end
+    when "file"
+      File.join(uri.path, subdir)
+    when nil
+      File.join(uri.path, subdir)
+    else
+      raise "Not a valid scheme for a loader: #{uri.scheme}. Use a 'file:' (or just a path), or 'gem://gemname[/path]"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loaders.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loaders.rb
new file mode 100644
index 0000000..c17cf5f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/loaders.rb
@@ -0,0 +1,233 @@
+class Puppet::Pops::Loaders
+  class LoaderError < Puppet::Error; end
+
+  attr_reader :static_loader
+  attr_reader :puppet_system_loader
+  attr_reader :public_environment_loader
+  attr_reader :private_environment_loader
+
+  def initialize(environment)
+    # The static loader can only be changed after a reboot
+    @@static_loader ||= Puppet::Pops::Loader::StaticLoader.new()
+
+    # Create the set of loaders
+    # 1. Puppet, loads from the "running" puppet - i.e. bundled functions, types, extension points and extensions
+    #    These cannot be cached since a  loaded instance will be bound to its closure scope which holds on to
+    #    a compiler and all loaded types. Subsequent request would find remains of the environment that loaded
+    #    the content. PUP-4461.
+    #
+    @puppet_system_loader = create_puppet_system_loader()
+
+    # 2. Environment loader - i.e. what is bound across the environment, may change for each setup
+    #    TODO: loaders need to work when also running in an agent doing catalog application. There is no
+    #    concept of environment the same way as when running as a master (except when doing apply).
+    #    The creation mechanisms should probably differ between the two.
+    #
+    @private_environment_loader = create_environment_loader(environment)
+
+    # 3. module loaders are set up from the create_environment_loader, they register themselves
+  end
+
+  # Clears the cached static and puppet_system loaders (to enable testing)
+  #
+  def self.clear
+    @@static_loader = nil
+    @puppet_system_loader = nil
+  end
+
+  def static_loader
+    @@static_loader
+  end
+
+  def puppet_system_loader
+    @puppet_system_loader
+  end
+
+  def public_loader_for_module(module_name)
+    md = @module_resolver[module_name] || (return nil)
+    # Note, this loader is not resolved until there is interest in the visibility of entities from the
+    # perspective of something contained in the module. (Many request may pass through a module loader
+    # without it loading anything.
+    # See {#private_loader_for_module}, and not in {#configure_loaders_for_modules}
+    md.public_loader
+  end
+
+  def private_loader_for_module(module_name)
+    md = @module_resolver[module_name] || (return nil)
+    # Since there is interest in the visibility from the perspective of entities contained in the
+    # module, it must be resolved (to provide this visibility).
+    # See {#configure_loaders_for_modules}
+    unless md.resolved?
+      @module_resolver.resolve(md)
+    end
+    md.private_loader
+  end
+
+  private
+
+  def create_puppet_system_loader()
+    Puppet::Pops::Loader::ModuleLoaders.system_loader_from(static_loader, self)
+  end
+
+  def create_environment_loader(environment)
+    # This defines where to start parsing/evaluating - the "initial import" (to use 3x terminology)
+    # Is either a reference to a single .pp file, or a directory of manifests. If the environment becomes
+    # a module and can hold functions, types etc. then these are available across all other modules without
+    # them declaring this dependency - it is however valuable to be able to treat it the same way
+    # bindings and other such system related configuration.
+
+    # This is further complicated by the many options available:
+    # - The environment may not have a directory, the code comes from one appointed 'manifest' (site.pp)
+    # - The environment may have a directory and also point to a 'manifest'
+    # - The code to run may be set in settings (code)
+
+    # Further complication is that there is nothing specifying what the visibility is into
+    # available modules. (3x is everyone sees everything).
+    # Puppet binder currently reads confdir/bindings - that is bad, it should be using the new environment support.
+
+    # The environment is not a namespace, so give it a nil "module_name"
+    module_name = nil
+    loader_name = "environment:#{environment.name}"
+    loader = Puppet::Pops::Loader::SimpleEnvironmentLoader.new(puppet_system_loader, loader_name)
+
+    # An environment has a module path even if it has a null loader
+    configure_loaders_for_modules(loader, environment)
+    # modules should see this loader
+    @public_environment_loader = loader
+
+    # Code in the environment gets to see all modules (since there is no metadata for the environment)
+    # but since this is not given to the module loaders, they can not load global code (since they can not
+    # have prior knowledge about this
+    loader = Puppet::Pops::Loader::DependencyLoader.new(loader, "environment", @module_resolver.all_module_loaders())
+
+    # The module loader gets the private loader via a lazy operation to look up the module's private loader.
+    # This does not work for an environment since it is not resolved the same way.
+    # TODO: The EnvironmentLoader could be a specialized loader instead of using a ModuleLoader to do the work.
+    #       This is subject to future design - an Environment may move more in the direction of a Module.
+    @public_environment_loader.private_loader = loader
+    loader
+  end
+
+  def configure_loaders_for_modules(parent_loader, environment)
+    @module_resolver = mr = ModuleResolver.new()
+    environment.modules.each do |puppet_module|
+      # Create data about this module
+      md = LoaderModuleData.new(puppet_module)
+      mr[puppet_module.name] = md
+      md.public_loader = Puppet::Pops::Loader::ModuleLoaders.module_loader_from(parent_loader, self, md.name, md.path)
+    end
+    # NOTE: Do not resolve all modules here - this is wasteful if only a subset of modules / functions are used
+    #       The resolution is triggered by asking for a module's private loader, since this means there is interest
+    #       in the visibility from that perspective.
+    #       If later, it is wanted that all resolutions should be made up-front (to capture errors eagerly, this
+    #       can be introduced (better for production), but may be irritating in development mode.
+  end
+
+  # =LoaderModuleData
+  # Information about a Module and its loaders.
+  # TODO: should have reference to real model element containing all module data; this is faking it
+  # TODO: Should use Puppet::Module to get the metadata (as a hash) - a somewhat blunt instrument, but that is
+  #       what is available with a reasonable API.
+  #
+  class LoaderModuleData
+
+    attr_accessor :state
+    attr_accessor :public_loader
+    attr_accessor :private_loader
+    attr_accessor :resolutions
+
+    # The Puppet::Module this LoaderModuleData represents in the loader configuration
+    attr_reader :puppet_module
+
+    # @param puppet_module [Puppet::Module] the module instance for the module being represented
+    #
+    def initialize(puppet_module)
+      @state = :initial
+      @puppet_module = puppet_module
+      @resolutions = []
+      @public_loader = nil
+      @private_loader = nil
+    end
+
+    def name
+      @puppet_module.name
+    end
+
+    def version
+      @puppet_module.version
+    end
+
+    def path
+      @puppet_module.path
+    end
+
+    def resolved?
+      @state == :resolved
+    end
+
+    def restrict_to_dependencies?
+      @puppet_module.has_metadata?
+    end
+
+    def unmet_dependencies?
+      @puppet_module.unmet_dependencies.any?
+    end
+
+    def dependency_names
+      @puppet_module.dependencies_as_modules.collect(&:name)
+    end
+  end
+
+  # Resolves module loaders - resolution of model dependencies is done by Puppet::Module
+  #
+  class ModuleResolver
+
+    def initialize()
+      @index = {}
+      @all_module_loaders = nil
+    end
+
+    def [](name)
+      @index[name]
+    end
+
+    def []=(name, module_data)
+      @index[name] = module_data
+    end
+
+    def all_module_loaders
+      @all_module_loaders ||= @index.values.map {|md| md.public_loader }
+    end
+
+    def resolve(module_data)
+      if module_data.resolved?
+        return
+      else
+        module_data.private_loader =
+          if module_data.restrict_to_dependencies?
+            create_loader_with_only_dependencies_visible(module_data)
+          else
+            create_loader_with_all_modules_visible(module_data)
+          end
+      end
+    end
+
+    private
+
+    def create_loader_with_all_modules_visible(from_module_data)
+      Puppet.debug("ModuleLoader: module '#{from_module_data.name}' has unknown dependencies - it will have all other modules visible")
+
+      Puppet::Pops::Loader::DependencyLoader.new(from_module_data.public_loader, from_module_data.name, all_module_loaders())
+    end
+
+    def create_loader_with_only_dependencies_visible(from_module_data)
+      if from_module_data.unmet_dependencies?
+        Puppet.warning("ModuleLoader: module '#{from_module_data.name}' has unresolved dependencies"+
+          " - it will only see those that are resolved."+
+          " Use 'puppet module list --tree' to see information about modules")
+      end
+      dependency_loaders = from_module_data.dependency_names.collect { |name| @index[name].public_loader }
+      Puppet::Pops::Loader::DependencyLoader.new(from_module_data.public_loader, from_module_data.name, dependency_loaders)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/migration/migration_checker.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/migration/migration_checker.rb
new file mode 100644
index 0000000..e89936c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/migration/migration_checker.rb
@@ -0,0 +1,45 @@
+# This class defines the private API of the MigrationChecker support.
+# @api private
+#
+class Puppet::Pops::Migration::MigrationChecker
+
+  def initialize()
+  end
+
+  # Produces a hash of available migrations; a map from a symbolic name in string form to a brief description.
+  def available_migrations()
+    { '3.8/4.0' => '3.8 future parser to 4.0 language migrations'}
+  end
+
+  # For 3.8/4.0
+  def report_ambiguous_integer(o)
+  end
+
+  # For 3.8/4.0
+  def report_ambiguous_float(o)
+  end
+
+  # For 3.8/4.0
+  def report_empty_string_true(value, o)
+  end
+
+  # For 3.8/4.0
+  def report_uc_bareword_type(value, o)
+  end
+
+  # For 3.8/4.0
+  def report_equality_type_mismatch(left, right, o)
+  end
+
+  # For 3.8/4.0
+  def report_option_type_mismatch(test_value, option_value, option_expr, matching_expr)
+  end
+
+  # For 3.8/4.0
+  def report_in_expression(o)
+  end
+
+  # For 3.8/4.0
+  def report_array_last_in_block(o)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/ast_transformer.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/ast_transformer.rb
new file mode 100644
index 0000000..2898534
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/ast_transformer.rb
@@ -0,0 +1,643 @@
+require 'puppet/parser/ast'
+
+# The receiver of `import(file)` calls; once per imported file, or nil if imports are ignored
+#
+# Transforms a Pops::Model to classic Puppet AST.
+# TODO: Documentation is currently skipped completely (it is only used for Rdoc)
+#
+class Puppet::Pops::Model::AstTransformer
+  AST = Puppet::Parser::AST
+  Model = Puppet::Pops::Model
+
+  attr_reader :importer
+  def initialize(source_file = "unknown-file", importer=nil)
+    @@transform_visitor ||= Puppet::Pops::Visitor.new(nil,"transform",0,0)
+    @@query_transform_visitor ||= Puppet::Pops::Visitor.new(nil,"query",0,0)
+    @@hostname_transform_visitor ||= Puppet::Pops::Visitor.new(nil,"hostname",0,0)
+    @importer = importer
+    @source_file = source_file
+  end
+
+  # Initialize klass from o (location) and hash (options to created instance).
+  # The object o is used to compute a source location. It may be nil. Source position is merged into
+  # the given options (non surgically). If o is non-nil, the first found source position going up
+  # the containment hierarchy is set. I.e. callers should pass nil if a source position is not wanted
+  # or known to be unobtainable for the object.
+  #
+  # @param o [Object, nil] object from which source position / location is obtained, may be nil
+  # @param klass [Class<Puppet::Parser::AST>] the ast class to create an instance of
+  # @param hash [Hash] hash with options for the class to create
+  #
+  def ast(o, klass, hash={})
+    # create and pass hash with file and line information
+    klass.new(merge_location(hash, o))
+  end
+
+  # THIS IS AN EXPENSIVE OPERATION
+  # The 3x AST requires line, pos etc. to be recorded directly in the AST nodes and this information
+  # must be computed.
+  # (Newer implementation only computes the information that is actually needed; typically when raising an
+  # exception).
+  #
+  def merge_location(hash, o)
+    if o
+      pos = {}
+      source_pos = Puppet::Pops::Utils.find_closest_positioned(o)
+      if source_pos
+        pos[:line] = source_pos.line
+        pos[:pos]  = source_pos.pos
+      end
+      pos[:file] = @source_file if @source_file
+      hash = hash.merge(pos)
+    end
+    hash
+  end
+
+  # Transforms pops expressions into AST 3.1 statements/expressions
+  def transform(o)
+    begin
+    @@transform_visitor.visit_this(self,o)
+    rescue StandardError => e
+      loc_data = {}
+      merge_location(loc_data, o)
+      raise Puppet::ParseError.new("Error while transforming to Puppet 3 AST: #{e.message}", 
+        loc_data[:file], loc_data[:line], loc_data[:pos], e)
+    end
+  end
+
+  # Transforms pops expressions into AST 3.1 query expressions
+  def query(o)
+    @@query_transform_visitor.visit_this(self, o)
+  end
+
+  # Transforms pops expressions into AST 3.1 hostnames
+  def hostname(o)
+    @@hostname_transform_visitor.visit_this(self, o)
+  end
+
+  def transform_LiteralFloat(o)
+    # Numbers are Names in the AST !! (Name a.k.a BareWord)
+    ast o, AST::Name, :value => o.value.to_s
+  end
+
+  def transform_LiteralInteger(o)
+    s = case o.radix
+    when 10
+      o.value.to_s
+    when 8
+      "0%o" % o.value
+    when 16
+      "0x%X" % o.value
+    else
+      "bad radix:" + o.value.to_s
+    end
+
+    # Numbers are Names in the AST !! (Name a.k.a BareWord)
+    ast o, AST::Name, :value => s
+  end
+
+  # Transforms all literal values to string (override for those that should not be AST::String)
+  #
+  def transform_LiteralValue(o)
+    ast o, AST::String, :value => o.value.to_s
+  end
+
+  def transform_LiteralBoolean(o)
+    ast o, AST::Boolean, :value => o.value
+  end
+
+  def transform_Factory(o)
+    transform(o.current)
+  end
+
+  def transform_ArithmeticExpression(o)
+    ast o, AST::ArithmeticOperator2, :lval => transform(o.left_expr), :rval=>transform(o.right_expr),
+    :operator => o.operator.to_s
+  end
+
+  def transform_Array(o)
+    ast nil, AST::ASTArray, :children => o.collect {|x| transform(x) }
+  end
+
+  # Puppet AST only allows:
+  # * variable[expression] => Hasharray Access
+  # * NAME [expressions] => Resource Reference(s)
+  # * type [epxressions] => Resource Reference(s)
+  # * HashArrayAccesses[expression] => HasharrayAccesses
+  #
+  # i.e. it is not possible to do `func()[3]`, `[1,2,3][$x]`, `{foo=>10, bar=>20}[$x]` etc. since
+  # LHS is not an expression
+  #
+  # Validation for 3.x semantics should validate the illegal cases. This transformation may fail,
+  # or ignore excess information if the expressions are not correct.
+  # This means that the transformation does not have to evaluate the lhs to detect the target expression.
+  #
+  # Hm, this seems to have changed, the LHS (variable) is evaluated if evaluateable, else it is used as is.
+  #
+  def transform_AccessExpression(o)
+    case o.left_expr
+    when Model::QualifiedName
+      ast o, AST::ResourceReference, :type => o.left_expr.value, :title => transform(o.keys)
+
+    when Model::QualifiedReference
+      ast o, AST::ResourceReference, :type => o.left_expr.value, :title => transform(o.keys)
+
+    when Model::VariableExpression
+      ast o, AST::HashOrArrayAccess, :variable => transform(o.left_expr), :key => transform(o.keys()[0])
+
+    else
+      ast o, AST::HashOrArrayAccess, :variable => transform(o.left_expr), :key => transform(o.keys()[0])
+    end
+  end
+
+  # Puppet AST has a complicated structure
+  # LHS can not be an expression, it must be a type (which is downcased).
+  # type = a downcased QualifiedName
+  #
+  def transform_CollectExpression(o)
+    raise "LHS is not a type" unless o.type_expr.is_a? Model::QualifiedReference
+    type = o.type_expr.value().downcase()
+    args = { :type => type }
+
+    # This somewhat peculiar encoding is used by the 3.1 AST.
+    query = transform(o.query)
+    if query.is_a? Symbol
+      args[:form] =  query
+    else
+      args[:form] = query.form
+      args[:query] = query
+      query.type = type
+    end
+
+    if o.operations.size > 0
+      args[:override] = transform(o.operations)
+    end
+    ast o, AST::Collection, args
+  end
+
+  def transform_EppExpression(o)
+    # TODO: Not supported in 3x TODO_EPP
+    parameters = o.parameters.collect {|p| transform(p) }
+    args = { :parameters => parameters }
+    args[:children] = transform(o.body) unless is_nop?(o.body)
+    Puppet::Parser::AST::Epp.new(merge_location(args, o))
+  end
+
+  def transform_ExportedQuery(o)
+    if is_nop?(o.expr)
+      result = :exported
+    else
+      result = query(o.expr)
+      result.form = :exported
+    end
+    result
+  end
+
+  def transform_VirtualQuery(o)
+    if is_nop?(o.expr)
+      result = :virtual
+    else
+      result = query(o.expr)
+      result.form = :virtual
+    end
+    result
+  end
+
+  # Ensures transformation fails if a 3.1 non supported object is encountered in a query expression
+  #
+  def query_Object(o)
+    raise "Not a valid expression in a collection query: "+o.class.name
+  end
+
+  # Puppet AST only allows == and !=, and left expr is restricted, but right value is an expression
+  #
+  def query_ComparisonExpression(o)
+    if [:'==', :'!='].include? o.operator
+      ast o, AST::CollExpr, :test1 => query(o.left_expr), :oper => o.operator.to_s, :test2 => transform(o.right_expr)
+    else
+      raise "Not a valid comparison operator in a collection query: " + o.operator.to_s
+    end
+  end
+
+  def query_AndExpression(o)
+    ast o, AST::CollExpr, :test1 => query(o.left_expr), :oper => 'and', :test2 => query(o.right_expr)
+  end
+
+  def query_OrExpression(o)
+    ast o, AST::CollExpr, :test1 => query(o.left_expr), :oper => 'or', :test2 => query(o.right_expr)
+  end
+
+  def query_ParenthesizedExpression(o)
+    result = query(o.expr) # produces CollExpr
+    result.parens = true
+    result
+  end
+
+  def query_VariableExpression(o)
+    transform(o)
+  end
+
+  def query_QualifiedName(o)
+    transform(o)
+  end
+
+  def query_LiteralNumber(o)
+    transform(o) # number to string in correct radix
+  end
+
+  def query_LiteralString(o)
+    transform(o)
+  end
+
+  def query_LiteralBoolean(o)
+    transform(o)
+  end
+
+  def transform_QualifiedName(o)
+    ast o, AST::Name, :value => o.value
+  end
+
+  def transform_QualifiedReference(o)
+    ast o, AST::Type, :value => o.value
+  end
+
+  def transform_ComparisonExpression(o)
+    ast o, AST::ComparisonOperator, :operator => o.operator.to_s, :lval => transform(o.left_expr), :rval => transform(o.right_expr)
+  end
+
+  def transform_AndExpression(o)
+    ast o, AST::BooleanOperator, :operator => 'and', :lval => transform(o.left_expr), :rval => transform(o.right_expr)
+  end
+
+  def transform_OrExpression(o)
+    ast o, AST::BooleanOperator, :operator => 'or', :lval => transform(o.left_expr), :rval => transform(o.right_expr)
+  end
+
+  def transform_InExpression(o)
+    ast o, AST::InOperator, :lval => transform(o.left_expr), :rval => transform(o.right_expr)
+  end
+
+  # Assignment in AST 3.1 is to variable or hasharray accesses !!! See Bug #16116
+  def transform_AssignmentExpression(o)
+    args = {:value => transform(o.right_expr) }
+    case o.operator
+    when :'+='
+      args[:append] = true
+    when :'='
+    else
+      raise "The operator #{o.operator} is not supported by Puppet 3."
+    end
+
+    args[:name] = case o.left_expr
+    when Model::VariableExpression
+      ast o, AST::Name, {:value => o.left_expr.expr.value }
+    when Model::AccessExpression
+      transform(o.left_expr)
+    else
+      raise "LHS is not an expression that can be assigned to"
+    end
+    ast o, AST::VarDef, args
+  end
+
+  # Produces (name => expr) or (name +> expr)
+  def transform_AttributeOperation(o)
+    args = { :value => transform(o.value_expr) }
+    args[:add] = true if o.operator == :'+>'
+    args[:param] = o.attribute_name
+    ast o, AST::ResourceParam, args
+  end
+
+  def transform_LiteralList(o)
+    # Uses default transform of Ruby Array to ASTArray
+    transform(o.values)
+  end
+
+  # Literal hash has strange behavior in Puppet 3.1. See Bug #19426, and this implementation is bug
+  # compatible
+  def transform_LiteralHash(o)
+    if o.entries.size == 0
+      ast o, AST::ASTHash, {:value=> {}}
+    else
+      value = {}
+      o.entries.each {|x| value.merge! transform(x) }
+      ast o, AST::ASTHash, {:value=> value}
+    end
+  end
+
+  # Transforms entry into a hash (they are later merged with strange effects: Bug #19426).
+  # Puppet 3.x only allows:
+  # * NAME
+  # * quotedtext
+  # As keys (quoted text can be an interpolated string which is compared as a key in a less than satisfactory way).
+  #
+  def transform_KeyedEntry(o)
+    value = transform(o.value)
+    key = case o.key
+    when Model::QualifiedName
+      o.key.value
+    when Model::LiteralString
+      transform o.key
+    when Model::LiteralNumber
+      transform o.key
+    when Model::ConcatenatedString
+      transform o.key
+    else
+      raise "Illegal hash key expression of type (#{o.key.class})"
+    end
+    {key => value}
+  end
+
+  def transform_MatchExpression(o)
+    ast o, AST::MatchOperator, :operator => o.operator.to_s, :lval => transform(o.left_expr), :rval => transform(o.right_expr)
+  end
+
+  def transform_LiteralString(o)
+    ast o, AST::String, :value => o.value
+  end
+
+  def transform_LambdaExpression(o)
+    astargs = { :parameters => o.parameters.collect {|p| transform(p) } }
+    astargs.merge!({ :children => transform(o.body) }) if o.body         # do not want children if it is nil/nop
+    ast o, AST::Lambda, astargs
+  end
+
+  def transform_LiteralDefault(o)
+    ast o, AST::Default, :value => :default
+  end
+
+  def transform_LiteralUndef(o)
+    ast o, AST::Undef, :value => :undef
+  end
+
+  def transform_LiteralRegularExpression(o)
+    ast o, AST::Regex, :value => o.value
+  end
+
+  def transform_Nop(o)
+    ast o, AST::Nop
+  end
+
+  # In the 3.1. grammar this is a hash that is merged with other elements to form a method call
+  # Also in 3.1. grammar there are restrictions on the LHS (that are only there for grammar issues).
+  #
+  def transform_NamedAccessExpression(o)
+    receiver = transform(o.left_expr)
+    name = o.right_expr
+    raise "Unacceptable function/method name" unless name.is_a? Model::QualifiedName
+    {:receiver => receiver, :name => name.value}
+  end
+
+  def transform_NilClass(o)
+    ast o, AST::Nop, {}
+  end
+
+  def transform_NotExpression(o)
+    ast o, AST::Not, :value => transform(o.expr)
+  end
+
+  def transform_VariableExpression(o)
+    # assumes the expression is a QualifiedName
+    ast o, AST::Variable, :value => o.expr.value
+  end
+
+  # In Puppet 3.1, the ConcatenatedString is responsible for the evaluation and stringification of
+  # expression segments. Expressions and Strings are kept in an array.
+  def transform_TextExpression(o)
+    transform(o.expr)
+  end
+
+  def transform_UnaryMinusExpression(o)
+    ast o, AST::Minus, :value => transform(o.expr)
+  end
+
+  # Puppet 3.1 representation of a BlockExpression is an AST::Array - this makes it impossible to differentiate
+  # between a LiteralArray and a Sequence. (Should it return the collected array, or the last expression?)
+  # (A BlockExpression has now been introduced in the AST to solve this).
+  #
+  def transform_BlockExpression(o)
+    children = []
+    # remove nops resulting from import
+    o.statements.each {|s| r = transform(s); children << r unless is_nop?(r) }
+    ast o, AST::BlockExpression, :children => children  # o.statements.collect {|s| transform(s) }
+  end
+
+  # Interpolated strings are kept in an array of AST (string or other expression).
+  def transform_ConcatenatedString(o)
+    ast o, AST::Concat, :value => o.segments.collect {|x| transform(x)}
+  end
+
+  def transform_HostClassDefinition(o)
+    parameters = o.parameters.collect {|p| transform(p) }
+    args = {
+      :arguments => parameters,
+      :parent => o.parent_class,
+    }
+    args[:code] = transform(o.body) unless is_nop?(o.body)
+    Puppet::Parser::AST::Hostclass.new(o.name, merge_location(args, o))
+  end
+
+  def transform_HeredocExpression(o)
+    # TODO_HEREDOC Not supported in 3x
+    args = {:syntax=> o.syntax(), :expr => transform(o.text_expr()) }
+    Puppet::Parser::AST::Heredoc.new(merge_location(args, o))
+  end
+
+  def transform_NodeDefinition(o)
+    # o.host_matches are expressions, and 3.1 AST requires special object AST::HostName
+    # where a HostName is one of NAME, STRING, DEFAULT or Regexp - all of these are strings except regexp
+    #
+    args = {
+      :code => transform(o.body)
+    }
+    args[:parent] = hostname(o.parent) unless is_nop?(o.parent)
+    if(args[:parent].is_a?(Array))
+      raise "Illegal expression - unacceptable as a node parent"
+    end
+    Puppet::Parser::AST::Node.new(hostname(o.host_matches), merge_location(args, o))
+  end
+
+  # Transforms Array of host matching expressions into a (Ruby) array of AST::HostName
+  def hostname_Array(o)
+    o.collect {|x| ast x, AST::HostName, :value => hostname(x) }
+  end
+
+  def hostname_LiteralValue(o)
+    return o.value
+  end
+
+  def hostname_QualifiedName(o)
+    return o.value
+  end
+
+  def hostname_LiteralNumber(o)
+    transform(o) # Number to string with correct radix
+  end
+
+  def hostname_LiteralDefault(o)
+    return 'default'
+  end
+
+  def hostname_LiteralRegularExpression(o)
+    ast o, AST::Regex, :value => o.value
+  end
+
+  def hostname_Object(o)
+    raise "Illegal expression - unacceptable as a node name"
+  end
+
+  def transform_RelationshipExpression(o)
+    Puppet::Parser::AST::Relationship.new(transform(o.left_expr), transform(o.right_expr), o.operator.to_s, merge_location({}, o))
+  end
+
+  def transform_RenderStringExpression(o)
+    # TODO_EPP Not supported in 3x
+    ast o, AST::RenderString, :value => o.value
+  end
+
+  def transform_RenderExpression(o)
+    # TODO_EPP Not supported in 3x
+    ast o, AST::RenderExpression, :value => transform(o.expr)
+  end
+
+  def transform_ResourceTypeDefinition(o)
+    parameters = o.parameters.collect {|p| transform(p) }
+    args = { :arguments => parameters }
+    args[:code] = transform(o.body) unless is_nop?(o.body)
+
+    Puppet::Parser::AST::Definition.new(o.name, merge_location(args, o))
+  end
+
+  # Transformation of ResourceOverrideExpression is slightly more involved than a straight forward
+  # transformation.
+  # A ResourceOverrideExppression has "resources" which should be an AccessExpression
+  # on the form QualifiedName[expressions], or QualifiedReference[expressions] to be valid.
+  # It also has a set of attribute operations.
+  #
+  # The AST equivalence is an AST::ResourceOverride with a ResourceReference as its LHS, and
+  # a set of Parameters.
+  # ResourceReference has type as a string, and the expressions representing
+  # the "titles" to be an ASTArray.
+  #
+  def transform_ResourceOverrideExpression(o)
+    raise "Unsupported transformation - use the new evaluator"
+  end
+
+  # Parameter is a parameter in a definition of some kind.
+  # It is transformed to an array on the form `[name]´, or `[name, value]´.
+  def transform_Parameter(o)
+    if o.value
+      [o.name, transform(o.value)]
+    else
+      [o.name]
+    end
+  end
+
+  # For non query expressions, parentheses can be dropped in the resulting AST.
+  def transform_ParenthesizedExpression(o)
+    transform(o.expr)
+  end
+
+  def transform_Program(o)
+    transform(o.body)
+  end
+
+  def transform_IfExpression(o)
+    args = { :test => transform(o.test), :statements => transform(o.then_expr) }
+    args[:else] = transform(o.else_expr) # Tests say Nop should be there (unless is_nop? o.else_expr), probably not needed
+    ast o, AST::IfStatement, args
+  end
+
+  # Unless is not an AST object, instead an AST::IfStatement is used with an AST::Not around the test
+  #
+  def transform_UnlessExpression(o)
+    args = { :test => ast(o, AST::Not, :value => transform(o.test)),
+      :statements => transform(o.then_expr) }
+    # AST 3.1 does not allow else on unless in the grammar, but it is ok since unless is encoded as an if !x
+    args.merge!({:else => transform(o.else_expr)}) unless is_nop?(o.else_expr)
+    ast o, AST::IfStatement, args
+  end
+
+  # Puppet 3.1 AST only supports calling a function by name (it is not possible to produce a function
+  # that is then called).
+  # rval_required (for an expression)
+  # functor_expr (lhs - the "name" expression)
+  # arguments - list of arguments
+  #
+  def transform_CallNamedFunctionExpression(o)
+    name = o.functor_expr
+    raise "Unacceptable expression for name of function" unless name.is_a? Model::QualifiedName
+    args = {
+      :name => name.value,
+      :arguments => transform(o.arguments),
+      :ftype => o.rval_required ? :rvalue : :statement
+    }
+    args[:pblock] = transform(o.lambda) if o.lambda
+    ast o, AST::Function, args
+  end
+
+  # Transformation of CallMethodExpression handles a NamedAccessExpression functor and
+  # turns this into a 3.1 AST::MethodCall.
+  #
+  def transform_CallMethodExpression(o)
+    name = o.functor_expr
+    raise "Unacceptable expression for name of function" unless name.is_a? Model::NamedAccessExpression
+    # transform of NamedAccess produces a hash, add arguments to it
+    astargs = transform(name).merge(:arguments => transform(o.arguments))
+    astargs.merge!(:lambda => transform(o.lambda)) if o.lambda # do not want a Nop as the lambda
+    ast o, AST::MethodCall, astargs
+
+  end
+
+  def transform_CaseExpression(o)
+    # Expects expression, AST::ASTArray of AST
+    ast o, AST::CaseStatement, :test => transform(o.test), :options => transform(o.options)
+  end
+
+  def transform_CaseOption(o)
+    ast o, AST::CaseOpt, :value => transform(o.values), :statements => transform(o.then_expr)
+  end
+
+  def transform_ResourceBody(o)
+    raise "Unsupported transformation - use the new evaluator"
+  end
+
+  def transform_ResourceDefaultsExpression(o)
+    raise "Unsupported transformation - use the new evaluator"
+  end
+
+  # Transformation of ResourceExpression requires calling a method on the resulting
+  # AST::Resource if it is virtual or exported
+  #
+  def transform_ResourceExpression(o)
+    raise "Unsupported transformation - use the new evaluator"
+  end
+
+  # Transformation of SelectorExpression is limited to certain types of expressions.
+  # This is probably due to constraints in the old grammar rather than any real concerns.
+  def transform_SelectorExpression(o)
+    case o.left_expr
+    when Model::CallNamedFunctionExpression
+    when Model::AccessExpression
+    when Model::VariableExpression
+    when Model::ConcatenatedString
+    else
+      raise "Unacceptable select expression" unless o.left_expr.kind_of? Model::Literal
+    end
+    ast o, AST::Selector, :param => transform(o.left_expr), :values => transform(o.selectors)
+  end
+
+  def transform_SelectorEntry(o)
+    ast o, AST::ResourceParam, :param => transform(o.matching_expr), :value => transform(o.value_expr)
+  end
+
+  def transform_Object(o)
+    raise "Unacceptable transform - found an Object without a rule: #{o.class}"
+  end
+
+  # Nil, nop
+  # Bee bopp a luh-lah, a bop bop boom.
+  #
+  def is_nop?(o)
+    o.nil? || o.is_a?(Model::Nop)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/ast_tree_dumper.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/ast_tree_dumper.rb
new file mode 100644
index 0000000..00c4ae4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/ast_tree_dumper.rb
@@ -0,0 +1,386 @@
+require 'puppet/parser/ast'
+
+# Dumps a Pops::Model in reverse polish notation; i.e. LISP style
+# The intention is to use this for debugging output
+# TODO: BAD NAME - A DUMP is a Ruby Serialization
+#
+class Puppet::Pops::Model::AstTreeDumper < Puppet::Pops::Model::TreeDumper
+  AST = Puppet::Parser::AST
+  Model = Puppet::Pops::Model
+
+  def dump_LiteralFloat o
+    o.value.to_s
+  end
+
+  def dump_LiteralInteger o
+    case o.radix
+    when 10
+      o.value.to_s
+    when 8
+      "0%o" % o.value
+    when 16
+      "0x%X" % o.value
+    else
+      "bad radix:" + o.value.to_s
+    end
+  end
+
+  def dump_Expression(o)
+    "(pops-expression #{Puppet::Pops::Model::ModelTreeDumper.new().dump(o.value)})"
+  end
+
+  def dump_Factory o
+    do_dump(o.current)
+  end
+
+  def dump_ArithmeticOperator o
+    [o.operator.to_s, do_dump(o.lval), do_dump(o.rval)]
+  end
+  def dump_Relationship o
+    [o.arrow.to_s, do_dump(o.left), do_dump(o.right)]
+  end
+
+  # Hostname is tricky, it is either a bare word, a string, or default, or regular expression
+  # Least evil, all strings except default are quoted
+  def dump_HostName o
+    result = do_dump o.value
+    unless o.value.is_a? AST::Regex
+      result = result == "default" ? ":default" : "'#{result}'"
+    end
+    result
+  end
+
+  # x[y] prints as (slice x y)
+  def dump_HashOrArrayAccess o
+    var = o.variable.is_a?(String) ? "$#{o.variable}" : do_dump(o.variable)
+    ["slice", var, do_dump(o.key)]
+  end
+
+  # The AST Collection knows about exported or virtual query, not the query.
+  def dump_Collection o
+    result = ["collect", do_dump(o.type), :indent, :break]
+    if o.form == :virtual
+      q = ["<| |>"]
+    else
+      q = ["<<| |>>"]
+    end
+    q << do_dump(o.query) unless is_nop?(o.query)
+    q <<  :indent
+    result << q
+    o.override do |ao|
+      result << :break << do_dump(ao)
+    end
+    result += [:dedent, :dedent ]
+    result
+  end
+
+  def dump_CollExpr o
+    operator = case o.oper
+    when 'and'
+      '&&'
+    when 'or'
+      '||'
+    else
+      o.oper
+    end
+    [operator, do_dump(o.test1), do_dump(o.test2)]
+  end
+
+  def dump_ComparisonOperator o
+    [o.operator.to_s, do_dump(o.lval), do_dump(o.rval)]
+  end
+
+  def dump_Boolean o
+    o.to_s
+  end
+
+  def dump_BooleanOperator o
+    operator = o.operator == 'and' ? '&&' : '||'
+    [operator, do_dump(o.lval), do_dump(o.rval)]
+  end
+
+  def dump_InOperator o
+    ["in", do_dump(o.lval), do_dump(o.rval)]
+  end
+
+  # $x = ...
+  # $x += ...
+  #
+  def dump_VarDef o
+    operator = o.append ? "+=" : "="
+    [operator, '$' + do_dump(o.name), do_dump(o.value)]
+  end
+
+  # Produces (name => expr) or (name +> expr)
+  def dump_ResourceParam o
+    operator = o.add ? "+>" : "=>"
+    [do_dump(o.param), operator, do_dump(o.value)]
+  end
+
+  def dump_Array o
+    o.collect {|e| do_dump(e) }
+  end
+
+  def dump_ASTArray o
+    ["[]"] + o.children.collect {|x| do_dump(x)}
+  end
+
+  def dump_ASTHash o
+    ["{}"] + o.value.sort_by{|k,v| k.to_s}.collect {|x| [do_dump(x[0]), do_dump(x[1])]}
+#    ["{}"] + o.value.collect {|x| [do_dump(x[0]), do_dump(x[1])]}
+  end
+
+  def dump_MatchOperator o
+    [o.operator.to_s, do_dump(o.lval), do_dump(o.rval)]
+  end
+
+  # Dump a Ruby String in single quotes unless it is a number.
+  def dump_String o
+
+    if o.is_a? String
+      o               # A Ruby String, not quoted
+    elsif Puppet::Pops::Utils.to_n(o.value)
+      o.value         # AST::String that is a number without quotes
+    else
+      "'#{o.value}'"  # AST::String that is not a number
+    end
+  end
+
+  def dump_Lambda o
+    result = ["lambda"]
+    result << ["parameters"] + o.parameters.collect {|p| _dump_ParameterArray(p) } if o.parameters.size() > 0
+    if o.children == []
+      result << [] # does not have a lambda body
+    else
+      result << do_dump(o.children)
+    end
+    result
+  end
+
+  def dump_Default o
+    ":default"
+  end
+
+  def dump_Undef o
+    ":undef"
+  end
+
+  # Note this is Regex (the AST kind), not Ruby Regexp
+  def dump_Regex o
+    "/#{o.value.source}/"
+  end
+
+  def dump_Nop o
+    ":nop"
+  end
+
+  def dump_NilClass o
+    "()"
+  end
+
+  def dump_Not o
+    ['!', dump(o.value)]
+  end
+
+  def dump_Variable o
+    "$#{dump(o.value)}"
+  end
+
+  def dump_Minus o
+    ['-', do_dump(o.value)]
+  end
+
+  def dump_BlockExpression o
+    ["block"] + o.children.collect {|x| do_dump(x) }
+  end
+
+  # Interpolated strings are shown as (cat seg0 seg1 ... segN)
+  def dump_Concat o
+    ["cat"] + o.value.collect {|x| x.is_a?(AST::String) ? " "+do_dump(x) : ["str", do_dump(x)]}
+  end
+
+  def dump_Hostclass o
+    # ok, this is kind of crazy stuff in the AST, information in a context instead of in AST, and
+    # parameters are in a Ruby Array with each parameter being an Array...
+    #
+    context = o.context
+    args = context[:arguments]
+    parent = context[:parent]
+    result = ["class", o.name]
+    result << ["inherits", parent] if parent
+    result << ["parameters"] + args.collect {|p| _dump_ParameterArray(p) } if args && args.size() > 0
+    if is_nop?(o.code)
+      result << []
+    else
+      result << do_dump(o.code)
+    end
+    result
+  end
+
+  def dump_Name o
+    o.value
+  end
+
+  def dump_Node o
+    context = o.context
+    parent = context[:parent]
+    code = context[:code]
+
+    result = ["node"]
+    result << ["matches"] + o.names.collect {|m| do_dump(m) }
+    result << ["parent", do_dump(parent)] if !is_nop?(parent)
+    if is_nop?(code)
+      result << []
+    else
+      result << do_dump(code)
+    end
+    result
+  end
+
+  def dump_Definition o
+    # ok, this is even crazier that Hostclass. The name of the define does not have an accessor
+    # and some things are in the context (but not the name). Parameters are called arguments and they
+    # are in a Ruby Array where each parameter is an array of 1 or 2 elements.
+    #
+    context = o.context
+    name = o.instance_variable_get("@name")
+    args = context[:arguments]
+    code = context[:code]
+    result = ["define", name]
+    result << ["parameters"] + args.collect {|p| _dump_ParameterArray(p) } if args && args.size() > 0
+    if is_nop?(code)
+      result << []
+    else
+      result << do_dump(code)
+    end
+    result
+  end
+
+  def dump_ResourceReference o
+    result = ["slice", do_dump(o.type)]
+    if o.title.children.size == 1
+      result << do_dump(o.title[0])
+    else
+      result << do_dump(o.title.children)
+    end
+    result
+  end
+
+  def dump_ResourceOverride o
+    result = ["override", do_dump(o.object), :indent]
+    o.parameters.each do |p|
+      result << :break << do_dump(p)
+    end
+    result << :dedent
+    result
+  end
+
+  # Puppet AST encodes a parameter as a one or two slot Array.
+  # This is not a polymorph dump method.
+  #
+  def _dump_ParameterArray o
+    if o.size == 2
+      ["=", o[0], do_dump(o[1])]
+    else
+      o[0]
+    end
+  end
+
+  def dump_IfStatement o
+    result = ["if", do_dump(o.test), :indent, :break,
+      ["then", :indent, do_dump(o.statements), :dedent]]
+    result +=
+    [:break,
+      ["else", :indent, do_dump(o.else), :dedent],
+      :dedent] unless is_nop? o.else
+    result
+  end
+
+  # Produces (invoke name args...) when not required to produce an rvalue, and
+  # (call name args ... ) otherwise.
+  #
+  def dump_Function o
+    # somewhat ugly as Function hides its "ftype" instance variable
+    result = [o.instance_variable_get("@ftype") == :rvalue ? "call" : "invoke", do_dump(o.name)]
+    o.arguments.collect {|a| result << do_dump(a) }
+    result << do_dump(o.pblock) if o.pblock
+    result
+  end
+
+  def dump_MethodCall o
+    # somewhat ugly as Method call (does the same as function) and hides its "ftype" instance variable
+    result = [o.instance_variable_get("@ftype") == :rvalue ? "call-method" : "invoke-method",
+      [".", do_dump(o.receiver), do_dump(o.name)]]
+    o.arguments.collect {|a| result << do_dump(a) }
+    result << do_dump(o.lambda) if o.lambda
+    result
+  end
+
+  def dump_CaseStatement o
+    result = ["case", do_dump(o.test), :indent]
+    o.options.each do |s|
+      result << :break << do_dump(s)
+    end
+    result << :dedent
+  end
+
+  def dump_CaseOpt o
+    result = ["when"]
+    result << o.value.collect {|x| do_dump(x) }
+    # A bit of trickery to get it into the same shape as Pops output
+    if is_nop?(o.statements)
+      result << ["then", []]  # Puppet AST has a nop if there is no body
+    else
+      result << ["then", do_dump(o.statements) ]
+    end
+    result
+  end
+
+  def dump_ResourceInstance o
+    result = [do_dump(o.title), :indent]
+    o.parameters.each do |p|
+      result << :break << do_dump(p)
+    end
+    result << :dedent
+    result
+  end
+
+  def dump_ResourceDefaults o
+    result = ["resource-defaults", do_dump(o.type), :indent]
+    o.parameters.each do |p|
+      result << :break << do_dump(p)
+    end
+    result << :dedent
+    result
+  end
+
+  def dump_Resource o
+    if o.exported
+      form = 'exported-'
+    elsif o.virtual
+      form = 'virtual-'
+    else
+      form = ''
+    end
+    result = [form+"resource", do_dump(o.type), :indent]
+    o.instances.each do |b|
+      result << :break << do_dump(b)
+    end
+    result << :dedent
+    result
+  end
+
+  def dump_Selector o
+    values = o.values
+    values = [values] unless values.instance_of? AST::ASTArray or values.instance_of? Array
+    ["?", do_dump(o.param)] + values.collect {|x| do_dump(x) }
+  end
+
+  def dump_Object o
+    ['dev-error-no-polymorph-dump-for:', o.class.to_s, o.to_s]
+  end
+
+  def is_nop? o
+    o.nil? || o.is_a?(Model::Nop) || o.is_a?(AST::Nop)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/factory.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/factory.rb
new file mode 100644
index 0000000..4e90f80
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/factory.rb
@@ -0,0 +1,1056 @@
+# Factory is a helper class that makes construction of a Pops Model
+# much more convenient. It can be viewed as a small internal DSL for model
+# constructions.
+# For usage see tests using the factory.
+#
+# @todo All those uppercase methods ... they look bad in one way, but stand out nicely in the grammar...
+#   decide if they should change into lower case names (some of the are lower case)...
+#
+class Puppet::Pops::Model::Factory
+  Model = Puppet::Pops::Model
+
+  attr_accessor :current
+
+  alias_method :model, :current
+
+  # Shared build_visitor, since there are many instances of Factory being used
+  @@build_visitor = Puppet::Pops::Visitor.new(self, "build")
+  @@interpolation_visitor = Puppet::Pops::Visitor.new(self, "interpolate")
+
+  # Initialize a factory with a single object, or a class with arguments applied to build of
+  # created instance
+  #
+  def initialize o, *args
+    @current = case o
+    when Model::PopsObject
+      o
+    when Puppet::Pops::Model::Factory
+      o.current
+    else
+      build(o, *args)
+    end
+  end
+
+  # Polymorphic build
+  def build(o, *args)
+    begin
+      @@build_visitor.visit_this(self, o, *args)
+    rescue =>e
+      # debug here when in trouble...
+      raise e
+    end
+  end
+
+  # Polymorphic interpolate
+  def interpolate()
+    begin
+      @@interpolation_visitor.visit_this_0(self, current)
+    rescue =>e
+      # debug here when in trouble...
+      raise e
+    end
+  end
+
+  # Building of Model classes
+
+  def build_ArithmeticExpression(o, op, a, b)
+    o.operator = op
+    build_BinaryExpression(o, a, b)
+  end
+
+  def build_AssignmentExpression(o, op, a, b)
+    o.operator = op
+    build_BinaryExpression(o, a, b)
+  end
+
+  def build_AttributeOperation(o, name, op, value)
+    o.operator = op
+    o.attribute_name = name.to_s # BOOLEAN is allowed in the grammar
+    o.value_expr = build(value)
+    o
+  end
+
+  def build_AttributesOperation(o, value)
+    o.expr = build(value)
+    o
+  end
+
+  def build_AccessExpression(o, left, *keys)
+    o.left_expr = to_ops(left)
+    keys.each {|expr| o.addKeys(to_ops(expr)) }
+    o
+  end
+
+  def build_BinaryExpression(o, left, right)
+    o.left_expr = to_ops(left)
+    o.right_expr = to_ops(right)
+    o
+  end
+
+  def build_BlockExpression(o, *args)
+    args.each {|expr| o.addStatements(to_ops(expr)) }
+    o
+  end
+
+  def build_CollectExpression(o, type_expr, query_expr, attribute_operations)
+    o.type_expr = to_ops(type_expr)
+    o.query = build(query_expr)
+    attribute_operations.each {|op| o.addOperations(build(op)) }
+    o
+  end
+
+  def build_ComparisonExpression(o, op, a, b)
+    o.operator = op
+    build_BinaryExpression(o, a, b)
+  end
+
+  def build_ConcatenatedString(o, *args)
+    args.each {|expr| o.addSegments(build(expr)) }
+    o
+  end
+
+  def build_CreateTypeExpression(o, name, super_name = nil)
+    o.name = name
+    o.super_name = super_name
+    o
+  end
+
+  def build_CreateEnumExpression(o, *args)
+    o.name = args.slice(0) if args.size == 2
+    o.values = build(args.last)
+    o
+  end
+
+  def build_CreateAttributeExpression(o, name, datatype_expr)
+    o.name = name
+    o.type = to_ops(datatype_expr)
+    o
+  end
+
+  def build_HeredocExpression(o, name, expr)
+    o.syntax = name
+    o.text_expr = build(expr)
+    o
+  end
+
+  # @param name [String] a valid classname
+  # @param parameters [Array<Model::Parameter>] may be empty
+  # @param parent_class_name [String, nil] a valid classname referencing a parent class, optional.
+  # @param body [Array<Expression>, Expression, nil] expression that constitute the body
+  # @return [Model::HostClassDefinition] configured from the parameters
+  #
+  def build_HostClassDefinition(o, name, parameters, parent_class_name, body)
+    build_NamedDefinition(o, name, parameters, body)
+    o.parent_class = parent_class_name if parent_class_name
+    o
+  end
+
+  def build_ResourceOverrideExpression(o, resources, attribute_operations)
+    o.resources = build(resources)
+    attribute_operations.each {|ao| o.addOperations(build(ao)) }
+    o
+  end
+
+  def build_ReservedWord(o, name, future)
+    o.word = name
+    o.future = future
+    o
+  end
+
+  def build_KeyedEntry(o, k, v)
+    o.key = to_ops(k)
+    o.value = to_ops(v)
+    o
+  end
+
+  def build_LiteralHash(o, *keyed_entries)
+    keyed_entries.each {|entry| o.addEntries build(entry) }
+    o
+  end
+
+  def build_LiteralList(o, *values)
+    values.each {|v| o.addValues build(v) }
+    o
+  end
+
+  def build_LiteralFloat(o, val)
+    o.value = val
+    o
+  end
+
+  def build_LiteralInteger(o, val, radix)
+    o.value = val
+    o.radix = radix
+    o
+  end
+
+  def build_IfExpression(o, t, ift, els)
+    o.test = build(t)
+    o.then_expr = build(ift)
+    o.else_expr= build(els)
+    o
+  end
+
+  def build_MatchExpression(o, op, a, b)
+    o.operator = op
+    build_BinaryExpression(o, a, b)
+  end
+
+  # Builds body :) from different kinds of input
+  # @overload f_build_body(nothing)
+  #   @param nothing [nil] unchanged, produces nil
+  # @overload f_build_body(array)
+  #   @param array [Array<Expression>] turns into a BlockExpression
+  # @overload f_build_body(expr)
+  #   @param expr [Expression] produces the given expression
+  # @overload f_build_body(obj)
+  #   @param obj [Object] produces the result of calling #build with body as argument
+  def f_build_body(body)
+    case body
+    when NilClass
+      nil
+    when Array
+      Puppet::Pops::Model::Factory.new(Model::BlockExpression, *body)
+    else
+      build(body)
+    end
+  end
+
+  def build_LambdaExpression(o, parameters, body)
+    parameters.each {|p| o.addParameters(build(p)) }
+    b = f_build_body(body)
+    o.body = to_ops(b) if b
+    o
+  end
+
+  def build_NamedDefinition(o, name, parameters, body)
+    parameters.each {|p| o.addParameters(build(p)) }
+    b = f_build_body(body)
+    o.body = b.current if b
+    o.name = name
+    o
+  end
+
+  # @param o [Model::NodeDefinition]
+  # @param hosts [Array<Expression>] host matches
+  # @param parent [Expression] parent node matcher
+  # @param body [Object] see {#f_build_body}
+  def build_NodeDefinition(o, hosts, parent, body)
+    hosts.each {|h| o.addHost_matches(build(h)) }
+    o.parent = build(parent) if parent # no nop here
+    b = f_build_body(body)
+    o.body = b.current if b
+    o
+  end
+
+  def build_Parameter(o, name, expr)
+    o.name = name
+    o.value = build(expr) if expr # don't build a nil/nop
+    o
+  end
+
+  def build_QualifiedReference(o, name)
+    o.value = name.to_s.downcase
+    o
+  end
+
+  def build_RelationshipExpression(o, op, a, b)
+    o.operator = op
+    build_BinaryExpression(o, a, b)
+  end
+
+  def build_ResourceExpression(o, type_name, bodies)
+    o.type_name = build(type_name)
+    bodies.each {|b| o.addBodies(build(b)) }
+    o
+  end
+
+  def build_RenderStringExpression(o, string)
+    o.value = string;
+    o
+  end
+
+  def build_ResourceBody(o, title_expression, attribute_operations)
+    o.title = build(title_expression)
+    attribute_operations.each {|ao| o.addOperations(build(ao)) }
+    o
+  end
+
+  def build_ResourceDefaultsExpression(o, type_ref, attribute_operations)
+    o.type_ref = build(type_ref)
+    attribute_operations.each {|ao| o.addOperations(build(ao)) }
+    o
+  end
+
+  def build_SelectorExpression(o, left, *selectors)
+    o.left_expr = to_ops(left)
+    selectors.each {|s| o.addSelectors(build(s)) }
+    o
+  end
+
+  # Builds a SubLocatedExpression - this wraps the expression in a sublocation configured
+  # from the given token
+  # A SubLocated holds its own locator that is used for subexpressions holding positions relative
+  # to what it describes.
+  #
+  def build_SubLocatedExpression(o, token, expression)
+    o.expr = build(expression)
+    o.offset = token.offset
+    o.length =  token.length
+    locator = token.locator
+    o.locator = locator
+    o.leading_line_count = locator.leading_line_count
+    o.leading_line_offset = locator.leading_line_offset
+    # Index is held in sublocator's parent locator - needed to be able to reconstruct
+    o.line_offsets = locator.locator.line_index
+    o
+  end
+
+  def build_SelectorEntry(o, matching, value)
+    o.matching_expr = build(matching)
+    o.value_expr = build(value)
+    o
+  end
+
+  def build_QueryExpression(o, expr)
+    ops = to_ops(expr)
+    o.expr = ops unless Puppet::Pops::Model::Factory.nop? ops
+    o
+  end
+
+  def build_UnaryExpression(o, expr)
+    ops = to_ops(expr)
+    o.expr = ops unless Puppet::Pops::Model::Factory.nop? ops
+    o
+  end
+
+  def build_Program(o, body, definitions, locator)
+    o.body = to_ops(body)
+    # non containment
+    definitions.each { |d| o.addDefinitions(d) }
+    o.source_ref = locator.file
+    o.source_text = locator.string
+    o.line_offsets = locator.line_index
+    o.locator = locator
+    o
+  end
+
+  def build_QualifiedName(o, name)
+    o.value = name.to_s
+    o
+  end
+
+  def build_TokenValue(o)
+    raise "Factory can not deal with a Lexer Token. Got token: #{o}. Probably caused by wrong index in grammar val[n]."
+  end
+
+  # Puppet::Pops::Model::Factory helpers
+  def f_build_unary(klazz, expr)
+    Puppet::Pops::Model::Factory.new(build(klazz.new, expr))
+  end
+
+  def f_build_binary_op(klazz, op, left, right)
+    Puppet::Pops::Model::Factory.new(build(klazz.new, op, left, right))
+  end
+
+  def f_build_binary(klazz, left, right)
+    Puppet::Pops::Model::Factory.new(build(klazz.new, left, right))
+  end
+
+  def f_build_vararg(klazz, left, *arg)
+    Puppet::Pops::Model::Factory.new(build(klazz.new, left, *arg))
+  end
+
+  def f_arithmetic(op, r)
+    f_build_binary_op(Model::ArithmeticExpression, op, current, r)
+  end
+
+  def f_comparison(op, r)
+    f_build_binary_op(Model::ComparisonExpression, op, current, r)
+  end
+
+  def f_match(op, r)
+    f_build_binary_op(Model::MatchExpression, op, current, r)
+  end
+
+  # Operator helpers
+  def in(r)     f_build_binary(Model::InExpression, current, r);          end
+
+  def or(r)     f_build_binary(Model::OrExpression, current, r);          end
+
+  def and(r)    f_build_binary(Model::AndExpression, current, r);         end
+
+  def not();    f_build_unary(Model::NotExpression, self);                end
+
+  def minus();  f_build_unary(Model::UnaryMinusExpression, self);         end
+
+  def unfold(); f_build_unary(Model::UnfoldExpression, self);             end
+
+  def text();   f_build_unary(Model::TextExpression, self);               end
+
+  def var();    f_build_unary(Model::VariableExpression, self);           end
+
+  def [](*r);   f_build_vararg(Model::AccessExpression, current, *r);     end
+
+  def dot r;    f_build_binary(Model::NamedAccessExpression, current, r); end
+
+  def + r;      f_arithmetic(:+, r);                                      end
+
+  def - r;      f_arithmetic(:-, r);                                      end
+
+  def / r;      f_arithmetic(:/, r);                                      end
+
+  def * r;      f_arithmetic(:*, r);                                      end
+
+  def % r;      f_arithmetic(:%, r);                                      end
+
+  def << r;     f_arithmetic(:<<, r);                                     end
+
+  def >> r;     f_arithmetic(:>>, r);                                     end
+
+  def < r;      f_comparison(:<, r);                                      end
+
+  def <= r;     f_comparison(:<=, r);                                     end
+
+  def > r;      f_comparison(:>, r);                                      end
+
+  def >= r;     f_comparison(:>=, r);                                     end
+
+  def == r;     f_comparison(:==, r);                                     end
+
+  def ne r;     f_comparison(:'!=', r);                                   end
+
+  def =~ r;     f_match(:'=~', r);                                        end
+
+  def mne r;    f_match(:'!~', r);                                        end
+
+  def paren();  f_build_unary(Model::ParenthesizedExpression, current);   end
+
+  def relop op, r
+    f_build_binary_op(Model::RelationshipExpression, op.to_sym, current, r)
+  end
+
+  def select *args
+    Puppet::Pops::Model::Factory.new(build(Model::SelectorExpression, current, *args))
+  end
+
+  # For CaseExpression, setting the default for an already build CaseExpression
+  def default r
+    current.addOptions(Puppet::Pops::Model::Factory.WHEN(:default, r).current)
+    self
+  end
+
+  def lambda=(lambda)
+    current.lambda = lambda.current
+    self
+  end
+
+  # Assignment =
+  def set(r)
+    f_build_binary_op(Model::AssignmentExpression, :'=', current, r)
+  end
+
+  # Assignment +=
+  def plus_set(r)
+    f_build_binary_op(Model::AssignmentExpression, :'+=', current, r)
+  end
+
+  # Assignment -=
+  def minus_set(r)
+    f_build_binary_op(Model::AssignmentExpression, :'-=', current, r)
+  end
+
+  def attributes(*args)
+    args.each {|a| current.addAttributes(build(a)) }
+    self
+  end
+
+  # Catch all delegation to current
+  def method_missing(meth, *args, &block)
+    if current.respond_to?(meth)
+      current.send(meth, *args, &block)
+    else
+      super
+    end
+  end
+
+  def respond_to?(meth, include_all=false)
+    current.respond_to?(meth, include_all) || super
+  end
+
+  def self.record_position(o, start_locatable, end_locateable)
+    new(o).record_position(start_locatable, end_locateable)
+  end
+
+  # Records the position (start -> end) and computes the resulting length.
+  #
+  def record_position(start_locatable, end_locatable)
+    from = start_locatable.is_a?(Puppet::Pops::Model::Factory) ? start_locatable.current : start_locatable
+    to   = end_locatable.is_a?(Puppet::Pops::Model::Factory) ? end_locatable.current  : end_locatable
+    to = from if to.nil? || to.offset.nil?
+    o = current
+    # record information directly in the Model::Positioned object
+    o.offset = from.offset
+    o.length ||= to.offset - from.offset + to.length
+    self
+  end
+
+  # @return [Puppet::Pops::Adapters::SourcePosAdapter] with location information
+  def loc()
+    Puppet::Pops::Adapters::SourcePosAdapter.adapt(current)
+  end
+
+  # Sets the form of the resource expression (:regular (the default), :virtual, or :exported).
+  # Produces true if the expression was a resource expression, false otherwise.
+  #
+  def self.set_resource_form(expr, form)
+    expr = expr.current if expr.is_a?(Puppet::Pops::Model::Factory)
+    # Note: Validation handles illegal combinations
+    return false unless expr.is_a?(Puppet::Pops::Model::AbstractResource)
+    expr.form = form
+    return true
+  end
+
+  # Returns symbolic information about an expected shape of a resource expression given the LHS of a resource expr.
+  #
+  # * `name { }` => `:resource`,  create a resource of the given type
+  # * `Name { }` => ':defaults`, set defaults for the referenced type
+  # * `Name[] { }` => `:override`, overrides instances referenced by LHS
+  # * _any other_ => ':error', all other are considered illegal
+  #
+  def self.resource_shape(expr)
+    expr = expr.current if expr.is_a?(Puppet::Pops::Model::Factory)
+    case expr
+    when Model::QualifiedName
+      :resource
+    when Model::QualifiedReference
+      :defaults
+    when Model::AccessExpression
+      # if Resource[e], then it is not resource specific
+      if expr.left_expr.is_a?(Model::QualifiedReference) && expr.left_expr.value == 'resource' && expr.keys.size == 1
+        :defaults
+      else
+        :override
+      end
+    when 'class'
+      :class
+    else
+      :error
+    end
+  end
+  # Factory starting points
+
+  def self.literal(o);                   new(o);                                                 end
+
+  def self.minus(o);                     new(o).minus;                                           end
+
+  def self.unfold(o);                    new(o).unfold;                                          end
+
+  def self.var(o);                       new(o).var;                                             end
+
+  def self.block(*args);                 new(Model::BlockExpression, *args);                     end
+
+  def self.string(*args);                new(Model::ConcatenatedString, *args);                  end
+
+  def self.text(o);                      new(o).text;                                            end
+
+  def self.IF(test_e,then_e,else_e);     new(Model::IfExpression, test_e, then_e, else_e);       end
+
+  def self.UNLESS(test_e,then_e,else_e); new(Model::UnlessExpression, test_e, then_e, else_e);   end
+
+  def self.CASE(test_e,*options);        new(Model::CaseExpression, test_e, *options);           end
+
+  def self.WHEN(values_list, block);     new(Model::CaseOption, values_list, block);             end
+
+  def self.MAP(match, value);            new(Model::SelectorEntry, match, value);                end
+
+  def self.TYPE(name, super_name=nil);   new(Model::CreateTypeExpression, name, super_name);     end
+
+  def self.ATTR(name, type_expr=nil);    new(Model::CreateAttributeExpression, name, type_expr); end
+
+  def self.ENUM(*args);                  new(Model::CreateEnumExpression, *args);                end
+
+  def self.KEY_ENTRY(key, val);          new(Model::KeyedEntry, key, val);                       end
+
+  def self.HASH(entries);                new(Model::LiteralHash, *entries);                      end
+
+  def self.HEREDOC(name, expr);          new(Model::HeredocExpression, name, expr);              end
+
+  def self.SUBLOCATE(token, expr)        new(Model::SubLocatedExpression, token, expr);          end
+
+  def self.LIST(entries);                new(Model::LiteralList, *entries);                      end
+
+  def self.PARAM(name, expr=nil);        new(Model::Parameter, name, expr);                      end
+
+  def self.NODE(hosts, parent, body);    new(Model::NodeDefinition, hosts, parent, body);        end
+
+
+  # Parameters
+
+  # Mark parameter as capturing the rest of arguments
+  def captures_rest()
+    current.captures_rest = true
+  end
+
+  # Set Expression that should evaluate to the parameter's type
+  def type_expr(o)
+    current.type_expr = to_ops(o)
+  end
+
+  # Creates a QualifiedName representation of o, unless o already represents a QualifiedName in which
+  # case it is returned.
+  #
+  def self.fqn(o)
+    o = o.current if o.is_a?(Puppet::Pops::Model::Factory)
+    o = new(Model::QualifiedName, o) unless o.is_a? Model::QualifiedName
+    o
+  end
+
+  # Creates a QualifiedName representation of o, unless o already represents a QualifiedName in which
+  # case it is returned.
+  #
+  def self.fqr(o)
+    o = o.current if o.is_a?(Puppet::Pops::Model::Factory)
+    o = new(Model::QualifiedReference, o) unless o.is_a? Model::QualifiedReference
+    o
+  end
+
+  def self.TEXT(expr)
+    new(Model::TextExpression, new(expr).interpolate)
+  end
+
+  # TODO_EPP
+  def self.RENDER_STRING(o)
+    new(Model::RenderStringExpression, o)
+  end
+
+  def self.RENDER_EXPR(expr)
+    new(Model::RenderExpression, expr)
+  end
+
+  def self.EPP(parameters, body)
+    if parameters.nil?
+      params = []
+      parameters_specified = false
+    else
+      params = parameters
+      parameters_specified = true
+    end
+    LAMBDA(params, new(Model::EppExpression, parameters_specified, body))
+  end
+
+  def self.RESERVED(name, future=false)
+    new(Model::ReservedWord, name, future)
+  end
+
+  # TODO: This is the same a fqn factory method, don't know if callers to fqn and QNAME can live with the
+  # same result or not yet - refactor into one method when decided.
+  #
+  def self.QNAME(name)
+    new(Model::QualifiedName, name)
+  end
+
+  def self.NUMBER(name_or_numeric)
+    if n_radix = Puppet::Pops::Utils.to_n_with_radix(name_or_numeric)
+      val, radix = n_radix
+      if val.is_a?(Float)
+        new(Model::LiteralFloat, val)
+      else
+        new(Model::LiteralInteger, val, radix)
+      end
+    else
+      # Bad number should already have been caught by lexer - this should never happen
+      raise ArgumentError, "Internal Error, NUMBER token does not contain a valid number, #{name_or_numeric}"
+    end
+  end
+
+  # Convert input string to either a qualified name, a LiteralInteger with radix, or a LiteralFloat
+  #
+  def self.QNAME_OR_NUMBER(name)
+    if n_radix = Puppet::Pops::Utils.to_n_with_radix(name)
+      val, radix = n_radix
+      if val.is_a?(Float)
+        new(Model::LiteralFloat, val)
+      else
+        new(Model::LiteralInteger, val, radix)
+      end
+    else
+      new(Model::QualifiedName, name)
+    end
+  end
+
+  def self.QREF(name)
+    new(Model::QualifiedReference, name)
+  end
+
+  def self.VIRTUAL_QUERY(query_expr)
+    new(Model::VirtualQuery, query_expr)
+  end
+
+  def self.EXPORTED_QUERY(query_expr)
+    new(Model::ExportedQuery, query_expr)
+  end
+
+  def self.ATTRIBUTE_OP(name, op, expr)
+    new(Model::AttributeOperation, name, op, expr)
+  end
+
+  def self.ATTRIBUTES_OP(expr)
+    new(Model::AttributesOperation, expr)
+  end
+
+  def self.CALL_NAMED(name, rval_required, argument_list)
+    unless name.kind_of?(Model::PopsObject)
+      name = Puppet::Pops::Model::Factory.fqn(name) unless name.is_a?(Puppet::Pops::Model::Factory)
+    end
+    new(Model::CallNamedFunctionExpression, name, rval_required, *argument_list)
+  end
+
+  def self.CALL_METHOD(functor, argument_list)
+    new(Model::CallMethodExpression, functor, true, nil, *argument_list)
+  end
+
+  def self.COLLECT(type_expr, query_expr, attribute_operations)
+    new(Model::CollectExpression, type_expr, query_expr, attribute_operations)
+  end
+
+  def self.NAMED_ACCESS(type_name, bodies)
+    new(Model::NamedAccessExpression, type_name, bodies)
+  end
+
+  def self.RESOURCE(type_name, bodies)
+    new(Model::ResourceExpression, type_name, bodies)
+  end
+
+  def self.RESOURCE_DEFAULTS(type_name, attribute_operations)
+    new(Model::ResourceDefaultsExpression, type_name, attribute_operations)
+  end
+
+  def self.RESOURCE_OVERRIDE(resource_ref, attribute_operations)
+    new(Model::ResourceOverrideExpression, resource_ref, attribute_operations)
+  end
+
+  def self.RESOURCE_BODY(resource_title, attribute_operations)
+    new(Model::ResourceBody, resource_title, attribute_operations)
+  end
+
+  def self.PROGRAM(body, definitions, locator)
+    new(Model::Program, body, definitions, locator)
+  end
+
+  # Builds a BlockExpression if args size > 1, else the single expression/value in args
+  def self.block_or_expression(*args)
+    if args.size > 1
+      new(Model::BlockExpression, *args)
+    else
+      new(args[0])
+    end
+  end
+
+  def self.HOSTCLASS(name, parameters, parent, body)
+    new(Model::HostClassDefinition, name, parameters, parent, body)
+  end
+
+  def self.DEFINITION(name, parameters, body)
+    new(Model::ResourceTypeDefinition, name, parameters, body)
+  end
+
+  def self.LAMBDA(parameters, body)
+    new(Model::LambdaExpression, parameters, body)
+  end
+
+  def self.nop? o
+    o.nil? || o.is_a?(Puppet::Pops::Model::Nop)
+  end
+
+  STATEMENT_CALLS = {
+    'require' => true,
+    'realize' => true,
+    'include' => true,
+    'contain' => true,
+    'tag'     => true,
+
+    'debug'   => true,
+    'info'    => true,
+    'notice'  => true,
+    'warning' => true,
+    'err'     => true,
+
+    'fail'    => true,
+    'import'  => true  # discontinued, but transform it to make it call error reporting function
+  }
+  # Returns true if the given name is a "statement keyword" (require, include, contain,
+  # error, notice, info, debug
+  #
+  def name_is_statement(name)
+    STATEMENT_CALLS[name]
+  end
+
+  class ArgsToNonCallError < RuntimeError
+    attr_reader :args, :name_expr
+    def initialize(args, name_expr)
+      @args = args
+      @name_expr = name_expr
+    end
+  end
+
+  # Transforms an array of expressions containing literal name expressions to calls if followed by an
+  # expression, or expression list.
+  #
+  def self.transform_calls(expressions)
+    expressions.reduce([]) do |memo, expr|
+      expr = expr.current if expr.is_a?(Puppet::Pops::Model::Factory)
+      name = memo[-1]
+      if name.is_a?(Model::QualifiedName) && STATEMENT_CALLS[name.value]
+        if expr.is_a?(Array)
+          expr = expr.reject {|e| e.is_a?(Puppet::Pops::Parser::LexerSupport::TokenValue) }
+        else
+          expr = [expr]
+        end
+        the_call = Puppet::Pops::Model::Factory.CALL_NAMED(name, false, expr)
+        # last positioned is last arg if there are several
+        record_position(the_call, name, expr.is_a?(Array) ? expr[-1]  : expr)
+        memo[-1] = the_call
+        if expr.is_a?(Model::CallNamedFunctionExpression)
+          # Patch statement function call to expression style
+          # This is needed because it is first parsed as a "statement" and the requirement changes as it becomes
+          # an argument to the name to call transform above.
+          expr.rval_required = true
+        end
+      elsif expr.is_a?(Array)
+        raise ArgsToNonCallError.new(expr, name)
+      else
+        memo << expr
+        if expr.is_a?(Model::CallNamedFunctionExpression)
+          # Patch rvalue expression function call to statement style.
+          # This is not really required but done to be AST model compliant
+          expr.rval_required = false
+        end
+      end
+      memo
+    end
+
+  end
+
+  # Transforms a left expression followed by an untitled resource (in the form of attribute_operations)
+  # @param left [Factory, Expression] the lhs followed what may be a hash
+  def self.transform_resource_wo_title(left, attribute_ops)
+    # Returning nil means accepting the given as a potential resource expression
+    return nil unless attribute_ops.is_a? Array
+    return nil unless left.current.is_a?(Puppet::Pops::Model::QualifiedName)
+    keyed_entries = attribute_ops.map do |ao|
+      return nil if ao.operator == :'+>'
+      KEY_ENTRY(ao.attribute_name, ao.value_expr)
+    end
+    result = block_or_expression(*transform_calls([left, HASH(keyed_entries)]))
+    result
+  end
+
+
+  # Building model equivalences of Ruby objects
+  # Allows passing regular ruby objects to the factory to produce instructions
+  # that when evaluated produce the same thing.
+
+  def build_String(o)
+    x = Model::LiteralString.new
+    x.value = o;
+    x
+  end
+
+  def build_NilClass(o)
+    x = Model::Nop.new
+    x
+  end
+
+  def build_TrueClass(o)
+    x = Model::LiteralBoolean.new
+    x.value = o
+    x
+  end
+
+  def build_FalseClass(o)
+    x = Model::LiteralBoolean.new
+    x.value = o
+    x
+  end
+
+  def build_Fixnum(o)
+    x = Model::LiteralInteger.new
+    x.value = o;
+    x
+  end
+
+  def build_Float(o)
+    x = Model::LiteralFloat.new
+    x.value = o;
+    x
+  end
+
+  def build_Regexp(o)
+    x = Model::LiteralRegularExpression.new
+    x.value = o;
+    x
+  end
+
+  def build_EppExpression(o, parameters_specified, body)
+    o.parameters_specified = parameters_specified
+    b = f_build_body(body)
+    o.body = b.current if b
+    o
+  end
+
+  # If building a factory, simply unwrap the model oject contained in the factory.
+  def build_Factory(o)
+    o.current
+  end
+
+  # Creates a String literal, unless the symbol is one of the special :undef, or :default
+  # which instead creates a LiterlUndef, or a LiteralDefault.
+  # Supports :undef because nil creates a no-op instruction.
+  def build_Symbol(o)
+    case o
+    when :undef
+      Model::LiteralUndef.new
+    when :default
+      Model::LiteralDefault.new
+    else
+      build_String(o.to_s)
+    end
+  end
+
+  # Creates a LiteralList instruction from an Array, where the entries are built.
+  def build_Array(o)
+    x = Model::LiteralList.new
+    o.each { |v| x.addValues(build(v)) }
+    x
+  end
+
+  # Create a LiteralHash instruction from a hash, where keys and values are built
+  # The hash entries are added in sorted order based on key.to_s
+  #
+  def build_Hash(o)
+    x = Model::LiteralHash.new
+    (o.sort_by {|k,v| k.to_s}).each {|k,v| x.addEntries(build(Model::KeyedEntry.new, k, v)) }
+    x
+  end
+
+  # @param rval_required [Boolean] if the call must produce a value
+  def build_CallExpression(o, functor, rval_required, *args)
+    o.functor_expr = to_ops(functor)
+    o.rval_required = rval_required
+    args.each {|x| o.addArguments(to_ops(x)) }
+    o
+  end
+
+  def build_CallMethodExpression(o, functor, rval_required, lambda, *args)
+    build_CallExpression(o, functor, rval_required, *args)
+    o.lambda = lambda
+    o
+  end
+
+  def build_CaseExpression(o, test, *args)
+    o.test = build(test)
+    args.each {|opt| o.addOptions(build(opt)) }
+    o
+  end
+
+  def build_CaseOption(o, value_list, then_expr)
+    value_list = [value_list] unless value_list.is_a? Array
+    value_list.each { |v| o.addValues(build(v)) }
+    b = f_build_body(then_expr)
+    o.then_expr = to_ops(b) if b
+    o
+  end
+
+  # Build a Class by creating an instance of it, and then calling build on the created instance
+  # with the given arguments
+  def build_Class(o, *args)
+    build(o.new(), *args)
+  end
+
+  def interpolate_Factory(o)
+    interpolate(o.current)
+  end
+
+  def interpolate_LiteralInteger(o)
+    # convert number to a variable
+    self.class.new(o).var
+  end
+
+  def interpolate_Object(o)
+    o
+  end
+
+  def interpolate_QualifiedName(o)
+    self.class.new(o).var
+  end
+
+  # rewrite left expression to variable if it is name, number, and recurse if it is an access expression
+  # this is for interpolation support in new lexer (${NAME}, ${NAME[}}, ${NUMBER}, ${NUMBER[]} - all
+  # other expressions requires variables to be preceded with $
+  #
+  def interpolate_AccessExpression(o)
+    if is_interop_rewriteable?(o.left_expr)
+      o.left_expr = to_ops(self.class.new(o.left_expr).interpolate)
+    end
+    o
+  end
+
+  def interpolate_NamedAccessExpression(o)
+    if is_interop_rewriteable?(o.left_expr)
+        o.left_expr = to_ops(self.class.new(o.left_expr).interpolate)
+    end
+    o
+  end
+
+  # Rewrite method calls on the form ${x.each ...} to ${$x.each}
+  def interpolate_CallMethodExpression(o)
+    if is_interop_rewriteable?(o.functor_expr)
+      o.functor_expr = to_ops(self.class.new(o.functor_expr).interpolate)
+    end
+    o
+  end
+
+  def is_interop_rewriteable?(o)
+    case o
+    when Model::AccessExpression, Model::QualifiedName,
+      Model::NamedAccessExpression, Model::CallMethodExpression
+      true
+    when Model::LiteralInteger
+      # Only decimal integers can represent variables, else it is a number
+      o.radix == 10
+    else
+      false
+    end
+  end
+
+  # Checks if the object is already a model object, or build it
+  def to_ops(o, *args)
+    case o
+    when Model::PopsObject
+      o
+    when Puppet::Pops::Model::Factory
+      o.current
+    else
+      build(o, *args)
+    end
+  end
+
+  def self.concat(*args)
+    new(args.map do |e|
+      e = e.current if e.is_a?(self)
+      case e
+      when Model::LiteralString
+        e.value
+      when String
+        e
+      else
+        raise ArgumentError, "can only concatenate strings, got #{e.class}"
+      end
+    end.join(''))
+  end
+
+  def to_s
+    Puppet::Pops::Model::ModelTreeDumper.new.dump(self)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/model.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/model.rb
new file mode 100644
index 0000000..9e2a079
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/model.rb
@@ -0,0 +1,114 @@
+#
+# The Puppet Pops Metamodel Implementation
+#
+# The Puppet Pops Metamodel consists of two parts; the metamodel expressed with RGen in model_meta.rb,
+# and this file which mixes in implementation details.
+#
+
+require 'rgen/metamodel_builder'
+require 'rgen/ecore/ecore'
+require 'rgen/ecore/ecore_ext'
+require 'rgen/ecore/ecore_to_ruby'
+
+module Puppet::Pops
+  require 'puppet/pops/model/model_meta'
+
+  # TODO: See PUP-2978 for possible performance optimization
+
+  # Mix in implementation into the generated code
+  module Model
+
+    class PopsObject
+      include Puppet::Pops::Visitable
+      include Puppet::Pops::Adaptable
+      include Puppet::Pops::Containment
+    end
+
+    class LocatableExpression
+      module ClassModule
+        # Go through the gymnastics of making either value or pattern settable
+        # with synchronization to the other form. A derived value cannot be serialized
+        # and we want to serialize the pattern. When recreating the object we need to
+        # recreate it from the pattern string.
+        # The below sets both values if one is changed.
+        #
+        def locator
+          unless result = getLocator
+            setLocator(result = Puppet::Pops::Parser::Locator.locator(source_text, source_ref(), line_offsets))
+          end
+          result
+        end
+      end
+    end
+
+    class SubLocatedExpression
+      module ClassModule
+        def locator
+          unless result = getLocator
+            # Adapt myself to get the Locator for me
+            adapter = Puppet::Pops::Adapters::SourcePosAdapter.adapt(self)
+            # Get the program (root), and deal with case when not contained in a program
+            program = eAllContainers.find {|c| c.is_a?(Program) }
+            source_ref = program.nil? ? '' : program.source_ref
+
+            # An outer locator is needed since SubLocator only deals with offsets. This outer locator
+            # has 0,0 as origin.
+            outer_locator = Puppet::Pops::Parser::Locator.locator(adpater.extract_text, source_ref, line_offsets)
+
+            # Create a sublocator that describes an offset from the outer
+            # NOTE: the offset of self is the same as the sublocator's leading_offset
+            result = Puppet::Pops::Parser::Locator::SubLocator.new(outer_locator,
+              leading_line_count, offset, leading_line_offset)
+            setLocator(result)
+          end
+          result
+        end
+      end
+    end
+
+    class LiteralRegularExpression
+      module ClassModule
+        # Go through the gymnastics of making either value or pattern settable
+        # with synchronization to the other form. A derived value cannot be serialized
+        # and we want to serialize the pattern. When recreating the object we need to
+        # recreate it from the pattern string.
+        # The below sets both values if one is changed.
+        #
+        def value= regexp
+          setValue regexp
+          setPattern regexp.to_s
+        end
+
+        def pattern= regexp_string
+          setPattern regexp_string
+          setValue Regexp.new(regexp_string)
+        end
+      end
+    end
+
+    class AbstractResource
+      module ClassModule
+        def virtual_derived
+          form == :virtual || form == :exported
+        end
+
+        def exported_derived
+          form == :exported
+        end
+      end
+    end
+
+    class Program < PopsObject
+      module ClassModule
+        def locator
+          unless result = getLocator
+            setLocator(result = Puppet::Pops::Parser::Locator.locator(source_text, source_ref(), line_offsets))
+          end
+          result
+        end
+      end
+    end
+
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/model_label_provider.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/model_label_provider.rb
new file mode 100644
index 0000000..63c24d4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/model_label_provider.rb
@@ -0,0 +1,106 @@
+# A provider of labels for model object, producing a human name for the model object.
+# As an example, if object is an ArithmeticExpression with operator +, `#a_an(o)` produces "a '+' Expression",
+# #the(o) produces "the + Expression", and #label produces "+ Expression".
+#
+class Puppet::Pops::Model::ModelLabelProvider < Puppet::Pops::LabelProvider
+  def initialize
+    @@label_visitor ||= Puppet::Pops::Visitor.new(self,"label",0,0)
+  end
+
+  # Produces a label for the given objects type/operator without article.
+  # If a Class is given, its name is used as label
+  #
+  def label o
+    @@label_visitor.visit(o)
+  end
+
+  def label_Factory o                     ; label(o.current)                    end
+  def label_Array o                       ; "Array"                             end
+  def label_LiteralInteger o              ; "Literal Integer"                   end
+  def label_LiteralFloat o                ; "Literal Float"                     end
+  def label_ArithmeticExpression o        ; "'#{o.operator}' expression"        end
+  def label_AccessExpression o            ; "'[]' expression"                   end
+  def label_MatchExpression o             ; "'#{o.operator}' expression"        end
+  def label_CollectExpression o           ; label(o.query)                      end
+  def label_EppExpression o               ; "Epp Template"                      end
+  def label_ExportedQuery o               ; "Exported Query"                    end
+  def label_VirtualQuery o                ; "Virtual Query"                     end
+  def label_QueryExpression o             ; "Collect Query"                     end
+  def label_ComparisonExpression o        ; "'#{o.operator}' expression"        end
+  def label_AndExpression o               ; "'and' expression"                  end
+  def label_OrExpression o                ; "'or' expression"                   end
+  def label_InExpression o                ; "'in' expression"                   end
+  def label_AssignmentExpression o        ; "'#{o.operator}' expression"        end
+  def label_AttributeOperation o          ; "'#{o.operator}' expression"        end
+  def label_LiteralList o                 ; "Array Expression"                  end
+  def label_LiteralHash o                 ; "Hash Expression"                   end
+  def label_KeyedEntry o                  ; "Hash Entry"                        end
+  def label_LiteralBoolean o              ; "Boolean"                           end
+  def label_TrueClass o                   ; "Boolean"                           end
+  def label_FalseClass o                  ; "Boolean"                           end
+  def label_LiteralString o               ; "String"                            end
+  def label_LambdaExpression o            ; "Lambda"                            end
+  def label_LiteralDefault o              ; "'default' expression"              end
+  def label_LiteralUndef o                ; "'undef' expression"                end
+  def label_LiteralRegularExpression o    ; "Regular Expression"                end
+  def label_Nop o                         ; "Nop Expression"                    end
+  def label_NamedAccessExpression o       ; "'.' expression"                    end
+  def label_NilClass o                    ; "Undef Value"                       end
+  def label_NotExpression o               ; "'not' expression"                  end
+  def label_VariableExpression o          ; "Variable"                          end
+  def label_TextExpression o              ; "Expression in Interpolated String" end
+  def label_UnaryMinusExpression o        ; "Unary Minus"                       end
+  def label_UnfoldExpression o            ; "Unfold"                            end
+  def label_BlockExpression o             ; "Block Expression"                  end
+  def label_ConcatenatedString o          ; "Double Quoted String"              end
+  def label_HeredocExpression o           ; "'@(#{o.syntax})' expression"       end
+  def label_HostClassDefinition o         ; "Host Class Definition"             end
+  def label_NodeDefinition o              ; "Node Definition"                   end
+  def label_ResourceTypeDefinition o      ; "'define' expression"               end
+  def label_ResourceOverrideExpression o  ; "Resource Override"                 end
+  def label_Parameter o                   ; "Parameter Definition"              end
+  def label_ParenthesizedExpression o     ; "Parenthesized Expression"          end
+  def label_IfExpression o                ; "'if' statement"                    end
+  def label_UnlessExpression o            ; "'unless' Statement"                end
+  def label_CallNamedFunctionExpression o ; "Function Call"                     end
+  def label_CallMethodExpression o        ; "Method call"                       end
+  def label_CaseExpression o              ; "'case' statement"                  end
+  def label_CaseOption o                  ; "Case Option"                       end
+  def label_RenderStringExpression o      ; "Epp Text"                          end
+  def label_RenderExpression o            ; "Epp Interpolated Expression"       end
+  def label_RelationshipExpression o      ; "'#{o.operator}' expression"        end
+  def label_ResourceBody o                ; "Resource Instance Definition"      end
+  def label_ResourceDefaultsExpression o  ; "Resource Defaults Expression"      end
+  def label_ResourceExpression o          ; "Resource Statement"                end
+  def label_SelectorExpression o          ; "Selector Expression"               end
+  def label_SelectorEntry o               ; "Selector Option"                   end
+  def label_Integer o                     ; "Integer"                           end
+  def label_Fixnum o                      ; "Integer"                           end
+  def label_Bignum o                      ; "Integer"                           end
+  def label_Float o                       ; "Float"                             end
+  def label_String o                      ; "String"                            end
+  def label_Regexp o                      ; "Regexp"                            end
+  def label_Object o                      ; "Object"                            end
+  def label_Hash o                        ; "Hash"                              end
+  def label_QualifiedName o               ; "Name"                              end
+  def label_QualifiedReference o          ; "Type-Name"                         end
+  def label_PAnyType o                    ; "#{Puppet::Pops::Types::TypeCalculator.string(o)}-Type" end
+  def label_ReservedWord o                ; "Reserved Word '#{o.word}'"         end
+
+  def label_PResourceType o
+    if o.title
+      "#{Puppet::Pops::Types::TypeCalculator.string(o)} Resource-Reference"
+    else
+      "#{Puppet::Pops::Types::TypeCalculator.string(o)}-Type"
+    end
+  end
+
+  def label_Class o
+    if o <= Puppet::Pops::Types::PAnyType
+      simple_name = o.name.split('::').last
+      simple_name[1..-5] + "-Type"
+    else
+      o.name
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/model_meta.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/model_meta.rb
new file mode 100644
index 0000000..3b1d408
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/model_meta.rb
@@ -0,0 +1,579 @@
+#
+# The Puppet Pops Metamodel
+#
+# This module contains a formal description of the Puppet Pops (*P*uppet *OP*eration instruction*S*).
+# It describes a Metamodel containing DSL instructions, a description of PuppetType and related
+# classes needed to evaluate puppet logic.
+# The metamodel resembles the existing AST model, but it is a semantic model of instructions and
+# the types that they operate on rather than an Abstract Syntax Tree, although closely related.
+#
+# The metamodel is anemic (has no behavior) except basic datatype and type
+# assertions and reference/containment assertions.
+# The metamodel is also a generalized description of the Puppet DSL to enable the
+# same metamodel to be used to express Puppet DSL models (instances) with different semantics as
+# the language evolves.
+#
+# The metamodel is concretized by a validator for a particular version of
+# the Puppet DSL language.
+#
+# This metamodel is expressed using RGen.
+#
+
+require 'rgen/metamodel_builder'
+
+module Puppet::Pops::Model
+  extend RGen::MetamodelBuilder::ModuleExtension
+
+  # A base class for modeled objects that makes them Visitable, and Adaptable.
+  #
+  class PopsObject < RGen::MetamodelBuilder::MMBase
+    abstract
+  end
+
+  # A Positioned object has an offset measured in an opaque unit (representing characters) from the start
+  # of a source text (starting
+  # from 0), and a length measured in the same opaque unit. The resolution of the opaque unit requires the
+  # aid of a Locator instance that knows about the measure. This information is stored in the model's
+  # root node - a Program.
+  #
+  # The offset and length are optional if the source of the model is not from parsed text.
+  #
+  class Positioned < PopsObject
+    abstract
+    has_attr 'offset', Integer
+    has_attr 'length', Integer
+  end
+
+  # @abstract base class for expressions
+  class Expression < Positioned
+    abstract
+  end
+
+  # A Nop - the "no op" expression.
+  # @note not really needed since the evaluator can evaluate nil with the meaning of NoOp
+  # @todo deprecate? May be useful if there is the need to differentiate between nil and Nop when transforming model.
+  #
+  class Nop < Expression
+  end
+
+  # A binary expression is abstract and has a left and a right expression. The order of evaluation
+  # and semantics are determined by the concrete subclass.
+  #
+  class BinaryExpression < Expression
+    abstract
+    #
+    # @!attribute [rw] left_expr
+    #   @return [Expression]
+    contains_one_uni 'left_expr', Expression, :lowerBound => 1
+    contains_one_uni 'right_expr', Expression, :lowerBound => 1
+  end
+
+  # An unary expression is abstract and contains one expression. The semantics are determined by
+  # a concrete subclass.
+  #
+  class UnaryExpression < Expression
+    abstract
+    contains_one_uni 'expr', Expression, :lowerBound => 1
+  end
+
+  # A class that simply evaluates to the contained expression.
+  # It is of value in order to preserve user entered parentheses in transformations, and
+  # transformations from model to source.
+  #
+  class ParenthesizedExpression < UnaryExpression; end
+
+  # A boolean not expression, reversing the truth of the unary expr.
+  #
+  class NotExpression < UnaryExpression; end
+
+  # An arithmetic expression reversing the polarity of the numeric unary expr.
+  #
+  class UnaryMinusExpression < UnaryExpression; end
+
+  # Unfolds an array (a.k.a 'splat')
+  class UnfoldExpression < UnaryExpression; end
+
+  OpAssignment = RGen::MetamodelBuilder::DataTypes::Enum.new(
+    :literals => [:'=', :'+=', :'-='],
+    :name => 'OpAssignment')
+
+  # An assignment expression assigns a value to the lval() of the left_expr.
+  #
+  class AssignmentExpression < BinaryExpression
+    has_attr 'operator', OpAssignment, :lowerBound => 1
+  end
+
+  OpArithmetic = RGen::MetamodelBuilder::DataTypes::Enum.new(
+    :literals => [:'+', :'-', :'*', :'%', :'/', :'<<', :'>>' ],
+    :name => 'OpArithmetic')
+
+  # An arithmetic expression applies an arithmetic operator on left and right expressions.
+  #
+  class ArithmeticExpression < BinaryExpression
+    has_attr 'operator', OpArithmetic, :lowerBound => 1
+  end
+
+  OpRelationship = RGen::MetamodelBuilder::DataTypes::Enum.new(
+    :literals => [:'->', :'<-', :'~>', :'<~'],
+    :name => 'OpRelationship')
+
+  # A relationship expression associates the left and right expressions
+  #
+  class RelationshipExpression < BinaryExpression
+    has_attr 'operator', OpRelationship, :lowerBound => 1
+  end
+
+  # A binary expression, that accesses the value denoted by right in left. i.e. typically
+  # expressed concretely in a language as left[right].
+  #
+  class AccessExpression < Expression
+    contains_one_uni 'left_expr', Expression, :lowerBound => 1
+    contains_many_uni 'keys', Expression, :lowerBound => 1
+  end
+
+  OpComparison = RGen::MetamodelBuilder::DataTypes::Enum.new(
+    :literals => [:'==', :'!=', :'<', :'>', :'<=', :'>=' ],
+    :name => 'OpComparison')
+
+  # A comparison expression compares left and right using a comparison operator.
+  #
+  class ComparisonExpression < BinaryExpression
+    has_attr 'operator', OpComparison, :lowerBound => 1
+  end
+
+  OpMatch = RGen::MetamodelBuilder::DataTypes::Enum.new(
+    :literals => [:'!~', :'=~'],
+    :name => 'OpMatch')
+
+  # A match expression matches left and right using a matching operator.
+  #
+  class MatchExpression < BinaryExpression
+    has_attr 'operator', OpMatch, :lowerBound => 1
+  end
+
+  # An 'in' expression checks if left is 'in' right
+  #
+  class InExpression < BinaryExpression; end
+
+  # A boolean expression applies a logical connective operator (and, or) to left and right expressions.
+  #
+  class BooleanExpression < BinaryExpression
+    abstract
+  end
+
+  # An and expression applies the logical connective operator and to left and right expression
+  # and does not evaluate the right expression if the left expression is false.
+  #
+  class AndExpression < BooleanExpression; end
+
+  # An or expression applies the logical connective operator or to the left and right expression
+  # and does not evaluate the right expression if the left expression is true
+  #
+  class OrExpression < BooleanExpression; end
+
+  # A literal list / array containing 0:M expressions.
+  #
+  class LiteralList < Expression
+    contains_many_uni 'values', Expression
+  end
+
+  # A Keyed entry has a key and a value expression. It is typically used as an entry in a Hash.
+  #
+  class KeyedEntry < Positioned
+    contains_one_uni 'key', Expression, :lowerBound => 1
+    contains_one_uni 'value', Expression, :lowerBound => 1
+  end
+
+  # A literal hash is a collection of KeyedEntry objects
+  #
+  class LiteralHash < Expression
+    contains_many_uni 'entries', KeyedEntry
+  end
+
+  # A block contains a list of expressions
+  #
+  class BlockExpression < Expression
+    contains_many_uni 'statements', Expression
+  end
+
+  # A case option entry in a CaseStatement
+  #
+  class CaseOption < Expression
+    contains_many_uni 'values', Expression, :lowerBound => 1
+    contains_one_uni 'then_expr', Expression, :lowerBound => 1
+  end
+
+  # A case expression has a test, a list of options (multi values => block map).
+  # One CaseOption may contain a LiteralDefault as value. This option will be picked if nothing
+  # else matched.
+  #
+  class CaseExpression < Expression
+    contains_one_uni 'test', Expression, :lowerBound => 1
+    contains_many_uni 'options', CaseOption
+  end
+
+  # A query expression is an expression that is applied to some collection.
+  # The contained optional expression may contain different types of relational expressions depending
+  # on what the query is applied to.
+  #
+  class QueryExpression < Expression
+    abstract
+    contains_one_uni 'expr', Expression, :lowerBound => 0
+  end
+
+  # An exported query is a special form of query that searches for exported objects.
+  #
+  class ExportedQuery < QueryExpression
+  end
+
+  # A virtual query is a special form of query that searches for virtual objects.
+  #
+  class VirtualQuery < QueryExpression
+  end
+
+  OpAttribute = RGen::MetamodelBuilder::DataTypes::Enum.new(
+    :literals => [:'=>', :'+>', ],
+    :name => 'OpAttribute')
+
+  class AbstractAttributeOperation < Positioned
+  end
+
+  # An attribute operation sets or appends a value to a named attribute.
+  #
+  class AttributeOperation < AbstractAttributeOperation
+    has_attr 'attribute_name', String, :lowerBound => 1
+    has_attr 'operator', OpAttribute, :lowerBound => 1
+    contains_one_uni 'value_expr', Expression, :lowerBound => 1
+  end
+
+  # An attribute operation containing an expression that must evaluate to a Hash
+  #
+  class AttributesOperation < AbstractAttributeOperation
+    contains_one_uni 'expr', Expression, :lowerBound => 1
+  end
+
+  # An object that collects stored objects from the central cache and returns
+  # them to the current host. Operations may optionally be applied.
+  #
+  class CollectExpression < Expression
+    contains_one_uni 'type_expr', Expression, :lowerBound => 1
+    contains_one_uni 'query', QueryExpression, :lowerBound => 1
+    contains_many_uni 'operations', AbstractAttributeOperation
+  end
+
+  class Parameter < Positioned
+    has_attr 'name', String, :lowerBound => 1
+    contains_one_uni 'value', Expression
+    contains_one_uni 'type_expr', Expression, :lowerBound => 0
+    has_attr 'captures_rest', Boolean
+  end
+
+  # Abstract base class for definitions.
+  #
+  class Definition < Expression
+    abstract
+  end
+
+  # Abstract base class for named and parameterized definitions.
+  class NamedDefinition < Definition
+    abstract
+    has_attr 'name', String, :lowerBound => 1
+    contains_many_uni 'parameters', Parameter
+    contains_one_uni 'body', Expression
+  end
+
+  # A resource type definition (a 'define' in the DSL).
+  #
+  class ResourceTypeDefinition < NamedDefinition
+  end
+
+  # A node definition matches hosts using Strings, or Regular expressions. It may inherit from
+  # a parent node (also using a String or Regular expression).
+  #
+  class NodeDefinition < Definition
+    contains_one_uni 'parent', Expression
+    contains_many_uni 'host_matches', Expression, :lowerBound => 1
+    contains_one_uni 'body', Expression
+  end
+
+  class LocatableExpression < Expression
+    has_many_attr 'line_offsets', Integer
+    has_attr 'locator', Object, :lowerBound => 1, :transient => true
+  end
+
+  # Contains one expression which has offsets reported virtually (offset against the Program's
+  # overall locator).
+  #
+  class SubLocatedExpression < Expression
+    contains_one_uni 'expr', Expression, :lowerBound => 1
+
+    # line offset index for contained expressions
+    has_many_attr 'line_offsets', Integer
+
+    # Number of preceding lines (before the line_offsets)
+    has_attr 'leading_line_count', Integer
+
+    # The offset of the leading source line (i.e. size of "left margin").
+    has_attr 'leading_line_offset', Integer
+
+    # The locator for the sub-locatable's children (not for the sublocator itself)
+    # The locator is not serialized and is recreated on demand from the indexing information
+    # in self.
+    #
+    has_attr 'locator', Object, :lowerBound => 1, :transient => true
+  end
+
+  # A heredoc is a wrapper around a LiteralString or a ConcatenatedStringExpression with a specification
+  # of syntax. The expectation is that "syntax" has meaning to a validator. A syntax of nil or '' means
+  # "unspecified syntax".
+  #
+  class HeredocExpression < Expression
+    has_attr 'syntax', String
+    contains_one_uni 'text_expr', Expression, :lowerBound => 1
+  end
+
+  # A class definition
+  #
+  class HostClassDefinition < NamedDefinition
+    has_attr 'parent_class', String
+  end
+
+  # i.e {|parameters| body }
+  class LambdaExpression < Expression
+    contains_many_uni 'parameters', Parameter
+    contains_one_uni 'body', Expression
+  end
+
+  # If expression. If test is true, the then_expr part should be evaluated, else the (optional)
+  # else_expr. An 'elsif' is simply an else_expr = IfExpression, and 'else' is simply else == Block.
+  # a 'then' is typically a Block.
+  #
+  class IfExpression < Expression
+    contains_one_uni 'test', Expression, :lowerBound => 1
+    contains_one_uni 'then_expr', Expression, :lowerBound => 1
+    contains_one_uni 'else_expr', Expression
+  end
+
+  # An if expression with boolean reversed test.
+  #
+  class UnlessExpression < IfExpression
+  end
+
+  # An abstract call.
+  #
+  class CallExpression < Expression
+    abstract
+    # A bit of a crutch; functions are either procedures (void return) or has an rvalue
+    # this flag tells the evaluator that it is a failure to call a function that is void/procedure
+    # where a value is expected.
+    #
+    has_attr 'rval_required', Boolean, :defaultValueLiteral => "false"
+    contains_one_uni 'functor_expr', Expression, :lowerBound => 1
+    contains_many_uni 'arguments', Expression
+    contains_one_uni 'lambda', Expression
+  end
+
+  # A function call where the functor_expr should evaluate to something callable.
+  #
+  class CallFunctionExpression < CallExpression; end
+
+  # A function call where the given functor_expr should evaluate to the name
+  # of a function.
+  #
+  class CallNamedFunctionExpression < CallExpression; end
+
+  # A method/function call where the function expr is a NamedAccess and with support for
+  # an optional lambda block
+  #
+  class CallMethodExpression < CallExpression
+  end
+
+  # Abstract base class for literals.
+  #
+  class Literal < Expression
+    abstract
+  end
+
+  # A literal value is an abstract value holder. The type of the contained value is
+  # determined by the concrete subclass.
+  #
+  class LiteralValue < Literal
+    abstract
+  end
+
+  # A Regular Expression Literal.
+  #
+  class LiteralRegularExpression < LiteralValue
+    has_attr 'value', Object, :lowerBound => 1, :transient => true
+    has_attr 'pattern', String, :lowerBound => 1
+  end
+
+  # A Literal String
+  #
+  class LiteralString < LiteralValue
+    has_attr 'value', String, :lowerBound => 1
+  end
+
+  class LiteralNumber < LiteralValue
+    abstract
+  end
+
+  # A literal number has a radix of decimal (10), octal (8), or hex (16) to enable string conversion with the input radix.
+  # By default, a radix of 10 is used.
+  #
+  class LiteralInteger < LiteralNumber
+    has_attr 'radix', Integer, :lowerBound => 1, :defaultValueLiteral => "10"
+    has_attr 'value', Integer, :lowerBound => 1
+  end
+
+  class LiteralFloat < LiteralNumber
+    has_attr 'value', Float, :lowerBound => 1
+  end
+
+  # The DSL `undef`.
+  #
+  class LiteralUndef < Literal; end
+
+  # The DSL `default`
+  class LiteralDefault < Literal; end
+
+  # DSL `true` or `false`
+  class LiteralBoolean < LiteralValue
+    has_attr 'value', Boolean, :lowerBound => 1
+  end
+
+  # A text expression is an interpolation of an expression. If the embedded expression is
+  # a QualifiedName, it is taken as a variable name and resolved. All other expressions are evaluated.
+  # The result is transformed to a string.
+  #
+  class TextExpression < UnaryExpression; end
+
+  # An interpolated/concatenated string. The contained segments are expressions. Verbatim sections
+  # should be LiteralString instances, and interpolated expressions should either be
+  # TextExpression instances (if QualifiedNames should be turned into variables), or any other expression
+  # if such treatment is not needed.
+  #
+  class ConcatenatedString < Expression
+    contains_many_uni 'segments', Expression
+  end
+
+  # A DSL NAME (one or multiple parts separated by '::').
+  #
+  class QualifiedName < LiteralValue
+    has_attr 'value', String, :lowerBound => 1
+  end
+
+  # Represents a parsed reserved word. If the 'future' attribute is true
+  # the ReserwedWord functions as a deprecation warning + string value
+  #
+  class ReservedWord < LiteralValue
+    has_attr 'word', String, :lowerBound => 1
+    has_attr 'future', Boolean
+  end
+
+  # A DSL CLASSREF (one or multiple parts separated by '::' where (at least) the first part starts with an upper case letter).
+  #
+  class QualifiedReference < LiteralValue
+    has_attr 'value', String, :lowerBound => 1
+  end
+
+  # A Variable expression looks up value of expr (some kind of name) in scope.
+  # The expression is typically a QualifiedName, or QualifiedReference.
+  #
+  class VariableExpression < UnaryExpression; end
+
+  # Epp start
+  class EppExpression < Expression
+    # EPP can be specified without giving any parameter specification.
+    # However, the parameters of the lambda in that case are the empty
+    # array, which is the same as when the parameters are explicity
+    # specified as empty. This attribute tracks that difference.
+    has_attr 'parameters_specified', Boolean
+    contains_one_uni 'body', Expression
+  end
+
+  # A string to render
+  class RenderStringExpression < LiteralString
+  end
+
+  # An expression to evluate and render
+  class RenderExpression < UnaryExpression
+  end
+
+  # A resource body describes one resource instance
+  #
+  class ResourceBody < Positioned
+    contains_one_uni 'title', Expression
+    contains_many_uni 'operations', AbstractAttributeOperation
+  end
+
+  ResourceFormEnum = RGen::MetamodelBuilder::DataTypes::Enum.new(
+    :literals => [:regular, :virtual, :exported ],
+    :name => 'ResourceFormEnum')
+
+  # An abstract resource describes the form of the resource (regular, virtual or exported)
+  # and adds convenience methods to ask if it is virtual or exported.
+  # All derived classes may not support all forms, and these needs to be validated
+  #
+  class AbstractResource < Expression
+    abstract
+    has_attr 'form', ResourceFormEnum, :lowerBound => 1, :defaultValueLiteral => "regular"
+    has_attr 'virtual', Boolean, :derived => true
+    has_attr 'exported', Boolean, :derived => true
+  end
+
+  # A resource expression is used to instantiate one or many resource. Resources may optionally
+  # be virtual or exported, an exported resource is always virtual.
+  #
+  class ResourceExpression < AbstractResource
+    contains_one_uni 'type_name', Expression, :lowerBound => 1
+    contains_many_uni 'bodies', ResourceBody
+  end
+
+  # A resource defaults sets defaults for a resource type. This class inherits from AbstractResource
+  # but does only support the :regular form (this is intentional to be able to produce better error messages
+  # when illegal forms are applied to a model.
+  #
+  class ResourceDefaultsExpression < AbstractResource
+    contains_one_uni 'type_ref', Expression
+    contains_many_uni 'operations', AbstractAttributeOperation
+  end
+
+  # A resource override overrides already set values.
+  #
+  class ResourceOverrideExpression < AbstractResource
+    contains_one_uni 'resources', Expression, :lowerBound => 1
+    contains_many_uni 'operations', AbstractAttributeOperation
+  end
+
+  # A selector entry describes a map from matching_expr to value_expr.
+  #
+  class SelectorEntry < Positioned
+    contains_one_uni 'matching_expr', Expression, :lowerBound => 1
+    contains_one_uni 'value_expr', Expression, :lowerBound => 1
+  end
+
+  # A selector expression represents a mapping from a left_expr to a matching SelectorEntry.
+  #
+  class SelectorExpression < Expression
+    contains_one_uni 'left_expr', Expression, :lowerBound => 1
+    contains_many_uni 'selectors', SelectorEntry
+  end
+
+  # A named access expression looks up a named part. (e.g. $a.b)
+  #
+  class NamedAccessExpression < BinaryExpression; end
+
+  # A Program is the top level construct returned by the parser
+  # it contains the parsed result in the body, and has a reference to the full source text,
+  # and its origin. The line_offset's is an array with the start offset of each line.
+  #
+  class Program < PopsObject
+    contains_one_uni 'body', Expression
+    has_many 'definitions', Definition
+    has_attr 'source_text', String
+    has_attr 'source_ref', String
+    has_many_attr 'line_offsets', Integer
+    has_attr 'locator', Object, :lowerBound => 1, :transient => true
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/model_tree_dumper.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/model_tree_dumper.rb
new file mode 100644
index 0000000..4455414
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/model_tree_dumper.rb
@@ -0,0 +1,407 @@
+# Dumps a Pops::Model in reverse polish notation; i.e. LISP style
+# The intention is to use this for debugging output
+# TODO: BAD NAME - A DUMP is a Ruby Serialization
+#
+class Puppet::Pops::Model::ModelTreeDumper < Puppet::Pops::Model::TreeDumper
+  def dump_Array o
+    o.collect {|e| do_dump(e) }
+  end
+
+  def dump_LiteralFloat o
+    o.value.to_s
+  end
+
+  def dump_LiteralInteger o
+    case o.radix
+    when 10
+      o.value.to_s
+    when 8
+      "0%o" % o.value
+    when 16
+      "0x%X" % o.value
+    else
+      "bad radix:" + o.value.to_s
+    end
+  end
+
+  def dump_LiteralValue o
+    o.value.to_s
+  end
+
+  def dump_Factory o
+    do_dump(o.current)
+  end
+
+  def dump_ArithmeticExpression o
+    [o.operator.to_s, do_dump(o.left_expr), do_dump(o.right_expr)]
+  end
+
+  # x[y] prints as (slice x y)
+  def dump_AccessExpression o
+    if o.keys.size <= 1
+      ["slice", do_dump(o.left_expr), do_dump(o.keys[0])]
+    else
+      ["slice", do_dump(o.left_expr), do_dump(o.keys)]
+    end
+  end
+
+  def dump_MatchesExpression o
+    [o.operator.to_s, do_dump(o.left_expr), do_dump(o.right_expr)]
+  end
+
+  def dump_CollectExpression o
+    result = ["collect", do_dump(o.type_expr), :indent, :break, do_dump(o.query), :indent]
+    o.operations do |ao|
+      result << :break << do_dump(ao)
+    end
+    result += [:dedent, :dedent ]
+    result
+  end
+
+  def dump_EppExpression o
+    result = ["epp"]
+#    result << ["parameters"] + o.parameters.collect {|p| do_dump(p) } if o.parameters.size() > 0
+    if o.body
+      result << do_dump(o.body)
+    else
+      result << []
+    end
+    result
+  end
+
+  def dump_ExportedQuery o
+    result = ["<<| |>>"]
+    result += dump_QueryExpression(o) unless is_nop?(o.expr)
+    result
+  end
+
+  def dump_VirtualQuery o
+    result = ["<| |>"]
+    result += dump_QueryExpression(o) unless is_nop?(o.expr)
+    result
+  end
+
+  def dump_QueryExpression o
+    [do_dump(o.expr)]
+  end
+
+  def dump_ComparisonExpression o
+    [o.operator.to_s, do_dump(o.left_expr), do_dump(o.right_expr)]
+  end
+
+  def dump_AndExpression o
+    ["&&", do_dump(o.left_expr), do_dump(o.right_expr)]
+  end
+
+  def dump_OrExpression o
+    ["||", do_dump(o.left_expr), do_dump(o.right_expr)]
+  end
+
+  def dump_InExpression o
+    ["in", do_dump(o.left_expr), do_dump(o.right_expr)]
+  end
+
+  def dump_AssignmentExpression o
+    [o.operator.to_s, do_dump(o.left_expr), do_dump(o.right_expr)]
+  end
+
+  # Produces (name => expr) or (name +> expr)
+  def dump_AttributeOperation o
+    [o.attribute_name, o.operator, do_dump(o.value_expr)]
+  end
+
+  def dump_AttributesOperation o
+    ['* =>', do_dump(o.expr)]
+  end
+
+  def dump_LiteralList o
+    ["[]"] + o.values.collect {|x| do_dump(x)}
+  end
+
+  def dump_LiteralHash o
+    ["{}"] + o.entries.collect {|x| do_dump(x)}
+  end
+
+  def dump_KeyedEntry o
+    [do_dump(o.key), do_dump(o.value)]
+  end
+
+  def dump_MatchExpression o
+    [o.operator.to_s, do_dump(o.left_expr), do_dump(o.right_expr)]
+  end
+
+  def dump_LiteralString o
+    "'#{o.value}'"
+  end
+
+  def dump_LambdaExpression o
+    result = ["lambda"]
+    result << ["parameters"] + o.parameters.collect {|p| do_dump(p) } if o.parameters.size() > 0
+    if o.body
+      result << do_dump(o.body)
+    else
+      result << []
+    end
+    result
+  end
+
+  def dump_LiteralDefault o
+    ":default"
+  end
+
+  def dump_LiteralUndef o
+    ":undef"
+  end
+
+  def dump_LiteralRegularExpression o
+    "/#{o.value.source}/"
+  end
+
+  def dump_Nop o
+    ":nop"
+  end
+
+  def dump_NamedAccessExpression o
+    [".", do_dump(o.left_expr), do_dump(o.right_expr)]
+  end
+
+  def dump_NilClass o
+    "()"
+  end
+
+  def dump_NotExpression o
+    ['!', dump(o.expr)]
+  end
+
+  def dump_VariableExpression o
+    "$#{dump(o.expr)}"
+  end
+
+  # Interpolation (to string) shown as (str expr)
+  def dump_TextExpression o
+    ["str", do_dump(o.expr)]
+  end
+
+  def dump_UnaryMinusExpression o
+    ['-', do_dump(o.expr)]
+  end
+
+  def dump_UnfoldExpression o
+    ['unfold', do_dump(o.expr)]
+  end
+
+  def dump_BlockExpression o
+    result = ["block", :indent]
+    o.statements.each {|x| result << :break; result << do_dump(x) }
+    result << :dedent << :break
+    result
+  end
+
+  # Interpolated strings are shown as (cat seg0 seg1 ... segN)
+  def dump_ConcatenatedString o
+    ["cat"] + o.segments.collect {|x| do_dump(x)}
+  end
+
+  def dump_HeredocExpression(o)
+    result = ["@(#{o.syntax})", :indent, :break, do_dump(o.text_expr), :dedent, :break]
+  end
+
+  def dump_HostClassDefinition o
+    result = ["class", o.name]
+    result << ["inherits", o.parent_class] if o.parent_class
+    result << ["parameters"] + o.parameters.collect {|p| do_dump(p) } if o.parameters.size() > 0
+    if o.body
+      result << do_dump(o.body)
+    else
+      result << []
+    end
+    result
+  end
+
+  def dump_NodeDefinition o
+    result = ["node"]
+    result << ["matches"] + o.host_matches.collect {|m| do_dump(m) }
+    result << ["parent", do_dump(o.parent)] if o.parent
+    if o.body
+      result << do_dump(o.body)
+    else
+      result << []
+    end
+    result
+  end
+
+  def dump_NamedDefinition o
+    # the nil must be replaced with a string
+    result = [nil, o.name]
+    result << ["parameters"] + o.parameters.collect {|p| do_dump(p) } if o.parameters.size() > 0
+    if o.body
+      result << do_dump(o.body)
+    else
+      result << []
+    end
+    result
+  end
+
+  def dump_ResourceTypeDefinition o
+    result = dump_NamedDefinition(o)
+    result[0] = 'define'
+    result
+  end
+
+  def dump_ResourceOverrideExpression o
+    form = o.form == :regular ? '' : o.form.to_s + "-"
+    result = [form+"override", do_dump(o.resources), :indent]
+    o.operations.each do |p|
+      result << :break << do_dump(p)
+    end
+    result << :dedent
+    result
+  end
+
+  def dump_ReservedWord o
+    [ 'reserved', o.word ]
+  end
+
+  # Produces parameters as name, or (= name value)
+  def dump_Parameter o
+    name_prefix = o.captures_rest ? '*' : ''
+    name_part = "#{name_prefix}#{o.name}"
+    if o.value && o.type_expr
+      ["=t", do_dump(o.type_expr), name_part, do_dump(o.value)]
+    elsif o.value
+      ["=", name_part, do_dump(o.value)]
+    elsif o.type_expr
+      ["t", do_dump(o.type_expr), name_part]
+    else
+      name_part
+    end
+  end
+
+  def dump_ParenthesizedExpression o
+    do_dump(o.expr)
+  end
+
+  # Hides that Program exists in the output (only its body is shown), the definitions are just
+  # references to contained classes, resource types, and nodes
+  def dump_Program(o)
+    dump(o.body)
+  end
+
+  def dump_IfExpression o
+    result = ["if", do_dump(o.test), :indent, :break,
+      ["then", :indent, do_dump(o.then_expr), :dedent]]
+    result +=
+    [:break,
+      ["else", :indent, do_dump(o.else_expr), :dedent],
+      :dedent] unless is_nop? o.else_expr
+    result
+  end
+
+  def dump_UnlessExpression o
+    result = ["unless", do_dump(o.test), :indent, :break,
+      ["then", :indent, do_dump(o.then_expr), :dedent]]
+    result +=
+    [:break,
+      ["else", :indent, do_dump(o.else_expr), :dedent],
+      :dedent] unless is_nop? o.else_expr
+    result
+  end
+
+  # Produces (invoke name args...) when not required to produce an rvalue, and
+  # (call name args ... ) otherwise.
+  #
+  def dump_CallNamedFunctionExpression o
+    result = [o.rval_required ? "call" : "invoke", do_dump(o.functor_expr)]
+    o.arguments.collect {|a| result << do_dump(a) }
+    result
+  end
+
+  #    def dump_CallNamedFunctionExpression o
+  #      result = [o.rval_required ? "call" : "invoke", do_dump(o.functor_expr)]
+  #      o.arguments.collect {|a| result << do_dump(a) }
+  #      result
+  #    end
+
+  def dump_CallMethodExpression o
+    result = [o.rval_required ? "call-method" : "invoke-method", do_dump(o.functor_expr)]
+    o.arguments.collect {|a| result << do_dump(a) }
+    result << do_dump(o.lambda) if o.lambda
+    result
+  end
+
+  def dump_CaseExpression o
+    result = ["case", do_dump(o.test), :indent]
+    o.options.each do |s|
+      result << :break << do_dump(s)
+    end
+    result << :dedent
+  end
+
+  def dump_CaseOption o
+    result = ["when"]
+    result << o.values.collect {|x| do_dump(x) }
+    result << ["then", do_dump(o.then_expr) ]
+    result
+  end
+
+  def dump_RelationshipExpression o
+    [o.operator.to_s, do_dump(o.left_expr), do_dump(o.right_expr)]
+  end
+
+  def dump_RenderStringExpression o
+    ["render-s", " '#{o.value}'"]
+  end
+
+  def dump_RenderExpression o
+    ["render", do_dump(o.expr)]
+  end
+
+  def dump_ResourceBody o
+    result = [do_dump(o.title), :indent]
+    o.operations.each do |p|
+      result << :break << do_dump(p)
+    end
+    result << :dedent
+    result
+  end
+
+  def dump_ResourceDefaultsExpression o
+    form = o.form == :regular ? '' : o.form.to_s + "-"
+    result = [form+"resource-defaults", do_dump(o.type_ref), :indent]
+    o.operations.each do |p|
+      result << :break << do_dump(p)
+    end
+    result << :dedent
+    result
+  end
+
+  def dump_ResourceExpression o
+    form = o.form == :regular ? '' : o.form.to_s + "-"
+    result = [form+"resource", do_dump(o.type_name), :indent]
+    o.bodies.each do |b|
+      result << :break << do_dump(b)
+    end
+    result << :dedent
+    result
+  end
+
+  def dump_SelectorExpression o
+    ["?", do_dump(o.left_expr)] + o.selectors.collect {|x| do_dump(x) }
+  end
+
+  def dump_SelectorEntry o
+    [do_dump(o.matching_expr), "=>", do_dump(o.value_expr)]
+  end
+
+  def dump_SubLocatedExpression o
+    ["sublocated", do_dump(o.expr)]
+  end
+
+  def dump_Object o
+    [o.class.to_s, o.to_s]
+  end
+
+  def is_nop? o
+    o.nil? || o.is_a?(Puppet::Pops::Model::Nop)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/tree_dumper.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/tree_dumper.rb
new file mode 100644
index 0000000..518b06d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/model/tree_dumper.rb
@@ -0,0 +1,59 @@
+# Base class for formatted textual dump of a "model"
+#
+class Puppet::Pops::Model::TreeDumper
+  attr_accessor :indent_count
+  def initialize initial_indentation = 0
+    @@dump_visitor ||= Puppet::Pops::Visitor.new(nil,"dump",0,0)
+    @indent_count = initial_indentation
+  end
+
+  def dump(o)
+    format(do_dump(o))
+  end
+
+  def do_dump(o)
+    @@dump_visitor.visit_this(self, o)
+  end
+
+  def indent
+    "  " * indent_count
+  end
+
+  def format(x)
+    result = ""
+    parts = format_r(x)
+    parts.each_index do |i|
+      if i > 0
+        # separate with space unless previous ends with whitepsace or (
+        result << ' ' if parts[i] != ")" && parts[i-1] !~ /.*(?:\s+|\()$/ && parts[i] !~ /^\s+/
+      end
+      result << parts[i].to_s
+    end
+    result
+  end
+
+  def format_r(x)
+    result = []
+    case x
+    when :break
+      result << "\n" + indent
+    when :indent
+      @indent_count += 1
+    when :dedent
+      @indent_count -= 1
+    when Array
+      result << '('
+      result += x.collect {|a| format_r(a) }.flatten
+      result << ')'
+    when Symbol
+      result << x.to_s # Allows Symbols in arrays e.g. ["text", =>, "text"]
+    else
+      result << x
+    end
+    result
+  end
+
+  def is_nop? o
+    o.nil? || o.is_a?(Puppet::Pops::Model::Nop)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/code_merger.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/code_merger.rb
new file mode 100644
index 0000000..79e1328
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/code_merger.rb
@@ -0,0 +1,17 @@
+
+class Puppet::Pops::Parser::CodeMerger
+
+  # Concatenates the logic in the array of parse results into one parse result.
+  # @return Puppet::Parser::AST::BlockExpression
+  #
+  def concatenate(parse_results)
+    # this is a bit brute force as the result is already 3x ast with wrapped 4x content
+    # this could be combined in a more elegant way, but it is only used to process a handful of files
+    # at the beginning of a puppet run. TODO: Revisit for Puppet 4x when there is no 3x ast at the top.
+    #
+    children = parse_results.select {|x| !x.nil? && x.code}.reduce([]) do |memo, parsed_class|
+      memo << parsed_class.code
+    end
+    Puppet::Parser::AST::BlockExpression.new(:children => children)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/egrammar.ra b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/egrammar.ra
new file mode 100644
index 0000000..5137a90
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/egrammar.ra
@@ -0,0 +1,769 @@
+# vim: syntax=ruby
+
+# Parser using the Pops model, expression based
+
+class Puppet::Pops::Parser::Parser
+
+token STRING DQPRE DQMID DQPOST
+token WORD
+token LBRACK  RBRACK LBRACE RBRACE SYMBOL FARROW COMMA TRUE
+token FALSE EQUALS APPENDS DELETES LESSEQUAL NOTEQUAL DOT COLON LLCOLLECT RRCOLLECT
+token QMARK LPAREN RPAREN ISEQUAL GREATEREQUAL GREATERTHAN LESSTHAN
+token IF ELSE
+token DEFINE ELSIF VARIABLE CLASS INHERITS NODE BOOLEAN
+token NAME SEMIC CASE DEFAULT AT ATAT LCOLLECT RCOLLECT CLASSREF
+token NOT OR AND UNDEF PARROW PLUS MINUS TIMES DIV LSHIFT RSHIFT UMINUS
+token MATCH NOMATCH REGEX IN_EDGE OUT_EDGE IN_EDGE_SUB OUT_EDGE_SUB
+token IN UNLESS PIPE
+token LAMBDA SELBRACE
+token NUMBER
+token HEREDOC SUBLOCATE
+token RENDER_STRING RENDER_EXPR EPP_START EPP_END EPP_END_TRIM
+token FUNCTION
+token PRIVATE ATTR TYPE
+token APPLICATION_R CONSUMES_R PRODUCES_R
+token LOW
+
+prechigh
+  left  HIGH
+  left  SEMIC
+  left  PIPE
+  left  LPAREN
+  left  RPAREN
+  left  DOT
+  nonassoc EPP_START
+  left  LBRACK LISTSTART
+  left  RBRACK
+  left  QMARK
+  left  LCOLLECT LLCOLLECT
+  right NOT
+  nonassoc SPLAT
+  nonassoc UMINUS
+  left  IN
+  left  MATCH NOMATCH
+  left  TIMES DIV MODULO
+  left  MINUS PLUS
+  left  LSHIFT RSHIFT
+  left  NOTEQUAL ISEQUAL
+  left  GREATEREQUAL GREATERTHAN LESSTHAN LESSEQUAL
+  left  AND
+  left  OR
+  left  LBRACE
+  left  SELBRACE
+  left  RBRACE
+  right AT ATAT
+  right APPENDS DELETES EQUALS
+  left  IN_EDGE OUT_EDGE IN_EDGE_SUB OUT_EDGE_SUB
+  left  FARROW
+  left  COMMA
+  nonassoc RENDER_EXPR
+  nonassoc RENDER_STRING
+  left  LOW
+preclow
+
+rule
+# Produces [Model::Program] with a body containing what was parsed
+program
+  : statements     { result = create_program(Factory.block_or_expression(*val[0])) }
+  | epp_expression { result = create_program(Factory.block_or_expression(*val[0])) }
+  |                { result = create_empty_program() }
+
+# Produces a semantic model (non validated, but semantically adjusted).
+statements
+  : syntactic_statements { result = transform_calls(val[0]) }
+
+# Collects sequence of elements into a list that the statements rule can transform
+# (Needed because language supports function calls without parentheses around arguments).
+# Produces Array<Model::Expression>
+#
+syntactic_statements
+  : syntactic_statement                            { result = [val[0]]}
+  | syntactic_statements SEMIC syntactic_statement { result = val[0].push val[2] }
+  | syntactic_statements syntactic_statement       { result = val[0].push val[1] }
+
+# Produce a single expression or Array of expression
+# This exists to handle multiple arguments to non parenthesized function call. If e is expression,
+# the a program can consists of e [e,e,e] where the first may be a name of a function to call.
+#
+syntactic_statement
+  : assignment                             =LOW { result = val[0] }
+  | syntactic_statement COMMA assignment   =LOW { result = aryfy(val[0]).push(val[1]).push(val[2]) }
+
+# Assignment (is right recursive since assignment is right associative)
+assignment
+  : relationship =LOW
+  | relationship EQUALS  assignment         { result = val[0].set(val[2])      ; loc result, val[1] }
+  | relationship APPENDS assignment         { result = val[0].plus_set(val[2]) ; loc result, val[1] }
+  | relationship DELETES assignment         { result = val[0].minus_set(val[2]); loc result, val[1] }
+
+assignments
+  : assignment                              { result = [val[0]] }
+  | assignments COMMA assignment            { result = val[0].push(val[2]) }
+
+relationship
+  : resource =LOW
+  | relationship IN_EDGE      resource      { result = val[0].relop(val[1][:value], val[2]); loc result, val[1] }
+  | relationship IN_EDGE_SUB  resource      { result = val[0].relop(val[1][:value], val[2]); loc result, val[1] }
+  | relationship OUT_EDGE     resource      { result = val[0].relop(val[1][:value], val[2]); loc result, val[1] }
+  | relationship OUT_EDGE_SUB resource      { result = val[0].relop(val[1][:value], val[2]); loc result, val[1] }
+
+#-- RESOURCE
+#
+resource
+  : expression = LOW
+
+    #---VIRTUAL
+  | AT resource {
+      result = val[1]
+      unless Factory.set_resource_form(result, :virtual)
+        # This is equivalent to a syntax error - additional semantic restrictions apply
+        error val[0], "Virtual (@) can only be applied to a Resource Expression"
+      end
+      # relocate the result
+      loc result, val[0], val[1]
+    }
+
+    #---EXPORTED
+  | ATAT resource {
+      result = val[1]
+      unless Factory.set_resource_form(result, :exported)
+        # This is equivalent to a syntax error - additional semantic restrictions apply
+        error val[0], "Exported (@@) can only be applied to a Resource Expression"
+      end
+      # relocate the result
+      loc result, val[0], val[1]
+    }
+
+    #---RESOURCE TITLED 3x and 4x
+  | resource LBRACE expression COLON attribute_operations additional_resource_bodies RBRACE {
+      bodies = [Factory.RESOURCE_BODY(val[2], val[4])] + val[5]
+      result = Factory.RESOURCE(val[0], bodies)
+      loc result, val[0], val[6]
+    }
+
+    #---CLASS RESOURCE
+  | CLASS LBRACE resource_bodies endsemi RBRACE {
+        result = Factory.RESOURCE(Factory.fqn(token_text(val[0])), val[2])
+        loc result, val[0], val[4]
+    }
+
+    # --RESOURCE 3X Expression
+    #   Handles both 3x overrides and defaults (i.e. single resource_body without title colon)
+    #   Slated for possible deprecation since it requires transformation and mix static/evaluation check
+    #
+  | resource LBRACE attribute_operations endcomma RBRACE {
+       result = case Factory.resource_shape(val[0])
+       when :resource, :class
+        # This catches deprecated syntax.
+        # If the attribute operations does not include +>, then the found expression
+        # is actually a LEFT followed by LITERAL_HASH
+        #
+        unless tmp = transform_resource_wo_title(val[0], val[2])
+          error val[1], "Syntax error resource body without title or hash with +>"
+        end
+        tmp
+      when :defaults
+        Factory.RESOURCE_DEFAULTS(val[0], val[2])
+      when :override
+        # This was only done for override in original - TODO should it be here at all
+        Factory.RESOURCE_OVERRIDE(val[0], val[2])
+      else
+        error val[0], "Expression is not valid as a resource, resource-default, or resource-override"
+      end
+     loc result, val[0], val[4]
+    }
+
+  resource_body
+    : expression COLON attribute_operations endcomma { result = Factory.RESOURCE_BODY(val[0], val[2]) }
+
+  resource_bodies
+    : resource_body                         =HIGH { result = [val[0]] }
+    | resource_bodies SEMIC resource_body   =HIGH { result = val[0].push val[2] }
+
+  # This is a rule for the intermediate state where RACC has seen enough tokens to understand that
+  # what is expressed is a Resource Expression, it now has to get to the finishing line
+  #
+  additional_resource_bodies
+    : endcomma                         { result = [] }
+    | endcomma SEMIC                   { result = [] }
+    | endcomma SEMIC resource_bodies endsemi { result = val[2] }
+
+#-- EXPRESSION
+#
+expression
+  : primary_expression
+  | call_function_expression
+  | expression LBRACK       expressions RBRACK =LBRACK { result = val[0][*val[2]]         ; loc result, val[0], val[3] }
+  | expression IN           expression                 { result = val[0].in val[2]        ; loc result, val[1] }
+  | expression MATCH        expression                 { result = val[0] =~  val[2]       ; loc result, val[1] }
+  | expression NOMATCH      expression                 { result = val[0].mne val[2]       ; loc result, val[1] }
+  | expression PLUS         expression                 { result = val[0] +   val[2]       ; loc result, val[1] }
+  | expression MINUS        expression                 { result = val[0] -   val[2]       ; loc result, val[1] }
+  | expression DIV          expression                 { result = val[0] /   val[2]       ; loc result, val[1] }
+  | expression TIMES        expression                 { result = val[0] *   val[2]       ; loc result, val[1] }
+  | expression MODULO       expression                 { result = val[0] %   val[2]       ; loc result, val[1] }
+  | expression LSHIFT       expression                 { result = val[0] <<  val[2]       ; loc result, val[1] }
+  | expression RSHIFT       expression                 { result = val[0] >>  val[2]       ; loc result, val[1] }
+  |            MINUS        expression         =UMINUS { result = val[1].minus()          ; loc result, val[0] }
+  |            TIMES        expression         =SPLAT  { result = val[1].unfold()         ; loc result, val[0] }
+  | expression NOTEQUAL     expression                 { result = val[0].ne  val[2]       ; loc result, val[1] }
+  | expression ISEQUAL      expression                 { result = val[0] ==  val[2]       ; loc result, val[1] }
+  | expression GREATERTHAN  expression                 { result = val[0] >   val[2]       ; loc result, val[1] }
+  | expression GREATEREQUAL expression                 { result = val[0] >=  val[2]       ; loc result, val[1] }
+  | expression LESSTHAN     expression                 { result = val[0] <   val[2]       ; loc result, val[1] }
+  | expression LESSEQUAL    expression                 { result = val[0] <=  val[2]       ; loc result, val[1] }
+  |            NOT          expression                 { result = val[1].not              ; loc result, val[0] }
+  | expression AND          expression                 { result = val[0].and val[2]       ; loc result, val[1] }
+  | expression OR           expression                 { result = val[0].or  val[2]       ; loc result, val[1] }
+  | expression QMARK selector_entries                  { result = val[0].select(*val[2])  ; loc result, val[0] }
+  |            LPAREN       assignment RPAREN          { result = val[1].paren()          ; loc result, val[0] }
+
+
+#---EXPRESSIONS
+#   (i.e. "argument list")
+#
+# This expression list can not contain function calls without parentheses around arguments
+# Produces Array<Model::Expression>
+#
+expressions
+  : expression                   { result = [val[0]] }
+  | expressions COMMA expression { result = val[0].push(val[2]) }
+
+primary_expression
+  : variable
+  | call_method_with_lambda_expression
+  | collection_expression
+  | case_expression
+  | if_expression
+  | unless_expression
+  | definition_expression
+  | hostclass_expression
+  | node_definition_expression
+  | epp_render_expression
+  | reserved_word
+  | array
+  | hash
+  | regex
+  | quotedtext
+  | type
+  | NUMBER       { result = Factory.NUMBER(val[0][:value])          ; loc result, val[0] }
+  | BOOLEAN      { result = Factory.literal(val[0][:value])         ; loc result, val[0] }
+  | DEFAULT      { result = Factory.literal(:default)               ; loc result, val[0] }
+  | UNDEF        { result = Factory.literal(:undef)                 ; loc result, val[0] }
+  | NAME         { result = Factory.QNAME_OR_NUMBER(val[0][:value]) ; loc result, val[0] }
+
+
+#---CALL FUNCTION
+#
+# Produces Model::CallNamedFunction
+
+call_function_expression
+  : expression LPAREN assignments endcomma RPAREN {
+      result = Factory.CALL_NAMED(val[0], true, val[2])
+      loc result, val[0], val[4]
+    }
+  | expression LPAREN RPAREN {
+      result = Factory.CALL_NAMED(val[0], true, [])
+      loc result, val[0], val[2]
+    }
+  | expression LPAREN assignments endcomma RPAREN lambda {
+      result = Factory.CALL_NAMED(val[0], true, val[2])
+      loc result, val[0], val[4]
+      result.lambda = val[5]
+    }
+  | expression LPAREN RPAREN  lambda {
+      result = Factory.CALL_NAMED(val[0], true, [])
+      loc result, val[0], val[2]
+      result.lambda = val[3]
+    }
+
+#---CALL METHOD
+#
+call_method_with_lambda_expression
+  : call_method_expression         =LOW { result = val[0] }
+  | call_method_expression lambda       { result = val[0]; val[0].lambda = val[1] }
+
+  call_method_expression
+    : named_access LPAREN assignments RPAREN { result = Factory.CALL_METHOD(val[0], val[2]); loc result, val[1], val[3] }
+    | named_access LPAREN RPAREN             { result = Factory.CALL_METHOD(val[0], []); loc result, val[1], val[3] }
+    | named_access =LOW                      { result = Factory.CALL_METHOD(val[0], []); loc result, val[0] }
+
+  named_access
+    : expression DOT NAME {
+        result = val[0].dot(Factory.fqn(val[2][:value]))
+        loc result, val[1], val[2]
+      }
+
+#---LAMBDA
+#
+lambda
+  : lambda_parameter_list lambda_rest {
+      result = Factory.LAMBDA(val[0][:value], val[1][:value])
+      loc result, val[0][:start], val[1][:end]
+    }
+
+lambda_rest
+  : LBRACE statements RBRACE  { result = {:end => val[2], :value =>val[1] } }
+  | LBRACE RBRACE             { result = {:end => val[1], :value => nil } }
+
+
+lambda_parameter_list
+  : PIPE PIPE                     { result = {:start => val[0], :value => [] } }
+  | PIPE parameters endcomma PIPE { result = {:start => val[0], :value => val[1] } }
+
+#---CONDITIONALS
+
+#--IF
+#
+if_expression
+  : IF if_part {
+      result = val[1]
+      loc(result, val[0], val[1])
+    }
+
+  # Produces Model::IfExpression
+  if_part
+    : expression LBRACE statements RBRACE else {
+        result = Factory.IF(val[0], Factory.block_or_expression(*val[2]), val[4])
+        loc(result, val[0], (val[4] ? val[4] : val[3]))
+      }
+    | expression LBRACE RBRACE else {
+        result = Factory.IF(val[0], nil, val[3])
+        loc(result, val[0], (val[3] ? val[3] : val[2]))
+      }
+
+  # Produces [Model::Expression, nil] - nil if there is no else or elsif part
+  else
+    : # nothing
+    | ELSIF if_part {
+        result = val[1]
+        loc(result, val[0], val[1])
+      }
+    | ELSE LBRACE statements RBRACE {
+        result = Factory.block_or_expression(*val[2])
+        loc result, val[0], val[3]
+      }
+    | ELSE LBRACE RBRACE {
+        result = nil # don't think a nop is needed here either
+      }
+
+#--UNLESS
+#
+unless_expression
+  : UNLESS expression LBRACE statements RBRACE unless_else {
+      result = Factory.UNLESS(val[1], Factory.block_or_expression(*val[3]), val[5])
+      loc result, val[0], val[4]
+    }
+  | UNLESS expression LBRACE RBRACE unless_else {
+      result = Factory.UNLESS(val[1], nil, val[4])
+      loc result, val[0], val[4]
+    }
+
+  # Different from else part of if, since "elsif" is not supported, but 'else' is
+  #
+  # Produces [Model::Expression, nil] - nil if there is no else or elsif part
+  unless_else
+    : # nothing
+    | ELSE LBRACE statements RBRACE {
+        result = Factory.block_or_expression(*val[2])
+        loc result, val[0], val[3]
+      }
+    | ELSE LBRACE RBRACE {
+        result = nil # don't think a nop is needed here either
+      }
+
+#--- CASE EXPRESSION
+#
+case_expression
+  : CASE expression LBRACE case_options RBRACE {
+      result = Factory.CASE(val[1], *val[3])
+      loc result, val[0], val[4]
+    }
+
+  # Produces Array<Model::CaseOption>
+  case_options
+    : case_option               { result = [val[0]] }
+    | case_options case_option  { result = val[0].push val[1] }
+
+  # Produced Model::CaseOption (aka When)
+  case_option
+    : expressions COLON LBRACE options_statements RBRACE {
+        result = Factory.WHEN(val[0], val[3]); loc result, val[1], val[4]
+      }
+
+  options_statements
+    : nil
+    | statements
+
+  # This special construct is required or racc will produce the wrong result when the selector entry
+  # LHS is generalized to any expression (LBRACE looks like a hash). Thus it is not possible to write
+  # a selector with a single entry where the entry LHS is a hash.
+  # The SELBRACE token is a LBRACE that follows a QMARK, and this is produced by the lexer with a lookback
+  # Produces Array<Model::SelectorEntry>
+  #
+  selector_entries
+    : selector_entry
+    | SELBRACE selector_entry_list endcomma RBRACE {
+        result = val[1]
+      }
+
+  # Produces Array<Model::SelectorEntry>
+  selector_entry_list
+    : selector_entry                           { result = [val[0]] }
+    | selector_entry_list COMMA selector_entry { result = val[0].push val[2] }
+
+  # Produces a Model::SelectorEntry
+  # This FARROW wins over FARROW in Hash
+  selector_entry
+    : expression FARROW expression { result = Factory.MAP(val[0], val[2]) ; loc result, val[1] }
+
+#---COLLECTION
+#
+# A Collection is a predicate applied to a set of objects with an implied context (used variables are
+# attributes of the object.
+# i.e. this is equivalent to source.select(QUERY).apply(ATTRIBUTE_OPERATIONS)
+#
+collection_expression
+  : expression collect_query LBRACE attribute_operations endcomma RBRACE {
+      result = Factory.COLLECT(val[0], val[1], val[3])
+      loc result, val[0], val[5]
+    }
+  | expression collect_query =LOW {
+      result = Factory.COLLECT(val[0], val[1], [])
+      loc result, val[0], val[1]
+    }
+
+  collect_query
+    : LCOLLECT  optional_query RCOLLECT  { result = Factory.VIRTUAL_QUERY(val[1])   ; loc result, val[0], val[2] }
+    | LLCOLLECT optional_query RRCOLLECT { result = Factory.EXPORTED_QUERY(val[1])  ; loc result, val[0], val[2] }
+
+  optional_query
+    : nil
+    | expression
+
+#---ATTRIBUTE OPERATIONS (Not an expression)
+#
+attribute_operations
+  :                                                { result = [] }
+  | attribute_operation                            { result = [val[0]] }
+  | attribute_operations COMMA attribute_operation { result = val[0].push(val[2]) }
+
+  # Produces String
+  # QUESTION: Why is BOOLEAN valid as an attribute name?
+  #
+  attribute_name
+    : NAME
+    | keyword
+    | APPLICATION_R
+    | CONSUMES_R
+    | PRODUCES_R
+#    | BOOLEAN
+
+  # In this version, illegal combinations are validated instead of producing syntax errors
+  # (Can give nicer error message "+> is not applicable to...")
+  # Produces Model::AttributeOperation
+  #
+  attribute_operation
+    : attribute_name FARROW expression {
+        result = Factory.ATTRIBUTE_OP(val[0][:value], :'=>', val[2])
+        loc result, val[0], val[2]
+      }
+    | attribute_name PARROW expression {
+        result = Factory.ATTRIBUTE_OP(val[0][:value], :'+>', val[2])
+        loc result, val[0], val[2]
+      }
+  | TIMES FARROW expression {
+      result = Factory.ATTRIBUTES_OP(val[2]) ; loc result, val[0], val[2]
+   }
+
+#---DEFINE
+#
+# Produces Model::Definition
+#
+definition_expression
+  : DEFINE classname parameter_list LBRACE opt_statements RBRACE {
+      result = add_definition(Factory.DEFINITION(classname(val[1][:value]), val[2], val[4]))
+      loc result, val[0], val[5]
+      # New lexer does not keep track of this, this is done in validation
+      if @lexer.respond_to?(:'indefine=')
+        @lexer.indefine = false
+      end
+    }
+
+#---HOSTCLASS
+#
+# Produces Model::HostClassDefinition
+#
+hostclass_expression
+  : CLASS stacked_classname parameter_list classparent LBRACE opt_statements RBRACE {
+      # Remove this class' name from the namestack as all nested classes have been parsed
+      namepop
+      result = add_definition(Factory.HOSTCLASS(classname(val[1][:value]), val[2], token_text(val[3]), val[5]))
+      loc result, val[0], val[6]
+    }
+
+  # Record the classname so nested classes gets a fully qualified name at parse-time
+  # This is a separate rule since racc does not support intermediate actions.
+  #
+  stacked_classname
+    : classname { namestack(val[0][:value]) ; result = val[0] }
+
+  opt_statements
+    : statements
+    | nil
+
+  # Produces String, name or nil result
+  classparent
+    : nil
+    | INHERITS classnameordefault { result = val[1] }
+
+  # Produces String (this construct allows a class to be named "default" and to be referenced as
+  # the parent class.
+  # TODO: Investigate the validity
+  # Produces a String (classname), or a token (DEFAULT).
+  #
+  classnameordefault
+    : classname
+    | DEFAULT
+
+#---NODE
+#
+# Produces Model::NodeDefinition
+#
+node_definition_expression
+  : NODE hostnames endcomma nodeparent LBRACE statements RBRACE {
+      result = add_definition(Factory.NODE(val[1], val[3], val[5]))
+      loc result, val[0], val[6]
+    }
+  | NODE hostnames endcomma nodeparent LBRACE RBRACE {
+      result = add_definition(Factory.NODE(val[1], val[3], nil))
+      loc result, val[0], val[5]
+    }
+
+  # Hostnames is not a list of names, it is a list of name matchers (including a Regexp).
+  # (The old implementation had a special "Hostname" object with some minimal validation)
+  #
+  # Produces Array<Model::LiteralExpression>
+  #
+  hostnames
+    : hostname                 { result = [result] }
+    | hostnames COMMA hostname { result = val[0].push(val[2]) }
+
+  # Produces a LiteralExpression (string, :default, or regexp)
+  # String with interpolation is validated for better error message
+  hostname
+    : dotted_name
+    | quotedtext
+    | DEFAULT     { result = Factory.literal(:default); loc result, val[0] }
+    | regex
+
+  dotted_name
+    : name_or_number   { result = Factory.literal(val[0][:value]); loc result, val[0] }
+    | dotted_name DOT name_or_number { result = Factory.concat(val[0], '.', val[2][:value]); loc result, val[0], val[2] }
+
+  name_or_number
+    : NAME
+    | NUMBER
+
+  # Produces Expression, since hostname is an Expression
+  nodeparent
+    : nil
+    | INHERITS hostname { result = val[1] }
+
+#---FUNCTION DEFINITION
+#
+#function_definition
+  # For now the function word will just be reserved, in the future it will
+  # produce a function definition
+  # FUNCTION classname parameter_list LBRACE opt_statements RBRACE {
+  #   result = add_definition(Factory.FUNCTION(val[1][:value], val[2], val[4]))
+  #   loc result, val[0], val[5]
+  # }
+
+#---NAMES AND PARAMETERS COMMON TO SEVERAL RULES
+#   Produces String
+#   TODO: The error that "class" is not a valid classname is bad - classname rule is also used for other things
+classname
+  : NAME
+  | WORD
+  | CLASSREF
+  | APPLICATION_R
+  | CONSUMES_R
+  | PRODUCES_R
+  | CLASS { error val[0], "'class' is not a valid classname" }
+
+# Produces Array<Model::Parameter>
+parameter_list
+  : nil                               { result = [] }
+  | LPAREN  RPAREN                    { result = [] }
+  | LPAREN parameters endcomma RPAREN { result = val[1] }
+
+# Produces Array<Model::Parameter>
+parameters
+  : parameter                  { result = [val[0]] }
+  | parameters COMMA parameter { result = val[0].push(val[2]) }
+
+# Produces Model::Parameter
+parameter
+  : untyped_parameter
+  | typed_parameter
+
+untyped_parameter
+  : regular_parameter
+  | splat_parameter
+
+regular_parameter
+  : VARIABLE EQUALS expression { result = Factory.PARAM(val[0][:value], val[2]) ; loc result, val[0] }
+  | VARIABLE                   { result = Factory.PARAM(val[0][:value]); loc result, val[0] }
+
+splat_parameter
+  : TIMES regular_parameter { result = val[1]; val[1].captures_rest() }
+
+typed_parameter
+  : parameter_type untyped_parameter { val[1].type_expr(val[0]) ; result = val[1] }
+
+parameter_type
+  : type { result = val[0] }
+  | type LBRACK expressions RBRACK { result = val[0][*val[2]] ; loc result, val[0], val[3] }
+
+#--VARIABLE
+#
+variable
+  : VARIABLE { result = Factory.fqn(val[0][:value]).var ; loc result, val[0] }
+
+#---RESERVED WORDS
+#
+reserved_word
+  : FUNCTION  { result = Factory.RESERVED(val[0][:value]) ; loc result, val[0] }
+  | PRIVATE   { result = Factory.RESERVED(val[0][:value]) ; loc result, val[0] }
+  | TYPE      { result = Factory.RESERVED(val[0][:value]) ; loc result, val[0] }
+  | ATTR      { result = Factory.RESERVED(val[0][:value]) ; loc result, val[0] }
+  | APPLICATION_R { result = Factory.RESERVED(val[0][:value], true) ; loc result, val[0] }
+  | CONSUMES_R    { result = Factory.RESERVED(val[0][:value], true) ; loc result, val[0] }
+  | PRODUCES_R    { result = Factory.RESERVED(val[0][:value], true) ; loc result, val[0] }
+
+#---LITERALS (dynamic and static)
+#
+
+array
+  : LISTSTART assignments endcomma  RBRACK { result = Factory.LIST(val[1]); loc result, val[0], val[3] }
+  | LISTSTART                       RBRACK { result = Factory.literal([]) ; loc result, val[0], val[1] }
+  | LBRACK    assignments endcomma  RBRACK { result = Factory.LIST(val[1]); loc result, val[0], val[3] }
+  | LBRACK                          RBRACK { result = Factory.literal([]) ; loc result, val[0], val[1] }
+
+hash
+  : LBRACE hashpairs RBRACE       { result = Factory.HASH(val[1]); loc result, val[0], val[2] }
+  | LBRACE hashpairs COMMA RBRACE { result = Factory.HASH(val[1]); loc result, val[0], val[3] }
+  | LBRACE RBRACE                 { result = Factory.literal({}) ; loc result, val[0], val[1] }
+
+  hashpairs
+    : hashpair                 { result = [val[0]] }
+    | hashpairs COMMA hashpair { result = val[0].push val[2] }
+
+  hashpair
+    : assignment FARROW assignment { result = Factory.KEY_ENTRY(val[0], val[2]); loc result, val[1] }
+
+quotedtext
+  : string
+  | dq_string
+  | heredoc
+
+string
+  : STRING  { result = Factory.literal(val[0][:value]) ; loc result, val[0] }
+  | WORD    { result = Factory.literal(val[0][:value]) ; loc result, val[0] }
+
+dq_string       : dqpre dqrval           { result = Factory.string(val[0], *val[1]) ; loc result, val[0], val[1][-1] }
+dqpre           : DQPRE                  { result = Factory.literal(val[0][:value]); loc result, val[0] }
+dqpost          : DQPOST                 { result = Factory.literal(val[0][:value]); loc result, val[0] }
+dqmid           : DQMID                  { result = Factory.literal(val[0][:value]); loc result, val[0] }
+dqrval          : text_expression dqtail { result = [val[0]] + val[1] }
+text_expression : assignment             { result = Factory.TEXT(val[0]) }
+
+dqtail
+  : dqpost        { result = [val[0]] }
+  | dqmid dqrval  { result = [val[0]] + val[1] }
+
+heredoc
+  : HEREDOC sublocated_text  { result = Factory.HEREDOC(val[0][:value], val[1]); loc result, val[0] }
+
+sublocated_text
+  : SUBLOCATE string    { result = Factory.SUBLOCATE(val[0], val[1]); loc result, val[0] }
+  | SUBLOCATE dq_string { result = Factory.SUBLOCATE(val[0], val[1]); loc result, val[0] }
+
+epp_expression
+  : EPP_START epp_parameters_list optional_statements { result = Factory.EPP(val[1], val[2]); loc result, val[0] }
+
+optional_statements
+  :
+  | statements
+
+epp_parameters_list
+  :                                  =LOW{ result = nil }
+  | PIPE PIPE                        { result = [] }
+  | PIPE parameters endcomma PIPE    { result = val[1] }
+
+epp_render_expression
+  : RENDER_STRING                  { result = Factory.RENDER_STRING(val[0][:value]); loc result, val[0] }
+  | RENDER_EXPR expression epp_end { result = Factory.RENDER_EXPR(val[1]); loc result, val[0], val[2] }
+  | RENDER_EXPR LBRACE statements RBRACE epp_end { result = Factory.RENDER_EXPR(Factory.block_or_expression(*val[2])); loc result, val[0], val[4] }
+
+epp_end
+  : EPP_END
+  | EPP_END_TRIM
+
+type     : CLASSREF { result = Factory.QREF(val[0][:value])  ; loc result, val[0] }
+
+regex
+  : REGEX { result = Factory.literal(val[0][:value]); loc result, val[0] }
+
+#---MARKERS, SPECIAL TOKENS, SYNTACTIC SUGAR, etc.
+
+endcomma
+  : #
+  | COMMA { result = nil }
+
+endsemi
+  : #
+  | SEMIC
+
+keyword
+  : AND
+  | CASE
+  | CLASS
+  | DEFAULT
+  | DEFINE
+  | ELSE
+  | ELSIF
+  | IF
+  | IN
+  | INHERITS
+  | NODE
+  | OR
+  | UNDEF
+  | UNLESS
+  | TYPE
+  | ATTR
+  | FUNCTION
+  | PRIVATE
+
+nil
+  : { result = nil}
+
+end
+
+---- header ----
+require 'puppet'
+require 'puppet/pops'
+
+module Puppet
+  class ParseError < Puppet::Error; end
+  class ImportError < Racc::ParseError; end
+  class AlreadyImportedError < ImportError; end
+end
+
+---- inner ----
+
+# Make emacs happy
+# Local Variables:
+# mode: ruby
+# End:
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/eparser.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/eparser.rb
new file mode 100644
index 0000000..28447e1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/eparser.rb
@@ -0,0 +1,2795 @@
+#
+# DO NOT MODIFY!!!!
+# This file is automatically generated by Racc 1.4.9
+# from Racc grammer file "".
+#
+
+require 'racc/parser.rb'
+
+require 'puppet'
+require 'puppet/pops'
+
+module Puppet
+  class ParseError < Puppet::Error; end
+  class ImportError < Racc::ParseError; end
+  class AlreadyImportedError < ImportError; end
+end
+
+module Puppet
+  module Pops
+    module Parser
+      class Parser < Racc::Parser
+
+module_eval(<<'...end egrammar.ra/module_eval...', 'egrammar.ra', 765)
+
+# Make emacs happy
+# Local Variables:
+# mode: ruby
+# End:
+...end egrammar.ra/module_eval...
+##### State transition tables begin ###
+
+clist = [
+'61,64,331,-248,62,56,289,57,-247,83,-250,-249,247,141,286,387,332,406',
+'383,-133,382,-132,289,104,18,107,288,102,103,161,42,289,45,248,47,12',
+'-131,46,36,39,347,44,37,10,11,-248,142,69,17,106,-247,38,-250,-249,15',
+'16,287,87,88,90,89,-133,70,-132,85,86,-236,-245,43,278,279,84,35,65',
+'-129,67,68,66,-131,348,48,49,51,50,52,53,54,61,64,55,263,62,56,264,57',
+'91,83,61,64,260,383,62,382,267,266,313,284,326,-236,-245,104,18,107',
+'265,102,103,-129,42,247,45,354,47,121,82,46,36,39,247,44,37,356,69,82',
+'82,69,17,106,82,38,248,69,15,16,74,87,88,90,89,248,70,343,85,86,240',
+'340,43,364,365,84,35,65,284,67,68,285,367,265,48,49,51,50,52,53,54,61',
+'64,55,314,62,56,370,57,91,83,260,326,375,376,316,260,259,258,380,320',
+'384,386,330,104,18,107,114,102,103,236,42,239,45,393,47,12,237,46,36',
+'39,72,44,37,10,11,395,247,69,17,106,284,38,236,82,15,16,82,119,226,90',
+'89,113,70,225,85,86,114,399,43,115,74,84,35,65,127,67,68,402,284,127',
+'48,49,51,50,52,53,54,61,64,55,405,62,56,158,57,91,83,119,327,326,156',
+'113,409,386,411,412,116,117,118,115,104,18,107,413,102,103,128,42,416',
+'45,417,47,12,321,46,36,39,418,44,37,10,11,247,127,69,17,106,82,38,74',
+'426,15,16,71,428,69,116,117,118,70,429,430,114,248,316,43,,,114,35,65',
+'110,67,68,247,,,48,49,51,50,52,53,54,61,64,55,69,62,56,,57,334,119,',
+'248,,113,,119,,,114,113,,115,,,18,276,,115,,,42,,45,,47,12,,46,36,39',
+',44,37,10,11,,,69,17,119,,38,,113,15,16,373,,116,117,118,115,70,,116',
+'117,118,,43,,114,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62',
+'56,,57,422,83,,116,117,118,119,,,,113,,,,,104,18,107,115,102,103,,42',
+',45,,47,12,,46,36,39,,44,37,10,11,,,69,17,106,,38,,,15,16,75,76,77,',
+',,70,116,117,118,,,43,,,84,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64',
+'55,,62,56,,57,336,83,,,,,,,,,78,80,79,81,,104,18,107,,102,103,,42,,45',
+',47,12,,46,36,39,,44,37,10,11,,,69,17,106,,38,,,15,16,,,,90,89,,70,',
+'85,86,,,43,,,84,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56',
+',57,91,83,,,,,,,,,,,,,,104,18,107,,102,103,,42,,45,,47,12,,46,36,39',
+',44,37,10,11,,,69,17,106,,38,,,15,16,,,,,,,70,,85,86,,,43,,,84,35,65',
+',67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,,83,,,,,,,,,,,,,',
+'104,18,107,,102,103,,42,,45,,47,12,,46,36,39,,44,37,10,11,,,69,17,106',
+',38,,,15,16,,,,,,,70,,85,86,,,43,,,84,35,65,,67,68,,,,48,49,51,50,52',
+'53,54,61,64,55,83,62,56,,57,,83,,,,,,,,104,,107,,102,103,104,18,107',
+',102,103,,42,,45,,47,121,,46,36,39,,44,37,106,,,,69,17,106,,38,,,15',
+'16,,,85,86,,,70,,,84,,,43,,,84,35,65,,67,68,,,,48,49,51,50,52,53,54',
+'61,64,55,83,62,56,,57,,83,,,,,,,,104,,107,,102,103,104,18,107,,102,103',
+',42,,45,,47,121,,46,36,39,,44,37,106,,,,69,17,106,,38,,,15,16,,,,,,',
+'70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,83,62,56',
+',57,,,,,,,,,,104,,107,,102,103,,18,,,,,,42,,45,,47,121,,46,36,39,,44',
+'37,106,,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48',
+'49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45',
+',47,121,,46,36,39,,44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,',
+'35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,',
+',,,,,18,,,,,,42,,45,,47,12,,46,36,39,,44,37,10,11,,,69,17,,,38,,,15',
+'16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55',
+',62,56,,57,420,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,12,,46,36,39,,44,37',
+'10,11,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49',
+'51,50,52,53,54,61,64,55,,62,56,,57,415,,,,,,,,,,,,,,,,18,,,,,,42,,45',
+',47,12,,46,36,39,,44,37,10,11,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43',
+',,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,',
+',,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39,,44,37,,,,,69,17,,,38,,,15',
+'16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55',
+',62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39,,44,37,',
+',,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50',
+'52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121',
+',46,36,39,,44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67',
+'68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,',
+',,,42,,45,,47,12,,46,36,39,,44,37,10,11,,,69,17,,,38,,,15,16,,,,,,,70',
+',,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57',
+'349,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,12,,46,36,39,,44,37,10,11,,,69',
+'17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53',
+'54,61,64,55,,62,56,145,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,12,,46',
+'36,39,,44,37,10,11,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67',
+'68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,147,57,,,,,,,,,,,,,,,,,18',
+',,,,,42,,45,,47,12,,46,36,39,,44,37,10,11,,,69,17,,,38,,,15,16,,,,,',
+',70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56',
+',57,149,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,12,,46,36,39,,44,37,10,11',
+',,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50',
+'52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,12,',
+'46,36,39,,44,37,10,11,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65',
+',67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18',
+',,,,,42,,45,,47,121,,46,36,39,,44,37,,,,,69,17,,,38,,,15,16,,,,,,,70',
+',,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57',
+',,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39,,44,37,,,,,69,17,,',
+'38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54',
+'61,64,55,,62,56,,160,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39',
+',44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48',
+'49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45',
+',47,12,,46,36,39,,44,37,10,11,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43',
+',,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,',
+',,,,,,,,18,,,,,,42,,45,,47,12,,46,36,39,,44,37,10,11,,,69,17,,,38,,',
+'15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64',
+'55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39,,44,37',
+',,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51',
+'50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,12',
+',46,36,39,,44,37,10,11,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65',
+',67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18',
+',,,,,42,,45,,47,12,,46,36,39,,44,37,10,11,,,69,17,,,38,,,15,16,,,,,',
+',70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56',
+',57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,12,,46,36,39,,44,37,10,11,,,69',
+'17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53',
+'54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,12,,46,36',
+'39,,44,37,10,11,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68',
+',,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,',
+'42,,45,,47,12,,46,36,39,,44,37,10,11,,,69,17,,,38,,,15,16,,,,,,,70,',
+',,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,',
+',,,,,,,,,,,,,,,18,,,,,,42,,45,,47,12,,46,36,39,,44,37,10,11,,,69,17',
+',,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54',
+'61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39',
+',44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48',
+'49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45',
+',47,12,,46,36,39,,44,37,10,11,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43',
+',,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,',
+',,,,,,,,18,,,,,,177,194,186,195,47,187,197,188,36,176,,179,174,,,,,69',
+'17,198,193,175,,,15,173,,,,,,,70,,,,,196,178,,,,35,65,,67,68,,,,189',
+'190,192,191,182,183,184,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,',
+'42,,45,,47,121,,46,36,39,,44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,,,,',
+',43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,',
+',,,,,,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39,,44,37,,,,,69,17,,,38,',
+',15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64',
+'55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39,,44,37',
+',,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51',
+'50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121',
+',46,36,39,,44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67',
+'68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,',
+',,,42,,45,,47,121,,46,36,39,,44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,',
+',,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,',
+',,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39,,44,37,,,,,69,17,,,38',
+',,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61',
+'64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39,,44',
+'37,,,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49',
+'51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47',
+'121,,46,36,39,,44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65',
+',67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18',
+',,,,,42,,45,,47,121,,46,36,39,,44,37,,,,,69,17,,,38,,,15,16,,,,,,,70',
+',,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57',
+',,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39,,44,37,,,,,69,17,,',
+'38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54',
+'61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39',
+',44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48',
+'49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45',
+',47,121,,46,36,39,,44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,',
+'35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,',
+',,,,,18,,,,,,42,,45,,47,121,,46,36,39,,44,37,,,,,69,17,,,38,,,15,16',
+',,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62',
+'56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39,,44,37,,,,,69',
+'17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53',
+'54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121,,46,36',
+'39,,44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,',
+',48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42',
+',45,,47,121,,46,36,39,,44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43',
+',,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,',
+',,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39,,44,37,,,,,69,17,,,38,,,15',
+'16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55',
+',62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39,,44,37,',
+',,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50',
+'52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121',
+',46,36,39,,44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67',
+'68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,',
+',,,42,,45,,47,121,,46,36,39,,44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,',
+',,,,43,,,222,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57',
+',,,,,,,,,,,,,,,,18,224,,,,,42,,45,,47,12,,46,36,39,,44,37,10,11,,,69',
+'17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53',
+'54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,12,,46,36',
+'39,,44,37,10,11,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68',
+',,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,',
+'42,,45,,47,121,,46,36,39,,44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,,,,',
+',43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,',
+',,,,,,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39,,44,37,,,,,69,17,,,38,',
+',15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64',
+'55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39,,44,37',
+',,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51',
+'50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121',
+',46,36,39,,44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67',
+'68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,',
+',,,42,,45,,47,121,,46,36,39,,44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,',
+',,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,',
+',,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39,,44,37,,,,,69,17,,,38',
+',,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61',
+'64,55,,62,56,,57,,,285,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39',
+',44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48',
+'49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45',
+',47,12,,46,36,39,,44,37,10,11,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43',
+',,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,',
+',,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39,,44,37,,,,,69,17,,,38,,,15',
+'16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55',
+',62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39,,44,37,',
+',,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50',
+'52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121',
+',46,36,39,,44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67',
+'68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,149,,,,,,,,,,,,,,,,18',
+',,,,,42,,45,,47,12,,46,36,39,,44,37,10,11,,,69,17,,,38,,,15,16,,,,,',
+',70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56',
+',57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,12,,46,36,39,,44,37,10,11,,,69',
+'17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53',
+'54,61,64,55,,62,56,,57,324,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,12,,46',
+'36,39,,44,37,10,11,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67',
+'68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,252',
+',,,,42,,45,,47,12,,46,36,39,,44,37,10,11,,,69,17,,,38,,,15,16,,,,,,',
+'70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,',
+'57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,12,,46,36,39,,44,37,10,11,,,69',
+'17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53',
+'54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,121,,46,36',
+'39,,44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,',
+',48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42',
+',45,,47,121,,46,36,39,,44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43',
+',,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,388,,,,',
+',,,,,,,,,,,18,,,,,,42,,45,,47,121,,46,36,39,,44,37,,,,,69,17,,,38,,',
+'15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64',
+'55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47,12,,46,36,39,,44,37',
+'10,11,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65,,67,68,,,,48,49',
+'51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18,,,,,,42,,45,,47',
+'121,,46,36,39,,44,37,,,,,69,17,,,38,,,15,16,,,,,,,70,,,,,,43,,,,35,65',
+',67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57,,,,,,,,,,,,,,,,,18',
+',,,,,42,,45,,47,121,,46,36,39,,44,37,,,,,69,17,,,38,,,15,16,,,,,,,70',
+',,,,,43,,,,35,65,,67,68,,,,48,49,51,50,52,53,54,61,64,55,,62,56,,57',
+',,,,,,,,,,,,,,,,18,61,64,,,62,42,,45,,47,12,,46,36,39,,44,37,10,11,',
+',69,17,,,38,,,15,16,,,,,,,70,,141,,,138,43,,,,35,65,83,67,68,,,,48,49',
+'51,50,52,53,54,70,104,55,107,83,102,103,,,,142,65,,,,,,,104,,107,,102',
+'103,,,,106,,,,,,,,87,88,90,89,92,93,,85,86,106,,,,,84,,,87,88,90,89',
+'92,93,,85,86,,83,,255,,84,,,,,,,91,99,94,104,,107,,102,103,,95,97,96',
+'98,,61,64,91,,62,,,,,,,,,,106,,,,101,100,,,87,88,90,89,92,93,,85,86',
+'83,,254,,,84,,,141,,,138,99,94,104,,107,,102,103,,95,97,96,98,,61,64',
+',91,62,70,,,,,,,,,106,142,65,,101,100,,,87,88,90,89,92,93,,85,86,83',
+',253,,,84,,,141,,,138,99,94,104,,107,,102,103,,95,97,96,98,,,,,91,,70',
+',,,,,,,,106,142,65,,101,100,,,87,88,90,89,92,93,83,85,86,,,,,,84,,,',
+'99,94,104,317,107,,102,103,,95,97,96,98,,,,,,,,91,,,,,,,,106,,,,101',
+'100,,83,87,88,90,89,92,93,,85,86,,,99,94,104,84,107,,102,103,,95,97',
+'96,98,,,,,,,,,,,,,,,91,106,,,,101,100,,83,87,88,90,89,92,93,,85,86,',
+',99,94,104,84,107,83,102,103,,95,97,96,98,,278,279,,,94,104,,107,,102',
+'103,,95,91,106,,,,101,100,,,87,88,90,89,92,93,,85,86,106,,,,,84,,,87',
+'88,90,89,92,93,,85,86,,83,,,,84,,,,,,,91,99,94,104,282,107,,102,103',
+',95,97,96,98,,,,91,,,,,,,,,,,,106,,,,101,100,,83,87,88,90,89,92,93,',
+'85,86,,,99,94,104,84,107,,102,103,,95,97,96,98,,,,,,,,,,,,,,,91,106',
+',,,101,100,,83,87,88,90,89,92,93,,85,86,,,99,94,104,84,107,,102,103',
+',95,97,96,98,,,,,,,,,,,,,,,91,106,,,,101,100,,83,87,88,90,89,92,93,',
+'85,86,,,99,94,104,84,107,,102,103,,95,97,96,98,,,,,,,,,,,,,,,91,106',
+',,,101,100,,83,87,88,90,89,92,93,,85,86,,,99,94,104,84,107,83,102,103',
+',95,97,96,98,,,,,,94,104,,107,,102,103,,95,91,106,,,,101,100,,,87,88',
+'90,89,92,93,,85,86,106,,,,,84,,,87,88,90,89,92,93,83,85,86,,,,,,84,',
+',,99,94,104,91,107,,102,103,,95,97,96,98,,,,,,,,91,,,,,,,,106,,,,101',
+'100,,83,87,88,90,89,92,93,,85,86,,,99,94,104,84,107,,102,103,,95,97',
+'96,98,,,,,,,,,,,,,,,91,106,,,,101,100,,83,87,88,90,89,92,93,,85,86,',
+',99,94,104,84,107,83,102,103,,95,97,96,98,,,,,,94,104,,107,,102,103',
+',95,91,106,,,,101,100,,,87,88,90,89,92,93,,85,86,106,,,,,84,,,87,88',
+'90,89,92,93,83,85,86,,,,,,84,,,,99,94,104,91,107,,102,103,,95,97,96',
+'98,,,,,,,,91,,,,,,,,106,,,,,,,,87,88,90,89,92,93,83,85,86,,,290,,,84',
+',,,99,94,104,,107,,102,103,,95,97,96,98,,,,,,,,91,,,,,,,,106,,,,101',
+'100,,83,87,88,90,89,92,93,,85,86,,,99,94,104,84,107,83,102,103,,95,97',
+'96,98,,,,,,94,104,,107,,102,103,,95,91,106,,,,,100,,,87,88,90,89,92',
+'93,,85,86,106,,,,,84,,,87,88,90,89,92,93,83,85,86,,,,,,84,,,,99,94,104',
+'91,107,,102,103,,95,97,96,98,61,64,,,62,,,91,,,,,,,,106,,,,101,100,',
+',87,88,90,89,92,93,,85,86,,,,,,84,,141,,,138,,305,194,304,195,,302,197',
+'306,,296,,301,303,,,,,91,70,198,193,307,,,,300,,,142,65,,,,,,,,196,308',
+',,,,,,,,,,,311,312,310,309,297,298,299,305,194,304,195,,302,197,306',
+',296,,301,303,,,,,,,198,193,307,,,,300,,,,,,,,,,,,196,308,,,,,,,,,,',
+',311,312,310,309,297,298,299,305,194,304,195,,302,197,306,,296,,301',
+'303,,,,,,,198,193,307,,,,300,,,,,,,,,,,,196,308,,,,,,,,,,,,311,312,310',
+'309,297,298,299,305,194,304,195,,302,197,306,,296,,301,303,,,,,,,198',
+'193,307,,,,300,,,,,,,,,,,,196,308,,,,,,,,,,,,311,312,310,309,297,298',
+'299' ]
+        racc_action_table = arr = ::Array.new(8687, nil)
+        idx = 0
+        clist.each do |str|
+          str.split(',', -1).each do |i|
+            arr[idx] = i.to_i unless i.empty?
+            idx += 1
+          end
+        end
+
+clist = [
+'0,0,251,192,0,0,337,0,191,210,190,189,249,259,185,337,251,379,380,184',
+'380,183,379,210,0,210,200,210,210,71,0,200,0,249,0,0,182,0,0,0,261,0',
+'0,0,0,192,259,0,0,210,191,0,190,189,0,0,185,210,210,210,210,184,0,183',
+'210,210,174,175,0,354,354,210,0,0,176,0,0,0,182,262,0,0,0,0,0,0,0,417',
+'417,0,148,417,417,148,417,210,209,156,156,223,334,156,334,153,153,228',
+'172,275,174,175,209,417,209,280,209,209,176,417,127,417,281,417,417',
+'170,417,417,417,326,417,417,283,127,169,168,417,417,209,167,417,127',
+'326,417,417,162,209,209,209,209,326,417,257,209,209,127,256,417,291',
+'293,209,417,417,295,417,417,300,315,151,417,417,417,417,417,417,417',
+'4,4,417,230,4,4,318,4,209,205,146,322,323,325,231,144,136,134,333,234',
+'335,336,250,205,4,205,121,205,205,133,4,126,4,341,4,4,124,4,4,4,4,4',
+'4,4,4,353,248,4,4,205,355,4,111,109,4,4,108,121,105,205,205,121,4,104',
+'205,205,187,363,4,121,73,205,4,4,365,4,4,366,369,224,4,4,4,4,4,4,4,412',
+'412,4,374,412,412,66,412,205,120,187,247,241,65,187,383,384,386,387',
+'121,121,121,187,120,412,120,390,120,120,41,412,397,412,398,412,412,236',
+'412,412,412,404,412,412,412,412,236,40,412,412,120,8,412,5,414,412,412',
+'1,419,236,187,187,187,412,421,423,186,236,427,412,,,12,412,412,12,412',
+'412,158,,,412,412,412,412,412,412,412,253,253,412,158,253,253,,253,253',
+'186,,158,,186,,12,,,320,12,,186,,,253,158,,12,,,253,,253,,253,253,,253',
+'253,253,,253,253,253,253,,,253,253,320,,253,,320,253,253,320,,186,186',
+'186,320,253,,12,12,12,,253,,45,,253,253,,253,253,,,,253,253,253,253',
+'253,253,253,411,411,253,,411,411,,411,411,202,,320,320,320,45,,,,45',
+',,,,202,411,202,45,202,202,,411,,411,,411,411,,411,411,411,,411,411',
+'411,411,,,411,411,202,,411,,,411,411,7,7,7,,,,411,45,45,45,,,411,,,202',
+'411,411,,411,411,,,,411,411,411,411,411,411,411,254,254,411,,254,254',
+',254,254,204,,,,,,,,,7,7,7,7,,204,254,204,,204,204,,254,,254,,254,254',
+',254,254,254,,254,254,254,254,,,254,254,204,,254,,,254,254,,,,204,204',
+',254,,204,204,,,254,,,204,254,254,,254,254,,,,254,254,254,254,254,254',
+'254,10,10,254,,10,10,,10,204,208,,,,,,,,,,,,,,208,10,208,,208,208,,10',
+',10,,10,10,,10,10,10,,10,10,10,10,,,10,10,208,,10,,,10,10,,,,,,,10,',
+'208,208,,,10,,,208,10,10,,10,10,,,,10,10,10,10,10,10,10,11,11,10,,11',
+'11,,11,,206,,,,,,,,,,,,,,206,11,206,,206,206,,11,,11,,11,11,,11,11,11',
+',11,11,11,11,,,11,11,206,,11,,,11,11,,,,,,,11,,206,206,,,11,,,206,11',
+'11,,11,11,,,,11,11,11,11,11,11,11,255,255,11,207,255,255,,255,,203,',
+',,,,,,207,,207,,207,207,203,255,203,,203,203,,255,,255,,255,255,,255',
+'255,255,,255,255,207,,,,255,255,203,,255,,,255,255,,,207,207,,,255,',
+',207,,,255,,,203,255,255,,255,255,,,,255,255,255,255,255,255,255,15',
+'15,255,122,15,15,,15,,201,,,,,,,,122,,122,,122,122,201,15,201,,201,201',
+',15,,15,,15,15,,15,15,15,,15,15,122,,,,15,15,201,,15,,,15,15,,,,,,,15',
+',,,,,15,,,,15,15,,15,15,,,,15,15,15,15,15,15,15,16,16,15,123,16,16,',
+'16,,,,,,,,,,123,,123,,123,123,,16,,,,,,16,,16,,16,16,,16,16,16,,16,16',
+'123,,,,16,16,,,16,,,16,16,,,,,,,16,,,,,,16,,,,16,16,,16,16,,,,16,16',
+'16,16,16,16,16,17,17,16,,17,17,,17,,,,,,,,,,,,,,,,,17,,,,,,17,,17,,17',
+'17,,17,17,17,,17,17,,,,,17,17,,,17,,,17,17,,,,,,,17,,,,,,17,,,,17,17',
+',17,17,,,,17,17,17,17,17,17,17,18,18,17,,18,18,,18,,,,,,,,,,,,,,,,,18',
+',,,,,18,,18,,18,18,,18,18,18,,18,18,18,18,,,18,18,,,18,,,18,18,,,,,',
+',18,,,,,,18,,,,18,18,,18,18,,,,18,18,18,18,18,18,18,409,409,18,,409',
+'409,,409,409,,,,,,,,,,,,,,,,409,,,,,,409,,409,,409,409,,409,409,409',
+',409,409,409,409,,,409,409,,,409,,,409,409,,,,,,,409,,,,,,409,,,,409',
+'409,,409,409,,,,409,409,409,409,409,409,409,393,393,409,,393,393,,393',
+'393,,,,,,,,,,,,,,,,393,,,,,,393,,393,,393,393,,393,393,393,,393,393',
+'393,393,,,393,393,,,393,,,393,393,,,,,,,393,,,,,,393,,,,393,393,,393',
+'393,,,,393,393,393,393,393,393,393,42,42,393,,42,42,,42,,,,,,,,,,,,',
+',,,,42,,,,,,42,,42,,42,42,,42,42,42,,42,42,,,,,42,42,,,42,,,42,42,,',
+',,,,42,,,,,,42,,,,42,42,,42,42,,,,42,42,42,42,42,42,42,43,43,42,,43',
+'43,,43,,,,,,,,,,,,,,,,,43,,,,,,43,,43,,43,43,,43,43,43,,43,43,,,,,43',
+'43,,,43,,,43,43,,,,,,,43,,,,,,43,,,,43,43,,43,43,,,,43,43,43,43,43,43',
+'43,44,44,43,,44,44,,44,,,,,,,,,,,,,,,,,44,,,,,,44,,44,,44,44,,44,44',
+'44,,44,44,,,,,44,44,,,44,,,44,44,,,,,,,44,,,,,,44,,,,44,44,,44,44,,',
+',44,44,44,44,44,44,44,260,260,44,,260,260,,260,,,,,,,,,,,,,,,,,260,',
+',,,,260,,260,,260,260,,260,260,260,,260,260,260,260,,,260,260,,,260',
+',,260,260,,,,,,,260,,,,,,260,,,,260,260,,260,260,,,,260,260,260,260',
+'260,260,260,264,264,260,,264,264,,264,264,,,,,,,,,,,,,,,,264,,,,,,264',
+',264,,264,264,,264,264,264,,264,264,264,264,,,264,264,,,264,,,264,264',
+',,,,,,264,,,,,,264,,,,264,264,,264,264,,,,264,264,264,264,264,264,264',
+'55,55,264,,55,55,55,55,,,,,,,,,,,,,,,,,55,,,,,,55,,55,,55,55,,55,55',
+'55,,55,55,55,55,,,55,55,,,55,,,55,55,,,,,,,55,,,,,,55,,,,55,55,,55,55',
+',,,55,55,55,55,55,55,55,56,56,55,,56,56,56,56,,,,,,,,,,,,,,,,,56,,,',
+',,56,,56,,56,56,,56,56,56,,56,56,56,56,,,56,56,,,56,,,56,56,,,,,,,56',
+',,,,,56,,,,56,56,,56,56,,,,56,56,56,56,56,56,56,57,57,56,,57,57,,57',
+'57,,,,,,,,,,,,,,,,57,,,,,,57,,57,,57,57,,57,57,57,,57,57,57,57,,,57',
+'57,,,57,,,57,57,,,,,,,57,,,,,,57,,,,57,57,,57,57,,,,57,57,57,57,57,57',
+'57,63,63,57,,63,63,,63,,,,,,,,,,,,,,,,,63,,,,,,63,,63,,63,63,,63,63',
+'63,,63,63,63,63,,,63,63,,,63,,,63,63,,,,,,,63,,,,,,63,,,,63,63,,63,63',
+',,,63,63,63,63,63,63,63,382,382,63,,382,382,,382,,,,,,,,,,,,,,,,,382',
+',,,,,382,,382,,382,382,,382,382,382,,382,382,,,,,382,382,,,382,,,382',
+'382,,,,,,,382,,,,,,382,,,,382,382,,382,382,,,,382,382,382,382,382,382',
+'382,222,222,382,,222,222,,222,,,,,,,,,,,,,,,,,222,,,,,,222,,222,,222',
+'222,,222,222,222,,222,222,,,,,222,222,,,222,,,222,222,,,,,,,222,,,,',
+',222,,,,222,222,,222,222,,,,222,222,222,222,222,222,222,68,68,222,,68',
+'68,,68,,,,,,,,,,,,,,,,,68,,,,,,68,,68,,68,68,,68,68,68,,68,68,,,,,68',
+'68,,,68,,,68,68,,,,,,,68,,,,,,68,,,,68,68,,68,68,,,,68,68,68,68,68,68',
+'68,370,370,68,,370,370,,370,,,,,,,,,,,,,,,,,370,,,,,,370,,370,,370,370',
+',370,370,370,,370,370,370,370,,,370,370,,,370,,,370,370,,,,,,,370,,',
+',,,370,,,,370,370,,370,370,,,,370,370,370,370,370,370,370,72,72,370',
+',72,72,,72,,,,,,,,,,,,,,,,,72,,,,,,72,,72,,72,72,,72,72,72,,72,72,72',
+'72,,,72,72,,,72,,,72,72,,,,,,,72,,,,,,72,,,,72,72,,72,72,,,,72,72,72',
+'72,72,72,72,364,364,72,,364,364,,364,,,,,,,,,,,,,,,,,364,,,,,,364,,364',
+',364,364,,364,364,364,,364,364,,,,,364,364,,,364,,,364,364,,,,,,,364',
+',,,,,364,,,,364,364,,364,364,,,,364,364,364,364,364,364,364,74,74,364',
+',74,74,,74,,,,,,,,,,,,,,,,,74,,,,,,74,,74,,74,74,,74,74,74,,74,74,74',
+'74,,,74,74,,,74,,,74,74,,,,,,,74,,,,,,74,,,,74,74,,74,74,,,,74,74,74',
+'74,74,74,74,75,75,74,,75,75,,75,,,,,,,,,,,,,,,,,75,,,,,,75,,75,,75,75',
+',75,75,75,,75,75,75,75,,,75,75,,,75,,,75,75,,,,,,,75,,,,,,75,,,,75,75',
+',75,75,,,,75,75,75,75,75,75,75,76,76,75,,76,76,,76,,,,,,,,,,,,,,,,,76',
+',,,,,76,,76,,76,76,,76,76,76,,76,76,76,76,,,76,76,,,76,,,76,76,,,,,',
+',76,,,,,,76,,,,76,76,,76,76,,,,76,76,76,76,76,76,76,77,77,76,,77,77',
+',77,,,,,,,,,,,,,,,,,77,,,,,,77,,77,,77,77,,77,77,77,,77,77,77,77,,,77',
+'77,,,77,,,77,77,,,,,,,77,,,,,,77,,,,77,77,,77,77,,,,77,77,77,77,77,77',
+'77,78,78,77,,78,78,,78,,,,,,,,,,,,,,,,,78,,,,,,78,,78,,78,78,,78,78',
+'78,,78,78,78,78,,,78,78,,,78,,,78,78,,,,,,,78,,,,,,78,,,,78,78,,78,78',
+',,,78,78,78,78,78,78,78,79,79,78,,79,79,,79,,,,,,,,,,,,,,,,,79,,,,,',
+'79,,79,,79,79,,79,79,79,,79,79,79,79,,,79,79,,,79,,,79,79,,,,,,,79,',
+',,,,79,,,,79,79,,79,79,,,,79,79,79,79,79,79,79,316,316,79,,316,316,',
+'316,,,,,,,,,,,,,,,,,316,,,,,,316,,316,,316,316,,316,316,316,,316,316',
+',,,,316,316,,,316,,,316,316,,,,,,,316,,,,,,316,,,,316,316,,316,316,',
+',,316,316,316,316,316,316,316,81,81,316,,81,81,,81,,,,,,,,,,,,,,,,,81',
+',,,,,81,,81,,81,81,,81,81,81,,81,81,81,81,,,81,81,,,81,,,81,81,,,,,',
+',81,,,,,,81,,,,81,81,,81,81,,,,81,81,81,81,81,81,81,82,82,81,,82,82',
+',82,,,,,,,,,,,,,,,,,82,,,,,,82,82,82,82,82,82,82,82,82,82,,82,82,,,',
+',82,82,82,82,82,,,82,82,,,,,,,82,,,,,82,82,,,,82,82,,82,82,,,,82,82',
+'82,82,82,82,82,83,83,82,,83,83,,83,,,,,,,,,,,,,,,,,83,,,,,,83,,83,,83',
+'83,,83,83,83,,83,83,,,,,83,83,,,83,,,83,83,,,,,,,83,,,,,,83,,,,83,83',
+',83,83,,,,83,83,83,83,83,83,83,84,84,83,,84,84,,84,,,,,,,,,,,,,,,,,84',
+',,,,,84,,84,,84,84,,84,84,84,,84,84,,,,,84,84,,,84,,,84,84,,,,,,,84',
+',,,,,84,,,,84,84,,84,84,,,,84,84,84,84,84,84,84,85,85,84,,85,85,,85',
+',,,,,,,,,,,,,,,,85,,,,,,85,,85,,85,85,,85,85,85,,85,85,,,,,85,85,,,85',
+',,85,85,,,,,,,85,,,,,,85,,,,85,85,,85,85,,,,85,85,85,85,85,85,85,86',
+'86,85,,86,86,,86,,,,,,,,,,,,,,,,,86,,,,,,86,,86,,86,86,,86,86,86,,86',
+'86,,,,,86,86,,,86,,,86,86,,,,,,,86,,,,,,86,,,,86,86,,86,86,,,,86,86',
+'86,86,86,86,86,87,87,86,,87,87,,87,,,,,,,,,,,,,,,,,87,,,,,,87,,87,,87',
+'87,,87,87,87,,87,87,,,,,87,87,,,87,,,87,87,,,,,,,87,,,,,,87,,,,87,87',
+',87,87,,,,87,87,87,87,87,87,87,88,88,87,,88,88,,88,,,,,,,,,,,,,,,,,88',
+',,,,,88,,88,,88,88,,88,88,88,,88,88,,,,,88,88,,,88,,,88,88,,,,,,,88',
+',,,,,88,,,,88,88,,88,88,,,,88,88,88,88,88,88,88,89,89,88,,89,89,,89',
+',,,,,,,,,,,,,,,,89,,,,,,89,,89,,89,89,,89,89,89,,89,89,,,,,89,89,,,89',
+',,89,89,,,,,,,89,,,,,,89,,,,89,89,,89,89,,,,89,89,89,89,89,89,89,90',
+'90,89,,90,90,,90,,,,,,,,,,,,,,,,,90,,,,,,90,,90,,90,90,,90,90,90,,90',
+'90,,,,,90,90,,,90,,,90,90,,,,,,,90,,,,,,90,,,,90,90,,90,90,,,,90,90',
+'90,90,90,90,90,91,91,90,,91,91,,91,,,,,,,,,,,,,,,,,91,,,,,,91,,91,,91',
+'91,,91,91,91,,91,91,,,,,91,91,,,91,,,91,91,,,,,,,91,,,,,,91,,,,91,91',
+',91,91,,,,91,91,91,91,91,91,91,92,92,91,,92,92,,92,,,,,,,,,,,,,,,,,92',
+',,,,,92,,92,,92,92,,92,92,92,,92,92,,,,,92,92,,,92,,,92,92,,,,,,,92',
+',,,,,92,,,,92,92,,92,92,,,,92,92,92,92,92,92,92,93,93,92,,93,93,,93',
+',,,,,,,,,,,,,,,,93,,,,,,93,,93,,93,93,,93,93,93,,93,93,,,,,93,93,,,93',
+',,93,93,,,,,,,93,,,,,,93,,,,93,93,,93,93,,,,93,93,93,93,93,93,93,94',
+'94,93,,94,94,,94,,,,,,,,,,,,,,,,,94,,,,,,94,,94,,94,94,,94,94,94,,94',
+'94,,,,,94,94,,,94,,,94,94,,,,,,,94,,,,,,94,,,,94,94,,94,94,,,,94,94',
+'94,94,94,94,94,95,95,94,,95,95,,95,,,,,,,,,,,,,,,,,95,,,,,,95,,95,,95',
+'95,,95,95,95,,95,95,,,,,95,95,,,95,,,95,95,,,,,,,95,,,,,,95,,,,95,95',
+',95,95,,,,95,95,95,95,95,95,95,96,96,95,,96,96,,96,,,,,,,,,,,,,,,,,96',
+',,,,,96,,96,,96,96,,96,96,96,,96,96,,,,,96,96,,,96,,,96,96,,,,,,,96',
+',,,,,96,,,,96,96,,96,96,,,,96,96,96,96,96,96,96,97,97,96,,97,97,,97',
+',,,,,,,,,,,,,,,,97,,,,,,97,,97,,97,97,,97,97,97,,97,97,,,,,97,97,,,97',
+',,97,97,,,,,,,97,,,,,,97,,,,97,97,,97,97,,,,97,97,97,97,97,97,97,98',
+'98,97,,98,98,,98,,,,,,,,,,,,,,,,,98,,,,,,98,,98,,98,98,,98,98,98,,98',
+'98,,,,,98,98,,,98,,,98,98,,,,,,,98,,,,,,98,,,,98,98,,98,98,,,,98,98',
+'98,98,98,98,98,99,99,98,,99,99,,99,,,,,,,,,,,,,,,,,99,,,,,,99,,99,,99',
+'99,,99,99,99,,99,99,,,,,99,99,,,99,,,99,99,,,,,,,99,,,,,,99,,,,99,99',
+',99,99,,,,99,99,99,99,99,99,99,100,100,99,,100,100,,100,,,,,,,,,,,,',
+',,,,100,,,,,,100,,100,,100,100,,100,100,100,,100,100,,,,,100,100,,,100',
+',,100,100,,,,,,,100,,,,,,100,,,,100,100,,100,100,,,,100,100,100,100',
+'100,100,100,101,101,100,,101,101,,101,,,,,,,,,,,,,,,,,101,,,,,,101,',
+'101,,101,101,,101,101,101,,101,101,,,,,101,101,,,101,,,101,101,,,,,',
+',101,,,,,,101,,,,101,101,,101,101,,,,101,101,101,101,101,101,101,102',
+'102,101,,102,102,,102,,,,,,,,,,,,,,,,,102,,,,,,102,,102,,102,102,,102',
+'102,102,,102,102,,,,,102,102,,,102,,,102,102,,,,,,,102,,,,,,102,,,102',
+'102,102,,102,102,,,,102,102,102,102,102,102,102,103,103,102,,103,103',
+',103,,,,,,,,,,,,,,,,,103,103,,,,,103,,103,,103,103,,103,103,103,,103',
+'103,103,103,,,103,103,,,103,,,103,103,,,,,,,103,,,,,,103,,,,103,103',
+',103,103,,,,103,103,103,103,103,103,103,265,265,103,,265,265,,265,,',
+',,,,,,,,,,,,,,265,,,,,,265,,265,,265,265,,265,265,265,,265,265,265,265',
+',,265,265,,,265,,,265,265,,,,,,,265,,,,,,265,,,,265,265,,265,265,,,',
+'265,265,265,265,265,265,265,179,179,265,,179,179,,179,,,,,,,,,,,,,,',
+',,179,,,,,,179,,179,,179,179,,179,179,179,,179,179,,,,,179,179,,,179',
+',,179,179,,,,,,,179,,,,,,179,,,,179,179,,179,179,,,,179,179,179,179',
+'179,179,179,106,106,179,,106,106,,106,,,,,,,,,,,,,,,,,106,,,,,,106,',
+'106,,106,106,,106,106,106,,106,106,,,,,106,106,,,106,,,106,106,,,,,',
+',106,,,,,,106,,,,106,106,,106,106,,,,106,106,106,106,106,106,106,107',
+'107,106,,107,107,,107,,,,,,,,,,,,,,,,,107,,,,,,107,,107,,107,107,,107',
+'107,107,,107,107,,,,,107,107,,,107,,,107,107,,,,,,,107,,,,,,107,,,,107',
+'107,,107,107,,,,107,107,107,107,107,107,107,178,178,107,,178,178,,178',
+',,,,,,,,,,,,,,,,178,,,,,,178,,178,,178,178,,178,178,178,,178,178,,,',
+',178,178,,,178,,,178,178,,,,,,,178,,,,,,178,,,,178,178,,178,178,,,,178',
+'178,178,178,178,178,178,177,177,178,,177,177,,177,,,,,,,,,,,,,,,,,177',
+',,,,,177,,177,,177,177,,177,177,177,,177,177,,,,,177,177,,,177,,,177',
+'177,,,,,,,177,,,,,,177,,,,177,177,,177,177,,,,177,177,177,177,177,177',
+'177,110,110,177,,110,110,,110,,,,,,,,,,,,,,,,,110,,,,,,110,,110,,110',
+'110,,110,110,110,,110,110,,,,,110,110,,,110,,,110,110,,,,,,,110,,,,',
+',110,,,,110,110,,110,110,,,,110,110,110,110,110,110,110,173,173,110',
+',173,173,,173,,,173,,,,,,,,,,,,,,173,,,,,,173,,173,,173,173,,173,173',
+'173,,173,173,,,,,173,173,,,173,,,173,173,,,,,,,173,,,,,,173,,,,173,173',
+',173,173,,,,173,173,173,173,173,173,173,270,270,173,,270,270,,270,,',
+',,,,,,,,,,,,,,270,,,,,,270,,270,,270,270,,270,270,270,,270,270,270,270',
+',,270,270,,,270,,,270,270,,,,,,,270,,,,,,270,,,,270,270,,270,270,,,',
+'270,270,270,270,270,270,270,285,285,270,,285,285,,285,,,,,,,,,,,,,,',
+',,285,,,,,,285,,285,,285,285,,285,285,285,,285,285,,,,,285,285,,,285',
+',,285,285,,,,,,,285,,,,,,285,,,,285,285,,285,285,,,,285,285,285,285',
+'285,285,285,286,286,285,,286,286,,286,,,,,,,,,,,,,,,,,286,,,,,,286,',
+'286,,286,286,,286,286,286,,286,286,,,,,286,286,,,286,,,286,286,,,,,',
+',286,,,,,,286,,,,286,286,,286,286,,,,286,286,286,286,286,286,286,287',
+'287,286,,287,287,,287,,,,,,,,,,,,,,,,,287,,,,,,287,,287,,287,287,,287',
+'287,287,,287,287,,,,,287,287,,,287,,,287,287,,,,,,,287,,,,,,287,,,,287',
+'287,,287,287,,,,287,287,287,287,287,287,287,160,160,287,,160,160,,160',
+'160,,,,,,,,,,,,,,,,160,,,,,,160,,160,,160,160,,160,160,160,,160,160',
+'160,160,,,160,160,,,160,,,160,160,,,,,,,160,,,,,,160,,,,160,160,,160',
+'160,,,,160,160,160,160,160,160,160,340,340,160,,340,340,,340,,,,,,,',
+',,,,,,,,,340,,,,,,340,,340,,340,340,,340,340,340,,340,340,340,340,,',
+'340,340,,,340,,,340,340,,,,,,,340,,,,,,340,,,,340,340,,340,340,,,,340',
+'340,340,340,340,340,340,239,239,340,,239,239,,239,239,,,,,,,,,,,,,,',
+',239,,,,,,239,,239,,239,239,,239,239,239,,239,239,239,239,,,239,239',
+',,239,,,239,239,,,,,,,239,,,,,,239,,,,239,239,,239,239,,,,239,239,239',
+'239,239,239,239,128,128,239,,128,128,,128,,,,,,,,,,,,,,,,,128,128,,',
+',,128,,128,,128,128,,128,128,128,,128,128,128,128,,,128,128,,,128,,',
+'128,128,,,,,,,128,,,,,,128,,,,128,128,,128,128,,,,128,128,128,128,128',
+'128,128,157,157,128,,157,157,,157,,,,,,,,,,,,,,,,,157,,,,,,157,,157',
+',157,157,,157,157,157,,157,157,157,157,,,157,157,,,157,,,157,157,,,',
+',,,157,,,,,,157,,,,157,157,,157,157,,,,157,157,157,157,157,157,157,289',
+'289,157,,289,289,,289,,,,,,,,,,,,,,,,,289,,,,,,289,,289,,289,289,,289',
+'289,289,,289,289,,,,,289,289,,,289,,,289,289,,,,,,,289,,,,,,289,,,,289',
+'289,,289,289,,,,289,289,289,289,289,289,289,290,290,289,,290,290,,290',
+',,,,,,,,,,,,,,,,290,,,,,,290,,290,,290,290,,290,290,290,,290,290,,,',
+',290,290,,,290,,,290,290,,,,,,,290,,,,,,290,,,,290,290,,290,290,,,,290',
+'290,290,290,290,290,290,338,338,290,,338,338,,338,338,,,,,,,,,,,,,,',
+',338,,,,,,338,,338,,338,338,,338,338,338,,338,338,,,,,338,338,,,338',
+',,338,338,,,,,,,338,,,,,,338,,,,338,338,,338,338,,,,338,338,338,338',
+'338,338,338,331,331,338,,331,331,,331,,,,,,,,,,,,,,,,,331,,,,,,331,',
+'331,,331,331,,331,331,331,,331,331,331,331,,,331,331,,,331,,,331,331',
+',,,,,,331,,,,,,331,,,,331,331,,331,331,,,,331,331,331,331,331,331,331',
+'330,330,331,,330,330,,330,,,,,,,,,,,,,,,,,330,,,,,,330,,330,,330,330',
+',330,330,330,,330,330,,,,,330,330,,,330,,,330,330,,,,,,,330,,,,,,330',
+',,,330,330,,330,330,,,,330,330,330,330,330,330,330,327,327,330,,327',
+'327,,327,,,,,,,,,,,,,,,,,327,,,,,,327,,327,,327,327,,327,327,327,,327',
+'327,,,,,327,327,,,327,,,327,327,,,,,,,327,,,,,,327,,,,327,327,,327,327',
+',,,327,327,327,327,327,327,327,80,80,327,,80,80,,80,,,,,,,,,,,,,,,,',
+'80,258,258,,,258,80,,80,,80,80,,80,80,80,,80,80,80,80,,,80,80,,,80,',
+',80,80,,,,,,,80,,258,,,258,80,,,,80,80,212,80,80,,,,80,80,80,80,80,80',
+'80,258,212,80,212,211,212,212,,,,258,258,,,,,,,211,,211,,211,211,,,',
+'212,,,,,,,,212,212,212,212,212,212,,212,212,211,,,,,212,,,211,211,211',
+'211,211,211,,211,211,,132,,132,,211,,,,,,,212,132,132,132,,132,,132',
+'132,,132,132,132,132,,46,46,211,,46,,,,,,,,,,132,,,,132,132,,,132,132',
+'132,132,132,132,,132,132,131,,131,,,132,,,46,,,46,131,131,131,,131,',
+'131,131,,131,131,131,131,,188,188,,132,188,46,,,,,,,,,131,46,46,,131',
+'131,,,131,131,131,131,131,131,,131,131,129,,129,,,131,,,188,,,188,129',
+'129,129,,129,,129,129,,129,129,129,129,,,,,131,,188,,,,,,,,,129,188',
+'188,,129,129,,,129,129,129,129,129,129,232,129,129,,,,,,129,,,,232,232',
+'232,232,232,,232,232,,232,232,232,232,,,,,,,,129,,,,,,,,232,,,,232,232',
+',159,232,232,232,232,232,232,,232,232,,,159,159,159,232,159,,159,159',
+',159,159,159,159,,,,,,,,,,,,,,,232,159,,,,159,159,,9,159,159,159,159',
+'159,159,,159,159,,,9,9,9,159,9,214,9,9,,9,9,9,9,,159,159,,,214,214,',
+'214,,214,214,,214,159,9,,,,9,9,,,9,9,9,9,9,9,,9,9,214,,,,,9,,,214,214',
+'214,214,214,214,,214,214,,171,,,,214,,,,,,,9,171,171,171,171,171,,171',
+'171,,171,171,171,171,,,,214,,,,,,,,,,,,171,,,,171,171,,362,171,171,171',
+'171,171,171,,171,171,,,362,362,362,171,362,,362,362,,362,362,362,362',
+',,,,,,,,,,,,,,171,362,,,,362,362,,358,362,362,362,362,362,362,,362,362',
+',,358,358,358,362,358,,358,358,,358,358,358,358,,,,,,,,,,,,,,,362,358',
+',,,358,358,,227,358,358,358,358,358,358,,358,358,,,227,227,227,358,227',
+',227,227,,227,227,227,227,,,,,,,,,,,,,,,358,227,,,,227,227,,199,227',
+'227,227,227,227,227,,227,227,,,199,199,199,227,199,213,199,199,,199',
+'199,199,199,,,,,,213,213,,213,,213,213,,213,227,199,,,,199,199,,,199',
+'199,199,199,199,199,,199,199,213,,,,,199,,,213,213,213,213,213,213,359',
+'213,213,,,,,,213,,,,359,359,359,199,359,,359,359,,359,359,359,359,,',
+',,,,,213,,,,,,,,359,,,,359,359,,360,359,359,359,359,359,359,,359,359',
+',,360,360,360,359,360,,360,360,,360,360,360,360,,,,,,,,,,,,,,,359,360',
+',,,360,360,,361,360,360,360,360,360,360,,360,360,,,361,361,361,360,361',
+'215,361,361,,361,361,361,361,,,,,,215,215,,215,,215,215,,215,360,361',
+',,,361,361,,,361,361,361,361,361,361,,361,361,215,,,,,361,,,215,215',
+'215,215,215,215,217,215,215,,,,,,215,,,,217,217,217,361,217,,217,217',
+',217,217,217,217,,,,,,,,215,,,,,,,,217,,,,,,,,217,217,217,217,217,217',
+'219,217,217,,,219,,,217,,,,219,219,219,,219,,219,219,,219,219,219,219',
+',,,,,,,217,,,,,,,,219,,,,219,219,,218,219,219,219,219,219,219,,219,219',
+',,218,218,218,219,218,216,218,218,,218,218,218,218,,,,,,216,216,,216',
+',216,216,,216,219,218,,,,,218,,,218,218,218,218,218,218,,218,218,216',
+',,,,218,,,216,216,216,216,216,216,378,216,216,,,,,,216,,,,378,378,378',
+'218,378,,378,378,,378,378,378,378,343,343,,,343,,,216,,,,,,,,378,,,',
+'378,378,,,378,378,378,378,378,378,,378,378,,,,,,378,,343,,,343,,284',
+'284,284,284,,284,284,284,,284,,284,284,,,,,378,343,284,284,284,,,,284',
+',,343,343,,,,,,,,284,284,,,,,,,,,,,,284,284,284,284,284,284,284,282',
+'282,282,282,,282,282,282,,282,,282,282,,,,,,,282,282,282,,,,282,,,,',
+',,,,,,,282,282,,,,,,,,,,,,282,282,282,282,282,282,282,226,226,226,226',
+',226,226,226,,226,,226,226,,,,,,,226,226,226,,,,226,,,,,,,,,,,,226,226',
+',,,,,,,,,,,226,226,226,226,226,226,226,317,317,317,317,,317,317,317',
+',317,,317,317,,,,,,,317,317,317,,,,317,,,,,,,,,,,,317,317,,,,,,,,,,',
+',317,317,317,317,317,317,317' ]
+        racc_action_check = arr = ::Array.new(8687, nil)
+        idx = 0
+        clist.each do |str|
+          str.split(',', -1).each do |i|
+            arr[idx] = i.to_i unless i.empty?
+            idx += 1
+          end
+        end
+
+racc_action_pointer = [
+    -2,   317,   nil,   nil,   172,   300,   nil,   475,   302,  7712,
+   607,   694,   326,   nil,   nil,   868,   955,  1042,  1129,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   236,   264,  1390,  1477,  1564,   412,  7481,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,  1825,  1912,  1999,   nil,   nil,
+   nil,   nil,   nil,  2086,   nil,   198,   196,   nil,  2347,   nil,
+   nil,    29,  2521,   231,  2695,  2782,  2869,  2956,  3043,  3130,
+  7306,  3304,  3391,  3478,  3565,  3652,  3739,  3826,  3913,  4000,
+  4087,  4174,  4261,  4348,  4435,  4522,  4609,  4696,  4783,  4870,
+  4957,  5044,  5131,  5218,   196,   223,  5479,  5566,   221,   218,
+  5827,   200,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   263,   194,   866,   953,   183,   nil,   196,    82,  6610,  7564,
+   nil,  7507,  7450,   177,   178,   nil,   169,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   176,   nil,   171,   nil,    80,   nil,
+   nil,   154,   nil,    99,   nil,   nil,    95,  6697,   302,  7665,
+  6349,   nil,   130,   nil,   nil,   nil,   nil,   128,   124,   123,
+   114,  7787,    93,  5914,    54,    55,    62,  5740,  5653,  5392,
+   nil,   nil,    24,     9,     7,     2,   320,   234,  7538,    -1,
+    -2,    -4,    -9,   nil,   nil,   nil,   nil,   nil,   nil,  7975,
+    18,   872,   437,   785,   524,   176,   698,   779,   611,    89,
+     2,  7392,  7375,  7992,  7729,  8157,  8329,  8211,  8312,  8265,
+   nil,   nil,  2260,    86,   182,   nil,  8541,  7928,    57,   nil,
+   153,   146,  7618,   nil,   155,   nil,   270,   nil,   nil,  6523,
+   nil,   260,   nil,   nil,   nil,   nil,   nil,   256,   184,   -24,
+   189,   -11,   nil,   346,   520,   781,   145,   112,  7331,   -28,
+  1651,    32,    71,   nil,  1738,  5305,   nil,   nil,   nil,   nil,
+  6001,   nil,   nil,   nil,   nil,    94,   nil,   nil,   nil,   nil,
+   101,   110,  8484,   120,  8427,  6088,  6175,  6262,   nil,  6784,
+  6871,   143,   nil,   130,   nil,   148,   nil,   nil,   nil,   nil,
+   152,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   155,  3217,  8598,   171,   nil,
+   360,   nil,   172,   176,   nil,   116,    91,  7219,   nil,   nil,
+  7132,  7045,   nil,   182,    67,   184,   162,    -7,  6958,   nil,
+  6436,   198,   nil,  8413,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   148,   -11,   211,   nil,   nil,  7881,  8046,
+  8093,  8140,  7834,   231,  2608,   177,   241,   nil,   nil,   239,
+  2434,   nil,   nil,   nil,   237,   nil,   nil,   nil,  8383,     9,
+   -15,   nil,  2173,   267,   244,   nil,   269,   270,   nil,   nil,
+   277,   nil,   nil,  1303,   nil,   nil,   nil,   282,   252,   nil,
+   nil,   nil,   nil,   nil,   291,   nil,   nil,   nil,   nil,  1216,
+   nil,   433,   259,   nil,   304,   nil,   nil,    85,   nil,   308,
+   nil,   314,   nil,   315,   nil,   nil,   nil,   286,   nil,   nil,
+   nil,   nil ]
+
+racc_action_default = [
+    -3,  -252,    -1,    -2,    -4,    -5,    -8,   -10,   -16,   -21,
+  -252,  -252,  -252,   -33,   -34,  -252,  -252,  -252,  -252,   -61,
+   -62,   -63,   -64,   -65,   -66,   -67,   -68,   -69,   -70,   -71,
+   -72,   -73,   -74,   -75,   -76,   -77,   -78,   -79,   -80,   -81,
+   -86,   -90,  -252,  -252,  -252,  -252,  -252,  -182,  -183,  -184,
+  -185,  -186,  -187,  -188,  -189,  -252,  -252,  -252,  -200,  -201,
+  -202,  -203,  -204,  -252,  -206,  -252,  -219,  -222,  -252,  -227,
+  -228,  -252,  -252,    -7,  -252,  -252,  -252,  -252,  -252,  -252,
+  -252,  -252,  -126,  -252,  -252,  -252,  -252,  -252,  -252,  -252,
+  -252,  -252,  -252,  -252,  -252,  -252,  -252,  -252,  -252,  -252,
+  -252,  -252,  -252,  -252,  -252,  -121,  -251,  -251,   -22,   -23,
+  -252,  -251,  -139,  -160,  -161,  -162,  -163,  -164,  -165,  -166,
+   -46,  -252,   -47,   -54,  -252,   -87,  -252,  -252,  -252,  -252,
+   -97,  -252,  -252,  -251,  -229,  -148,  -150,  -151,  -152,  -153,
+  -154,  -156,  -157,   -14,  -229,  -191,  -229,  -193,  -252,  -196,
+  -197,  -252,  -205,  -252,  -210,  -213,  -252,  -217,  -252,  -252,
+  -252,   432,    -6,    -9,   -11,   -12,   -13,   -17,   -18,   -19,
+   -20,  -252,  -229,  -252,   -79,   -80,   -81,  -240,  -246,  -234,
+  -127,  -130,  -187,  -188,  -189,  -252,  -237,  -235,  -243,  -183,
+  -184,  -185,  -186,  -233,  -238,  -239,  -241,  -242,  -244,   -59,
+  -252,   -36,   -37,   -38,   -39,   -40,   -41,   -42,   -43,   -44,
+   -45,   -48,   -49,   -50,   -51,   -52,   -53,   -55,   -56,  -252,
+   -57,  -115,  -252,  -229,   -83,   -91,  -126,  -125,  -252,  -124,
+  -252,  -231,  -252,   -28,  -251,  -167,  -252,   -58,   -92,  -252,
+   -95,  -229,  -170,  -172,  -173,  -174,  -175,  -177,  -252,  -252,
+  -180,  -252,   -89,  -252,  -252,  -252,  -252,  -251,  -230,  -252,
+  -230,  -252,  -252,  -194,  -252,  -252,  -207,  -208,  -209,  -211,
+  -252,  -214,  -215,  -216,  -218,  -229,  -220,  -223,  -225,  -226,
+    -8,  -252,  -126,  -252,  -230,  -252,  -252,  -252,   -35,  -252,
+  -252,  -229,  -117,  -252,   -85,  -229,  -129,  -131,  -132,  -133,
+  -252,  -234,  -235,  -236,  -237,  -240,  -243,  -245,  -246,  -247,
+  -248,  -249,  -250,  -122,  -123,  -252,  -232,  -126,  -252,  -142,
+  -252,  -168,  -229,  -252,   -94,  -252,  -230,  -252,  -178,  -179,
+  -252,  -252,   -88,  -252,  -100,  -252,  -106,  -252,  -252,  -110,
+  -251,  -252,  -158,  -252,  -149,  -155,   -15,  -190,  -192,  -195,
+  -198,  -199,  -212,  -252,  -252,  -229,   -26,  -128,  -136,  -134,
+  -135,   -60,  -119,  -252,  -230,   -82,  -252,   -25,   -29,  -229,
+  -251,  -143,  -144,  -145,  -252,   -93,   -96,  -171,  -176,  -252,
+  -100,   -99,  -252,  -252,  -106,  -105,  -252,  -252,  -109,  -111,
+  -252,  -140,  -141,  -252,  -159,  -221,  -224,  -252,   -30,  -116,
+  -118,   -84,  -120,   -27,  -252,  -169,  -181,   -98,  -101,  -252,
+  -104,  -252,  -251,  -137,  -252,  -147,   -24,   -31,  -138,  -252,
+  -103,  -252,  -108,  -252,  -113,  -114,  -146,  -231,  -102,  -107,
+  -112,   -32 ]
+
+racc_goto_table = [
+     2,   120,   122,   123,   125,   124,   137,   231,   139,   235,
+   133,   200,   152,   257,   172,   221,   250,   315,   241,   344,
+   339,   277,   390,   261,   234,   262,    73,   423,   129,   131,
+   132,   235,   228,   230,   338,   291,   408,   357,   108,   109,
+   238,   385,   143,   143,   151,   381,   256,   250,   220,   275,
+   154,   283,   404,   368,   159,   318,   371,   144,   146,   341,
+   397,   163,   164,   165,   166,   345,   377,   329,   171,   199,
+   201,   202,   203,   204,   205,   206,   207,   208,   209,   210,
+   211,   212,   213,   214,   215,   216,   217,   218,   219,   410,
+   143,   407,   227,   227,   162,   328,   232,   350,   271,   272,
+     3,   269,   293,   389,   394,   223,   167,   168,   169,   170,
+   270,   268,   155,   157,   273,   143,     1,   nil,   nil,   nil,
+   325,   nil,   nil,   nil,   nil,   250,   nil,   322,   nil,   nil,
+   251,   nil,   319,   nil,   nil,   292,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   280,   137,   nil,
+   139,   133,   nil,   nil,   353,   342,   nil,   274,   295,   122,
+   281,   nil,   nil,   129,   131,   132,   nil,   nil,   nil,   nil,
+   363,   nil,   nil,   nil,   366,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   294,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   374,   nil,   nil,   nil,   nil,   nil,   nil,   219,   nil,
+   nil,   nil,   nil,   431,   355,   250,   396,   nil,   137,   352,
+   139,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   398,   nil,   nil,   nil,   392,   323,
+   nil,   199,   nil,   nil,   nil,   nil,   nil,   346,   403,   369,
+   nil,   151,   351,   333,   335,   nil,   nil,   154,   379,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   392,   nil,
+   nil,   358,   359,   360,   nil,   361,   362,   400,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   372,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   232,   137,   nil,   139,   nil,   nil,   nil,   nil,
+   424,   nil,   nil,   378,   427,   nil,   199,   nil,   346,   nil,
+   nil,   nil,   nil,   nil,   199,   nil,   nil,   nil,   nil,   401,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   219,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   129,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   414,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   232,   nil,   nil,   nil,   nil,   nil,   419,
+   nil,   421,   425 ]
+
+racc_goto_check = [
+     2,    10,    10,    10,    37,     6,    35,    13,    34,    49,
+    57,    19,    80,    15,    11,    50,    36,    14,    42,    65,
+    47,    88,    59,    15,    58,    15,     5,    48,    10,    10,
+    10,    49,    53,    53,    46,    51,    43,    54,     9,     9,
+    41,    45,     6,     6,     6,    44,    58,    36,    20,    42,
+     6,    15,    59,    16,    10,    61,    62,     8,     8,    64,
+    12,     6,     6,     6,     6,    67,    68,    69,    10,    10,
+    10,    10,    10,    10,    10,    10,    10,    10,    10,    10,
+    10,    10,    10,    10,    10,    10,    10,    10,    10,    45,
+     6,    44,    10,    10,     5,    71,    10,    75,    76,    77,
+     3,    81,    15,    47,    65,     8,     9,     9,     9,     9,
+    82,    84,    85,    86,    87,     6,     1,   nil,   nil,   nil,
+    15,   nil,   nil,   nil,   nil,    36,   nil,    42,   nil,   nil,
+     8,   nil,    49,   nil,   nil,    50,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,     6,    35,   nil,
+    34,    57,   nil,   nil,    15,    49,   nil,     2,    11,    10,
+     2,   nil,   nil,    10,    10,    10,   nil,   nil,   nil,   nil,
+    15,   nil,   nil,   nil,    15,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,    37,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,    15,   nil,   nil,   nil,   nil,   nil,   nil,    10,   nil,
+   nil,   nil,   nil,    14,    11,    36,    88,   nil,    35,    80,
+    34,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,    15,   nil,   nil,   nil,    49,     2,
+   nil,    10,   nil,   nil,   nil,   nil,   nil,     6,    15,    11,
+   nil,     6,     6,     2,     2,   nil,   nil,     6,    19,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,    49,   nil,
+   nil,    10,    10,    10,   nil,    10,    10,    50,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,    57,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,    10,    35,   nil,    34,   nil,   nil,   nil,   nil,
+    49,   nil,   nil,    10,    13,   nil,    10,   nil,     6,   nil,
+   nil,   nil,   nil,   nil,    10,   nil,   nil,   nil,   nil,    37,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+    10,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,    10,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,     2,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,    10,   nil,   nil,   nil,   nil,   nil,     2,
+   nil,     2,     2 ]
+
+racc_goto_pointer = [
+   nil,   116,     0,   100,   nil,    22,   -13,   nil,     2,    28,
+   -14,   -68,  -295,  -103,  -214,  -121,  -263,   nil,   nil,   -72,
+   -54,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,   nil,
+   nil,   nil,   nil,   nil,   -38,   -40,  -111,   -36,   nil,   nil,
+   nil,   -86,  -109,  -346,  -289,  -295,  -221,  -235,  -385,  -102,
+   -87,  -187,   nil,   -74,  -247,   nil,   nil,   -35,   -87,  -318,
+   nil,  -179,  -264,   nil,  -198,  -239,   nil,  -194,  -260,  -182,
+   nil,  -153,   nil,   nil,   nil,  -167,   -58,   -57,   nil,   nil,
+   -51,   -52,   -43,   nil,   -42,    47,    47,   -43,  -138 ]
+
+racc_goto_default = [
+   nil,   nil,   391,   nil,     4,     5,     6,     7,   nil,     8,
+     9,   nil,   nil,   nil,   nil,   nil,   233,    13,    14,   337,
+   nil,    19,    20,    21,    22,    23,    24,    25,    26,    27,
+    28,    29,    30,    31,    32,    33,    34,   nil,    40,    41,
+   126,   nil,   nil,   130,   nil,   nil,   nil,   nil,   nil,   229,
+   nil,   nil,   105,   nil,   180,   185,   181,   112,   nil,   nil,
+   111,   nil,   nil,   134,   nil,   135,   136,   140,   242,   243,
+   244,   245,   246,   249,   148,   150,    58,    59,    60,    63,
+   nil,   nil,   nil,   153,   nil,   nil,   nil,   nil,   nil ]
+
+racc_reduce_table = [
+  0, 0, :racc_error,
+  1, 95, :_reduce_1,
+  1, 95, :_reduce_2,
+  0, 95, :_reduce_3,
+  1, 96, :_reduce_4,
+  1, 98, :_reduce_5,
+  3, 98, :_reduce_6,
+  2, 98, :_reduce_7,
+  1, 99, :_reduce_8,
+  3, 99, :_reduce_9,
+  1, 100, :_reduce_none,
+  3, 100, :_reduce_11,
+  3, 100, :_reduce_12,
+  3, 100, :_reduce_13,
+  1, 102, :_reduce_14,
+  3, 102, :_reduce_15,
+  1, 101, :_reduce_none,
+  3, 101, :_reduce_17,
+  3, 101, :_reduce_18,
+  3, 101, :_reduce_19,
+  3, 101, :_reduce_20,
+  1, 103, :_reduce_none,
+  2, 103, :_reduce_22,
+  2, 103, :_reduce_23,
+  7, 103, :_reduce_24,
+  5, 103, :_reduce_25,
+  5, 103, :_reduce_26,
+  4, 110, :_reduce_27,
+  1, 107, :_reduce_28,
+  3, 107, :_reduce_29,
+  1, 106, :_reduce_30,
+  2, 106, :_reduce_31,
+  4, 106, :_reduce_32,
+  1, 104, :_reduce_none,
+  1, 104, :_reduce_none,
+  4, 104, :_reduce_35,
+  3, 104, :_reduce_36,
+  3, 104, :_reduce_37,
+  3, 104, :_reduce_38,
+  3, 104, :_reduce_39,
+  3, 104, :_reduce_40,
+  3, 104, :_reduce_41,
+  3, 104, :_reduce_42,
+  3, 104, :_reduce_43,
+  3, 104, :_reduce_44,
+  3, 104, :_reduce_45,
+  2, 104, :_reduce_46,
+  2, 104, :_reduce_47,
+  3, 104, :_reduce_48,
+  3, 104, :_reduce_49,
+  3, 104, :_reduce_50,
+  3, 104, :_reduce_51,
+  3, 104, :_reduce_52,
+  3, 104, :_reduce_53,
+  2, 104, :_reduce_54,
+  3, 104, :_reduce_55,
+  3, 104, :_reduce_56,
+  3, 104, :_reduce_57,
+  3, 104, :_reduce_58,
+  1, 113, :_reduce_59,
+  3, 113, :_reduce_60,
+  1, 111, :_reduce_none,
+  1, 111, :_reduce_none,
+  1, 111, :_reduce_none,
+  1, 111, :_reduce_none,
+  1, 111, :_reduce_none,
+  1, 111, :_reduce_none,
+  1, 111, :_reduce_none,
+  1, 111, :_reduce_none,
+  1, 111, :_reduce_none,
+  1, 111, :_reduce_none,
+  1, 111, :_reduce_none,
+  1, 111, :_reduce_none,
+  1, 111, :_reduce_none,
+  1, 111, :_reduce_none,
+  1, 111, :_reduce_none,
+  1, 111, :_reduce_none,
+  1, 111, :_reduce_77,
+  1, 111, :_reduce_78,
+  1, 111, :_reduce_79,
+  1, 111, :_reduce_80,
+  1, 111, :_reduce_81,
+  5, 112, :_reduce_82,
+  3, 112, :_reduce_83,
+  6, 112, :_reduce_84,
+  4, 112, :_reduce_85,
+  1, 116, :_reduce_86,
+  2, 116, :_reduce_87,
+  4, 132, :_reduce_88,
+  3, 132, :_reduce_89,
+  1, 132, :_reduce_90,
+  3, 133, :_reduce_91,
+  2, 131, :_reduce_92,
+  3, 135, :_reduce_93,
+  2, 135, :_reduce_94,
+  2, 134, :_reduce_95,
+  4, 134, :_reduce_96,
+  2, 119, :_reduce_97,
+  5, 137, :_reduce_98,
+  4, 137, :_reduce_99,
+  0, 138, :_reduce_none,
+  2, 138, :_reduce_101,
+  4, 138, :_reduce_102,
+  3, 138, :_reduce_103,
+  6, 120, :_reduce_104,
+  5, 120, :_reduce_105,
+  0, 139, :_reduce_none,
+  4, 139, :_reduce_107,
+  3, 139, :_reduce_108,
+  5, 118, :_reduce_109,
+  1, 140, :_reduce_110,
+  2, 140, :_reduce_111,
+  5, 141, :_reduce_112,
+  1, 142, :_reduce_none,
+  1, 142, :_reduce_none,
+  1, 114, :_reduce_none,
+  4, 114, :_reduce_116,
+  1, 145, :_reduce_117,
+  3, 145, :_reduce_118,
+  3, 144, :_reduce_119,
+  6, 117, :_reduce_120,
+  2, 117, :_reduce_121,
+  3, 146, :_reduce_122,
+  3, 146, :_reduce_123,
+  1, 147, :_reduce_none,
+  1, 147, :_reduce_none,
+  0, 105, :_reduce_126,
+  1, 105, :_reduce_127,
+  3, 105, :_reduce_128,
+  1, 149, :_reduce_none,
+  1, 149, :_reduce_none,
+  1, 149, :_reduce_none,
+  1, 149, :_reduce_none,
+  1, 149, :_reduce_none,
+  3, 148, :_reduce_134,
+  3, 148, :_reduce_135,
+  3, 148, :_reduce_136,
+  6, 121, :_reduce_137,
+  7, 122, :_reduce_138,
+  1, 154, :_reduce_139,
+  1, 153, :_reduce_none,
+  1, 153, :_reduce_none,
+  1, 155, :_reduce_none,
+  2, 155, :_reduce_143,
+  1, 156, :_reduce_none,
+  1, 156, :_reduce_none,
+  7, 123, :_reduce_146,
+  6, 123, :_reduce_147,
+  1, 157, :_reduce_148,
+  3, 157, :_reduce_149,
+  1, 159, :_reduce_none,
+  1, 159, :_reduce_none,
+  1, 159, :_reduce_152,
+  1, 159, :_reduce_none,
+  1, 160, :_reduce_154,
+  3, 160, :_reduce_155,
+  1, 161, :_reduce_none,
+  1, 161, :_reduce_none,
+  1, 158, :_reduce_none,
+  2, 158, :_reduce_159,
+  1, 151, :_reduce_none,
+  1, 151, :_reduce_none,
+  1, 151, :_reduce_none,
+  1, 151, :_reduce_none,
+  1, 151, :_reduce_none,
+  1, 151, :_reduce_none,
+  1, 151, :_reduce_166,
+  1, 152, :_reduce_167,
+  2, 152, :_reduce_168,
+  4, 152, :_reduce_169,
+  1, 136, :_reduce_170,
+  3, 136, :_reduce_171,
+  1, 162, :_reduce_none,
+  1, 162, :_reduce_none,
+  1, 163, :_reduce_none,
+  1, 163, :_reduce_none,
+  3, 165, :_reduce_176,
+  1, 165, :_reduce_177,
+  2, 166, :_reduce_178,
+  2, 164, :_reduce_179,
+  1, 167, :_reduce_180,
+  4, 167, :_reduce_181,
+  1, 115, :_reduce_182,
+  1, 125, :_reduce_183,
+  1, 125, :_reduce_184,
+  1, 125, :_reduce_185,
+  1, 125, :_reduce_186,
+  1, 125, :_reduce_187,
+  1, 125, :_reduce_188,
+  1, 125, :_reduce_189,
+  4, 126, :_reduce_190,
+  2, 126, :_reduce_191,
+  4, 126, :_reduce_192,
+  2, 126, :_reduce_193,
+  3, 127, :_reduce_194,
+  4, 127, :_reduce_195,
+  2, 127, :_reduce_196,
+  1, 168, :_reduce_197,
+  3, 168, :_reduce_198,
+  3, 169, :_reduce_199,
+  1, 129, :_reduce_none,
+  1, 129, :_reduce_none,
+  1, 129, :_reduce_none,
+  1, 170, :_reduce_203,
+  1, 170, :_reduce_204,
+  2, 171, :_reduce_205,
+  1, 173, :_reduce_206,
+  1, 175, :_reduce_207,
+  1, 176, :_reduce_208,
+  2, 174, :_reduce_209,
+  1, 177, :_reduce_210,
+  1, 178, :_reduce_211,
+  2, 178, :_reduce_212,
+  2, 172, :_reduce_213,
+  2, 179, :_reduce_214,
+  2, 179, :_reduce_215,
+  3, 97, :_reduce_216,
+  0, 181, :_reduce_none,
+  1, 181, :_reduce_none,
+  0, 180, :_reduce_219,
+  2, 180, :_reduce_220,
+  4, 180, :_reduce_221,
+  1, 124, :_reduce_222,
+  3, 124, :_reduce_223,
+  5, 124, :_reduce_224,
+  1, 182, :_reduce_none,
+  1, 182, :_reduce_none,
+  1, 130, :_reduce_227,
+  1, 128, :_reduce_228,
+  0, 109, :_reduce_none,
+  1, 109, :_reduce_230,
+  0, 108, :_reduce_none,
+  1, 108, :_reduce_none,
+  1, 150, :_reduce_none,
+  1, 150, :_reduce_none,
+  1, 150, :_reduce_none,
+  1, 150, :_reduce_none,
+  1, 150, :_reduce_none,
+  1, 150, :_reduce_none,
+  1, 150, :_reduce_none,
+  1, 150, :_reduce_none,
+  1, 150, :_reduce_none,
+  1, 150, :_reduce_none,
+  1, 150, :_reduce_none,
+  1, 150, :_reduce_none,
+  1, 150, :_reduce_none,
+  1, 150, :_reduce_none,
+  1, 150, :_reduce_none,
+  1, 150, :_reduce_none,
+  1, 150, :_reduce_none,
+  1, 150, :_reduce_none,
+  0, 143, :_reduce_251 ]
+
+racc_reduce_n = 252
+
+racc_shift_n = 432
+
+racc_token_table = {
+  false => 0,
+  :error => 1,
+  :STRING => 2,
+  :DQPRE => 3,
+  :DQMID => 4,
+  :DQPOST => 5,
+  :WORD => 6,
+  :LBRACK => 7,
+  :RBRACK => 8,
+  :LBRACE => 9,
+  :RBRACE => 10,
+  :SYMBOL => 11,
+  :FARROW => 12,
+  :COMMA => 13,
+  :TRUE => 14,
+  :FALSE => 15,
+  :EQUALS => 16,
+  :APPENDS => 17,
+  :DELETES => 18,
+  :LESSEQUAL => 19,
+  :NOTEQUAL => 20,
+  :DOT => 21,
+  :COLON => 22,
+  :LLCOLLECT => 23,
+  :RRCOLLECT => 24,
+  :QMARK => 25,
+  :LPAREN => 26,
+  :RPAREN => 27,
+  :ISEQUAL => 28,
+  :GREATEREQUAL => 29,
+  :GREATERTHAN => 30,
+  :LESSTHAN => 31,
+  :IF => 32,
+  :ELSE => 33,
+  :DEFINE => 34,
+  :ELSIF => 35,
+  :VARIABLE => 36,
+  :CLASS => 37,
+  :INHERITS => 38,
+  :NODE => 39,
+  :BOOLEAN => 40,
+  :NAME => 41,
+  :SEMIC => 42,
+  :CASE => 43,
+  :DEFAULT => 44,
+  :AT => 45,
+  :ATAT => 46,
+  :LCOLLECT => 47,
+  :RCOLLECT => 48,
+  :CLASSREF => 49,
+  :NOT => 50,
+  :OR => 51,
+  :AND => 52,
+  :UNDEF => 53,
+  :PARROW => 54,
+  :PLUS => 55,
+  :MINUS => 56,
+  :TIMES => 57,
+  :DIV => 58,
+  :LSHIFT => 59,
+  :RSHIFT => 60,
+  :UMINUS => 61,
+  :MATCH => 62,
+  :NOMATCH => 63,
+  :REGEX => 64,
+  :IN_EDGE => 65,
+  :OUT_EDGE => 66,
+  :IN_EDGE_SUB => 67,
+  :OUT_EDGE_SUB => 68,
+  :IN => 69,
+  :UNLESS => 70,
+  :PIPE => 71,
+  :LAMBDA => 72,
+  :SELBRACE => 73,
+  :NUMBER => 74,
+  :HEREDOC => 75,
+  :SUBLOCATE => 76,
+  :RENDER_STRING => 77,
+  :RENDER_EXPR => 78,
+  :EPP_START => 79,
+  :EPP_END => 80,
+  :EPP_END_TRIM => 81,
+  :FUNCTION => 82,
+  :PRIVATE => 83,
+  :ATTR => 84,
+  :TYPE => 85,
+  :APPLICATION_R => 86,
+  :CONSUMES_R => 87,
+  :PRODUCES_R => 88,
+  :LOW => 89,
+  :HIGH => 90,
+  :LISTSTART => 91,
+  :SPLAT => 92,
+  :MODULO => 93 }
+
+racc_nt_base = 94
+
+racc_use_result_var = true
+
+Racc_arg = [
+  racc_action_table,
+  racc_action_check,
+  racc_action_default,
+  racc_action_pointer,
+  racc_goto_table,
+  racc_goto_check,
+  racc_goto_default,
+  racc_goto_pointer,
+  racc_nt_base,
+  racc_reduce_table,
+  racc_token_table,
+  racc_shift_n,
+  racc_reduce_n,
+  racc_use_result_var ]
+
+Racc_token_to_s_table = [
+  "$end",
+  "error",
+  "STRING",
+  "DQPRE",
+  "DQMID",
+  "DQPOST",
+  "WORD",
+  "LBRACK",
+  "RBRACK",
+  "LBRACE",
+  "RBRACE",
+  "SYMBOL",
+  "FARROW",
+  "COMMA",
+  "TRUE",
+  "FALSE",
+  "EQUALS",
+  "APPENDS",
+  "DELETES",
+  "LESSEQUAL",
+  "NOTEQUAL",
+  "DOT",
+  "COLON",
+  "LLCOLLECT",
+  "RRCOLLECT",
+  "QMARK",
+  "LPAREN",
+  "RPAREN",
+  "ISEQUAL",
+  "GREATEREQUAL",
+  "GREATERTHAN",
+  "LESSTHAN",
+  "IF",
+  "ELSE",
+  "DEFINE",
+  "ELSIF",
+  "VARIABLE",
+  "CLASS",
+  "INHERITS",
+  "NODE",
+  "BOOLEAN",
+  "NAME",
+  "SEMIC",
+  "CASE",
+  "DEFAULT",
+  "AT",
+  "ATAT",
+  "LCOLLECT",
+  "RCOLLECT",
+  "CLASSREF",
+  "NOT",
+  "OR",
+  "AND",
+  "UNDEF",
+  "PARROW",
+  "PLUS",
+  "MINUS",
+  "TIMES",
+  "DIV",
+  "LSHIFT",
+  "RSHIFT",
+  "UMINUS",
+  "MATCH",
+  "NOMATCH",
+  "REGEX",
+  "IN_EDGE",
+  "OUT_EDGE",
+  "IN_EDGE_SUB",
+  "OUT_EDGE_SUB",
+  "IN",
+  "UNLESS",
+  "PIPE",
+  "LAMBDA",
+  "SELBRACE",
+  "NUMBER",
+  "HEREDOC",
+  "SUBLOCATE",
+  "RENDER_STRING",
+  "RENDER_EXPR",
+  "EPP_START",
+  "EPP_END",
+  "EPP_END_TRIM",
+  "FUNCTION",
+  "PRIVATE",
+  "ATTR",
+  "TYPE",
+  "APPLICATION_R",
+  "CONSUMES_R",
+  "PRODUCES_R",
+  "LOW",
+  "HIGH",
+  "LISTSTART",
+  "SPLAT",
+  "MODULO",
+  "$start",
+  "program",
+  "statements",
+  "epp_expression",
+  "syntactic_statements",
+  "syntactic_statement",
+  "assignment",
+  "relationship",
+  "assignments",
+  "resource",
+  "expression",
+  "attribute_operations",
+  "additional_resource_bodies",
+  "resource_bodies",
+  "endsemi",
+  "endcomma",
+  "resource_body",
+  "primary_expression",
+  "call_function_expression",
+  "expressions",
+  "selector_entries",
+  "variable",
+  "call_method_with_lambda_expression",
+  "collection_expression",
+  "case_expression",
+  "if_expression",
+  "unless_expression",
+  "definition_expression",
+  "hostclass_expression",
+  "node_definition_expression",
+  "epp_render_expression",
+  "reserved_word",
+  "array",
+  "hash",
+  "regex",
+  "quotedtext",
+  "type",
+  "lambda",
+  "call_method_expression",
+  "named_access",
+  "lambda_parameter_list",
+  "lambda_rest",
+  "parameters",
+  "if_part",
+  "else",
+  "unless_else",
+  "case_options",
+  "case_option",
+  "options_statements",
+  "nil",
+  "selector_entry",
+  "selector_entry_list",
+  "collect_query",
+  "optional_query",
+  "attribute_operation",
+  "attribute_name",
+  "keyword",
+  "classname",
+  "parameter_list",
+  "opt_statements",
+  "stacked_classname",
+  "classparent",
+  "classnameordefault",
+  "hostnames",
+  "nodeparent",
+  "hostname",
+  "dotted_name",
+  "name_or_number",
+  "parameter",
+  "untyped_parameter",
+  "typed_parameter",
+  "regular_parameter",
+  "splat_parameter",
+  "parameter_type",
+  "hashpairs",
+  "hashpair",
+  "string",
+  "dq_string",
+  "heredoc",
+  "dqpre",
+  "dqrval",
+  "dqpost",
+  "dqmid",
+  "text_expression",
+  "dqtail",
+  "sublocated_text",
+  "epp_parameters_list",
+  "optional_statements",
+  "epp_end" ]
+
+Racc_debug_parser = false
+
+##### State transition tables end #####
+
+# reduce 0 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 66)
+  def _reduce_1(val, _values, result)
+     result = create_program(Factory.block_or_expression(*val[0])) 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 67)
+  def _reduce_2(val, _values, result)
+     result = create_program(Factory.block_or_expression(*val[0])) 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 68)
+  def _reduce_3(val, _values, result)
+     result = create_empty_program() 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 72)
+  def _reduce_4(val, _values, result)
+     result = transform_calls(val[0]) 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 79)
+  def _reduce_5(val, _values, result)
+     result = [val[0]]
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 80)
+  def _reduce_6(val, _values, result)
+     result = val[0].push val[2] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 81)
+  def _reduce_7(val, _values, result)
+     result = val[0].push val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 88)
+  def _reduce_8(val, _values, result)
+     result = val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 89)
+  def _reduce_9(val, _values, result)
+     result = aryfy(val[0]).push(val[1]).push(val[2]) 
+    result
+  end
+.,.,
+
+# reduce 10 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 94)
+  def _reduce_11(val, _values, result)
+     result = val[0].set(val[2])      ; loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 95)
+  def _reduce_12(val, _values, result)
+     result = val[0].plus_set(val[2]) ; loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 96)
+  def _reduce_13(val, _values, result)
+     result = val[0].minus_set(val[2]); loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 99)
+  def _reduce_14(val, _values, result)
+     result = [val[0]] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 100)
+  def _reduce_15(val, _values, result)
+     result = val[0].push(val[2]) 
+    result
+  end
+.,.,
+
+# reduce 16 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 104)
+  def _reduce_17(val, _values, result)
+     result = val[0].relop(val[1][:value], val[2]); loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 105)
+  def _reduce_18(val, _values, result)
+     result = val[0].relop(val[1][:value], val[2]); loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 106)
+  def _reduce_19(val, _values, result)
+     result = val[0].relop(val[1][:value], val[2]); loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 107)
+  def _reduce_20(val, _values, result)
+     result = val[0].relop(val[1][:value], val[2]); loc result, val[1] 
+    result
+  end
+.,.,
+
+# reduce 21 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 116)
+  def _reduce_22(val, _values, result)
+          result = val[1]
+      unless Factory.set_resource_form(result, :virtual)
+        # This is equivalent to a syntax error - additional semantic restrictions apply
+        error val[0], "Virtual (@) can only be applied to a Resource Expression"
+      end
+      # relocate the result
+      loc result, val[0], val[1]
+    
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 127)
+  def _reduce_23(val, _values, result)
+          result = val[1]
+      unless Factory.set_resource_form(result, :exported)
+        # This is equivalent to a syntax error - additional semantic restrictions apply
+        error val[0], "Exported (@@) can only be applied to a Resource Expression"
+      end
+      # relocate the result
+      loc result, val[0], val[1]
+    
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 138)
+  def _reduce_24(val, _values, result)
+          bodies = [Factory.RESOURCE_BODY(val[2], val[4])] + val[5]
+      result = Factory.RESOURCE(val[0], bodies)
+      loc result, val[0], val[6]
+    
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 145)
+  def _reduce_25(val, _values, result)
+            result = Factory.RESOURCE(Factory.fqn(token_text(val[0])), val[2])
+        loc result, val[0], val[4]
+    
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 154)
+  def _reduce_26(val, _values, result)
+           result = case Factory.resource_shape(val[0])
+       when :resource, :class
+        # This catches deprecated syntax.
+        # If the attribute operations does not include +>, then the found expression
+        # is actually a LEFT followed by LITERAL_HASH
+        #
+        unless tmp = transform_resource_wo_title(val[0], val[2])
+          error val[1], "Syntax error resource body without title or hash with +>"
+        end
+        tmp
+      when :defaults
+        Factory.RESOURCE_DEFAULTS(val[0], val[2])
+      when :override
+        # This was only done for override in original - TODO should it be here at all
+        Factory.RESOURCE_OVERRIDE(val[0], val[2])
+      else
+        error val[0], "Expression is not valid as a resource, resource-default, or resource-override"
+      end
+     loc result, val[0], val[4]
+    
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 176)
+  def _reduce_27(val, _values, result)
+     result = Factory.RESOURCE_BODY(val[0], val[2]) 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 179)
+  def _reduce_28(val, _values, result)
+     result = [val[0]] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 180)
+  def _reduce_29(val, _values, result)
+     result = val[0].push val[2] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 186)
+  def _reduce_30(val, _values, result)
+     result = [] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 187)
+  def _reduce_31(val, _values, result)
+     result = [] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 188)
+  def _reduce_32(val, _values, result)
+     result = val[2] 
+    result
+  end
+.,.,
+
+# reduce 33 omitted
+
+# reduce 34 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 195)
+  def _reduce_35(val, _values, result)
+     result = val[0][*val[2]]         ; loc result, val[0], val[3] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 196)
+  def _reduce_36(val, _values, result)
+     result = val[0].in val[2]        ; loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 197)
+  def _reduce_37(val, _values, result)
+     result = val[0] =~  val[2]       ; loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 198)
+  def _reduce_38(val, _values, result)
+     result = val[0].mne val[2]       ; loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 199)
+  def _reduce_39(val, _values, result)
+     result = val[0] +   val[2]       ; loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 200)
+  def _reduce_40(val, _values, result)
+     result = val[0] -   val[2]       ; loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 201)
+  def _reduce_41(val, _values, result)
+     result = val[0] /   val[2]       ; loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 202)
+  def _reduce_42(val, _values, result)
+     result = val[0] *   val[2]       ; loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 203)
+  def _reduce_43(val, _values, result)
+     result = val[0] %   val[2]       ; loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 204)
+  def _reduce_44(val, _values, result)
+     result = val[0] <<  val[2]       ; loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 205)
+  def _reduce_45(val, _values, result)
+     result = val[0] >>  val[2]       ; loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 206)
+  def _reduce_46(val, _values, result)
+     result = val[1].minus()          ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 207)
+  def _reduce_47(val, _values, result)
+     result = val[1].unfold()         ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 208)
+  def _reduce_48(val, _values, result)
+     result = val[0].ne  val[2]       ; loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 209)
+  def _reduce_49(val, _values, result)
+     result = val[0] ==  val[2]       ; loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 210)
+  def _reduce_50(val, _values, result)
+     result = val[0] >   val[2]       ; loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 211)
+  def _reduce_51(val, _values, result)
+     result = val[0] >=  val[2]       ; loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 212)
+  def _reduce_52(val, _values, result)
+     result = val[0] <   val[2]       ; loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 213)
+  def _reduce_53(val, _values, result)
+     result = val[0] <=  val[2]       ; loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 214)
+  def _reduce_54(val, _values, result)
+     result = val[1].not              ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 215)
+  def _reduce_55(val, _values, result)
+     result = val[0].and val[2]       ; loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 216)
+  def _reduce_56(val, _values, result)
+     result = val[0].or  val[2]       ; loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 217)
+  def _reduce_57(val, _values, result)
+     result = val[0].select(*val[2])  ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 218)
+  def _reduce_58(val, _values, result)
+     result = val[1].paren()          ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 228)
+  def _reduce_59(val, _values, result)
+     result = [val[0]] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 229)
+  def _reduce_60(val, _values, result)
+     result = val[0].push(val[2]) 
+    result
+  end
+.,.,
+
+# reduce 61 omitted
+
+# reduce 62 omitted
+
+# reduce 63 omitted
+
+# reduce 64 omitted
+
+# reduce 65 omitted
+
+# reduce 66 omitted
+
+# reduce 67 omitted
+
+# reduce 68 omitted
+
+# reduce 69 omitted
+
+# reduce 70 omitted
+
+# reduce 71 omitted
+
+# reduce 72 omitted
+
+# reduce 73 omitted
+
+# reduce 74 omitted
+
+# reduce 75 omitted
+
+# reduce 76 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 248)
+  def _reduce_77(val, _values, result)
+     result = Factory.NUMBER(val[0][:value])          ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 249)
+  def _reduce_78(val, _values, result)
+     result = Factory.literal(val[0][:value])         ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 250)
+  def _reduce_79(val, _values, result)
+     result = Factory.literal(:default)               ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 251)
+  def _reduce_80(val, _values, result)
+     result = Factory.literal(:undef)                 ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 252)
+  def _reduce_81(val, _values, result)
+     result = Factory.QNAME_OR_NUMBER(val[0][:value]) ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 261)
+  def _reduce_82(val, _values, result)
+          result = Factory.CALL_NAMED(val[0], true, val[2])
+      loc result, val[0], val[4]
+    
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 265)
+  def _reduce_83(val, _values, result)
+          result = Factory.CALL_NAMED(val[0], true, [])
+      loc result, val[0], val[2]
+    
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 269)
+  def _reduce_84(val, _values, result)
+          result = Factory.CALL_NAMED(val[0], true, val[2])
+      loc result, val[0], val[4]
+      result.lambda = val[5]
+    
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 274)
+  def _reduce_85(val, _values, result)
+          result = Factory.CALL_NAMED(val[0], true, [])
+      loc result, val[0], val[2]
+      result.lambda = val[3]
+    
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 282)
+  def _reduce_86(val, _values, result)
+     result = val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 283)
+  def _reduce_87(val, _values, result)
+     result = val[0]; val[0].lambda = val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 286)
+  def _reduce_88(val, _values, result)
+     result = Factory.CALL_METHOD(val[0], val[2]); loc result, val[1], val[3] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 287)
+  def _reduce_89(val, _values, result)
+     result = Factory.CALL_METHOD(val[0], []); loc result, val[1], val[3] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 288)
+  def _reduce_90(val, _values, result)
+     result = Factory.CALL_METHOD(val[0], []); loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 292)
+  def _reduce_91(val, _values, result)
+            result = val[0].dot(Factory.fqn(val[2][:value]))
+        loc result, val[1], val[2]
+      
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 300)
+  def _reduce_92(val, _values, result)
+          result = Factory.LAMBDA(val[0][:value], val[1][:value])
+      loc result, val[0][:start], val[1][:end]
+    
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 305)
+  def _reduce_93(val, _values, result)
+     result = {:end => val[2], :value =>val[1] } 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 306)
+  def _reduce_94(val, _values, result)
+     result = {:end => val[1], :value => nil } 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 310)
+  def _reduce_95(val, _values, result)
+     result = {:start => val[0], :value => [] } 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 311)
+  def _reduce_96(val, _values, result)
+     result = {:start => val[0], :value => val[1] } 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 319)
+  def _reduce_97(val, _values, result)
+          result = val[1]
+      loc(result, val[0], val[1])
+    
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 326)
+  def _reduce_98(val, _values, result)
+            result = Factory.IF(val[0], Factory.block_or_expression(*val[2]), val[4])
+        loc(result, val[0], (val[4] ? val[4] : val[3]))
+      
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 330)
+  def _reduce_99(val, _values, result)
+            result = Factory.IF(val[0], nil, val[3])
+        loc(result, val[0], (val[3] ? val[3] : val[2]))
+      
+    result
+  end
+.,.,
+
+# reduce 100 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 338)
+  def _reduce_101(val, _values, result)
+            result = val[1]
+        loc(result, val[0], val[1])
+      
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 342)
+  def _reduce_102(val, _values, result)
+            result = Factory.block_or_expression(*val[2])
+        loc result, val[0], val[3]
+      
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 346)
+  def _reduce_103(val, _values, result)
+            result = nil # don't think a nop is needed here either
+      
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 353)
+  def _reduce_104(val, _values, result)
+          result = Factory.UNLESS(val[1], Factory.block_or_expression(*val[3]), val[5])
+      loc result, val[0], val[4]
+    
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 357)
+  def _reduce_105(val, _values, result)
+          result = Factory.UNLESS(val[1], nil, val[4])
+      loc result, val[0], val[4]
+    
+    result
+  end
+.,.,
+
+# reduce 106 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 367)
+  def _reduce_107(val, _values, result)
+            result = Factory.block_or_expression(*val[2])
+        loc result, val[0], val[3]
+      
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 371)
+  def _reduce_108(val, _values, result)
+            result = nil # don't think a nop is needed here either
+      
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 378)
+  def _reduce_109(val, _values, result)
+          result = Factory.CASE(val[1], *val[3])
+      loc result, val[0], val[4]
+    
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 384)
+  def _reduce_110(val, _values, result)
+     result = [val[0]] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 385)
+  def _reduce_111(val, _values, result)
+     result = val[0].push val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 390)
+  def _reduce_112(val, _values, result)
+            result = Factory.WHEN(val[0], val[3]); loc result, val[1], val[4]
+      
+    result
+  end
+.,.,
+
+# reduce 113 omitted
+
+# reduce 114 omitted
+
+# reduce 115 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 406)
+  def _reduce_116(val, _values, result)
+            result = val[1]
+      
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 411)
+  def _reduce_117(val, _values, result)
+     result = [val[0]] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 412)
+  def _reduce_118(val, _values, result)
+     result = val[0].push val[2] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 417)
+  def _reduce_119(val, _values, result)
+     result = Factory.MAP(val[0], val[2]) ; loc result, val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 427)
+  def _reduce_120(val, _values, result)
+          result = Factory.COLLECT(val[0], val[1], val[3])
+      loc result, val[0], val[5]
+    
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 431)
+  def _reduce_121(val, _values, result)
+          result = Factory.COLLECT(val[0], val[1], [])
+      loc result, val[0], val[1]
+    
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 436)
+  def _reduce_122(val, _values, result)
+     result = Factory.VIRTUAL_QUERY(val[1])   ; loc result, val[0], val[2] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 437)
+  def _reduce_123(val, _values, result)
+     result = Factory.EXPORTED_QUERY(val[1])  ; loc result, val[0], val[2] 
+    result
+  end
+.,.,
+
+# reduce 124 omitted
+
+# reduce 125 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 446)
+  def _reduce_126(val, _values, result)
+     result = [] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 447)
+  def _reduce_127(val, _values, result)
+     result = [val[0]] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 448)
+  def _reduce_128(val, _values, result)
+     result = val[0].push(val[2]) 
+    result
+  end
+.,.,
+
+# reduce 129 omitted
+
+# reduce 130 omitted
+
+# reduce 131 omitted
+
+# reduce 132 omitted
+
+# reduce 133 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 467)
+  def _reduce_134(val, _values, result)
+            result = Factory.ATTRIBUTE_OP(val[0][:value], :'=>', val[2])
+        loc result, val[0], val[2]
+      
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 471)
+  def _reduce_135(val, _values, result)
+            result = Factory.ATTRIBUTE_OP(val[0][:value], :'+>', val[2])
+        loc result, val[0], val[2]
+      
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 475)
+  def _reduce_136(val, _values, result)
+          result = Factory.ATTRIBUTES_OP(val[2]) ; loc result, val[0], val[2]
+   
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 484)
+  def _reduce_137(val, _values, result)
+          result = add_definition(Factory.DEFINITION(classname(val[1][:value]), val[2], val[4]))
+      loc result, val[0], val[5]
+      # New lexer does not keep track of this, this is done in validation
+      if @lexer.respond_to?(:'indefine=')
+        @lexer.indefine = false
+      end
+    
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 498)
+  def _reduce_138(val, _values, result)
+          # Remove this class' name from the namestack as all nested classes have been parsed
+      namepop
+      result = add_definition(Factory.HOSTCLASS(classname(val[1][:value]), val[2], token_text(val[3]), val[5]))
+      loc result, val[0], val[6]
+    
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 508)
+  def _reduce_139(val, _values, result)
+     namestack(val[0][:value]) ; result = val[0] 
+    result
+  end
+.,.,
+
+# reduce 140 omitted
+
+# reduce 141 omitted
+
+# reduce 142 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 517)
+  def _reduce_143(val, _values, result)
+     result = val[1] 
+    result
+  end
+.,.,
+
+# reduce 144 omitted
+
+# reduce 145 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 534)
+  def _reduce_146(val, _values, result)
+          result = add_definition(Factory.NODE(val[1], val[3], val[5]))
+      loc result, val[0], val[6]
+    
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 538)
+  def _reduce_147(val, _values, result)
+          result = add_definition(Factory.NODE(val[1], val[3], nil))
+      loc result, val[0], val[5]
+    
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 548)
+  def _reduce_148(val, _values, result)
+     result = [result] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 549)
+  def _reduce_149(val, _values, result)
+     result = val[0].push(val[2]) 
+    result
+  end
+.,.,
+
+# reduce 150 omitted
+
+# reduce 151 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 556)
+  def _reduce_152(val, _values, result)
+     result = Factory.literal(:default); loc result, val[0] 
+    result
+  end
+.,.,
+
+# reduce 153 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 560)
+  def _reduce_154(val, _values, result)
+     result = Factory.literal(val[0][:value]); loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 561)
+  def _reduce_155(val, _values, result)
+     result = Factory.concat(val[0], '.', val[2][:value]); loc result, val[0], val[2] 
+    result
+  end
+.,.,
+
+# reduce 156 omitted
+
+# reduce 157 omitted
+
+# reduce 158 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 570)
+  def _reduce_159(val, _values, result)
+     result = val[1] 
+    result
+  end
+.,.,
+
+# reduce 160 omitted
+
+# reduce 161 omitted
+
+# reduce 162 omitted
+
+# reduce 163 omitted
+
+# reduce 164 omitted
+
+# reduce 165 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 592)
+  def _reduce_166(val, _values, result)
+     error val[0], "'class' is not a valid classname" 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 596)
+  def _reduce_167(val, _values, result)
+     result = [] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 597)
+  def _reduce_168(val, _values, result)
+     result = [] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 598)
+  def _reduce_169(val, _values, result)
+     result = val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 602)
+  def _reduce_170(val, _values, result)
+     result = [val[0]] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 603)
+  def _reduce_171(val, _values, result)
+     result = val[0].push(val[2]) 
+    result
+  end
+.,.,
+
+# reduce 172 omitted
+
+# reduce 173 omitted
+
+# reduce 174 omitted
+
+# reduce 175 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 615)
+  def _reduce_176(val, _values, result)
+     result = Factory.PARAM(val[0][:value], val[2]) ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 616)
+  def _reduce_177(val, _values, result)
+     result = Factory.PARAM(val[0][:value]); loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 619)
+  def _reduce_178(val, _values, result)
+     result = val[1]; val[1].captures_rest() 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 622)
+  def _reduce_179(val, _values, result)
+     val[1].type_expr(val[0]) ; result = val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 625)
+  def _reduce_180(val, _values, result)
+     result = val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 626)
+  def _reduce_181(val, _values, result)
+     result = val[0][*val[2]] ; loc result, val[0], val[3] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 631)
+  def _reduce_182(val, _values, result)
+     result = Factory.fqn(val[0][:value]).var ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 636)
+  def _reduce_183(val, _values, result)
+     result = Factory.RESERVED(val[0][:value]) ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 637)
+  def _reduce_184(val, _values, result)
+     result = Factory.RESERVED(val[0][:value]) ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 638)
+  def _reduce_185(val, _values, result)
+     result = Factory.RESERVED(val[0][:value]) ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 639)
+  def _reduce_186(val, _values, result)
+     result = Factory.RESERVED(val[0][:value]) ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 640)
+  def _reduce_187(val, _values, result)
+     result = Factory.RESERVED(val[0][:value], true) ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 641)
+  def _reduce_188(val, _values, result)
+     result = Factory.RESERVED(val[0][:value], true) ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 642)
+  def _reduce_189(val, _values, result)
+     result = Factory.RESERVED(val[0][:value], true) ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 648)
+  def _reduce_190(val, _values, result)
+     result = Factory.LIST(val[1]); loc result, val[0], val[3] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 649)
+  def _reduce_191(val, _values, result)
+     result = Factory.literal([]) ; loc result, val[0], val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 650)
+  def _reduce_192(val, _values, result)
+     result = Factory.LIST(val[1]); loc result, val[0], val[3] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 651)
+  def _reduce_193(val, _values, result)
+     result = Factory.literal([]) ; loc result, val[0], val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 654)
+  def _reduce_194(val, _values, result)
+     result = Factory.HASH(val[1]); loc result, val[0], val[2] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 655)
+  def _reduce_195(val, _values, result)
+     result = Factory.HASH(val[1]); loc result, val[0], val[3] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 656)
+  def _reduce_196(val, _values, result)
+     result = Factory.literal({}) ; loc result, val[0], val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 659)
+  def _reduce_197(val, _values, result)
+     result = [val[0]] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 660)
+  def _reduce_198(val, _values, result)
+     result = val[0].push val[2] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 663)
+  def _reduce_199(val, _values, result)
+     result = Factory.KEY_ENTRY(val[0], val[2]); loc result, val[1] 
+    result
+  end
+.,.,
+
+# reduce 200 omitted
+
+# reduce 201 omitted
+
+# reduce 202 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 671)
+  def _reduce_203(val, _values, result)
+     result = Factory.literal(val[0][:value]) ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 672)
+  def _reduce_204(val, _values, result)
+     result = Factory.literal(val[0][:value]) ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 674)
+  def _reduce_205(val, _values, result)
+     result = Factory.string(val[0], *val[1]) ; loc result, val[0], val[1][-1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 675)
+  def _reduce_206(val, _values, result)
+     result = Factory.literal(val[0][:value]); loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 676)
+  def _reduce_207(val, _values, result)
+     result = Factory.literal(val[0][:value]); loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 677)
+  def _reduce_208(val, _values, result)
+     result = Factory.literal(val[0][:value]); loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 678)
+  def _reduce_209(val, _values, result)
+     result = [val[0]] + val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 679)
+  def _reduce_210(val, _values, result)
+     result = Factory.TEXT(val[0]) 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 682)
+  def _reduce_211(val, _values, result)
+     result = [val[0]] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 683)
+  def _reduce_212(val, _values, result)
+     result = [val[0]] + val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 686)
+  def _reduce_213(val, _values, result)
+     result = Factory.HEREDOC(val[0][:value], val[1]); loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 689)
+  def _reduce_214(val, _values, result)
+     result = Factory.SUBLOCATE(val[0], val[1]); loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 690)
+  def _reduce_215(val, _values, result)
+     result = Factory.SUBLOCATE(val[0], val[1]); loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 693)
+  def _reduce_216(val, _values, result)
+     result = Factory.EPP(val[1], val[2]); loc result, val[0] 
+    result
+  end
+.,.,
+
+# reduce 217 omitted
+
+# reduce 218 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 700)
+  def _reduce_219(val, _values, result)
+     result = nil 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 701)
+  def _reduce_220(val, _values, result)
+     result = [] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 702)
+  def _reduce_221(val, _values, result)
+     result = val[1] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 705)
+  def _reduce_222(val, _values, result)
+     result = Factory.RENDER_STRING(val[0][:value]); loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 706)
+  def _reduce_223(val, _values, result)
+     result = Factory.RENDER_EXPR(val[1]); loc result, val[0], val[2] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 707)
+  def _reduce_224(val, _values, result)
+     result = Factory.RENDER_EXPR(Factory.block_or_expression(*val[2])); loc result, val[0], val[4] 
+    result
+  end
+.,.,
+
+# reduce 225 omitted
+
+# reduce 226 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 713)
+  def _reduce_227(val, _values, result)
+     result = Factory.QREF(val[0][:value])  ; loc result, val[0] 
+    result
+  end
+.,.,
+
+module_eval(<<'.,.,', 'egrammar.ra', 716)
+  def _reduce_228(val, _values, result)
+     result = Factory.literal(val[0][:value]); loc result, val[0] 
+    result
+  end
+.,.,
+
+# reduce 229 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 722)
+  def _reduce_230(val, _values, result)
+     result = nil 
+    result
+  end
+.,.,
+
+# reduce 231 omitted
+
+# reduce 232 omitted
+
+# reduce 233 omitted
+
+# reduce 234 omitted
+
+# reduce 235 omitted
+
+# reduce 236 omitted
+
+# reduce 237 omitted
+
+# reduce 238 omitted
+
+# reduce 239 omitted
+
+# reduce 240 omitted
+
+# reduce 241 omitted
+
+# reduce 242 omitted
+
+# reduce 243 omitted
+
+# reduce 244 omitted
+
+# reduce 245 omitted
+
+# reduce 246 omitted
+
+# reduce 247 omitted
+
+# reduce 248 omitted
+
+# reduce 249 omitted
+
+# reduce 250 omitted
+
+module_eval(<<'.,.,', 'egrammar.ra', 749)
+  def _reduce_251(val, _values, result)
+     result = nil
+    result
+  end
+.,.,
+
+def _reduce_none(val, _values, result)
+  val[0]
+end
+
+      end   # class Parser
+      end   # module Parser
+    end   # module Pops
+  end   # module Puppet
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/epp_parser.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/epp_parser.rb
new file mode 100644
index 0000000..ea5415a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/epp_parser.rb
@@ -0,0 +1,51 @@
+# The EppParser is a specialized Puppet Parser that starts parsing in Epp Text mode
+class Puppet::Pops::Parser::EppParser < Puppet::Pops::Parser::Parser
+
+  # Initializes the epp parser support by creating a new instance of {Puppet::Pops::Parser::Lexer}
+  # configured to start in Epp Lexing mode.
+  # @return [void]
+  #
+  def initvars
+    self.lexer = Puppet::Pops::Parser::Lexer2.new()# {:mode => :epp})
+  end
+
+  # Parses a file expected to contain epp text/DSL logic.
+  def parse_file(file)
+    unless FileTest.exist?(file)
+      unless file =~ /\.epp$/
+        file = file + ".epp"
+      end
+    end
+    @lexer.file = file
+    _parse()
+  end
+
+  # Performs the parsing and returns the resulting model.
+  # The lexer holds state, and this is setup with {#parse_string}, or {#parse_file}.
+  #
+  # TODO: deal with options containing origin (i.e. parsing a string from externally known location).
+  # TODO: should return the model, not a Hostclass
+  #
+  # @api private
+  #
+  def _parse()
+    begin
+      @yydebug = false
+      main = yyparse(@lexer,:scan_epp)
+      # #Commented out now because this hides problems in the racc grammar while developing
+      # # TODO include this when test coverage is good enough.
+      #      rescue Puppet::ParseError => except
+      #        except.line ||= @lexer.line
+      #        except.file ||= @lexer.file
+      #        except.pos  ||= @lexer.pos
+      #        raise except
+      #      rescue => except
+      #        raise Puppet::ParseError.new(except.message, @lexer.file, @lexer.line, @lexer.pos, except)
+    end
+    return main
+  ensure
+    @lexer.clear
+    @namestack = []
+    @definitions = []
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/epp_support.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/epp_support.rb
new file mode 100644
index 0000000..5f6f8b2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/epp_support.rb
@@ -0,0 +1,258 @@
+# This module is an integral part of the Lexer.
+# It handles scanning of EPP (Embedded Puppet), a form of string/expression interpolation similar to ERB.
+#
+require 'strscan'
+module Puppet::Pops::Parser::EppSupport
+
+  TOKEN_RENDER_STRING = [:RENDER_STRING, nil, 0]
+  TOKEN_RENDER_EXPR   = [:RENDER_EXPR, nil, 0]
+
+  # Scans all of the content and returns it in an array
+  # Note that the terminating [false, false] token is included in the result.
+  #
+  def fullscan_epp
+    result = []
+    scan_epp {|token, value| result.push([token, value]) }
+    result
+  end
+
+  # A block must be passed to scan. It will be called with two arguments, a symbol for the token,
+  # and an instance of LexerSupport::TokenValue
+  # PERFORMANCE NOTE: The TokenValue is designed to reduce the amount of garbage / temporary data
+  # and to only convert the lexer's internal tokens on demand. It is slightly more costly to create an
+  # instance of a class defined in Ruby than an Array or Hash, but the gain is much bigger since transformation
+  # logic is avoided for many of its members (most are never used (e.g. line/pos information which is only of
+  # value in general for error messages, and for some expressions (which the lexer does not know about).
+  #
+  def scan_epp
+    # PERFORMANCE note: it is faster to access local variables than instance variables.
+    # This makes a small but notable difference since instance member access is avoided for
+    # every token in the lexed content.
+    #
+    scn   = @scanner
+    ctx   = @lexing_context
+    queue = @token_queue
+
+    lex_error(Puppet::Pops::Issues::EPP_INTERNAL_ERROR, :error => 'No string or file given to lexer to process.') unless scn
+
+    ctx[:epp_mode] = :text
+    enqueue_completed([:EPP_START, nil, 0], 0)
+
+    interpolate_epp
+
+    # This is the lexer's main loop
+    until queue.empty? && scn.eos? do
+      if token = queue.shift || lex_token
+        yield [ ctx[:after] = token[0], token[1] ]
+      end
+    end
+    if ctx[:epp_open_position]
+      lex_error(Puppet::Pops::Issues::EPP_UNBALANCED_TAG, {}, ctx[:epp_position])
+    end
+
+    # Signals end of input
+    yield [false, false]
+  end
+
+  def interpolate_epp(skip_leading=false)
+    scn = @scanner
+    ctx = @lexing_context
+    eppscanner = EppScanner.new(scn)
+    before = scn.pos
+
+    s = eppscanner.scan(skip_leading)
+
+    case eppscanner.mode
+    when :text
+      # Should be at end of scan, or something is terribly wrong
+      unless @scanner.eos?
+        lex_error(Puppet::Pops::Issues::EPP_INTERNAL_ERROR, :error => 'template scanner returns text mode and is not and end of input')
+      end
+      if s
+        # s may be nil if scanned text ends with an epp tag (i.e. no trailing text).
+        enqueue_completed([:RENDER_STRING, s, scn.pos - before], before)
+      end
+      ctx[:epp_open_position] = nil
+      # do nothing else, scanner is at the end
+
+    when :error
+      lex_error(eppscanner.issue)
+
+    when :epp
+      # It is meaningless to render empty string segments, and it is harmful to do this at
+      # the start of the scan as it prevents specification of parameters with <%- ($x, $y) -%>
+      #
+      if s && s.length > 0
+        enqueue_completed([:RENDER_STRING, s, scn.pos - before], before)
+      end
+      # switch epp_mode to general (embedded) pp logic (non rendered result)
+      ctx[:epp_mode] = :epp
+      ctx[:epp_open_position] = scn.pos
+
+    when :expr
+      # It is meaningless to render an empty string segment
+      if s && s.length > 0
+        enqueue_completed([:RENDER_STRING, s, scn.pos - before], before)
+      end
+      enqueue_completed(TOKEN_RENDER_EXPR, before)
+      # switch mode to "epp expr interpolation"
+      ctx[:epp_mode] = :expr
+      ctx[:epp_open_position] = scn.pos
+    else
+      lex_error(Puppet::Pops::Issues::EPP_INTERNAL_ERROR, :error => "Unknown mode #{eppscanner.mode} returned by template scanner")
+    end
+    nil
+  end
+
+  # A scanner specialized in processing text with embedded EPP (Embedded Puppet) tags.
+  # The scanner is initialized with a StringScanner which it mutates as scanning takes place.
+  # The intent is to use one instance of EppScanner per wanted scan, and this instance represents
+  # the state after the scan.
+  #
+  # @example Sample usage
+  #   a = "some text <% pp code %> some more text"
+  #   scan = StringScanner.new(a)
+  #   eppscan = EppScanner.new(scan)
+  #   str = eppscan.scan
+  #   eppscan.mode # => :epp
+  #   eppscan.lines # => 0
+  #   eppscan
+  #
+  # The scanner supports
+  # * scanning text until <%, <%-, <%=
+  # * while scanning text:
+  #   * tokens <%% and %%> are translated to <% and %> respetively and is returned as text.
+  #   * tokens <%# and %> (or ending with -%>) and the enclosed text is a comment and is not included in the returned text
+  #   * text following a comment that ends with -%> gets trailing whitespace (up to and including a line break) trimmed
+  #     and this whitespace is not included in the returned text.
+  # * The continuation {#mode} is set to one of:
+  #   * `:epp` - for a <% token
+  #   * `:expr` - for a <%= token
+  #   * `:text` - when there was no continuation mode (e.g. when input ends with text)
+  #   * ':error` - if the tokens are unbalanced (reaching the end without a closing matching token). An error message
+  #     is then also available via the method {#message}.
+  #
+  # Note that the intent is to use this specialized scanner to scan the text parts, when continuation mode is `:epp` or `:expr`
+  # the pp lexer should advance scanning (using the string scanner) until it reaches and consumes a `-%>` or '%>´ token. If it
+  # finds a `-%> token it should pass this on as a `skip_leading` parameter when it performs the next {#scan}.
+  #
+  class EppScanner
+    # The original scanner used by the lexer/container using EppScanner
+    attr_reader :scanner
+
+    # The resulting mode after the scan.
+    # The mode is one of `:text` (the initial mode), `:epp` embedded code (no output), `:expr` (embedded
+    # expression), or `:error`
+    #
+    attr_reader :mode
+
+    # An error issue if `mode == :error`, `nil` otherwise.
+    attr_reader :issue
+
+    # If the first scan should skip leading whitespace (typically detected by the pp lexer when the
+    # pp mode end-token is found (i.e. `-%>`) and then passed on to the scanner.
+    #
+    attr_reader :skip_leading
+
+    # Creates an EppScanner based on a StringScanner that represents the state where EppScanner should start scanning.
+    # The given scanner will be mutated (i.e. position moved) to reflect the EppScanner's end state after a scan.
+    #
+    def initialize(scanner)
+      @scanner = scanner
+    end
+
+    # Here for backwards compatibility.
+    # @deprecated Use issue instead
+    # @return [String] the issue message
+    def message
+      @issue.nil? ? nil : @issue.format
+    end
+
+    # Scans from the current position in the configured scanner, advances this scanner's position until the end
+    # of the input, or to the first position after a mode switching token (`<%`, `<%-` or `<%=`). Number of processed
+    # lines and continuation mode can be obtained via {#lines}, and {#mode}.
+    #
+    # @return [String, nil] the scanned and processed text, or nil if at the end of the input.
+    #
+    def scan(skip_leading=false)
+      @mode = :text
+      @skip_leading = skip_leading
+
+      return nil if scanner.eos?
+      s = ""
+      until scanner.eos?
+        part = @scanner.scan_until(/(<%)|\z/)
+        if @skip_leading
+          part.sub!(/^[ \t]*\r?(?:\n|\z)?/,'')
+          @skip_leading = false
+        end
+        # The spec for %%> is to transform it into a literal %>. This is done here, as %%> otherwise would go
+        # undetected in text mode. (i.e. it is not really necessary to escape %> with %%> in text mode unless
+        # adding checks stating that a literal %> is illegal in text (unbalanced).
+        #
+        part.gsub!(/%%>/, '%>')
+        s += part
+        case @scanner.peek(1)
+        when ""
+          # at the end
+          # if s ends with <% then this is an error (unbalanced <% %>)
+          if s.end_with? "<%"
+            @mode = :error
+            @issue = Puppet::Pops::Issues::EPP_UNBALANCED_EXPRESSION
+          else
+            mode = :epp
+          end
+          return s
+
+        when "-"
+          # trim trailing whitespace on same line from accumulated s
+          # return text and signal switch to pp mode
+          @scanner.getch # drop the -
+          s.sub!(/[ \t]*<%\z/, '')
+          @mode = :epp
+          return s
+
+        when "%"
+          # verbatim text
+          # keep the scanned <%, and continue scanning after skipping one %
+          # (i.e. do nothing here)
+          @scanner.getch # drop the % to get a literal <% in the output
+
+        when "="
+          # expression
+          # return text and signal switch to expression mode
+          # drop the scanned <%, and skip past -%>, or %>, but also skip %%>
+          @scanner.getch # drop the =
+          s.slice!(-2..-1)
+          @mode = :expr
+          return s
+
+        when "#"
+          # template comment
+          # drop the scanned <%, and skip past -%>, or %>, but also skip %%>
+          s.slice!(-2..-1)
+
+          # unless there is an immediate termination i.e. <%#%> scan for the next %> that is not
+          # preceded by a % (i.e. skip %%>)
+          part = scanner.scan_until(/[^%]%>/)
+          unless part
+            @issue = Puppet::Pops::Issues::EPP_UNBALANCED_COMMENT
+            @mode = :error
+            return s
+          end
+          # Always trim leading whitespace on the same line when there is a comment
+          s.sub!(/[ \t]*\z/, '')
+          @skip_leading = true if part.end_with?("-%>")
+          # Continue scanning for more text
+
+        else
+          # Switch to pp after having removed the <%
+          s.slice!(-2..-1)
+          @mode = :epp
+          return s
+        end
+      end
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/evaluating_parser.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/evaluating_parser.rb
new file mode 100644
index 0000000..3cb1b6b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/evaluating_parser.rb
@@ -0,0 +1,150 @@
+
+# Does not support "import" and parsing ruby files
+#
+class Puppet::Pops::Parser::EvaluatingParser
+
+  attr_reader :parser
+
+  def initialize()
+    @parser = Puppet::Pops::Parser::Parser.new()
+  end
+
+  def parse_string(s, file_source = 'unknown')
+    @file_source = file_source
+    clear()
+    # Handling of syntax error can be much improved (in general), now it bails out of the parser
+    # and does not have as rich information (when parsing a string), need to update it with the file source
+    # (ideally, a syntax error should be entered as an issue, and not just thrown - but that is a general problem
+    # and an improvement that can be made in the eparser (rather than here).
+    # Also a possible improvement (if the YAML parser returns positions) is to provide correct output of position.
+    #
+    begin
+      assert_and_report(parser.parse_string(s))
+    rescue Puppet::ParseErrorWithIssue => e
+      raise e
+    rescue Puppet::ParseError => e
+      # TODO: This is not quite right, why does not the exception have the correct file?
+      e.file = @file_source unless e.file.is_a?(String) && !e.file.empty?
+      raise e
+    end
+  end
+
+  def parse_file(file)
+    @file_source = file
+    clear()
+    assert_and_report(parser.parse_file(file))
+  end
+
+  def evaluate_string(scope, s, file_source='unknown')
+    evaluate(scope, parse_string(s, file_source))
+  end
+
+  def evaluate_file(file)
+    evaluate(parse_file(file))
+  end
+
+  def clear()
+    @acceptor = nil
+  end
+
+  # Create a closure that can be called in the given scope
+  def closure(model, scope)
+    Puppet::Pops::Evaluator::Closure.new(evaluator, model, scope)
+  end
+
+  def evaluate(scope, model)
+    return nil unless model
+    evaluator.evaluate(model, scope)
+  end
+
+  def evaluator
+    # Do not use the cached evaluator if this is a migration run
+    if (Puppet.lookup(:migration_checker) { nil })
+      return Puppet::Pops::Evaluator::EvaluatorImpl.new()
+    end
+    @@evaluator ||= Puppet::Pops::Evaluator::EvaluatorImpl.new()
+    @@evaluator
+  end
+
+  def convert_to_3x(object, scope)
+    val = evaluator.convert(object, scope, nil)
+  end
+
+  def validate(parse_result)
+    resulting_acceptor = acceptor()
+    validator(resulting_acceptor).validate(parse_result)
+    resulting_acceptor
+  end
+
+  def acceptor()
+    Puppet::Pops::Validation::Acceptor.new
+  end
+
+  def validator(acceptor)
+    Puppet::Pops::Validation::ValidatorFactory_4_0.new().validator(acceptor)
+  end
+
+  def assert_and_report(parse_result)
+    return nil unless parse_result
+    if parse_result.source_ref.nil? or parse_result.source_ref == ''
+      parse_result.source_ref = @file_source
+    end
+    validation_result = validate(parse_result)
+
+    Puppet::Pops::IssueReporter.assert_and_report(validation_result,
+                                          :emit_warnings => true)
+    parse_result
+  end
+
+  def quote(x)
+    self.class.quote(x)
+  end
+
+  # Translates an already parsed string that contains control characters, quotes
+  # and backslashes into a quoted string where all such constructs have been escaped.
+  # Parsing the return value of this method using the puppet parser should yield
+  # exactly the same string as the argument passed to this method
+  #
+  # The method makes an exception for the two character sequences \$ and \s. They
+  # will not be escaped since they have a special meaning in puppet syntax.
+  #
+  # TODO: Handle \uXXXX characters ??
+  #
+  # @param x [String] The string to quote and "unparse"
+  # @return [String] The quoted string
+  #
+  def self.quote(x)
+    escaped = '"'
+    p = nil
+    x.each_char do |c|
+      case p
+      when nil
+        # do nothing
+      when "\t"
+        escaped << '\\t'
+      when "\n"
+        escaped << '\\n'
+      when "\f"
+        escaped << '\\f'
+      # TODO: \cx is a range of characters - skip for now
+      #      when "\c"
+      #        escaped << '\\c'
+      when '"'
+        escaped << '\\"'
+      when '\\'
+        escaped << if c == '$' || c == 's'; p; else '\\\\'; end # don't escape \ when followed by s or $
+      else
+        escaped << p
+      end
+      p = c
+    end
+    escaped << p unless p.nil?
+    escaped << '"'
+  end
+
+  class EvaluatingEppParser < Puppet::Pops::Parser::EvaluatingParser
+    def initialize()
+      @parser = Puppet::Pops::Parser::EppParser.new()
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/heredoc_support.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/heredoc_support.rb
new file mode 100644
index 0000000..74a307d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/heredoc_support.rb
@@ -0,0 +1,140 @@
+module Puppet::Pops::Parser::HeredocSupport
+  include Puppet::Pops::Parser::LexerSupport
+
+  # Pattern for heredoc `@(endtag[:syntax][/escapes])
+  # Produces groups for endtag (group 1), syntax (group 2), and escapes (group 3)
+  #
+  PATTERN_HEREDOC = %r{@\(([^:/\r\n\)]+)(?::[:blank:]*([a-z][a-zA-Z0-9_+]+)[:blank:]*)?(?:/((?:\w|[$])*)[:blank:]*)?\)}
+
+
+  def heredoc
+    scn = @scanner
+    ctx = @lexing_context
+    locator = @locator
+    before = scn.pos
+
+    # scanner is at position before @(
+    # find end of the heredoc spec
+    str = scn.scan_until(/\)/) || lex_error(Puppet::Pops::Issues::HEREDOC_UNCLOSED_PARENTHESIS, :followed_by => followed_by)
+    pos_after_heredoc = scn.pos
+
+    # Note: allows '+' as separator in syntax, but this needs validation as empty segments are not allowed
+    md = str.match(PATTERN_HEREDOC)
+    lex_error(Puppet::Pops::Issues::HEREDOC_INVALID_SYNTAX) unless md
+    endtag = md[1]
+    syntax = md[2] || ''
+    escapes = md[3]
+
+    endtag.strip!
+
+    # Is this a dq string style heredoc? (endtag enclosed in "")
+    if endtag =~ /^"(.*)"$/
+      dqstring_style = true
+      endtag = $1.strip
+    end
+
+    lex_error(Puppet::Pops::Issues::HEREDOC_MISSING_ENDTAG) unless endtag.length >= 1
+
+    resulting_escapes = []
+    if escapes
+      escapes = "trnsuL$" if escapes.length < 1
+
+      escapes = escapes.split('')
+      unless escapes.length == escapes.uniq.length
+        lex_error(Puppet::Pops::Issues::HEREDOC_MULTIPLE_AT_ESCAPES, :escapes => escapes)
+      end
+      resulting_escapes = ["\\"]
+      escapes.each do |e|
+        case e
+        when "t", "r", "n", "s", "u", "$"
+          resulting_escapes << e
+        when "L"
+          resulting_escapes += ["\n", "\r\n"]
+        else
+          lex_error(Puppet::Pops::Issues::HEREDOC_INVALID_ESCAPE, :actual => e)
+        end
+      end
+    end
+
+    # Produce a heredoc token to make the syntax available to the grammar
+    enqueue_completed([:HEREDOC, syntax, pos_after_heredoc - before], before)
+
+    # If this is the second or subsequent heredoc on the line, the lexing context's :newline_jump contains
+    # the position after the \n where the next heredoc text should scan. If not set, this is the first
+    # and it should start scanning after the first found \n (or if not found == error).
+
+    if ctx[:newline_jump]
+      scn.pos = ctx[:newline_jump]
+    else
+      scn.scan_until(/\n/) || lex_error(Puppet::Pops::Issues::HEREDOC_WITHOUT_TEXT)
+    end
+    # offset 0 for the heredoc, and its line number
+    heredoc_offset = scn.pos
+    heredoc_line = locator.line_for_offset(heredoc_offset)-1
+
+    # Compute message to emit if there is no end (to make it refer to the opening heredoc position).
+    eof_error = create_lex_error(Puppet::Pops::Issues::HEREDOC_WITHOUT_END_TAGGED_LINE)
+
+    # Text from this position (+ lexing contexts offset for any preceding heredoc) is heredoc until a line
+    # that terminates the heredoc is found.
+
+    # (Endline in EBNF form): WS* ('|' WS*)? ('-' WS*)? endtag WS* \r? (\n|$)
+    endline_pattern = /([[:blank:]]*)(?:([|])[[:blank:]]*)?(?:(\-)[[:blank:]]*)?#{Regexp.escape(endtag)}[[:blank:]]*\r?(?:\n|\z)/
+    lines = []
+    while !scn.eos? do
+      one_line = scn.scan_until(/(?:\n|\z)/)
+      raise eof_error unless one_line
+      if md = one_line.match(endline_pattern)
+        leading      = md[1]
+        has_margin   = md[2] == '|'
+        remove_break = md[3] == '-'
+        # Record position where next heredoc (from same line as current @()) should start scanning for content
+        ctx[:newline_jump] = scn.pos
+
+
+        # Process captured lines - remove leading, and trailing newline
+        str = heredoc_text(lines, leading, has_margin, remove_break)
+
+        # Use a new lexer instance configured with a sub-locator to enable correct positioning
+        sublexer = self.class.new()
+        locator = Puppet::Pops::Parser::Locator::SubLocator.sub_locator(str,
+          locator.file, heredoc_line, heredoc_offset, leading.length())
+
+        # Emit a token that provides the grammar with location information about the lines on which the heredoc
+        # content is based.
+        enqueue([:SUBLOCATE,
+          Puppet::Pops::Parser::LexerSupport::TokenValue.new([:SUBLOCATE,
+            lines, lines.reduce(0) {|size, s| size + s.length} ],
+            heredoc_offset,
+            locator)])
+
+        sublexer.lex_unquoted_string(str, locator, resulting_escapes, dqstring_style)
+        sublexer.interpolate_uq_to(self)
+        # Continue scan after @(...)
+        scn.pos = pos_after_heredoc
+        return
+      else
+        lines << one_line
+      end
+    end
+    raise eof_error
+  end
+
+  # Produces the heredoc text string given the individual (unprocessed) lines as an array.
+  # @param lines [Array<String>] unprocessed lines of text in the heredoc w/o terminating line
+  # @param leading [String] the leading text up (up to pipe or other terminating char)
+  # @param has_margin [Boolean] if the left margin should be adjusted as indicated by `leading`
+  # @param remove_break [Boolean] if the line break (\r?\n) at the end of the last line should be removed or not
+  #
+  def heredoc_text(lines, leading, has_margin, remove_break)
+    if has_margin
+      leading_pattern = /^#{Regexp.escape(leading)}/
+      lines = lines.collect {|s| s.gsub(leading_pattern, '') }
+    end
+    result = lines.join('')
+    result.gsub!(/\r?\n$/, '') if remove_break
+    result
+  end
+
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/interpolation_support.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/interpolation_support.rb
new file mode 100644
index 0000000..ddc1afc
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/interpolation_support.rb
@@ -0,0 +1,237 @@
+# This module is an integral part of the Lexer.
+# It defines interpolation support
+# PERFORMANCE NOTE: There are 4 very similar methods in this module that are designed to be as
+# performant as possible. While it is possible to parameterize them into one common method, the overhead
+# of passing parameters and evaluating conditional logic has a negative impact on performance.
+#
+module Puppet::Pops::Parser::InterpolationSupport
+
+  PATTERN_VARIABLE       = %r{(::)?(\w+::)*\w+}
+
+  # This is the starting point for a double quoted string with possible interpolation
+  # The structure mimics that of the grammar.
+  # The logic is explicit (where the former implementation used parameters/strucures) given to a
+  # generic handler.
+  # (This is both easier to understand and faster).
+  #
+  def interpolate_dq
+    scn = @scanner
+    ctx = @lexing_context
+    before = scn.pos
+    # skip the leading " by doing a scan since the slurp_dqstring uses last matched when there is an error
+    scn.scan(/"/)
+    value,terminator = slurp_dqstring()
+    text = value
+    after = scn.pos
+    while true
+      case terminator
+      when '"'
+        # simple case, there was no interpolation, return directly
+        return emit_completed([:STRING, text, scn.pos-before], before)
+      when '${'
+        count = ctx[:brace_count]
+        ctx[:brace_count] += 1
+        # The ${ terminator is counted towards the string part
+        enqueue_completed([:DQPRE, text, scn.pos-before], before)
+        # Lex expression tokens until a closing (balanced) brace count is reached
+        enqueue_until count
+        break
+      when '$'
+        if varname = scn.scan(PATTERN_VARIABLE)
+          # The $ is counted towards the variable
+          enqueue_completed([:DQPRE, text, after-before-1], before)
+          enqueue_completed([:VARIABLE, varname, scn.pos - after + 1], after -1)
+          break
+        else
+          # false $ variable start
+          text += terminator
+          value,terminator = slurp_dqstring()
+          text += value
+          after = scn.pos
+        end
+      end
+    end
+    interpolate_tail_dq
+    # return the first enqueued token and shift the queue
+    @token_queue.shift
+  end
+
+  def interpolate_tail_dq
+    scn = @scanner
+    ctx = @lexing_context
+    before = scn.pos
+    value,terminator = slurp_dqstring
+    text = value
+    after = scn.pos
+    while true
+      case terminator
+      when '"'
+        # simple case, there was no further interpolation, return directly
+        enqueue_completed([:DQPOST, text, scn.pos-before], before)
+        return
+      when '${'
+        count = ctx[:brace_count]
+        ctx[:brace_count] += 1
+        # The ${ terminator is counted towards the string part
+        enqueue_completed([:DQMID, text, scn.pos-before], before)
+        # Lex expression tokens until a closing (balanced) brace count is reached
+        enqueue_until count
+        break
+      when '$'
+        if varname = scn.scan(PATTERN_VARIABLE)
+          # The $ is counted towards the variable
+          enqueue_completed([:DQMID, text, after-before-1], before)
+          enqueue_completed([:VARIABLE, varname, scn.pos - after +1], after -1)
+          break
+        else
+          # false $ variable start
+          text += terminator
+          value,terminator = slurp_dqstring
+          text += value
+          after = scn.pos
+        end
+      end
+    end
+    interpolate_tail_dq
+  end
+
+  # This is the starting point for a un-quoted string with possible interpolation
+  # The logic is explicit (where the former implementation used parameters/strucures) given to a
+  # generic handler.
+  # (This is both easier to understand and faster).
+  #
+  def interpolate_uq
+    scn = @scanner
+    ctx = @lexing_context
+    before = scn.pos
+    value,terminator = slurp_uqstring()
+    text = value
+    after = scn.pos
+    while true
+      case terminator
+      when ''
+        # simple case, there was no interpolation, return directly
+        enqueue_completed([:STRING, text, scn.pos-before], before)
+        return
+      when '${'
+        count = ctx[:brace_count]
+        ctx[:brace_count] += 1
+        # The ${ terminator is counted towards the string part
+        enqueue_completed([:DQPRE, text, scn.pos-before], before)
+        # Lex expression tokens until a closing (balanced) brace count is reached
+        enqueue_until count
+        break
+      when '$'
+        if varname = scn.scan(PATTERN_VARIABLE)
+          # The $ is counted towards the variable
+          enqueue_completed([:DQPRE, text, after-before-1], before)
+          enqueue_completed([:VARIABLE, varname, scn.pos - after + 1], after -1)
+          break
+        else
+          # false $ variable start
+          text += terminator
+          value,terminator = slurp_uqstring()
+          text += value
+          after = scn.pos
+        end
+      end
+    end
+    interpolate_tail_uq
+    nil
+  end
+
+  def interpolate_tail_uq
+    scn = @scanner
+    ctx = @lexing_context
+    before = scn.pos
+    value,terminator = slurp_uqstring
+    text = value
+    after = scn.pos
+    while true
+      case terminator
+      when ''
+        # simple case, there was no further interpolation, return directly
+        enqueue_completed([:DQPOST, text, scn.pos-before], before)
+        return
+      when '${'
+        count = ctx[:brace_count]
+        ctx[:brace_count] += 1
+        # The ${ terminator is counted towards the string part
+        enqueue_completed([:DQMID, text, scn.pos-before], before)
+        # Lex expression tokens until a closing (balanced) brace count is reached
+        enqueue_until count
+        break
+      when '$'
+        if varname = scn.scan(PATTERN_VARIABLE)
+          # The $ is counted towards the variable
+          enqueue_completed([:DQMID, text, after-before-1], before)
+          enqueue_completed([:VARIABLE, varname, scn.pos - after +1], after -1)
+          break
+        else
+          # false $ variable start
+          text += terminator
+          value,terminator = slurp_uqstring
+          text += value
+          after = scn.pos
+        end
+      end
+    end
+    interpolate_tail_uq
+  end
+
+  # Enqueues lexed tokens until either end of input, or the given brace_count is reached
+  #
+  def enqueue_until brace_count
+    scn = @scanner
+    ctx = @lexing_context
+    queue = @token_queue
+
+    scn.skip(self.class::PATTERN_WS)
+    queue_size = queue.size
+    until scn.eos? do
+      if token = lex_token
+        token_name = token[0]
+        ctx[:after] = token_name
+        if token_name == :RBRACE && ctx[:brace_count] == brace_count
+          qlength = queue.size - queue_size
+          if qlength == 1
+            # Single token is subject to replacement
+            queue[-1] = transform_to_variable(queue[-1])
+          elsif qlength > 1 && [:DOT, :LBRACK].include?(queue[queue_size + 1][0])
+            # A first word, number of name token followed by '[' or '.' is subject to replacement
+            # But not for other operators such as ?, +, - etc. where user must use a $ before the name
+            # to get a variable
+            queue[queue_size] = transform_to_variable(queue[queue_size])
+          end
+          return
+        end
+        queue << token
+      else
+        scn.skip(self.class::PATTERN_WS)
+      end
+    end
+  end
+
+  def transform_to_variable(token)
+    token_name = token[0]
+    if [:NUMBER, :NAME, :WORD].include?(token_name) || self.class::KEYWORD_NAMES[token_name]
+      t = token[1]
+      ta = t.token_array
+      [:VARIABLE, self.class::TokenValue.new([:VARIABLE, ta[1], ta[2]], t.offset, t.locator)]
+    else
+      token
+    end
+  end
+
+  # Interpolates unquoted string and transfers the result to the given lexer
+  # (This is used when a second lexer instance is used to lex a substring)
+  #
+  def interpolate_uq_to(lexer)
+    interpolate_uq
+    queue = @token_queue
+    until queue.empty? do
+      lexer.enqueue(queue.shift)
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/lexer2.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/lexer2.rb
new file mode 100644
index 0000000..9605e75
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/lexer2.rb
@@ -0,0 +1,700 @@
+# The Lexer is responsbile for turning source text into tokens.
+# This version is a performance enhanced lexer (in comparison to the 3.x and earlier "future parser" lexer.
+#
+# Old returns tokens [:KEY, value, { locator = }
+# Could return [[token], locator]
+# or Token.new([token], locator) with the same API x[0] = token_symbol, x[1] = self, x[:key] = (:value, :file, :line, :pos) etc
+
+require 'strscan'
+require 'puppet/pops/parser/lexer_support'
+require 'puppet/pops/parser/heredoc_support'
+require 'puppet/pops/parser/interpolation_support'
+require 'puppet/pops/parser/epp_support'
+require 'puppet/pops/parser/slurp_support'
+
+class Puppet::Pops::Parser::Lexer2
+  include Puppet::Pops::Parser::LexerSupport
+  include Puppet::Pops::Parser::HeredocSupport
+  include Puppet::Pops::Parser::InterpolationSupport
+  include Puppet::Pops::Parser::SlurpSupport
+  include Puppet::Pops::Parser::EppSupport
+
+  # ALl tokens have three slots, the token name (a Symbol), the token text (String), and a token text length.
+  # All operator and punctuation tokens reuse singleton arrays Tokens that require unique values create
+  # a unique array per token.
+  #
+  # PEFORMANCE NOTES:
+  # This construct reduces the amount of object that needs to be created for operators and punctuation.
+  # The length is pre-calculated for all singleton tokens. The length is used both to signal the length of
+  # the token, and to advance the scanner position (without having to advance it with a scan(regexp)).
+  #
+  TOKEN_LBRACK       = [:LBRACK,       '['.freeze,   1].freeze
+  TOKEN_LISTSTART    = [:LISTSTART,    '['.freeze,   1].freeze
+  TOKEN_RBRACK       = [:RBRACK,       ']'.freeze,   1].freeze
+  TOKEN_LBRACE       = [:LBRACE,       '{'.freeze,   1].freeze
+  TOKEN_RBRACE       = [:RBRACE,       '}'.freeze,   1].freeze
+  TOKEN_SELBRACE     = [:SELBRACE,     '{'.freeze,   1].freeze
+  TOKEN_LPAREN       = [:LPAREN,       '('.freeze,   1].freeze
+  TOKEN_RPAREN       = [:RPAREN,       ')'.freeze,   1].freeze
+
+  TOKEN_EQUALS       = [:EQUALS,       '='.freeze,   1].freeze
+  TOKEN_APPENDS      = [:APPENDS,      '+='.freeze,  2].freeze
+  TOKEN_DELETES      = [:DELETES,      '-='.freeze,  2].freeze
+
+  TOKEN_ISEQUAL      = [:ISEQUAL,      '=='.freeze,  2].freeze
+  TOKEN_NOTEQUAL     = [:NOTEQUAL,     '!='.freeze,  2].freeze
+  TOKEN_MATCH        = [:MATCH,        '=~'.freeze,  2].freeze
+  TOKEN_NOMATCH      = [:NOMATCH,      '!~'.freeze,  2].freeze
+  TOKEN_GREATEREQUAL = [:GREATEREQUAL, '>='.freeze,  2].freeze
+  TOKEN_GREATERTHAN  = [:GREATERTHAN,  '>'.freeze,   1].freeze
+  TOKEN_LESSEQUAL    = [:LESSEQUAL,    '<='.freeze,  2].freeze
+  TOKEN_LESSTHAN     = [:LESSTHAN,     '<'.freeze,   1].freeze
+
+  TOKEN_FARROW       = [:FARROW,       '=>'.freeze,  2].freeze
+  TOKEN_PARROW       = [:PARROW,       '+>'.freeze,  2].freeze
+
+  TOKEN_LSHIFT       = [:LSHIFT,       '<<'.freeze,  2].freeze
+  TOKEN_LLCOLLECT    = [:LLCOLLECT,    '<<|'.freeze, 3].freeze
+  TOKEN_LCOLLECT     = [:LCOLLECT,     '<|'.freeze,  2].freeze
+
+  TOKEN_RSHIFT       = [:RSHIFT,       '>>'.freeze,  2].freeze
+  TOKEN_RRCOLLECT    = [:RRCOLLECT,    '|>>'.freeze, 3].freeze
+  TOKEN_RCOLLECT     = [:RCOLLECT,     '|>'.freeze,  2].freeze
+
+  TOKEN_PLUS         = [:PLUS,         '+'.freeze,   1].freeze
+  TOKEN_MINUS        = [:MINUS,        '-'.freeze,   1].freeze
+  TOKEN_DIV          = [:DIV,          '/'.freeze,   1].freeze
+  TOKEN_TIMES        = [:TIMES,        '*'.freeze,   1].freeze
+  TOKEN_MODULO       = [:MODULO,       '%'.freeze,   1].freeze
+
+  TOKEN_NOT          = [:NOT,          '!'.freeze,   1].freeze
+  TOKEN_DOT          = [:DOT,          '.'.freeze,   1].freeze
+  TOKEN_PIPE         = [:PIPE,         '|'.freeze,   1].freeze
+  TOKEN_AT           = [:AT ,          '@'.freeze,   1].freeze
+  TOKEN_ATAT         = [:ATAT ,        '@@'.freeze,  2].freeze
+  TOKEN_COLON        = [:COLON,        ':'.freeze,   1].freeze
+  TOKEN_COMMA        = [:COMMA,        ','.freeze,   1].freeze
+  TOKEN_SEMIC        = [:SEMIC,        ';'.freeze,   1].freeze
+  TOKEN_QMARK        = [:QMARK,        '?'.freeze,   1].freeze
+  TOKEN_TILDE        = [:TILDE,        '~'.freeze,   1].freeze # lexed but not an operator in Puppet
+
+  TOKEN_REGEXP       = [:REGEXP,       nil,   0].freeze
+
+  TOKEN_IN_EDGE      = [:IN_EDGE,      '->'.freeze,  2].freeze
+  TOKEN_IN_EDGE_SUB  = [:IN_EDGE_SUB,  '~>'.freeze,  2].freeze
+  TOKEN_OUT_EDGE     = [:OUT_EDGE,     '<-'.freeze,  2].freeze
+  TOKEN_OUT_EDGE_SUB = [:OUT_EDGE_SUB, '<~'.freeze,  2].freeze
+
+  # Tokens that are always unique to what has been lexed
+  TOKEN_STRING         =  [:STRING, nil,          0].freeze
+  TOKEN_WORD           =  [:WORD, nil,            0].freeze
+  TOKEN_DQPRE          =  [:DQPRE,  nil,          0].freeze
+  TOKEN_DQMID          =  [:DQPRE,  nil,          0].freeze
+  TOKEN_DQPOS          =  [:DQPRE,  nil,          0].freeze
+  TOKEN_NUMBER         =  [:NUMBER, nil,          0].freeze
+  TOKEN_VARIABLE       =  [:VARIABLE, nil,        1].freeze
+  TOKEN_VARIABLE_EMPTY =  [:VARIABLE, ''.freeze,  1].freeze
+
+  # HEREDOC has syntax as an argument.
+  TOKEN_HEREDOC        =  [:HEREDOC, nil, 0].freeze
+
+  # EPP_START is currently a marker token, may later get syntax
+  TOKEN_EPPSTART       =  [:EPP_START, nil, 0].freeze
+  TOKEN_EPPEND         =  [:EPP_END, '%>', 2].freeze
+  TOKEN_EPPEND_TRIM    =  [:EPP_END_TRIM, '-%>', 3].freeze
+
+  # This is used for unrecognized tokens, will always be a single character. This particular instance
+  # is not used, but is kept here for documentation purposes.
+  TOKEN_OTHER        = [:OTHER,  nil,  0]
+
+  # Keywords are all singleton tokens with pre calculated lengths.
+  # Booleans are pre-calculated (rather than evaluating the strings "false" "true" repeatedly.
+  #
+  KEYWORDS = {
+    "case"     => [:CASE,     'case',     4],
+    "class"    => [:CLASS,    'class',    5],
+    "default"  => [:DEFAULT,  'default',  7],
+    "define"   => [:DEFINE,   'define',   6],
+    "if"       => [:IF,       'if',       2],
+    "elsif"    => [:ELSIF,    'elsif',    5],
+    "else"     => [:ELSE,     'else',     4],
+    "inherits" => [:INHERITS, 'inherits', 8],
+    "node"     => [:NODE,     'node',     4],
+    "and"      => [:AND,      'and',      3],
+    "or"       => [:OR,       'or',       2],
+    "undef"    => [:UNDEF,    'undef',    5],
+    "false"    => [:BOOLEAN,  false,      5],
+    "true"     => [:BOOLEAN,  true,       4],
+    "in"       => [:IN,       'in',       2],
+    "unless"   => [:UNLESS,   'unless',   6],
+    "function" => [:FUNCTION, 'function', 8],
+    "type"     => [:TYPE,     'type',     4],
+    "attr"     => [:ATTR,     'attr',     4],
+    "private"  => [:PRIVATE,  'private',  7],
+    # The following tokens exist in reserved form. Later they will be made
+    # live subject to a feature switch.
+    "application"  => [:APPLICATION_R,  'application',  11],
+    "consumes"     => [:CONSUMES_R,  'consumes',  8],
+    "produces"     => [:PRODUCES_R,  'produces',  8],
+  }
+
+  KEYWORDS.each {|k,v| v[1].freeze; v.freeze }
+  KEYWORDS.freeze
+
+  # Reverse lookup of keyword name to string
+  KEYWORD_NAMES = {}
+  KEYWORDS.each {|k, v| KEYWORD_NAMES[v[0]] = k }
+  KEYWORD_NAMES.freeze
+
+  PATTERN_WS        = %r{[[:blank:]\r]+}
+
+  # The single line comment includes the line ending.
+  PATTERN_COMMENT   = %r{#.*\r?}
+  PATTERN_MLCOMMENT = %r{/\*(.*?)\*/}m
+
+  PATTERN_REGEX     = %r{/[^/\n]*/}
+  PATTERN_REGEX_END = %r{/}
+  PATTERN_REGEX_A   = %r{\A/} # for replacement to ""
+  PATTERN_REGEX_Z   = %r{/\Z} # for replacement to ""
+  PATTERN_REGEX_ESC = %r{\\/} # for replacement to "/"
+
+  # The 3x patterns:
+  # PATTERN_CLASSREF       = %r{((::){0,1}[A-Z][-\w]*)+}
+  # PATTERN_NAME           = %r{((::)?[a-z0-9][-\w]*)(::[a-z0-9][-\w]*)*}
+
+  # The NAME and CLASSREF in 4x are strict. Each segment must start with
+  # a letter a-z and may not contain dashes (\w includes letters, digits and _).
+  #
+  PATTERN_CLASSREF       = %r{((::){0,1}[A-Z][\w]*)+}
+  PATTERN_NAME           = %r{^((::)?[a-z][\w]*)(::[a-z][\w]*)*$}
+
+  PATTERN_BARE_WORD     = %r{((?:::){0,1}(?:[a-z_](?:[\w-]*[\w])?))+}
+
+  PATTERN_DOLLAR_VAR     = %r{\$(::)?(\w+::)*\w+}
+  PATTERN_NUMBER         = %r{\b(?:0[xX][0-9A-Fa-f]+|0?\d+(?:\.\d+)?(?:[eE]-?\d+)?)\b}
+
+  # PERFORMANCE NOTE:
+  # Comparison against a frozen string is faster (than unfrozen).
+  #
+  STRING_BSLASH_BSLASH = '\\'.freeze
+
+  attr_reader :locator
+
+  def initialize()
+  end
+
+  # Clears the lexer state (it is not required to call this as it will be garbage collected
+  # and the next lex call (lex_string, lex_file) will reset the internal state.
+  #
+  def clear()
+    # not really needed, but if someone wants to ensure garbage is collected as early as possible
+    @scanner = nil
+    @locator = nil
+    @lexing_context = nil
+  end
+
+  # Convenience method, and for compatibility with older lexer. Use the lex_string instead which allows
+  # passing the path to use without first having to call file= (which reads the file if it exists).
+  # (Bad form to use overloading of assignment operator for something that is not really an assignment. Also,
+  # overloading of = does not allow passing more than one argument).
+  #
+  def string=(string)
+    lex_string(string, '')
+  end
+
+  def lex_string(string, path='')
+    initvars
+    @scanner = StringScanner.new(string)
+    @locator = Puppet::Pops::Parser::Locator.locator(string, path)
+  end
+
+  # Lexes an unquoted string.
+  # @param string [String] the string to lex
+  # @param locator [Puppet::Pops::Parser::Locator] the locator to use (a default is used if nil is given)
+  # @param escapes [Array<String>] array of character strings representing the escape sequences to transform
+  # @param interpolate [Boolean] whether interpolation of expressions should be made or not.
+  #
+  def lex_unquoted_string(string, locator, escapes, interpolate)
+    initvars
+    @scanner = StringScanner.new(string)
+    @locator = locator || Puppet::Pops::Parser::Locator.locator(string, '')
+    @lexing_context[:escapes] = escapes || UQ_ESCAPES
+    @lexing_context[:uq_slurp_pattern] = interpolate ? (escapes.include?('$') ? SLURP_UQ_PATTERN : SLURP_UQNE_PATTERN) : SLURP_ALL_PATTERN
+  end
+
+  # Convenience method, and for compatibility with older lexer. Use the lex_file instead.
+  # (Bad form to use overloading of assignment operator for something that is not really an assignment).
+  #
+  def file=(file)
+    lex_file(file)
+  end
+
+  # TODO: This method should not be used, callers should get the locator since it is most likely required to
+  # compute line, position etc given offsets.
+  #
+  def file
+    @locator ? @locator.file : nil
+  end
+
+  # Initializes lexing of the content of the given file. An empty string is used if the file does not exist.
+  #
+  def lex_file(file)
+    initvars
+    contents = Puppet::FileSystem.exist?(file) ? Puppet::FileSystem.read(file) : ""
+    @scanner = StringScanner.new(contents.freeze)
+    @locator = Puppet::Pops::Parser::Locator.locator(contents, file)
+  end
+
+  def initvars
+    @token_queue = []
+    # NOTE: additional keys are used; :escapes, :uq_slurp_pattern, :newline_jump, :epp_*
+    @lexing_context = {
+      :brace_count => 0,
+      :after => nil,
+    }
+  end
+
+  # Scans all of the content and returns it in an array
+  # Note that the terminating [false, false] token is included in the result.
+  #
+  def fullscan
+    result = []
+    scan {|token, value| result.push([token, value]) }
+    result
+  end
+
+  # A block must be passed to scan. It will be called with two arguments, a symbol for the token,
+  # and an instance of LexerSupport::TokenValue
+  # PERFORMANCE NOTE: The TokenValue is designed to reduce the amount of garbage / temporary data
+  # and to only convert the lexer's internal tokens on demand. It is slightly more costly to create an
+  # instance of a class defined in Ruby than an Array or Hash, but the gain is much bigger since transformation
+  # logic is avoided for many of its members (most are never used (e.g. line/pos information which is only of
+  # value in general for error messages, and for some expressions (which the lexer does not know about).
+  #
+  def scan
+    # PERFORMANCE note: it is faster to access local variables than instance variables.
+    # This makes a small but notable difference since instance member access is avoided for
+    # every token in the lexed content.
+    #
+    scn   = @scanner
+    ctx   = @lexing_context
+    queue = @token_queue
+
+    lex_error_without_pos(Puppet::Pops::Issues::NO_INPUT_TO_LEXER) unless scn
+
+    scn.skip(PATTERN_WS)
+
+    # This is the lexer's main loop
+    until queue.empty? && scn.eos? do
+      if token = queue.shift || lex_token
+        ctx[:after] = token[0]
+        yield token
+      end
+    end
+
+    # Signals end of input
+    yield [false, false]
+  end
+
+  # This lexes one token at the current position of the scanner.
+  # PERFORMANCE NOTE: Any change to this logic should be performance measured.
+  #
+  def lex_token
+    # Using three char look ahead (may be faster to do 2 char look ahead since only 2 tokens require a third
+    scn = @scanner
+    ctx = @lexing_context
+    before = @scanner.pos
+
+    # A look ahead of 3 characters is used since the longest operator ambiguity is resolved at that point.
+    # PERFORMANCE NOTE: It is faster to peek once and use three separate variables for lookahead 0, 1 and 2.
+    #
+    la = scn.peek(3)
+    return nil if la.empty?
+
+    # Ruby 1.8.7 requires using offset and length (or integers are returned.
+    # PERFORMANCE NOTE.
+    # It is slightly faster to use these local variables than accessing la[0], la[1] etc. in ruby 1.9.3
+    # But not big enough to warrant two completely different implementations.
+    #
+    la0 = la[0,1]
+    la1 = la[1,1]
+    la2 = la[2,1]
+
+    # PERFORMANCE NOTE:
+    # A case when, where all the cases are literal values is the fastest way to map from data to code.
+    # It is much faster than using a hash with lambdas, hash with symbol used to then invoke send etc.
+    # This case statement is evaluated for most character positions in puppet source, and great care must
+    # be taken to not introduce performance regressions.
+    #
+    case la0
+
+    when '.'
+      emit(TOKEN_DOT, before)
+
+    when ','
+      emit(TOKEN_COMMA, before)
+
+    when '['
+      if (before == 0 || scn.string[locator.char_offset(before)-1,1] =~ /[[:blank:]\r\n]+/)
+        emit(TOKEN_LISTSTART, before)
+      else
+        emit(TOKEN_LBRACK, before)
+      end
+
+    when ']'
+      emit(TOKEN_RBRACK, before)
+
+    when '('
+      emit(TOKEN_LPAREN, before)
+
+    when ')'
+      emit(TOKEN_RPAREN, before)
+
+    when ';'
+      emit(TOKEN_SEMIC, before)
+
+    when '?'
+      emit(TOKEN_QMARK, before)
+
+    when '*'
+      emit(TOKEN_TIMES, before)
+
+    when '%'
+      if la1 == '>' && ctx[:epp_mode]
+        scn.pos += 2
+        if ctx[:epp_mode] == :expr
+          enqueue_completed(TOKEN_EPPEND, before)
+        end
+        ctx[:epp_mode] = :text
+        interpolate_epp
+      else
+        emit(TOKEN_MODULO, before)
+      end
+
+    when '{'
+      # The lexer needs to help the parser since the technology used cannot deal with
+      # lookahead of same token with different precedence. This is solved by making left brace
+      # after ? into a separate token.
+      #
+      ctx[:brace_count] += 1
+      emit(if ctx[:after] == :QMARK
+        TOKEN_SELBRACE
+      else
+        TOKEN_LBRACE
+      end, before)
+
+    when '}'
+      ctx[:brace_count] -= 1
+      emit(TOKEN_RBRACE, before)
+
+      # TOKENS @, @@, @(
+    when '@'
+      case la1
+      when '@'
+        emit(TOKEN_ATAT, before) # TODO; Check if this is good for the grammar
+      when '('
+        heredoc
+      else
+        emit(TOKEN_AT, before)
+      end
+
+      # TOKENS |, |>, |>>
+    when '|'
+      emit(case la1
+      when '>'
+        la2 == '>' ? TOKEN_RRCOLLECT : TOKEN_RCOLLECT
+      else
+        TOKEN_PIPE
+      end, before)
+
+      # TOKENS =, =>, ==, =~
+    when '='
+      emit(case la1
+      when '='
+        TOKEN_ISEQUAL
+      when '>'
+        TOKEN_FARROW
+      when '~'
+        TOKEN_MATCH
+      else
+        TOKEN_EQUALS
+      end, before)
+
+      # TOKENS '+', '+=', and '+>'
+    when '+'
+      emit(case la1
+      when '='
+        TOKEN_APPENDS
+      when '>'
+        TOKEN_PARROW
+      else
+        TOKEN_PLUS
+      end, before)
+
+      # TOKENS '-', '->', and epp '-%>' (end of interpolation with trim)
+    when '-'
+      if ctx[:epp_mode] && la1 == '%' && la2 == '>'
+        scn.pos += 3
+        if ctx[:epp_mode] == :expr
+          enqueue_completed(TOKEN_EPPEND_TRIM, before)
+        end
+        interpolate_epp(:with_trim)
+      else
+        emit(case la1
+        when '>'
+          TOKEN_IN_EDGE
+        when '='
+          TOKEN_DELETES
+        else
+          TOKEN_MINUS
+        end, before)
+      end
+
+      # TOKENS !, !=, !~
+    when '!'
+      emit(case la1
+      when '='
+        TOKEN_NOTEQUAL
+      when '~'
+        TOKEN_NOMATCH
+      else
+        TOKEN_NOT
+      end, before)
+
+      # TOKENS ~>, ~
+    when '~'
+      emit(la1 == '>' ? TOKEN_IN_EDGE_SUB : TOKEN_TILDE, before)
+
+    when '#'
+      scn.skip(PATTERN_COMMENT)
+      nil
+
+      # TOKENS '/', '/*' and '/ regexp /'
+    when '/'
+      case la1
+      when '*'
+        scn.skip(PATTERN_MLCOMMENT)
+        nil
+
+      else
+        # regexp position is a regexp, else a div
+        if regexp_acceptable? && value = scn.scan(PATTERN_REGEX)
+          # Ensure an escaped / was not matched
+          while value[-2..-2] == STRING_BSLASH_BSLASH # i.e. \\
+            value += scn.scan_until(PATTERN_REGEX_END)
+          end
+          regex = value.sub(PATTERN_REGEX_A, '').sub(PATTERN_REGEX_Z, '').gsub(PATTERN_REGEX_ESC, '/')
+          emit_completed([:REGEX, Regexp.new(regex), scn.pos-before], before)
+        else
+          emit(TOKEN_DIV, before)
+        end
+      end
+
+      # TOKENS <, <=, <|, <<|, <<, <-, <~
+    when '<'
+      emit(case la1
+      when '<'
+        if la2 == '|'
+          TOKEN_LLCOLLECT
+        else
+          TOKEN_LSHIFT
+        end
+      when '='
+        TOKEN_LESSEQUAL
+      when '|'
+        TOKEN_LCOLLECT
+      when '-'
+        TOKEN_OUT_EDGE
+      when '~'
+        TOKEN_OUT_EDGE_SUB
+      else
+        TOKEN_LESSTHAN
+      end, before)
+
+      # TOKENS >, >=, >>
+    when '>'
+      emit(case la1
+      when '>'
+        TOKEN_RSHIFT
+      when '='
+        TOKEN_GREATEREQUAL
+      else
+        TOKEN_GREATERTHAN
+      end, before)
+
+      # TOKENS :, ::CLASSREF, ::NAME
+    when ':'
+      if la1 == ':'
+        before = scn.pos
+        # PERFORMANCE NOTE: This could potentially be speeded up by using a case/when listing all
+        # upper case letters. Alternatively, the 'A', and 'Z' comparisons may be faster if they are
+        # frozen.
+        #
+        if la2 >= 'A' && la2 <= 'Z'
+          # CLASSREF or error
+          value = scn.scan(PATTERN_CLASSREF)
+          if value
+            after = scn.pos
+            emit_completed([:CLASSREF, value.freeze, after-before], before)
+          else
+            # move to faulty position ('::<uc-letter>' was ok)
+            scn.pos = scn.pos + 3
+            lex_error(Puppet::Pops::Issues::ILLEGAL_FULLY_QUALIFIED_CLASS_REFERENCE)
+          end
+        else
+          value = scn.scan(PATTERN_BARE_WORD)
+          if value
+            if value =~ PATTERN_NAME
+              emit_completed([:NAME, value.freeze, scn.pos-before], before)
+            else
+              emit_completed([:WORD, value.freeze, scn.pos - before], before)
+            end
+          else
+            # move to faulty position ('::' was ok)
+            scn.pos = scn.pos + 2
+            lex_error(Puppet::Pops::Issues::ILLEGAL_FULLY_QUALIFIED_NAME)
+          end
+        end
+      else
+        emit(TOKEN_COLON, before)
+      end
+
+    when '$'
+      if value = scn.scan(PATTERN_DOLLAR_VAR)
+        emit_completed([:VARIABLE, value[1..-1].freeze, scn.pos - before], before)
+      else
+        # consume the $ and let higher layer complain about the error instead of getting a syntax error
+        emit(TOKEN_VARIABLE_EMPTY, before)
+      end
+
+    when '"'
+      # Recursive string interpolation, 'interpolate' either returns a STRING token, or
+      # a DQPRE with the rest of the string's tokens placed in the @token_queue
+      interpolate_dq
+
+    when "'"
+      emit_completed([:STRING, slurp_sqstring.freeze, scn.pos - before], before)
+
+    when '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
+      value = scn.scan(PATTERN_NUMBER)
+      if value
+        length = scn.pos - before
+        assert_numeric(value, length)
+        emit_completed([:NUMBER, value.freeze, length], before)
+      else
+        # move to faulty position ([0-9] was ok)
+        scn.pos = scn.pos + 1
+        lex_error(Puppet::Pops::Issues::ILLEGAL_NUMBER)
+      end
+
+    when 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '_'
+
+      value = scn.scan(PATTERN_BARE_WORD)
+      if value && value =~ PATTERN_NAME
+        emit_completed(KEYWORDS[value] || [:NAME, value.freeze, scn.pos - before], before)
+      elsif value
+        emit_completed([:WORD, value.freeze, scn.pos - before], before)
+      else
+        # move to faulty position ([a-z_] was ok)
+        scn.pos = scn.pos + 1
+        fully_qualified = scn.match?(/::/)
+        if fully_qualified
+          lex_error(Puppet::Pops::Issues::ILLEGAL_FULLY_QUALIFIED_NAME)
+        else
+          lex_error(Puppet::Pops::Issues::ILLEGAL_NAME_OR_BARE_WORD)
+        end
+      end
+
+    when 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
+      value = scn.scan(PATTERN_CLASSREF)
+      if value
+        emit_completed([:CLASSREF, value.freeze, scn.pos - before], before)
+      else
+        # move to faulty position ([A-Z] was ok)
+        scn.pos = scn.pos + 1
+        lex_error(Puppet::Pops::Issues::ILLEGAL_CLASS_REFERENCE)
+      end
+
+    when "\n"
+      # If heredoc_cont is in effect there are heredoc text lines to skip over
+      # otherwise just skip the newline.
+      #
+      if ctx[:newline_jump]
+        scn.pos = ctx[:newline_jump]
+        ctx[:newline_jump] = nil
+      else
+        scn.pos += 1
+      end
+      return nil
+
+    when ' ', "\t", "\r"
+      scn.skip(PATTERN_WS)
+      return nil
+
+    else
+      # In case of unicode spaces of various kinds that are captured by a regexp, but not by the
+      # simpler case expression above (not worth handling those special cases with better performance).
+      if scn.skip(PATTERN_WS)
+        nil
+      else
+        # "unrecognized char"
+        emit([:OTHER, la0, 1], before)
+      end
+    end
+  end
+
+  # Emits (produces) a token [:tokensymbol, TokenValue] and moves the scanner's position past the token
+  #
+  def emit(token, byte_offset)
+    @scanner.pos = byte_offset + token[2]
+    [token[0], TokenValue.new(token, byte_offset, @locator)]
+  end
+
+  # Emits the completed token on the form [:tokensymbol, TokenValue. This method does not alter
+  # the scanner's position.
+  #
+  def emit_completed(token, byte_offset)
+    [token[0], TokenValue.new(token, byte_offset, @locator)]
+  end
+
+  # Enqueues a completed token at the given offset
+  def enqueue_completed(token, byte_offset)
+    @token_queue << emit_completed(token, byte_offset)
+  end
+
+  # Allows subprocessors for heredoc etc to enqueue tokens that are tokenized by a different lexer instance
+  #
+  def enqueue(emitted_token)
+    @token_queue << emitted_token
+  end
+
+  # Answers after which tokens it is acceptable to lex a regular expression.
+  # PERFORMANCE NOTE:
+  # It may be beneficial to turn this into a hash with default value of true for missing entries.
+  # A case expression with literal values will however create a hash internally. Since a reference is
+  # always needed to the hash, this access is almost as costly as a method call.
+  #
+  def regexp_acceptable?
+    case @lexing_context[:after]
+
+    # Ends of (potential) R-value generating expressions
+    when :RPAREN, :RBRACK, :RRCOLLECT, :RCOLLECT
+      false
+
+    # End of (potential) R-value - but must be allowed because of case expressions
+    # Called out here to not be mistaken for a bug.
+    when :RBRACE
+      true
+
+    # Operands (that can be followed by DIV (even if illegal in grammar)
+    when :NAME, :CLASSREF, :NUMBER, :STRING, :BOOLEAN, :DQPRE, :DQMID, :DQPOST, :HEREDOC, :REGEX, :VARIABLE, :WORD
+      false
+
+    else
+      true
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/lexer_support.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/lexer_support.rb
new file mode 100644
index 0000000..af6079a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/lexer_support.rb
@@ -0,0 +1,139 @@
+# This is an integral part of the Lexer. It is broken out into a separate module
+# for maintainability of the code, and making the various parts of the lexer focused.
+#
+module Puppet::Pops::Parser::LexerSupport
+
+  # Returns "<eof>" if at end of input, else the following 5 characters with \n \r \t escaped
+  def followed_by
+    return "<eof>" if @scanner.eos?
+    result = @scanner.rest[0,5] + "..."
+    result.gsub!("\t", '\t')
+    result.gsub!("\n", '\n')
+    result.gsub!("\r", '\r')
+    result
+  end
+
+  # Returns a quoted string using " or ' depending on the given a strings's content
+  def format_quote(q)
+    if q == "'"
+      '"\'"'
+    else
+      "'#{q}'"
+    end
+  end
+
+  # Raises a Puppet::LexError with the given message
+  def lex_error_without_pos(issue, args = {})
+    raise Puppet::ParseErrorWithIssue.new(issue.format(args), nil, nil, nil, nil, issue.issue_code)
+  end
+
+  # Raises a Puppet::ParserErrorWithIssue with the given issue and arguments
+  def lex_error(issue, args = {}, pos=nil)
+    raise create_lex_error(issue, args, pos)
+  end
+
+  def filename
+    file = @locator.file
+    file.is_a?(String) && !file.empty? ? file : nil
+  end
+
+  def line(pos)
+    @locator.line_for_offset(pos || @scanner.pos)
+  end
+
+  def position(pos)
+    @locator.pos_on_line(pos || @scanner.pos)
+  end
+
+  def lex_warning(issue, args = {}, pos=nil)
+    Puppet::Util::Log.create({
+        :level => :warning,
+        :message => issue.format(args),
+        :issue_code => issue.issue_code,
+        :file => filename,
+        :line => line(pos),
+        :pos => position(pos),
+      })
+  end
+
+  # @param issue [Puppet::Pops::Issues::Issue] the issue
+  # @param args [Hash<Symbol,String>] Issue arguments
+  # @param pos [Integer]
+  # @return [Puppet::ParseErrorWithIssue] the created error
+  def create_lex_error(issue, args = {}, pos = nil)
+    Puppet::ParseErrorWithIssue.new(
+        issue.format(args),
+        filename,
+        line(pos),
+        position(pos),
+        nil,
+        issue.issue_code)
+  end
+
+  # Asserts that the given string value is a float, or an integer in decimal, octal or hex form.
+  # An error is raised if the given value does not comply.
+  #
+  def assert_numeric(value, length)
+    if value =~ /^0[xX].*$/
+      lex_error(Puppet::Pops::Issues::INVALID_HEX_NUMBER, {:value => value}, length)     unless value =~ /^0[xX][0-9A-Fa-f]+$/
+
+    elsif value =~ /^0[^.].*$/
+      lex_error(Puppet::Pops::Issues::INVALID_OCTAL_NUMBER, {:value => value}, length)   unless value =~ /^0[0-7]+$/
+
+    else
+      lex_error(Puppet::Pops::Issues::INVALID_DECIMAL_NUMBER, {:value => value}, length) unless value =~ /0?\d+(?:\.\d+)?(?:[eE]-?\d+)?/
+    end
+  end
+
+  # A TokenValue keeps track of the token symbol, the lexed text for the token, its length
+  # and its position in its source container. There is a cost associated with computing the
+  # line and position on line information.
+  #
+  class TokenValue < Puppet::Pops::Parser::Locatable
+    attr_reader :token_array
+    attr_reader :offset
+    attr_reader :locator
+
+    def initialize(token_array, offset, locator)
+      @token_array = token_array
+      @offset = offset
+      @locator = locator
+    end
+
+    def length
+      @token_array[2]
+    end
+
+    def [](key)
+      case key
+      when :value
+        @token_array[1]
+      when :file
+        @locator.file
+      when :line
+        @locator.line_for_offset(@offset)
+      when :pos
+        @locator.pos_on_line(@offset)
+      when :length
+        @token_array[2]
+      when :locator
+        @locator
+      when :offset
+        @offset
+      else
+        nil
+      end
+    end
+
+    def to_s
+      # This format is very compact and is intended for debugging output from racc parsser in
+      # debug mode. If this is made more elaborate the output from a debug run becomes very hard to read.
+      #
+      "'#{self[:value]} #{@token_array[0]}'"
+    end
+    # TODO: Make this comparable for testing
+    # vs symbolic, vs array with symbol and non hash, array with symbol and hash)
+    #
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/locatable.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/locatable.rb
new file mode 100644
index 0000000..45fc5ce
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/locatable.rb
@@ -0,0 +1,23 @@
+# Interface for something that is "locateable" (holds offset and length).
+class Puppet::Pops::Parser::Locatable
+
+  # The offset in the locator's content
+  def offset
+  end
+
+  # The length in the locator from the given offset
+  def length
+  end
+
+  # This class is useful for testing
+  class Fixed < Puppet::Pops::Parser::Locatable
+    attr_reader :offset
+    attr_reader :length
+
+    def initialize(offset, length)
+      @offset = offset
+      @length = length
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/locator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/locator.rb
new file mode 100644
index 0000000..c46c38e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/locator.rb
@@ -0,0 +1,291 @@
+# Helper class that keeps track of where line breaks are located and can answer questions about positions.
+#
+class Puppet::Pops::Parser::Locator
+
+  RUBY_1_9_3 = (1 << 16 | 9 << 8 | 3)
+  RUBY_2_0_0 = (2 << 16 | 0 << 8 | 0)
+  RUBYVER_ARRAY = RUBY_VERSION.split(".").collect {|s| s.to_i }
+  RUBYVER = (RUBYVER_ARRAY[0] << 16 | RUBYVER_ARRAY[1] << 8 | RUBYVER_ARRAY[2])
+
+  # Computes a symbol representing which ruby runtime this is running on
+  # This implementation will fail if there are more than 255 minor or micro versions of ruby
+  #
+  def self.locator_version
+    if RUBYVER >= RUBY_2_0_0
+      :ruby20
+    elsif RUBYVER >= RUBY_1_9_3
+      :ruby19
+    else
+      :ruby18
+    end
+  end
+  LOCATOR_VERSION = locator_version
+
+  # Constant set to true if multibyte is supported (includes multibyte extended regular expressions)
+  MULTIBYTE = !!(LOCATOR_VERSION == :ruby19 || LOCATOR_VERSION == :ruby20)
+
+  # Creates, or recreates a Locator. A Locator is created if index is not given (a scan is then
+  # performed of the given source string.
+  #
+  def self.locator(string, file, index = nil)
+    case LOCATOR_VERSION
+    when :ruby20, :ruby19
+      Locator19.new(string, file, index)
+    else
+      Locator18.new(string, file, index)
+    end
+  end
+
+  # Returns the file name associated with the string content
+  def file
+  end
+
+  # Returns the string content
+  def string
+  end
+
+  # Returns the position on line (first position on a line is 1)
+  def pos_on_line(offset)
+  end
+
+  # Returns the line number (first line is 1) for the given offset
+  def line_for_offset(offset)
+  end
+
+  # Returns the offset on line (first offset on a line is 0).
+  #
+  def offset_on_line(offset)
+  end
+
+  # Returns the character offset for a given reported offset
+  def char_offset(byte_offset)
+  end
+
+  # Returns the length measured in number of characters from the given start and end reported offset
+  def char_length(offset, end_offset)
+  end
+
+  # Returns the line index - an array of line offsets for the start position of each line, starting at 0 for
+  # the first line.
+  #
+  def line_index()
+  end
+
+  # A Sublocator locates a concrete locator (subspace) in a virtual space.
+  # The `leading_line_count` is the (virtual) number of lines preceding the first line in the concrete locator.
+  # The `leading_offset` is the (virtual) byte offset of the first byte in the concrete locator.
+  # The `leading_line_offset` is the (virtual) offset / margin in characters for each line.
+  #
+  # This illustrates characters in the sublocator (`.`) inside the subspace (`X`):
+  #
+  #      1:XXXXXXXX
+  #      2:XXXX.... .. ... ..
+  #      3:XXXX. . .... ..
+  #      4:XXXX............
+  #
+  # This sublocator would be configured with leading_line_count = 1,
+  # leading_offset=8, and leading_line_offset=4
+  #
+  # Note that leading_offset must be the same for all lines and measured in characters.
+  #
+  class SubLocator < Puppet::Pops::Parser::Locator
+    attr_reader :locator
+    attr_reader :leading_line_count
+    attr_reader :leading_offset
+    attr_reader :leading_line_offset
+
+    def self.sub_locator(string, file, leading_line_count, leading_offset, leading_line_offset)
+      self.new(Puppet::Pops::Parser::Locator.locator(string, file),
+        leading_line_count,
+        leading_offset,
+        leading_line_offset)
+    end
+
+    def initialize(locator, leading_line_count, leading_offset, leading_line_offset)
+      @locator = locator
+      @leading_line_count = leading_line_count
+      @leading_offset = leading_offset
+      @leading_line_offset = leading_line_offset
+    end
+
+    def file
+      @locator.file
+    end
+
+    def string
+      @locator.string
+    end
+
+    # Given offset is offset in the subspace
+    def line_for_offset(offset)
+      @locator.line_for_offset(offset) + @leading_line_count
+    end
+
+    # Given offset is offset in the subspace
+    def offset_on_line(offset)
+      @locator.offset_on_line(offset) + @leading_line_offset
+    end
+
+    # Given offset is offset in the subspace
+    def char_offset(offset)
+      effective_line = @locator.line_for_offset(offset)
+      locator.char_offset(offset) + (effective_line * @leading_line_offset) + @leading_offset
+    end
+
+    # Given offsets are offsets in the subspace
+    def char_length(offset, end_offset)
+      effective_line = @locator.line_for_offset(end_offset) - @locator.line_for_offset(offset)
+      locator.char_length(offset, end_offset) + (effective_line * @leading_line_offset)
+    end
+
+    def pos_on_line(offset)
+      offset_on_line(offset) +1
+    end
+  end
+
+  private
+
+  class AbstractLocator < Puppet::Pops::Parser::Locator
+    attr_accessor :line_index
+    attr_accessor :string
+    attr_accessor :prev_offset
+    attr_accessor :prev_line
+    attr_reader   :string
+    attr_reader   :file
+
+    # Create a locator based on a content string, and a boolean indicating if ruby version support multi-byte strings
+    # or not.
+    #
+    def initialize(string, file, index = nil)
+      @string = string.freeze
+      @file = file.freeze
+      @prev_offset = nil
+      @prev_line = nil
+      @line_index = index
+      compute_line_index unless !index.nil?
+    end
+
+    # Returns the position on line (first position on a line is 1)
+    def pos_on_line(offset)
+      offset_on_line(offset) +1
+    end
+
+    def to_location_hash(reported_offset, end_offset)
+      pos        = pos_on_line(reported_offset)
+      offset     = char_offset(reported_offset)
+      length     = char_length(reported_offset, end_offset)
+      start_line = line_for_offset(reported_offset)
+      { :line => start_line, :pos => pos, :offset => offset, :length => length}
+    end
+
+    # Returns the index of the smallest item for which the item > the given value
+    # This is a min binary search. Although written in Ruby it is only slightly slower than
+    # the corresponding method in C in Ruby 2.0.0 - the main benefit to use this method over
+    # the Ruby C version is that it returns the index (not the value) which means there is not need
+    # to have an additional structure to get the index (or record the index in the structure). This
+    # saves both memory and CPU. It also does not require passing a block that is called since this
+    # method is specialized to search the line index.
+    #
+    def ary_bsearch_i(ary, value)
+      low = 0
+      high = ary.length
+      mid = nil
+      smaller = false
+      satisfied = false
+      v = nil
+
+      while low < high do
+          mid = low + ((high - low) / 2)
+          v = (ary[mid] > value)
+          if v == true
+            satisfied = true
+            smaller = true
+          elsif !v
+            smaller = false
+          else
+            raise TypeError, "wrong argument, must be boolean or nil, got '#{v.class}'"
+          end
+
+          if smaller
+            high = mid
+          else
+            low = mid + 1;
+          end
+      end
+
+      return nil if low == ary.length
+      return nil if !satisfied
+      return low
+    end
+
+    # Common impl for 18 and 19 since scanner is byte based
+    def compute_line_index
+      scanner = StringScanner.new(string)
+      result = [0] # first line starts at 0
+      while scanner.scan_until(/\n/)
+        result << scanner.pos
+      end
+      self.line_index = result.freeze
+    end
+
+    # Returns the line number (first line is 1) for the given offset
+    def line_for_offset(offset)
+      if prev_offset == offset
+        # use cache
+        return prev_line
+      end
+      if line_nbr = ary_bsearch_i(line_index, offset)
+        # cache
+        prev_offset = offset
+        prev_line = line_nbr
+        return line_nbr
+      end
+      # If not found it is after last
+      # clear cache
+      prev_offset = prev_line = nil
+      return line_index.size
+    end
+  end
+
+  class Locator18 < AbstractLocator
+
+    def offset_on_line(offset)
+      line_offset = line_index[ line_for_offset(offset)-1 ]
+      offset - line_offset
+    end
+
+    def char_offset(char_offset)
+      char_offset
+    end
+
+    def char_length(offset, end_offset)
+      end_offset - offset
+    end
+
+  end
+
+  # This implementation is for Ruby19 and Ruby20. It uses byteslice to get strings from byte based offsets.
+  # For Ruby20 this is faster than using the Stringscanner.charpos method (byteslice outperforms it, when
+  # strings are frozen).
+  #
+  class Locator19 < AbstractLocator
+
+    # Returns the offset on line (first offset on a line is 0).
+    # Ruby 19 is multibyte but has no character position methods, must use byteslice
+    def offset_on_line(offset)
+      line_offset = line_index[ line_for_offset(offset)-1 ]
+      string.byteslice(line_offset, offset-line_offset).length
+    end
+
+    # Returns the character offset for a given byte offset
+    # Ruby 19 is multibyte but has no character position methods, must use byteslice
+    def char_offset(byte_offset)
+      string.byteslice(0, byte_offset).length
+    end
+
+    # Returns the length measured in number of characters from the given start and end byte offseta
+    def char_length(offset, end_offset)
+      string.byteslice(offset, end_offset - offset).length
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/parser_support.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/parser_support.rb
new file mode 100644
index 0000000..cda9147
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/parser_support.rb
@@ -0,0 +1,239 @@
+require 'puppet/parser/functions'
+require 'puppet/parser/files'
+require 'puppet/resource/type_collection'
+require 'puppet/resource/type_collection_helper'
+require 'puppet/resource/type'
+require 'monitor'
+
+# Supporting logic for the parser.
+# This supporting logic has slightly different responsibilities compared to the original Puppet::Parser::Parser.
+# It is only concerned with parsing.
+#
+class Puppet::Pops::Parser::Parser
+  # Note that the name of the contained class and the file name (currently parser_support.rb)
+  # needs to be different as the class is generated by Racc, and this file (parser_support.rb) is included as a mix in
+  #
+
+  # Simplify access to the Model factory
+  # Note that the parser/parser support does not have direct knowledge about the Model.
+  # All model construction/manipulation is made by the Factory.
+  #
+  Factory = Puppet::Pops::Model::Factory
+  Model = Puppet::Pops::Model
+
+  include Puppet::Resource::TypeCollectionHelper
+
+  attr_accessor :lexer
+  attr_reader :definitions
+
+  # Returns the token text of the given lexer token, or nil, if token is nil
+  def token_text t
+    return t if t.nil?
+    t = t.current if t.respond_to?(:current)
+    return t.value if t.is_a? Model::QualifiedName
+
+    # else it is a lexer token
+    t[:value]
+  end
+
+  # Produces the fully qualified name, with the full (current) namespace for a given name.
+  #
+  # This is needed because class bodies are lazily evaluated and an inner class' container(s) may not
+  # have been evaluated before some external reference is made to the inner class; its must therefore know its complete name
+  # before evaluation-time.
+  #
+  def classname(name)
+    [namespace, name].join('::').sub(/^::/, '')
+  end
+
+  # Raises a Parse error with location information. Information about file is always obtained from the
+  # lexer. Line and position is produced if the given semantic is a Positioned object and have been given an offset.
+  #
+  def error(semantic, message)
+    semantic = semantic.current() if semantic.is_a?(Puppet::Pops::Model::Factory)
+    # Adapt the model so it is possible to get location information.
+    # The model may not have been added to the source tree, so give it the lexer's locator
+    # directly instead of searching for the root Program where the locator is normally stored.
+    #
+    if semantic.is_a?(Puppet::Pops::Model::Positioned)
+      adapter = Puppet::Pops::Adapters::SourcePosAdapter.adapt(semantic)
+      adapter.locator = @lexer.locator
+    else
+      adapter = nil
+    end
+    except = Puppet::ParseError.new(message)
+    except.file = @lexer.locator.file
+    except.line = adapter.line if adapter
+    except.pos = adapter.pos if adapter
+    raise except
+  end
+
+  # Parses a file expected to contain pp DSL logic.
+  def parse_file(file)
+    unless Puppet::FileSystem.exist?(file)
+      unless file =~ /\.pp$/
+        file = file + ".pp"
+      end
+    end
+    @lexer.file = file
+    _parse()
+  end
+
+  def initialize()
+    @lexer = Puppet::Pops::Parser::Lexer2.new
+    @namestack = []
+    @definitions = []
+  end
+
+  # This is a callback from the generated parser (when an error occurs while parsing)
+  #
+  def on_error(token,value,stack)
+    if token == 0 # denotes end of file
+      value_at = 'end of file'
+    else
+      value_at = "'#{value[:value]}'"
+    end
+    error = Puppet::Pops::Issues::SYNTAX_ERROR.format(:where => value_at)
+    error = "#{error}, token: #{token}" if @yydebug
+
+    # Note, old parser had processing of "expected token here" - do not try to reinstate:
+    # The 'expected' is only of value at end of input, otherwise any parse error involving a
+    # start of a pair will be reported as expecting the close of the pair - e.g. "$x.each |$x {|", would
+    # report that "seeing the '{', the '}' is expected. That would be wrong.
+    # Real "expected" tokens are very difficult to compute (would require parsing of racc output data). Output of the stack
+    # could help, but can require extensive backtracking and produce many options.
+    #
+    # The lexer should handle the "expected instead of end of file for strings, and interpolation", other expectancies
+    # must be handled by the grammar. The lexer may have enqueued tokens far ahead - the lexer's opinion about this
+    # is not trustworthy.
+    #
+    file = nil
+    line = nil
+    pos  = nil
+    if token != 0
+      file = value[:file]
+      line = value[:line]
+      pos  = value[:pos]
+    else
+      # At end of input, use what the lexer thinks is the source file
+      file = lexer.file
+    end
+    file = nil unless file.is_a?(String) && !file.empty?
+    raise Puppet::ParseErrorWithIssue.new(error, file, line, pos, nil, issue_code = Puppet::Pops::Issues::SYNTAX_ERROR.issue_code)
+  end
+
+  # Parses a String of pp DSL code.
+  #
+  def parse_string(code, path = '')
+    @lexer.lex_string(code, path)
+    _parse()
+  end
+
+  # Mark the factory wrapped model object with location information
+  # @return [Puppet::Pops::Model::Factory] the given factory
+  # @api private
+  #
+  def loc(factory, start_locateable, end_locateable = nil)
+    factory.record_position(start_locateable, end_locateable)
+  end
+
+  # Mark the factory wrapped heredoc model object with location information
+  # @return [Puppet::Pops::Model::Factory] the given factory
+  # @api private
+  #
+  def heredoc_loc(factory, start_locateabke, end_locateable = nil)
+    factory.record_heredoc_position(start_locatable, end_locatable)
+  end
+
+  def aryfy(o)
+    o = [o] unless o.is_a?(Array)
+    o
+  end
+
+  def namespace
+    @namestack.join('::')
+  end
+
+  def namestack(name)
+    @namestack << name
+  end
+
+  def namepop()
+    @namestack.pop
+  end
+
+  def add_definition(definition)
+    @definitions << definition.current
+    definition
+  end
+
+  # Transforms an array of expressions containing literal name expressions to calls if followed by an
+  # expression, or expression list
+  #
+  def transform_calls(expressions)
+    # Factory transform raises an error if a non qualified name is followed by an argument list
+    # since there is no way that that can be transformed back to sanity. This occurs in situations like this:
+    #
+    #  $a = 10, notice hello
+    #
+    # where the "10, notice" forms an argument list. The parser builds an Array with the expressions and includes
+    # the comma tokens to enable the error to be reported against the first comma.
+    #
+    begin
+      Factory.transform_calls(expressions)
+    rescue Puppet::Pops::Model::Factory::ArgsToNonCallError => e
+      # e.args[1] is the first comma token in the list
+      # e.name_expr is the function name expression
+      if e.name_expr.is_a?(Puppet::Pops::Model::QualifiedName)
+        error(e.args[1], "attempt to pass argument list to the function '#{e.name_expr.value}' which cannot be called without parentheses")
+      else
+        error(e.args[1], "illegal comma separated argument list")
+      end
+    end
+  end
+
+  # Transforms a LEFT followed by the result of attribute_operations, this may be a call or an invalid sequence
+  def transform_resource_wo_title(left, resource)
+    Factory.transform_resource_wo_title(left, resource)
+  end
+
+  # Creates a program with the given body.
+  #
+  def create_program(body)
+    locator = @lexer.locator
+    Factory.PROGRAM(body, definitions, locator)
+  end
+
+  # Creates an empty program with a single No-op at the input's EOF offset with 0 length.
+  #
+  def create_empty_program()
+    locator = @lexer.locator
+    no_op = Factory.literal(nil)
+    # Create a synthetic NOOP token at EOF offset with 0 size. The lexer does not produce an EOF token that is
+    # visible to the grammar rules. Creating this token is mainly to reuse the positioning logic as it
+    # expects a token decorated with location information.
+    token_sym, token = @lexer.emit_completed([:NOOP,'',0], locator.string.bytesize)
+    loc(no_op, token)
+    # Program with a Noop
+    program = Factory.PROGRAM(no_op, [], locator)
+    program
+  end
+
+  # Performs the parsing and returns the resulting model.
+  # The lexer holds state, and this is setup with {#parse_string}, or {#parse_file}.
+  #
+  # @api private
+  #
+  def _parse()
+    begin
+      @yydebug = false
+      main = yyparse(@lexer,:scan)
+    end
+    return main
+  ensure
+    @lexer.clear
+    @namestack = []
+    @definitions = []
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/slurp_support.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/slurp_support.rb
new file mode 100644
index 0000000..c16441e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/parser/slurp_support.rb
@@ -0,0 +1,111 @@
+# This module is an integral part of the Lexer.
+# It defines the string slurping behavior - finding the string and non string parts in interpolated
+# strings, translating escape sequences in strings to their single character equivalence.
+#
+# PERFORMANCE NOTE: The various kinds of slurping could be made even more generic, but requires
+# additional parameter passing and evaluation of conditional logic.
+# TODO: More detailed performance analysis of excessive character escaping and interpolation.
+#
+module Puppet::Pops::Parser::SlurpSupport
+  include Puppet::Pops::Parser::LexerSupport
+
+  SLURP_SQ_PATTERN  = /(?:[^\\]|^|[^\\])(?:[\\]{2})*[']/
+  SLURP_DQ_PATTERN  = /(?:[^\\]|^|[^\\])(?:[\\]{2})*(["]|[$]\{?)/
+  SLURP_UQ_PATTERN  = /(?:[^\\]|^|[^\\])(?:[\\]{2})*([$]\{?|\z)/
+  # unquoted, no escapes
+  SLURP_UQNE_PATTERN  = /(\$\{?|\z)/m
+  SLURP_ALL_PATTERN = /.*(\z)/m
+  SQ_ESCAPES = %w{ \\ ' }
+  DQ_ESCAPES = %w{ \\  $ ' " r n t s u}+["\r\n", "\n"]
+  UQ_ESCAPES = %w{ \\  $ r n t s u}+["\r\n", "\n"]
+
+  def slurp_sqstring
+    # skip the leading '
+    @scanner.pos += 1
+    str = slurp(@scanner, SLURP_SQ_PATTERN, SQ_ESCAPES, :ignore_invalid_escapes)
+    lex_error(Puppet::Pops::Issues::UNCLOSED_QUOTE, :after => "\"'\"", :followed_by => followed_by) unless str
+    str[0..-2] # strip closing "'" from result
+  end
+
+  def slurp_dqstring
+    scn = @scanner
+    last = scn.matched
+    str = slurp(scn, SLURP_DQ_PATTERN, DQ_ESCAPES, false)
+    unless str
+      lex_error(Puppet::Pops::Issues::UNCLOSED_QUOTE, :after => format_quote(last), :followed_by => followed_by)
+    end
+
+    # Terminator may be a single char '"', '$', or two characters '${' group match 1 (scn[1]) from the last slurp holds this
+    terminator = scn[1]
+    [str[0..(-1 - terminator.length)], terminator]
+  end
+
+   # Copy from old lexer - can do much better
+   def slurp_uqstring
+     scn = @scanner
+     last = scn.matched
+     ignore = true
+
+     str = slurp(scn, @lexing_context[:uq_slurp_pattern], @lexing_context[:escapes], :ignore_invalid_escapes)
+
+     # Terminator may be a single char '$', two characters '${', or empty string '' at the end of intput.
+     # Group match 1 holds this.
+     # The exceptional case is found by looking at the subgroup 1 of the most recent match made by the scanner (i.e. @scanner[1]).
+     # This is the last match made by the slurp method (having called scan_until on the scanner).
+     # If there is a terminating character is must be stripped and returned separately.
+     #
+     terminator = scn[1]
+     [str[0..(-1 - terminator.length)], terminator]
+   end
+
+  # Slurps a string from the given scanner until the given pattern and then replaces any escaped
+  # characters given by escapes into their control-character equivalent or in case of line breaks, replaces the
+  # pattern \r?\n with an empty string.
+  # The returned string contains the terminating character. Returns nil if the scanner can not scan until the given
+  # pattern.
+  #
+  def slurp(scanner, pattern, escapes, ignore_invalid_escapes)
+    str = scanner.scan_until(pattern) || return
+
+    # Process unicode escapes first as they require getting 4 hex digits
+    # If later a \u is found it is warned not to be a unicode escape
+    if escapes.include?('u')
+      str.gsub!(/\\u(?:([\da-fA-F]{4})|\{([\da-fA-F]{1,6})\})/m) {
+        [($1 || $2).hex].pack("U")
+      }
+    end
+
+    begin
+    str.gsub!(/\\([^\r\n]|(?:\r?\n))/m) {
+      ch = $1
+      if escapes.include? ch
+        case ch
+        when 'r'   ; "\r"
+        when 'n'   ; "\n"
+        when 't'   ; "\t"
+        when 's'   ; " "
+        when 'u'
+          lex_warning(Puppet::Pops::Issues::ILLEGAL_UNICODE_ESCAPE)
+          "\\u"
+        when "\n"  ; ''
+        when "\r\n"; ''
+        else      ch
+        end
+      else
+        lex_warning(Puppet::Pops::Issues::UNRECOGNIZED_ESCAPE, :ch => ch) unless ignore_invalid_escapes
+        "\\#{ch}"
+      end
+    }
+    rescue ArgumentError => e
+      # A invalid byte sequence may be the result of faulty input as well, but that could not possibly
+      # have reached this far... Unfortunately there is no more specific error and a match on message is
+      # required to differentiate from other internal problems.
+      if e.message =~ /invalid byte sequence/
+        lex_error(Puppet::Pops::Issues::ILLEGAL_UNICODE_ESCAPE)
+      else
+        raise e
+      end
+    end
+    str
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/patterns.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/patterns.rb
new file mode 100644
index 0000000..bfd6b94
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/patterns.rb
@@ -0,0 +1,47 @@
+# The Patterns module contains common regular expression patters for the Puppet DSL language
+module Puppet::Pops::Patterns
+
+  # NUMERIC matches hex, octal, decimal, and floating point and captures several parts
+  # 0 = entire matched number, leading and trailing whitespace and sign included
+  # 1 = sign, +, - or nothing
+  # 2 = entire numeric part
+  # 3 = hexadecimal number
+  # 4 = non hex integer portion, possibly with leading 0 (octal)
+  # 5 = floating point part, starts with ".", decimals and optional exponent
+  #
+  # Thus, a hex number has group 3 value, an octal value has group 4 (if it starts with 0), and no group 3
+  # and a floating point value has group 4 and group 5.
+  #
+  NUMERIC = %r{\A[[:blank:]]*([-+]?)[[:blank:]]*((0[xX][0-9A-Fa-f]+)|(0?\d+)((?:\.\d+)?(?:[eE]-?\d+)?))[[:blank:]]*\z}
+
+  # ILLEGAL_P3_1_HOSTNAME matches if a hostname contains illegal characters.
+  # This check does not prevent pathological names like 'a....b', '.....', "---". etc.
+  ILLEGAL_HOSTNAME_CHARS = %r{[^-\w.]}
+
+  # NAME matches a name the same way as the lexer.
+  NAME = %r{\A((::)?[a-z]\w*)(::[a-z]\w*)*\z}
+
+  # CLASSREF_EXT matches a class reference the same way as the lexer - i.e. the external source form
+  # where each part must start with a capital letter A-Z.
+  #
+  CLASSREF_EXT = %r{\A((::){0,1}[A-Z][\w]*)+\z}
+
+  # CLASSREF matches a class reference the way it is represented internally in the
+  # model (i.e. in lower case).
+  #
+  CLASSREF = %r{\A((::){0,1}[a-z][\w]*)+\z}
+
+  # DOLLAR_VAR matches a variable name including the initial $ character
+  DOLLAR_VAR     = %r{\$(::)?(\w+::)*\w+}
+
+  # VAR_NAME matches the name part of a variable (The $ character is not included)
+  # Note, that only the final segment may start with an underscore.
+  VAR_NAME = %r{\A(:?(::)?[a-z]\w*)*(:?(::)?[a-z_]\w*)\z}
+
+  # PARAM_NAME matches the name part of a parameter (The $ character is not included)
+  PARAM_NAME = %r{\A[a-z_]\w*\z}
+
+  # A Numeric var name must be the decimal number 0, or a decimal number not starting with 0
+  NUMERIC_VAR_NAME = %r{\A(?:0|(?:[1-9][0-9]*))\z}
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/semantic_error.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/semantic_error.rb
new file mode 100644
index 0000000..5802602
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/semantic_error.rb
@@ -0,0 +1,17 @@
+# Error that is used to raise an Issue. See {Puppet::Pops::Issues}.
+#
+class Puppet::Pops::SemanticError < RuntimeError
+  attr_accessor :issue
+  attr_accessor :semantic
+  attr_accessor :options
+
+  # @param issue [Puppet::Pops::Issues::Issue] the issue describing the severity and message
+  # @param semantic [Puppet::Pops::Model::Locatable, nil] the expression causing the failure, or nil if unknown
+  # @param options [Hash] an options hash with Symbol to value mapping - these are the arguments to the issue
+  #
+  def initialize(issue, semantic=nil, options = {})
+    @issue = issue
+    @semantic = semantic
+    @options = options
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/types/class_loader.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/types/class_loader.rb
new file mode 100644
index 0000000..7353d92
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/types/class_loader.rb
@@ -0,0 +1,129 @@
+require 'rgen/metamodel_builder'
+
+# The ClassLoader provides a Class instance given a class name or a meta-type.
+# If the class is not already loaded, it is loaded using the Puppet Autoloader.
+# This means it can load a class from a gem, or from puppet modules.
+#
+class Puppet::Pops::Types::ClassLoader
+  @autoloader = Puppet::Util::Autoload.new("ClassLoader", "", :wrap => false)
+
+  # Returns a Class given a fully qualified class name.
+  # Lookup of class is never relative to the calling namespace.
+  # @param name [String, Array<String>, Array<Symbol>, Puppet::Pops::Types::PAnyType] A fully qualified
+  #   class name String (e.g. '::Foo::Bar', 'Foo::Bar'), a PAnyType, or a fully qualified name in Array form where each part
+  #   is either a String or a Symbol, e.g. `%w{Puppetx Puppetlabs SomeExtension}`.
+  # @return [Class, nil] the looked up class or nil if no such class is loaded
+  # @raise ArgumentError If the given argument has the wrong type
+  # @api public
+  #
+  def self.provide(name)
+    case name
+    when String
+      provide_from_string(name)
+
+    when Array
+      provide_from_name_path(name.join('::'), name)
+
+    when Puppet::Pops::Types::PAnyType, Puppet::Pops::Types::PType
+      provide_from_type(name)
+
+    else
+      raise ArgumentError, "Cannot provide a class from a '#{name.class.name}'"
+    end
+  end
+
+  private
+
+  def self.provide_from_type(type)
+    case type
+    when Puppet::Pops::Types::PRuntimeType
+      raise ArgumentError.new("Only Runtime type 'ruby' is supported, got #{type.runtime}") unless type.runtime == :ruby
+      provide_from_string(type.runtime_type_name)
+
+    when Puppet::Pops::Types::PBooleanType
+      # There is no other thing to load except this Enum meta type
+      RGen::MetamodelBuilder::MMBase::Boolean
+
+    when Puppet::Pops::Types::PType
+      # TODO: PType should has a type argument (a PAnyType) so the Class' class could be returned
+      #       (but this only matters in special circumstances when meta programming has been used).
+      Class
+
+    when Puppet::Pops::Type::POptionalType
+      # cannot make a distinction between optional and its type
+      provide_from_type(type.optional_type)
+
+    # Although not expected to be the first choice for getting a concrete class for these
+    # types, these are of value if the calling logic just has a reference to type.
+    #
+    when Puppet::Pops::Types::PArrayType    ; Array
+    when Puppet::Pops::Types::PTupleType    ; Array
+    when Puppet::Pops::Types::PHashType     ; Hash
+    when Puppet::Pops::Types::PStructType   ; Hash
+    when Puppet::Pops::Types::PRegexpType   ; Regexp
+    when Puppet::Pops::Types::PIntegerType  ; Integer
+    when Puppet::Pops::Types::PStringType   ; String
+    when Puppet::Pops::Types::PPatternType  ; String
+    when Puppet::Pops::Types::PEnumType     ; String
+    when Puppet::Pops::Types::PFloatType    ; Float
+    when Puppet::Pops::Types::PUndefType      ; NilClass
+    when Puppet::Pops::Types::PCallableType ; Proc
+    else
+      nil
+    end
+  end
+
+  def self.provide_from_string(name)
+    name_path = name.split('::')
+    # always from the root, so remove an empty first segment
+    if name_path[0].empty?
+      name_path = name_path[1..-1]
+    end
+    provide_from_name_path(name, name_path)
+  end
+
+  def self.provide_from_name_path(name, name_path)
+    # If class is already loaded, try this first
+    result = find_class(name_path)
+
+    unless result.is_a?(Class)
+      # Attempt to load it using the auto loader
+      loaded_path = nil
+      if paths_for_name(name).find {|path| loaded_path = path; @autoloader.load(path) }
+        result = find_class(name_path)
+        unless result.is_a?(Class)
+          raise RuntimeError, "Loading of #{name} using relative path: '#{loaded_path}' did not create expected class"
+        end
+      end
+    end
+    return nil unless result.is_a?(Class)
+    result
+  end
+
+  def self.find_class(name_path)
+    name_path.reduce(Object) do |ns, name|
+      begin
+        ns.const_get(name)
+      rescue NameError
+        return nil
+      end
+    end
+  end
+
+  def self.paths_for_name(fq_name)
+    [de_camel(fq_name), downcased_path(fq_name)]
+  end
+
+  def self.downcased_path(fq_name)
+    fq_name.to_s.gsub(/::/, '/').downcase
+  end
+
+  def self.de_camel(fq_name)
+    fq_name.to_s.gsub(/::/, '/').
+    gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
+    gsub(/([a-z\d])([A-Z])/,'\1_\2').
+    tr("-", "_").
+    downcase
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/types/enumeration.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/types/enumeration.rb
new file mode 100644
index 0000000..76dc59b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/types/enumeration.rb
@@ -0,0 +1,34 @@
+# The Enumeration class provides default Enumerable::Enumerator creation for Puppet Programming Language
+# runtime objects that supports the concept of enumeration.
+#
+class Puppet::Pops::Types::Enumeration
+  # Produces an Enumerable::Enumerator for Array, Hash, Integer, Integer Range, and String.
+  #
+  def self.enumerator(o)
+    @@singleton ||= new
+    @@singleton.enumerator(o)
+  end
+
+  # Produces an Enumerator for Array, Hash, Integer, Integer Range, and String.
+  #
+  def enumerator(o)
+    case o
+    when String
+      x = o.chars
+      # Ruby 1.8.7 returns Enumerable::Enumerator, Ruby 1.8.9 Enumerator, and 2.0.0 an Array
+      x.is_a?(Array) ? x.each : x
+    when Integer
+      o.times
+    when Array
+      o.each
+    when Hash
+      o.each
+    when Puppet::Pops::Types::PIntegerType
+      # Not enumerable if representing an infinite range
+      return nil if o.to.nil? || o.from.nil?
+      o.each
+    else
+      nil
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/types/type_calculator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/types/type_calculator.rb
new file mode 100644
index 0000000..0541c08
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/types/type_calculator.rb
@@ -0,0 +1,1878 @@
+# The TypeCalculator can answer questions about puppet types.
+#
+# The Puppet type system is primarily based on sub-classing. When asking the type calculator to infer types from Ruby in general, it
+# may not provide the wanted answer; it does not for instance take module inclusions and extensions into account. In general the type
+# system should be unsurprising for anyone being exposed to the notion of type. The type `Data` may require a bit more explanation; this
+# is an abstract type that includes all scalar types, as well as Array with an element type compatible with Data, and Hash with key
+# compatible with scalar and elements compatible with Data. Expressed differently; Data is what you typically express using JSON (with
+# the exception that the Puppet type system also includes Pattern (regular expression) as a scalar.
+#
+# Inference
+# ---------
+# The `infer(o)` method infers a Puppet type for scalar Ruby objects, and for Arrays and Hashes.
+# The inference result is instance specific for single typed collections
+# and allows answering questions about its embedded type. It does not however preserve multiple types in
+# a collection, and can thus not answer questions like `[1,a].infer() =~ Array[Integer, String]` since the inference
+# computes the common type Scalar when combining Integer and String.
+#
+# The `infer_generic(o)` method infers a generic Puppet type for scalar Ruby object, Arrays and Hashes.
+# This inference result does not contain instance specific information; e.g. Array[Integer] where the integer
+# range is the generic default. Just `infer` it also combines types into a common type.
+#
+# The `infer_set(o)` method works like `infer` but preserves all type information. It does not do any
+# reduction into common types or ranges. This method of inference is best suited for answering questions
+# about an object being an instance of a type. It correctly answers: `[1,a].infer_set() =~ Array[Integer, String]`
+#
+# The `generalize!(t)` method modifies an instance specific inference result to a generic. The method mutates
+# the given argument. Basically, this removes string instances from String, and range from Integer and Float.
+#
+# Assignability
+# -------------
+# The `assignable?(t1, t2)` method answers if t2 conforms to t1. The type t2 may be an instance, in which case
+# its type is inferred, or a type.
+#
+# Instance?
+# ---------
+# The `instance?(t, o)` method answers if the given object (instance) is an instance that is assignable to the given type.
+#
+# String
+# ------
+# Creates a string representation of a type.
+#
+# Creation of Type instances
+# --------------------------
+# Instance of the classes in the {Puppet::Pops::Types type model} are used to denote a specific type. It is most convenient
+# to use the {Puppet::Pops::Types::TypeFactory TypeFactory} when creating instances.
+#
+# @note
+#   In general, new instances of the wanted type should be created as they are assigned to models using containment, and a
+#   contained object can only be in one container at a time. Also, the type system may include more details in each type
+#   instance, such as if it may be nil, be empty, contain a certain count etc. Or put differently, the puppet types are not
+#   singletons.
+#
+# All types support `copy` which should be used when assigning a type where it is unknown if it is bound or not
+# to a parent type. A check can be made with `t.eContainer().nil?`
+#
+# Equality and Hash
+# -----------------
+# Type instances are equal in terms of Ruby eql? and `==` if they describe the same type, but they are not `equal?` if they are not
+# the same type instance. Two types that describe the same type have identical hash - this makes them usable as hash keys.
+#
+# Types and Subclasses
+# --------------------
+# In general, the type calculator should be used to answer questions if a type is a subtype of another (using {#assignable?}, or
+# {#instance?} if the question is if a given object is an instance of a given type (or is a subtype thereof).
+# Many of the types also have a Ruby subtype relationship; e.g. PHashType and PArrayType are both subtypes of PCollectionType, and
+# PIntegerType, PFloatType, PStringType,... are subtypes of PScalarType. Even if it is possible to answer certain questions about
+# type by looking at the Ruby class of the types this is considered an implementation detail, and such checks should in general
+# be performed by the type_calculator which implements the type system semantics.
+#
+# The PRuntimeType
+# -------------
+# The PRuntimeType corresponds to a type in the runtime system (currently only supported runtime is 'ruby'). The
+# type has a runtime_type_name that corresponds to a Ruby Class name.
+# A Runtime[ruby] type can be used to describe any ruby class except for the puppet types that are specialized
+# (i.e. PRuntimeType should not be used for Integer, String, etc. since there are specialized types for those).
+# When the type calculator deals with PRuntimeTypes and checks for assignability, it determines the
+# "common ancestor class" of two classes.
+# This check is made based on the superclasses of the two classes being compared. In order to perform this, the
+# classes must be present (i.e. they are resolved from the string form in the PRuntimeType to a
+# loaded, instantiated Ruby Class). In general this is not a problem, since the question to produce the common
+# super type for two objects means that the classes must be present or there would have been
+# no instances present in the first place. If however the classes are not present, the type
+# calculator will fall back and state that the two types at least have Any in common.
+#
+# @see Puppet::Pops::Types::TypeFactory TypeFactory for how to create instances of types
+# @see Puppet::Pops::Types::TypeParser TypeParser how to construct a type instance from a String
+# @see Puppet::Pops::Types Types for details about the type model
+#
+# Using the Type Calculator
+# -----
+# The type calculator can be directly used via its class methods. If doing time critical work and doing many
+# calls to the type calculator, it is more performant to create an instance and invoke the corresponding
+# instance methods. Note that inference is an expensive operation, rather than inferring the same thing
+# several times, it is in general better to infer once and then copy the result if mutation to a more generic form is
+# required.
+#
+# @api public
+#
+class Puppet::Pops::Types::TypeCalculator
+
+  Types = Puppet::Pops::Types
+  TheInfinity = 1.0 / 0.0 # because the Infinity symbol is not defined
+
+  # @api public
+  def self.assignable?(t1, t2)
+    singleton.assignable?(t1,t2)
+  end
+
+  # Answers, does the given callable accept the arguments given in args (an array or a tuple)
+  # @param callable [Puppet::Pops::Types::PCallableType] - the callable
+  # @param args [Puppet::Pops::Types::PArrayType, Puppet::Pops::Types::PTupleType] args optionally including a lambda callable at the end
+  # @return [Boolan] true if the callable accepts the arguments
+  #
+  # @api public
+  def self.callable?(callable, args)
+    singleton.callable?(callable, args)
+  end
+
+  # Produces a String representation of the given type.
+  # @param t [Puppet::Pops::Types::PAnyType] the type to produce a string form
+  # @return [String] the type in string form
+  #
+  # @api public
+  #
+  def self.string(t)
+    singleton.string(t)
+  end
+
+  # @api public
+  def self.infer(o)
+    singleton.infer(o)
+  end
+
+  # @api public
+  def self.generalize!(o)
+    singleton.generalize!(o)
+  end
+
+  # @api public
+  def self.infer_set(o)
+    singleton.infer_set(o)
+  end
+
+  # @api public
+  def self.debug_string(t)
+    singleton.debug_string(t)
+  end
+
+  # @api public
+  def self.enumerable(t)
+    singleton.enumerable(t)
+  end
+
+  # @api private
+  def self.singleton()
+    @tc_instance ||= new
+  end
+
+  # @api public
+  #
+  def initialize
+    @@assignable_visitor ||= Puppet::Pops::Visitor.new(nil,"assignable",1,1)
+    @@infer_visitor ||= Puppet::Pops::Visitor.new(nil,"infer",0,0)
+    @@infer_set_visitor ||= Puppet::Pops::Visitor.new(nil,"infer_set",0,0)
+    @@instance_of_visitor ||= Puppet::Pops::Visitor.new(nil,"instance_of",1,1)
+    @@string_visitor ||= Puppet::Pops::Visitor.new(nil,"string",0,0)
+    @@inspect_visitor ||= Puppet::Pops::Visitor.new(nil,"debug_string",0,0)
+    @@enumerable_visitor ||= Puppet::Pops::Visitor.new(nil,"enumerable",0,0)
+    @@extract_visitor ||= Puppet::Pops::Visitor.new(nil,"extract",0,0)
+    @@generalize_visitor ||= Puppet::Pops::Visitor.new(nil,"generalize",0,0)
+    @@callable_visitor ||= Puppet::Pops::Visitor.new(nil,"callable",1,1)
+
+    da = Types::PArrayType.new()
+    da.element_type = Types::PDataType.new()
+    @data_array = da
+
+    h = Types::PHashType.new()
+    h.element_type = Types::PDataType.new()
+    h.key_type = Types::PScalarType.new()
+    @data_hash = h
+
+    @data_t = Types::PDataType.new()
+    @scalar_t = Types::PScalarType.new()
+    @numeric_t = Types::PNumericType.new()
+    @t = Types::PAnyType.new()
+
+    # Data accepts a Tuple that has 0-infinity Data compatible entries (e.g. a Tuple equivalent to Array).
+    data_tuple = Types::PTupleType.new()
+    data_tuple.addTypes(Types::PDataType.new())
+    data_tuple.size_type = Types::PIntegerType.new()
+    data_tuple.size_type.from = 0
+    data_tuple.size_type.to = nil # infinity
+    @data_tuple_t = data_tuple
+
+    # Variant type compatible with Data
+    data_variant = Types::PVariantType.new()
+    data_variant.addTypes(@data_hash.copy)
+    data_variant.addTypes(@data_array.copy)
+    data_variant.addTypes(Types::PScalarType.new)
+    data_variant.addTypes(Types::PUndefType.new)
+    data_variant.addTypes(@data_tuple_t.copy)
+    @data_variant_t = data_variant
+
+    collection_default_size = Types::PIntegerType.new()
+    collection_default_size.from = 0
+    collection_default_size.to = nil # infinity
+    @collection_default_size_t = collection_default_size
+
+    non_empty_string = Types::PStringType.new
+    non_empty_string.size_type = Types::PIntegerType.new()
+    non_empty_string.size_type.from = 1
+    non_empty_string.size_type.to = nil # infinity
+    @non_empty_string_t = non_empty_string
+
+    @nil_t = Types::PUndefType.new
+  end
+
+  # Convenience method to get a data type for comparisons
+  # @api private the returned value may not be contained in another element
+  #
+  def data
+    @data_t
+  end
+
+  # Convenience method to get a variant compatible with the Data type.
+  # @api private the returned value may not be contained in another element
+  #
+  def data_variant
+    @data_variant_t
+  end
+
+  def self.data_variant
+    singleton.data_variant
+  end
+
+  # Answers the question 'is it possible to inject an instance of the given class'
+  # A class is injectable if it has a special *assisted inject* class method called `inject` taking
+  # an injector and a scope as argument, or if it has a zero args `initialize` method.
+  #
+  # @param klazz [Class, PRuntimeType] the class/type to check if it is injectable
+  # @return [Class, nil] the injectable Class, or nil if not injectable
+  # @api public
+  #
+  def injectable_class(klazz)
+    # Handle case when we get a PType instead of a class
+    if klazz.is_a?(Types::PRuntimeType)
+      klazz = Puppet::Pops::Types::ClassLoader.provide(klazz)
+    end
+
+    # data types can not be injected (check again, it is not safe to assume that given RubyRuntime klazz arg was ok)
+    return false unless type(klazz).is_a?(Types::PRuntimeType)
+    if (klazz.respond_to?(:inject) && klazz.method(:inject).arity() == -4) || klazz.instance_method(:initialize).arity() == 0
+      klazz
+    else
+      nil
+    end
+  end
+
+  # Answers 'can an instance of type t2 be assigned to a variable of type t'.
+  # Does not accept nil/undef unless the type accepts it.
+  #
+  # @api public
+  #
+  def assignable?(t, t2)
+    if t.is_a?(Class)
+      t = type(t)
+    end
+
+    if t2.is_a?(Class)
+      t2 = type(t2)
+    end
+    t2_class = t2.class
+
+    # Unit can be assigned to anything
+    return true if t2_class == Types::PUnitType
+
+    if t2_class == Types::PVariantType
+      # Assignable if all contained types are assignable
+      t2.types.all? { |vt| @@assignable_visitor.visit_this_1(self, t, vt) }
+    else
+      # Turn NotUndef[T] into T when T is not assignable from Undef
+      if t2_class == Types::PNotUndefType && !(t2.type.nil? || assignable?(t2.type, @nil_t))
+        assignable?(t, t2.type)
+      else
+        @@assignable_visitor.visit_this_1(self, t, t2)
+      end
+    end
+ end
+
+  # Returns an enumerable if the t represents something that can be iterated
+  def enumerable(t)
+    @@enumerable_visitor.visit_this_0(self, t)
+  end
+
+  # Answers, does the given callable accept the arguments given in args (an array or a tuple)
+  #
+  def callable?(callable, args)
+    return false if !self.class.is_kind_of_callable?(callable)
+    # Note that polymorphism is for the args type, the callable is always a callable
+    @@callable_visitor.visit_this_1(self, args, callable)
+  end
+
+  # Answers if the two given types describe the same type
+  def equals(left, right)
+    return false unless left.is_a?(Types::PAnyType) && right.is_a?(Types::PAnyType)
+    # Types compare per class only - an extra test must be made if the are mutually assignable
+    # to find all types that represent the same type of instance
+    #
+    left == right || (assignable?(right, left) && assignable?(left, right))
+  end
+
+  # Answers 'what is the Puppet Type corresponding to the given Ruby class'
+  # @param c [Class] the class for which a puppet type is wanted
+  # @api public
+  #
+  def type(c)
+    raise ArgumentError, "Argument must be a Class" unless c.is_a? Class
+
+    # Can't use a visitor here since we don't have an instance of the class
+    case
+    when c <= Integer
+      type = Types::PIntegerType.new()
+    when c == Float
+      type = Types::PFloatType.new()
+    when c == Numeric
+      type = Types::PNumericType.new()
+    when c == String
+      type = Types::PStringType.new()
+    when c == Regexp
+      type = Types::PRegexpType.new()
+    when c == NilClass
+      type = Types::PUndefType.new()
+    when c == FalseClass, c == TrueClass
+      type = Types::PBooleanType.new()
+    when c == Class
+      type = Types::PType.new()
+    when c == Array
+      # Assume array of data values
+      type = Types::PArrayType.new()
+      type.element_type = Types::PDataType.new()
+    when c == Hash
+      # Assume hash with scalar keys and data values
+      type = Types::PHashType.new()
+      type.key_type = Types::PScalarType.new()
+      type.element_type = Types::PDataType.new()
+    else
+      type = Types::PRuntimeType.new(:runtime => :ruby, :runtime_type_name => c.name)
+    end
+    type
+  end
+
+  # Generalizes value specific types. The given type is mutated and returned.
+  # @api public
+  def generalize!(o)
+    @@generalize_visitor.visit_this_0(self, o)
+    o.eAllContents.each { |x| @@generalize_visitor.visit_this_0(self, x) }
+    o
+  end
+
+  def generalize_Object(o)
+    # do nothing, there is nothing to change for most types
+  end
+
+  # @return [Boolean] true if the given argument is contained in a struct element key
+  def is_struct_element_key?(o)
+    c = o.eContainer
+    if c.is_a?(Types::POptionalType)
+      o = c
+      c = c.eContainer
+    end
+    c.is_a?(Types::PStructElement) && c.key_type.equal?(o)
+  end
+  private :is_struct_element_key?
+
+  def generalize_PStringType(o)
+    # Skip generalization if the string is contained in a PStructElement key.
+    unless is_struct_element_key?(o)
+      o.values = []
+      o.size_type = nil
+    end
+  end
+
+  def generalize_PCollectionType(o)
+    # erase the size constraint from Array and Hash (if one exists, it is transformed to -Infinity - + Infinity, which is
+    # not desirable.
+    o.size_type = nil
+  end
+
+  def generalize_PFloatType(o)
+    o.to = nil
+    o.from = nil
+  end
+
+  def generalize_PIntegerType(o)
+    o.to = nil
+    o.from = nil
+  end
+
+  # Answers 'what is the single common Puppet Type describing o', or if o is an Array or Hash, what is the
+  # single common type of the elements (or keys and elements for a Hash).
+  # @api public
+  #
+  def infer(o)
+    @@infer_visitor.visit_this_0(self, o)
+  end
+
+  def infer_generic(o)
+    result = generalize!(infer(o))
+    result
+  end
+
+  # Answers 'what is the set of Puppet Types of o'
+  # @api public
+  #
+  def infer_set(o)
+    @@infer_set_visitor.visit_this_0(self, o)
+  end
+
+  def instance_of(t, o)
+    @@instance_of_visitor.visit_this_1(self, t, o)
+  end
+
+  def instance_of_Object(t, o)
+    # Undef is Undef and Any, but nothing else when checking instance?
+    return false if (o.nil?) && t.class != Types::PAnyType
+    assignable?(t, infer(o))
+  end
+
+  # Anything is an instance of Unit
+  # @api private
+  def instance_of_PUnitType(t, o)
+    true
+  end
+
+  def instance_of_PArrayType(t, o)
+    return false unless o.is_a?(Array)
+    return false unless o.all? {|element| instance_of(t.element_type, element) }
+    size_t = t.size_type || @collection_default_size_t
+    # optimize by calling directly
+    return instance_of_PIntegerType(size_t, o.size)
+  end
+
+  # @api private
+  def instance_of_PIntegerType(t, o)
+    return false unless o.is_a?(Integer)
+    x = t.from
+    x = -Float::INFINITY if x.nil? || x == :default
+    y = t.to
+    y = Float::INFINITY if y.nil? || y == :default
+    return x < y ? x <= o && y >= o : y <= o && x >= o
+  end
+
+  # @api private
+  def instance_of_PStringType(t, o)
+    return false unless o.is_a?(String)
+    # true if size compliant
+    size_t = t.size_type
+    if size_t.nil? || instance_of_PIntegerType(size_t, o.size)
+      values = t.values
+      values.empty? || values.include?(o)
+    else
+      false
+    end
+  end
+
+  def instance_of_PTupleType(t, o)
+    return false unless o.is_a?(Array)
+    # compute the tuple's min/max size, and check if that size matches
+    size_t = t.size_type || Puppet::Pops::Types::TypeFactory.range(*t.size_range)
+
+    return false unless instance_of_PIntegerType(size_t, o.size)
+    o.each_with_index do |element, index|
+       return false unless instance_of(t.types[index] || t.types[-1], element)
+    end
+    true
+  end
+
+  def instance_of_PStructType(t, o)
+    return false unless o.is_a?(Hash)
+    matched = 0
+    t.elements.all? do |e|
+      key = e.name
+      v = o[key]
+      if v.nil? && !o.include?(key)
+        # Entry is missing. Only OK when key is optional
+        assignable?(e.key_type, @nil_t)
+      else
+        matched += 1
+        instance_of(e.value_type, v)
+      end
+    end && matched == o.size
+  end
+
+  def instance_of_PHashType(t, o)
+    return false unless o.is_a?(Hash)
+    key_t = t.key_type
+    element_t = t.element_type
+    return false unless o.keys.all? {|key| instance_of(key_t, key) } && o.values.all? {|value| instance_of(element_t, value) }
+    size_t = t.size_type || @collection_default_size_t
+    # optimize by calling directly
+    return instance_of_PIntegerType(size_t, o.size)
+  end
+
+  def instance_of_PDataType(t, o)
+    instance_of(@data_variant_t, o)
+  end
+
+  def instance_of_PNotUndefType(t, o)
+    !(o.nil? || o == :undef) && (t.type.nil? || instance_of(t.type, o))
+  end
+
+  def instance_of_PUndefType(t, o)
+    o.nil? || o == :undef
+  end
+
+  def instance_of_POptionalType(t, o)
+    instance_of_PUndefType(t, o) || instance_of(t.optional_type, o)
+  end
+
+  def instance_of_PVariantType(t, o)
+    # instance of variant if o is instance? of any of variant's types
+    t.types.any? { |option_t| instance_of(option_t, o) }
+  end
+
+  # Answers 'is o an instance of type t'
+  # @api public
+  #
+  def self.instance?(t, o)
+    singleton.instance_of(t,o)
+  end
+
+  # Answers 'is o an instance of type t'
+  # @api public
+  #
+  def instance?(t, o)
+    instance_of(t,o)
+  end
+
+  # Answers if t is a puppet type
+  # @api public
+  #
+  def is_ptype?(t)
+    return t.is_a?(Types::PAnyType)
+  end
+
+  # Answers if t represents the puppet type PUndefType
+  # @api public
+  #
+  def is_pnil?(t)
+    return t.nil? || t.is_a?(Types::PUndefType)
+  end
+
+  # Answers, 'What is the common type of t1 and t2?'
+  #
+  # TODO: The current implementation should be optimized for performance
+  #
+  # @api public
+  #
+  def common_type(t1, t2)
+    raise ArgumentError, 'two types expected' unless (is_ptype?(t1) || is_pnil?(t1)) && (is_ptype?(t2) || is_pnil?(t2))
+
+    # TODO: This is not right since Scalar U Undef is Any
+    # if either is nil, the common type is the other
+    if is_pnil?(t1)
+      return t2
+    elsif is_pnil?(t2)
+      return t1
+    end
+
+    # If either side is Unit, it is the other type
+    if t1.is_a?(Types::PUnitType)
+      return t2
+    elsif t2.is_a?(Types::PUnitType)
+      return t1
+    end
+
+    # Simple case, one is assignable to the other
+    if assignable?(t1, t2)
+      return t1
+    elsif assignable?(t2, t1)
+      return t2
+    end
+
+    # when both are arrays, return an array with common element type
+    if t1.is_a?(Types::PArrayType) && t2.is_a?(Types::PArrayType)
+      type = Types::PArrayType.new()
+      type.element_type = common_type(t1.element_type, t2.element_type)
+      return type
+    end
+
+    # when both are hashes, return a hash with common key- and element type
+    if t1.is_a?(Types::PHashType) && t2.is_a?(Types::PHashType)
+      type = Types::PHashType.new()
+      type.key_type = common_type(t1.key_type, t2.key_type)
+      type.element_type = common_type(t1.element_type, t2.element_type)
+      return type
+    end
+
+    # when both are host-classes, reduce to PHostClass[] (since one was not assignable to the other)
+    if t1.is_a?(Types::PHostClassType) && t2.is_a?(Types::PHostClassType)
+      return Types::PHostClassType.new()
+    end
+
+    # when both are resources, reduce to Resource[T] or Resource[] (since one was not assignable to the other)
+    if t1.is_a?(Types::PResourceType) && t2.is_a?(Types::PResourceType)
+      result = Types::PResourceType.new()
+      # only Resource[] unless the type name is the same
+      if t1.type_name == t2.type_name then result.type_name = t1.type_name end
+      # the cross assignability test above has already determined that they do not have the same type and title
+      return result
+    end
+
+    # Integers have range, expand the range to the common range
+    if t1.is_a?(Types::PIntegerType) && t2.is_a?(Types::PIntegerType)
+      t1range = from_to_ordered(t1.from, t1.to)
+      t2range = from_to_ordered(t2.from, t2.to)
+      t = Types::PIntegerType.new()
+      from = [t1range[0], t2range[0]].min
+      to = [t1range[1], t2range[1]].max
+      t.from = from unless from == TheInfinity
+      t.to = to unless to == TheInfinity
+      return t
+    end
+
+    # Floats have range, expand the range to the common range
+    if t1.is_a?(Types::PFloatType) && t2.is_a?(Types::PFloatType)
+      t1range = from_to_ordered(t1.from, t1.to)
+      t2range = from_to_ordered(t2.from, t2.to)
+      t = Types::PFloatType.new()
+      from = [t1range[0], t2range[0]].min
+      to = [t1range[1], t2range[1]].max
+      t.from = from unless from == TheInfinity
+      t.to = to unless to == TheInfinity
+      return t
+    end
+
+    if t1.is_a?(Types::PStringType) && t2.is_a?(Types::PStringType)
+      t = Types::PStringType.new()
+      t.values = t1.values | t2.values unless t1.values.empty? || t2.values.empty?
+      t.size_type = common_type(t1.size_type, t2.size_type) unless t1.size_type.nil? || t2.size_type.nil?
+      return t
+    end
+
+    if t1.is_a?(Types::PPatternType) && t2.is_a?(Types::PPatternType)
+      t = Types::PPatternType.new()
+      # must make copies since patterns are contained types, not data-types
+      t.patterns = (t1.patterns | t2.patterns).map(&:copy)
+      return t
+    end
+
+    if t1.is_a?(Types::PEnumType) && t2.is_a?(Types::PEnumType)
+      # The common type is one that complies with either set
+      t = Types::PEnumType.new
+      t.values = t1.values | t2.values
+      return t
+    end
+
+    if t1.is_a?(Types::PVariantType) && t2.is_a?(Types::PVariantType)
+      # The common type is one that complies with either set
+      t = Types::PVariantType.new
+      t.types = (t1.types | t2.types).map(&:copy)
+      return t
+    end
+
+    if t1.is_a?(Types::PRegexpType) && t2.is_a?(Types::PRegexpType)
+      # if they were identical, the general rule would return a parameterized regexp
+      # since they were not, the result is a generic regexp type
+      return Types::PPatternType.new()
+    end
+
+    if t1.is_a?(Types::PCallableType) && t2.is_a?(Types::PCallableType)
+      # They do not have the same signature, and one is not assignable to the other,
+      # what remains is the most general form of Callable
+      return Types::PCallableType.new()
+    end
+
+    # Common abstract types, from most specific to most general
+    if common_numeric?(t1, t2)
+      return Types::PNumericType.new()
+    end
+
+    if common_scalar?(t1, t2)
+      return Types::PScalarType.new()
+    end
+
+    if common_data?(t1,t2)
+      return Types::PDataType.new()
+    end
+
+    # Meta types Type[Integer] + Type[String] => Type[Data]
+    if t1.is_a?(Types::PType) && t2.is_a?(Types::PType)
+      type = Types::PType.new()
+      type.type = common_type(t1.type, t2.type)
+      return type
+    end
+
+    # If both are Runtime types
+    if t1.is_a?(Types::PRuntimeType) && t2.is_a?(Types::PRuntimeType)
+      if t1.runtime == t2.runtime && t1.runtime_type_name == t2.runtime_type_name
+        return t1
+      end
+      # finding the common super class requires that names are resolved to class
+      # NOTE: This only supports runtime type of :ruby
+      c1 = Types::ClassLoader.provide_from_type(t1)
+      c2 = Types::ClassLoader.provide_from_type(t2)
+      if c1 && c2
+        c2_superclasses = superclasses(c2)
+        superclasses(c1).each do|c1_super|
+          c2_superclasses.each do |c2_super|
+            if c1_super == c2_super
+              return Types::PRuntimeType.new(:runtime => :ruby, :runtime_type_name => c1_super.name)
+            end
+          end
+        end
+      end
+    end
+
+    # They better both be Any type, or the wrong thing was asked and nil is returned
+    if t1.is_a?(Types::PAnyType) && t2.is_a?(Types::PAnyType)
+      return Types::PAnyType.new()
+    end
+  end
+
+  # Produces the superclasses of the given class, including the class
+  def superclasses(c)
+    result = [c]
+    while s = c.superclass
+      result << s
+      c = s
+    end
+    result
+  end
+
+  # Produces a string representing the type
+  # @api public
+  #
+  def string(t)
+    @@string_visitor.visit_this_0(self, t)
+  end
+
+  # Produces a debug string representing the type (possibly with more information that the regular string format)
+  # @api public
+  #
+  def debug_string(t)
+    @@inspect_visitor.visit_this_0(self, t)
+  end
+
+
+  # Reduces an enumerable of types to a single common type.
+  # @api public
+  #
+  def reduce_type(enumerable)
+    enumerable.reduce(nil) {|memo, t| common_type(memo, t) }
+  end
+
+  # Reduce an enumerable of objects to a single common type
+  # @api public
+  #
+  def infer_and_reduce_type(enumerable)
+    reduce_type(enumerable.collect() {|o| infer(o) })
+  end
+
+  # The type of all classes is PType
+  # @api private
+  #
+  def infer_Class(o)
+    Types::PType.new()
+  end
+
+  # @api private
+  def infer_Closure(o)
+    o.type()
+  end
+
+  # @api private
+  def infer_Function(o)
+    o.class.dispatcher.to_type
+  end
+
+  # @api private
+  def infer_Object(o)
+    Types::PRuntimeType.new(:runtime => :ruby, :runtime_type_name => o.class.name)
+  end
+
+  # The type of all types is PType
+  # @api private
+  #
+  def infer_PAnyType(o)
+    type = Types::PType.new()
+    type.type = o.copy
+    type
+  end
+
+  # The type of all types is PType
+  # This is the metatype short circuit.
+  # @api private
+  #
+  def infer_PType(o)
+    type = Types::PType.new()
+    type.type = o.copy
+    type
+  end
+
+  # @api private
+  def infer_String(o)
+    t = Types::PStringType.new()
+    t.addValues(o)
+    t.size_type = size_as_type(o)
+    t
+  end
+
+  # @api private
+  def infer_Float(o)
+    t = Types::PFloatType.new()
+    t.from = o
+    t.to = o
+    t
+  end
+
+  # @api private
+  def infer_Integer(o)
+    t = Types::PIntegerType.new()
+    t.from = o
+    t.to = o
+    t
+  end
+
+  # @api private
+  def infer_Regexp(o)
+    t = Types::PRegexpType.new()
+    t.pattern = o.source
+    t
+  end
+
+  # @api private
+  def infer_NilClass(o)
+    Types::PUndefType.new()
+  end
+
+  # @api private
+  # @param o [Proc]
+  def infer_Proc(o)
+    min = 0
+    max = 0
+    if o.respond_to?(:parameters)
+      mapped_types = o.parameters.map do |p|
+        param_t = Types::PAnyType.new
+        case p[0]
+        when :rest
+          max = :default
+          break param_t
+        when :req
+          min += 1
+        end
+        max += 1
+      	param_t
+      end
+    else
+      # Cannot correctly compute the signature in Ruby 1.8.7 because arity for
+      # optional values is screwed up (there is no way to get the upper limit),
+      # an optional looks the same as a varargs.
+      arity = o.arity
+      if arity < 0
+        min = -arity - 1
+        max = :default # i.e. infinite (which is wrong when there are optional - flaw in 1.8.7)
+      else
+        min = max = arity
+      end
+      mapped_types = Array.new(min) { Types::PAnyType.new }
+    end
+    if min == 0 || min != max
+      mapped_types << min
+      mapped_types << max
+    end
+    Types::TypeFactory.callable(*mapped_types)
+  end
+
+  # @api private
+  def infer_PuppetProc(o)
+    infer_Closure(o.closure)
+  end
+
+  # Inference of :default as PDefaultType, and all other are Ruby[Symbol]
+  # @api private
+  def infer_Symbol(o)
+    case o
+    when :default
+      Types::PDefaultType.new()
+    else
+      infer_Object(o)
+    end
+  end
+
+  # @api private
+  def infer_TrueClass(o)
+    Types::PBooleanType.new()
+  end
+
+  # @api private
+  def infer_FalseClass(o)
+    Types::PBooleanType.new()
+  end
+
+  # @api private
+  # A Puppet::Parser::Resource, or Puppet::Resource
+  #
+  def infer_Resource(o)
+    t = Types::PResourceType.new()
+    t.type_name = o.type.to_s.downcase
+    # Only Puppet::Resource can have a title that is a symbol :undef, a PResource cannot.
+    # A mapping must be made to empty string. A nil value will result in an error later
+    title = o.title
+    t.title = (:undef == title  ? '' : title)
+    type = Types::PType.new()
+    type.type = t
+    type
+  end
+
+  # @api private
+  def infer_Array(o)
+    type = Types::PArrayType.new()
+    type.element_type =
+    if o.empty?
+      Types::PUndefType.new()
+    else
+      infer_and_reduce_type(o)
+    end
+    type.size_type = size_as_type(o)
+    type
+  end
+
+  # @api private
+  def infer_Hash(o)
+    type = Types::PHashType.new()
+    if o.empty?
+      ktype = Types::PUndefType.new()
+      etype = Types::PUndefType.new()
+    else
+      ktype = infer_and_reduce_type(o.keys())
+      etype = infer_and_reduce_type(o.values())
+    end
+    type.key_type = ktype
+    type.element_type = etype
+    type.size_type = size_as_type(o)
+    type
+  end
+
+  def size_as_type(collection)
+    size = collection.size
+    t = Types::PIntegerType.new()
+    t.from = size
+    t.to = size
+    t
+  end
+
+  # Common case for everything that intrinsically only has a single type
+  def infer_set_Object(o)
+    infer(o)
+  end
+
+  def infer_set_Array(o)
+    if o.empty?
+      type = Types::PArrayType.new()
+      type.element_type = Types::PUndefType.new()
+      type.size_type = size_as_type(o)
+    else
+      type = Types::PTupleType.new()
+      type.types = o.map() {|x| infer_set(x) }
+    end
+    type
+  end
+
+  def infer_set_Hash(o)
+    if o.empty?
+      type = Types::PHashType.new
+      type.key_type = Types::PUndefType.new
+      type.element_type = Types::PUndefType.new
+      type.size_type = size_as_type(o)
+    elsif o.keys.all? {|k| instance_of_PStringType(@non_empty_string_t, k) }
+      type = Types::PStructType.new
+      type.elements = o.map do |k,v|
+        element = Types::PStructElement.new
+        element.key_type = infer_String(k)
+        element.value_type = infer_set(v)
+        element
+      end
+    else
+      type = Types::PHashType.new
+      ktype = Types::PVariantType.new
+      ktype.types = o.keys.map {|k| infer_set(k) }
+      etype = Types::PVariantType.new
+      etype.types = o.values.map {|e| infer_set(e) }
+      type.key_type = unwrap_single_variant(ktype)
+      type.element_type = unwrap_single_variant(etype)
+      type.size_type = size_as_type(o)
+    end
+    type
+  end
+
+  def unwrap_single_variant(possible_variant)
+    if possible_variant.is_a?(Types::PVariantType) && possible_variant.types.size == 1
+      possible_variant.types[0]
+    else
+      possible_variant
+    end
+  end
+
+  # False in general type calculator
+  # @api private
+  def assignable_Object(t, t2)
+    false
+  end
+
+  # @api private
+  def assignable_PAnyType(t, t2)
+    t2.is_a?(Types::PAnyType)
+  end
+
+  # @api private
+  def assignable_PNotUndefType(t, t2)
+    !assignable?(t2, @nil_t) && (t.type.nil? || assignable?(t.type, t2))
+  end
+
+  # @api private
+  def assignable_PUndefType(t, t2)
+    # Only undef/nil is assignable to nil type
+    t2.is_a?(Types::PUndefType)
+  end
+
+  # Anything is assignable to a Unit type
+  # @api private
+  def assignable_PUnitType(t, t2)
+    true
+  end
+
+  # @api private
+  def assignable_PDefaultType(t, t2)
+    # Only default is assignable to default type
+    t2.is_a?(Types::PDefaultType)
+  end
+
+  # @api private
+  def assignable_PScalarType(t, t2)
+    t2.is_a?(Types::PScalarType)
+  end
+
+  # @api private
+  def assignable_PNumericType(t, t2)
+    t2.is_a?(Types::PNumericType)
+  end
+
+  # @api private
+  def assignable_PIntegerType(t, t2)
+    return false unless t2.is_a?(Types::PIntegerType)
+    trange =  from_to_ordered(t.from, t.to)
+    t2range = from_to_ordered(t2.from, t2.to)
+    # If t2 min and max are within the range of t
+    trange[0] <= t2range[0] && trange[1] >= t2range[1]
+  end
+
+  # Transform int range to a size constraint
+  # if range == nil the constraint is 1,1
+  # if range.from == nil min size = 1
+  # if range.to == nil max size == Infinity
+  #
+  def size_range(range)
+    return [1,1] if range.nil?
+    from = range.from
+    to = range.to
+    x = from.nil? ? 1 : from
+    y = to.nil? ? TheInfinity : to
+    [x, y]
+  end
+
+  # @api private
+  def from_to_ordered(from, to)
+    x = (from.nil? || from == :default) ? -TheInfinity : from
+    y = (to.nil? || to == :default) ? TheInfinity : to
+    if x < y
+      [x, y]
+    else
+      [y, x]
+    end
+  end
+
+  # @api private
+  def assignable_PVariantType(t, t2)
+    # Data is a specific variant
+    t2 = @data_variant_t if t2.is_a?(Types::PDataType)
+    if t2.is_a?(Types::PVariantType)
+      # A variant is assignable if all of its options are assignable to one of this type's options
+      return true if t == t2
+      t2.types.all? do |other|
+        # if the other is a Variant, all of its options, but be assignable to one of this type's options
+        other = other.is_a?(Types::PDataType) ? @data_variant_t : other
+        if other.is_a?(Types::PVariantType)
+          assignable?(t, other)
+        else
+          t.types.any? {|option_t| assignable?(option_t, other) }
+        end
+      end
+    else
+      # A variant is assignable if t2 is assignable to any of its types
+      t.types.any? { |option_t| assignable?(option_t, t2) }
+    end
+  end
+
+  # Catch all not callable combinations
+  def callable_Object(o, callable_t)
+    false
+  end
+
+  def callable_PTupleType(args_tuple, callable_t)
+    if args_tuple.size_type
+      raise ArgumentError, "Callable tuple may not have a size constraint when used as args"
+    end
+    # Assume no block was given - i.e. it is nil, and its type is PUndefType
+    block_t = @nil_t
+    if self.class.is_kind_of_callable?(args_tuple.types.last)
+      # a split is needed to make it possible to use required, optional, and varargs semantics
+      # of the tuple type.
+      #
+      args_tuple = args_tuple.copy
+      # to drop the callable, it must be removed explicitly since this is an rgen array
+      args_tuple.removeTypes(block_t = args_tuple.types.last())
+    else
+      # no block was given, if it is required, the below will fail
+    end
+    # unless argument types match parameter types
+    return false unless assignable?(callable_t.param_types, args_tuple)
+    # can the given block be *called* with a signature requirement specified by callable_t?
+    assignable?(callable_t.block_type || @nil_t, block_t)
+  end
+
+  # @api private
+  def self.is_kind_of_callable?(t, optional = true)
+    case t
+    when Types::PCallableType
+      true
+    when Types::POptionalType
+      optional && is_kind_of_callable?(t.optional_type, optional)
+    when Types::PVariantType
+      t.types.all? {|t2| is_kind_of_callable?(t2, optional) }
+    else
+      false
+    end
+  end
+
+  # @api private
+  def self.is_kind_of_optional?(t, optional = true)
+    case t
+    when Types::POptionalType
+      true
+    when Types::PVariantType
+      t.types.all? {|t2| is_kind_of_optional?(t2, optional) }
+    else
+      false
+    end
+  end
+
+  def callable_PArrayType(args_array, callable_t)
+    return false unless assignable?(callable_t.param_types, args_array)
+    # does not support calling with a block, but have to check that callable is ok with missing block
+    assignable?(callable_t.block_type || @nil_t, @nil_t)
+  end
+
+  def callable_PUndefType(nil_t, callable_t)
+    # if callable_t is Optional (or indeed PUndefType), this means that 'missing callable' is accepted
+    assignable?(callable_t, nil_t)
+  end
+
+  def callable_PCallableType(given_callable_t, required_callable_t)
+    # If the required callable is euqal or more specific than the given, the given is callable
+    assignable?(required_callable_t, given_callable_t)
+  end
+
+  def max(a,b)
+    a >=b ? a : b
+  end
+
+  def min(a,b)
+    a <= b ? a : b
+  end
+
+  def assignable_PTupleType(t, t2)
+    return true if t == t2 || t.types.empty? && (t2.is_a?(Types::PArrayType))
+    size_t = t.size_type || Puppet::Pops::Types::TypeFactory.range(*t.size_range)
+
+    if t2.is_a?(Types::PTupleType)
+      size_t2 = t2.size_type || Puppet::Pops::Types::TypeFactory.range(*t2.size_range)
+
+      # not assignable if the number of types in t2 is outside number of types in t1
+      if assignable?(size_t, size_t2)
+        t2.types.size.times do |index|
+          return false unless assignable?((t.types[index] || t.types[-1]), t2.types[index])
+        end
+        return true
+      else
+        return false
+      end
+    elsif t2.is_a?(Types::PArrayType)
+      t2_entry = t2.element_type
+
+      # Array of anything can not be assigned (unless tuple is tuple of anything) - this case
+      # was handled at the top of this method.
+      #
+      return false if t2_entry.nil?
+      size_t = t.size_type || Puppet::Pops::Types::TypeFactory.range(*t.size_range)
+      size_t2 = t2.size_type || @collection_default_size_t
+      return false unless assignable?(size_t, size_t2)
+      min(t.types.size, size_t2.range()[1]).times do |index|
+        return false unless assignable?((t.types[index] || t.types[-1]), t2_entry)
+      end
+      true
+    else
+      false
+    end
+  end
+
+  # Produces the tuple entry at the given index given a tuple type, its from/to constraints on the last
+  # type, and an index.
+  # Produces nil if the index is out of bounds
+  # from must be less than to, and from may not be less than 0
+  #
+  # @api private
+  #
+  def tuple_entry_at(tuple_t, from, to, index)
+    regular = (tuple_t.types.size - 1)
+    if index < regular
+      tuple_t.types[index]
+    elsif index < regular + to
+      # in the varargs part
+      tuple_t.types[-1]
+    else
+      nil
+    end
+  end
+
+  # @api private
+  #
+  def assignable_PStructType(t, t2)
+    if t2.is_a?(Types::PStructType)
+      h2 = t2.hashed_elements
+      matched = 0
+      t.elements.all? do |e1|
+        e2 = h2[e1.name]
+        if e2.nil?
+          assignable?(e1.key_type, @nil_t)
+        else
+          matched += 1
+          assignable?(e1.key_type, e2.key_type) && assignable?(e1.value_type, e2.value_type)
+        end
+      end && matched == h2.size
+    elsif t2.is_a?(Types::PHashType)
+      required = 0
+      required_elements_assignable = t.elements.all? do |e|
+        if assignable?(e.key_type, @nil_t)
+          true
+        else
+          required += 1
+          assignable?(e.value_type, t2.element_type)
+        end
+      end
+      if required_elements_assignable
+        size_t2 = t2.size_type || @collection_default_size_t
+        size_t = Types::PIntegerType.new
+        size_t.from = required
+        size_t.to = t.elements.size
+        assignable_PIntegerType(size_t, size_t2)
+      end
+    else
+      false
+    end
+  end
+
+  # @api private
+  def assignable_POptionalType(t, t2)
+    return true if t2.is_a?(Types::PUndefType)
+    return true if t.optional_type.nil?
+    if t2.is_a?(Types::POptionalType)
+      assignable?(t.optional_type, t2.optional_type || @t)
+    else
+      assignable?(t.optional_type, t2)
+    end
+  end
+
+  # @api private
+  def assignable_PEnumType(t, t2)
+    return true if t == t2
+    if t.values.empty?
+      return true if t2.is_a?(Types::PStringType) || t2.is_a?(Types::PEnumType) || t2.is_a?(Types::PPatternType)
+    end
+    case t2
+    when Types::PStringType
+      # if the set of strings are all found in the set of enums
+      !t2.values.empty?() && t2.values.all? { |s| t.values.any? { |e| e == s }}
+    when Types::PVariantType
+      t2.types.all? {|variant_t| assignable_PEnumType(t, variant_t) }
+    when Types::PEnumType
+      # empty means any enum
+      return true if t.values.empty?
+      !t2.values.empty? && t2.values.all? { |s| t.values.any? {|e| e == s }}
+    else
+      false
+    end
+  end
+
+  # @api private
+  def assignable_PStringType(t, t2)
+    if t.values.empty?
+      # A general string is assignable by any other string or pattern restricted string
+      # if the string has a size constraint it does not match since there is no reasonable way
+      # to compute the min/max length a pattern will match. For enum, it is possible to test that
+      # each enumerator value is within range
+      size_t = t.size_type || @collection_default_size_t
+      case t2
+      when Types::PStringType
+        # true if size compliant
+        size_t2 = t2.size_type || @collection_default_size_t
+        assignable_PIntegerType(size_t, size_t2)
+
+      when Types::PPatternType
+        # true if size constraint is at least 0 to +Infinity (which is the same as the default)
+        assignable_PIntegerType(size_t, @collection_default_size_t)
+
+      when Types::PEnumType
+        if t2.values && !t2.values.empty?
+          # true if all enum values are within range
+          min, max = t2.values.map(&:size).minmax
+          trange =  from_to_ordered(size_t.from, size_t.to)
+          t2range = [min, max]
+          # If t2 min and max are within the range of t
+          trange[0] <= t2range[0] && trange[1] >= t2range[1]
+        else
+          # enum represents all enums, and thus all strings, a sized constrained string can thus not
+          # be assigned any enum (unless it is max size).
+          assignable_PIntegerType(size_t, @collection_default_size_t)
+        end
+      else
+        # no other type matches string
+        false
+      end
+    elsif t2.is_a?(Types::PStringType)
+      # A specific string acts as a set of strings - must have exactly the same strings
+      # In this case, size does not matter since the definition is very precise anyway
+      Set.new(t.values) == Set.new(t2.values)
+    else
+      # All others are false, since no other type describes the same set of specific strings
+      false
+    end
+  end
+
+  # @api private
+  def assignable_PPatternType(t, t2)
+    return true if t == t2
+    case t2
+    when Types::PStringType, Types::PEnumType
+      values = t2.values
+    when Types::PVariantType
+      return t2.types.all? {|variant_t| assignable_PPatternType(t, variant_t) }
+    when Types::PPatternType
+      return t.patterns.empty? ? true : false
+    else
+      return false
+    end
+
+    if t2.values.empty?
+      # Strings / Enums (unknown which ones) cannot all match a pattern, but if there is no pattern it is ok
+      # (There should really always be a pattern, but better safe than sorry).
+      return t.patterns.empty? ? true : false
+    end
+    # all strings in String/Enum type must match one of the patterns in Pattern type,
+    # or Pattern represents all Patterns == all Strings
+    regexps = t.patterns.map {|p| p.regexp }
+    regexps.empty? || t2.values.all? { |v| regexps.any? {|re| re.match(v) } }
+  end
+
+  # @api private
+  def assignable_PFloatType(t, t2)
+    return false unless t2.is_a?(Types::PFloatType)
+    trange =  from_to_ordered(t.from, t.to)
+    t2range = from_to_ordered(t2.from, t2.to)
+    # If t2 min and max are within the range of t
+    trange[0] <= t2range[0] && trange[1] >= t2range[1]
+  end
+
+  # @api private
+  def assignable_PBooleanType(t, t2)
+    t2.is_a?(Types::PBooleanType)
+  end
+
+  # @api private
+  def assignable_PRegexpType(t, t2)
+    t2.is_a?(Types::PRegexpType) && (t.pattern.nil? || t.pattern == t2.pattern)
+  end
+
+  # @api private
+  def assignable_PCallableType(t, t2)
+    return false unless t2.is_a?(Types::PCallableType)
+    # nil param_types means, any other Callable is assignable
+    return true if t.param_types.nil?
+
+    # NOTE: these tests are made in reverse as it is calling the callable that is constrained
+    # (it's lower bound), not its upper bound
+    return false unless assignable?(t2.param_types, t.param_types)
+    # names are ignored, they are just information
+    # Blocks must be compatible
+    this_block_t = t.block_type || @nil_t
+    that_block_t = t2.block_type || @nil_t
+    assignable?(that_block_t, this_block_t)
+
+  end
+
+  # @api private
+  def assignable_PCollectionType(t, t2)
+    size_t = t.size_type || @collection_default_size_t
+    case t2
+    when Types::PCollectionType
+      size_t2 = t2.size_type || @collection_default_size_t
+      assignable_PIntegerType(size_t, size_t2)
+    when Types::PTupleType
+      # compute the tuple's min/max size, and check if that size matches
+      from, to = size_range(t2.size_type)
+      t2s = Types::PIntegerType.new()
+      t2s.from = t2.types.size - 1 + from
+      t2s.to = t2.types.size - 1 + to
+      assignable_PIntegerType(size_t, t2s)
+    when Types::PStructType
+      from = to = t2.elements.size
+      t2s = Types::PIntegerType.new()
+      t2s.from = from
+      t2s.to = to
+      assignable_PIntegerType(size_t, t2s)
+    else
+      false
+    end
+  end
+
+  # @api private
+  def assignable_PType(t, t2)
+    return false unless t2.is_a?(Types::PType)
+    return true if t.type.nil? # wide enough to handle all types
+    return false if t2.type.nil? # wider than t
+    assignable?(t.type, t2.type)
+  end
+
+  # Array is assignable if t2 is an Array and t2's element type is assignable, or if t2 is a Tuple
+  # where 
+  # @api private
+  def assignable_PArrayType(t, t2)
+    if t2.is_a?(Types::PArrayType)
+      return false unless t.element_type.nil? || assignable?(t.element_type, t2.element_type || @t)
+      assignable_PCollectionType(t, t2)
+
+    elsif t2.is_a?(Types::PTupleType)
+      return false unless t.element_type.nil? || t2.types.all? {|t2_element| assignable?(t.element_type, t2_element) }
+      t2_regular = t2.types[0..-2]
+      t2_ranged = t2.types[-1]
+      t2_from, t2_to = size_range(t2.size_type)
+      t2_required = t2_regular.size + t2_from
+
+      t_entry = t.element_type
+
+      # Tuple of anything can not be assigned (unless array is tuple of anything) - this case
+      # was handled at the top of this method.
+      #
+      return false if t_entry.nil?
+
+      # array type may be size constrained
+      size_t = t.size_type || @collection_default_size_t
+      min, max = size_t.range
+      # Tuple with fewer min entries can not be assigned
+      return false if t2_required < min
+      # Tuple with more optionally available entries can not be assigned
+      return false if t2_regular.size + t2_to > max
+      # each tuple type must be assignable to the element type
+      t2_required.times do |index|
+        t2_entry = tuple_entry_at(t2, t2_from, t2_to, index)
+        return false unless assignable?(t_entry, t2_entry)
+      end
+      # ... and so must the last, possibly optional (ranged) type
+      return assignable?(t_entry, t2_ranged)
+    else
+      false
+    end
+  end
+
+  # Hash is assignable if t2 is a Hash and t2's key and element types are assignable
+  # @api private
+  def assignable_PHashType(t, t2)
+    case t2
+    when Types::PHashType
+      return true if (t.size_type.nil? || t.size_type.from == 0) && t2.is_the_empty_hash?
+      return false unless t.key_type.nil? || assignable?(t.key_type, t2.key_type || @t)
+      return false unless t.element_type.nil? || assignable?(t.element_type, t2.element_type || @t)
+      assignable_PCollectionType(t, t2)
+    when Types::PStructType
+      # hash must accept String as key type
+      # hash must accept all value types
+      # hash must accept the size of the struct
+      size_t = t.size_type || @collection_default_size_t
+      min, max = size_t.range
+      struct_size = t2.elements.size
+      key_type = t.key_type
+      element_type = t.element_type
+      ( struct_size >= min && struct_size <= max &&
+        t2.elements.all? {|e| (key_type.nil? || instance_of(key_type, e.name)) && (element_type.nil? || assignable?(element_type, e.value_type)) })
+    else
+      false
+    end
+  end
+
+  # @api private
+  def assignable_PCatalogEntryType(t1, t2)
+    t2.is_a?(Types::PCatalogEntryType)
+  end
+
+  # @api private
+  def assignable_PHostClassType(t1, t2)
+    return false unless t2.is_a?(Types::PHostClassType)
+    # Class = Class[name}, Class[name] != Class
+    return true if t1.class_name.nil?
+    # Class[name] = Class[name]
+    return t1.class_name == t2.class_name
+  end
+
+  # @api private
+  def assignable_PResourceType(t1, t2)
+    return false unless t2.is_a?(Types::PResourceType)
+    return true if t1.type_name.nil?
+    return false if t1.type_name != t2.type_name
+    return true if t1.title.nil?
+    return t1.title == t2.title
+  end
+
+  # Data is assignable by other Data and by Array[Data] and Hash[Scalar, Data]
+  # @api private
+  def assignable_PDataType(t, t2)
+    # We cannot put the NotUndefType[Data] in the @data_variant_t since that causes an endless recursion
+    case t2
+    when Types::PDataType
+      true
+    when Types::PNotUndefType
+      assignable?(t, t2.type || @t)
+    else
+      assignable?(@data_variant_t, t2)
+    end
+  end
+
+  # Assignable if t2's has the same runtime and the runtime name resolves to
+  # a class that is the same or subclass of t1's resolved runtime type name
+  # @api private
+  def assignable_PRuntimeType(t1, t2)
+    return false unless t2.is_a?(Types::PRuntimeType)
+    return false unless t1.runtime == t2.runtime
+    return true if t1.runtime_type_name.nil?   # t1 is wider
+    return false if t2.runtime_type_name.nil?  # t1 not nil, so t2 can not be wider
+
+    # NOTE: This only supports Ruby, must change when/if the set of runtimes is expanded
+    c1 = class_from_string(t1.runtime_type_name)
+    c2 = class_from_string(t2.runtime_type_name)
+    return false unless c1.is_a?(Class) && c2.is_a?(Class)
+    !!(c2 <= c1)
+  end
+
+  # @api private
+  def debug_string_Object(t)
+    string(t)
+  end
+
+  # @api private
+  def string_PType(t)
+    if t.type.nil?
+      "Type"
+    else
+      "Type[#{string(t.type)}]"
+    end
+  end
+
+  # @api private
+  def string_NilClass(t)     ; '?'       ; end
+
+  # @api private
+  def string_String(t)       ; t         ; end
+
+  # @api private
+  def string_Symbol(t)       ; t.to_s    ; end
+
+  def string_PAnyType(t)     ; "Any"     ; end
+
+  # @api private
+  def string_PUndefType(t)     ; 'Undef'   ; end
+
+  # @api private
+  def string_PDefaultType(t) ; 'Default' ; end
+
+  # @api private
+  def string_PBooleanType(t) ; "Boolean" ; end
+
+  # @api private
+  def string_PScalarType(t)  ; "Scalar"  ; end
+
+  # @api private
+  def string_PDataType(t)    ; "Data"    ; end
+
+  # @api private
+  def string_PNumericType(t) ; "Numeric" ; end
+
+  # @api private
+  def string_PIntegerType(t)
+    range = range_array_part(t)
+    unless range.empty?
+      "Integer[#{range.join(', ')}]"
+    else
+      "Integer"
+    end
+  end
+
+  # Produces a string from an Integer range type that is used inside other type strings
+  # @api private
+  def range_array_part(t)
+    return [] if t.nil? || (t.from.nil? && t.to.nil?)
+    [t.from.nil? ? 'default' : t.from , t.to.nil? ? 'default' : t.to ]
+  end
+
+  # @api private
+  def string_PFloatType(t)
+    range = range_array_part(t)
+    unless range.empty?
+      "Float[#{range.join(', ')}]"
+    else
+      "Float"
+    end
+  end
+
+  # @api private
+  def string_PRegexpType(t)
+    t.pattern.nil? ? "Regexp" : "Regexp[#{t.regexp.inspect}]"
+  end
+
+  # @api private
+  def string_PStringType(t)
+    # skip values in regular output - see debug_string
+    range = range_array_part(t.size_type)
+    unless range.empty?
+      "String[#{range.join(', ')}]"
+    else
+      "String"
+    end
+  end
+
+  # @api private
+  def debug_string_PStringType(t)
+    range = range_array_part(t.size_type)
+    range_part = range.empty? ? '' : '[' << range.join(' ,') << '], '
+    "String[" << range_part << (t.values.map {|s| "'#{s}'" }).join(', ') << ']'
+  end
+
+  # @api private
+  def string_PEnumType(t)
+    return "Enum" if t.values.empty?
+    "Enum[" << t.values.map {|s| "'#{s}'" }.join(', ') << ']'
+  end
+
+  # @api private
+  def string_PVariantType(t)
+    return "Variant" if t.types.empty?
+    "Variant[" << t.types.map {|t2| string(t2) }.join(', ') << ']'
+  end
+
+  # @api private
+  def string_PTupleType(t)
+    range = range_array_part(t.size_type)
+    return "Tuple" if t.types.empty?
+    s = "Tuple[" << t.types.map {|t2| string(t2) }.join(', ')
+    unless range.empty?
+      s << ", " << range.join(', ')
+    end
+    s << "]"
+    s
+  end
+
+  # @api private
+  def string_PCallableType(t)
+    # generic
+    return "Callable" if t.param_types.nil?
+
+    if t.param_types.types.empty?
+      range = [0, 0]
+    else
+      range = range_array_part(t.param_types.size_type)
+    end
+    # translate to string, and skip Unit types
+    types = t.param_types.types.map {|t2| string(t2) unless t2.class == Types::PUnitType }.compact
+
+    s = "Callable[" << types.join(', ')
+    unless range.empty?
+      (s << ', ') unless types.empty?
+      s << range.join(', ')
+    end
+    # Add block T last (after min, max) if present)
+    #
+    unless t.block_type.nil?
+      (s << ', ') unless types.empty? && range.empty?
+      s << string(t.block_type)
+    end
+    s << "]"
+    s
+  end
+
+  # @api private
+  def string_PStructType(t)
+    return "Struct" if t.elements.empty?
+    "Struct[{" << t.elements.map {|element| string(element) }.join(', ') << "}]"
+  end
+
+  def string_PStructElement(t)
+    k = t.key_type
+    value_optional = assignable?(t.value_type, @nil_t)
+    key_string =
+      if k.is_a?(Types::POptionalType)
+        # Output as literal String
+        value_optional ? "'#{t.name}'" : string(k)
+      else
+        value_optional ? "NotUndef['#{t.name}']" : "'#{t.name}'"
+      end
+    "#{key_string}=>#{string(t.value_type)}"
+  end
+
+  # @api private
+  def string_PPatternType(t)
+    return "Pattern" if t.patterns.empty?
+    "Pattern[" << t.patterns.map {|s| "#{s.regexp.inspect}" }.join(', ') << ']'
+  end
+
+  # @api private
+  def string_PCollectionType(t)
+    range = range_array_part(t.size_type)
+    unless range.empty?
+      "Collection[#{range.join(', ')}]"
+    else
+      "Collection"
+    end
+  end
+
+  # @api private
+  def string_PUnitType(t)
+    "Unit"
+  end
+
+  # @api private
+  def string_PRuntimeType(t)   ; "Runtime[#{string(t.runtime)}, #{string(t.runtime_type_name)}]"  ; end
+
+  # @api private
+  def string_PArrayType(t)
+    parts = [string(t.element_type)] + range_array_part(t.size_type)
+    "Array[#{parts.join(', ')}]"
+  end
+
+  # @api private
+  def string_PHashType(t)
+    parts = [string(t.key_type), string(t.element_type)] + range_array_part(t.size_type)
+    "Hash[#{parts.join(', ')}]"
+  end
+
+  # @api private
+  def string_PCatalogEntryType(t)
+    "CatalogEntry"
+  end
+
+  # @api private
+  def string_PHostClassType(t)
+    if t.class_name
+      "Class[#{t.class_name}]"
+    else
+      "Class"
+    end
+  end
+
+  # @api private
+  def string_PResourceType(t)
+    if t.type_name
+      if t.title
+        "#{capitalize_segments(t.type_name)}['#{t.title}']"
+      else
+        capitalize_segments(t.type_name)
+      end
+    else
+      "Resource"
+    end
+  end
+
+  # @api private
+  def string_PNotUndefType(t)
+    contained_type = t.type
+    if contained_type.nil? || contained_type.class == Puppet::Pops::Types::PAnyType
+      'NotUndef'
+    else
+      if contained_type.is_a?(Puppet::Pops::Types::PStringType) && contained_type.values.size == 1
+        "NotUndef['#{contained_type.values[0]}']"
+      else
+        "NotUndef[#{string(contained_type)}]"
+      end
+    end
+  end
+
+  def string_POptionalType(t)
+    optional_type = t.optional_type
+    if optional_type.nil?
+      "Optional"
+    else
+      if optional_type.is_a?(Puppet::Pops::Types::PStringType) && optional_type.values.size == 1
+        "Optional['#{optional_type.values[0]}']"
+      else
+        "Optional[#{string(optional_type)}]"
+      end
+    end
+  end
+
+  # Catches all non enumerable types
+  # @api private
+  def enumerable_Object(o)
+    nil
+  end
+
+  # @api private
+  def enumerable_PIntegerType(t)
+    # Not enumerable if representing an infinite range
+    return nil if t.size == TheInfinity
+    t
+  end
+
+  def self.copy_as_tuple(t)
+    case t
+    when Types::PTupleType
+      t.copy
+    when Types::PArrayType
+      # transform array to tuple
+      result = Types::PTupleType.new
+      result.addTypes(t.element_type.copy)
+      result.size_type = t.size_type.nil? ? nil : t.size_type.copy
+      result
+    else
+      raise ArgumentError, "Internal Error: Only Array and Tuple can be given to copy_as_tuple"
+    end
+  end
+
+  private
+
+  NAME_SEGMENT_SEPARATOR = '::'.freeze
+
+  def capitalize_segments(s)
+    s.split(NAME_SEGMENT_SEPARATOR).map(&:capitalize).join(NAME_SEGMENT_SEPARATOR)
+  end
+
+  def class_from_string(str)
+    begin
+      str.split(NAME_SEGMENT_SEPARATOR).inject(Object) do |memo, name_segment|
+        memo.const_get(name_segment)
+      end
+    rescue NameError
+      return nil
+    end
+  end
+
+  def common_data?(t1, t2)
+    assignable?(@data_t, t1) && assignable?(@data_t, t2)
+  end
+
+  def common_scalar?(t1, t2)
+    assignable?(@scalar_t, t1) && assignable?(@scalar_t, t2)
+  end
+
+  def common_numeric?(t1, t2)
+    assignable?(@numeric_t, t1) && assignable?(@numeric_t, t2)
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/types/type_factory.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/types/type_factory.rb
new file mode 100644
index 0000000..13ade30
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/types/type_factory.rb
@@ -0,0 +1,491 @@
+# Helper module that makes creation of type objects simpler.
+# @api public
+#
+module Puppet::Pops::Types::TypeFactory
+  Types = Puppet::Pops::Types
+  @type_calculator = Types::TypeCalculator.singleton
+  @undef_t = Types::PUndefType.new
+
+  # Produces the Integer type
+  # @api public
+  #
+  def self.integer()
+    Types::PIntegerType.new()
+  end
+
+  # Produces an Integer range type
+  # @api public
+  #
+  def self.range(from, to)
+    # NOTE! Do not merge the following line to 4.x. It has the same check in the initialize method
+    raise ArgumentError, "'from' must be less or equal to 'to'. Got (#{from}, #{to}" if from.is_a?(Numeric) && to.is_a?(Numeric) && from > to
+
+    t = Types::PIntegerType.new()
+    # optimize eq with symbol (faster when it is left)
+    t.from = from unless (:default == from || from == 'default')
+    t.to = to unless (:default == to || to == 'default')
+    t
+  end
+
+  # Produces a Float range type
+  # @api public
+  #
+  def self.float_range(from, to)
+    # NOTE! Do not merge the following line to 4.x. It has the same check in the initialize method
+    raise ArgumentError, "'from' must be less or equal to 'to'. Got (#{from}, #{to}" if from.is_a?(Numeric) && to.is_a?(Numeric) && from > to
+
+    t = Types::PFloatType.new()
+    # optimize eq with symbol (faster when it is left)
+    t.from = Float(from) unless :default == from || from.nil?
+    t.to = Float(to) unless :default == to || to.nil?
+    t
+  end
+
+  # Produces the Float type
+  # @api public
+  #
+  def self.float()
+    Types::PFloatType.new()
+  end
+
+  # Produces the Numeric type
+  # @api public
+  #
+  def self.numeric()
+    Types::PNumericType.new()
+  end
+
+  # Produces a string representation of the type
+  # @api public
+  #
+  def self.label(t)
+    @type_calculator.string(t)
+  end
+
+  # Produces the String type, optionally with specific string values
+  # @api public
+  #
+  def self.string(*values)
+    t = Types::PStringType.new()
+    values.each {|v| t.addValues(v) }
+    t
+  end
+
+  # Produces the Optional type, i.e. a short hand for Variant[T, Undef]
+  # If the given 'optional_type' argument is a String, then it will be
+  # converted into a String type that represents that string.
+  #
+  # @param optional_type [String,PAnyType,nil] the optional type
+  # @return [POptionalType] the created type
+  #
+  # @api public
+  #
+  def self.optional(optional_type = nil)
+    t = Types::POptionalType.new
+    t.optional_type = optional_type.is_a?(String) ? string(optional_type) : type_of(optional_type)
+    t
+  end
+
+  # Produces the Enum type, optionally with specific string values
+  # @api public
+  #
+  def self.enum(*values)
+    t = Types::PEnumType.new()
+    values.each {|v| t.addValues(v) }
+    t
+  end
+
+  # Produces the Variant type, optionally with the "one of" types
+  # @api public
+  #
+  def self.variant(*types)
+    t = Types::PVariantType.new()
+    types.each {|v| t.addTypes(type_of(v)) }
+    t
+  end
+
+  # Produces the Struct type, either a non parameterized instance representing
+  # all structs (i.e. all hashes) or a hash with entries where the key is
+  # either a literal String, an Enum with one entry, or a String representing exactly one value.
+  # The key type may also be wrapped in a NotUndef or an Optional.
+  #
+  # The value can be a ruby class, a String (interpreted as the name of a ruby class) or
+  # a Type.
+  #
+  # @param hash [Hash<Object, Object>] key => value hash
+  # @return [PStructType] the created Struct type
+  #
+  def self.struct(hash = {})
+    tc = @type_calculator
+    t = Types::PStructType.new
+    t.elements = hash.map do |key_type, value_type|
+      value_type = type_of(value_type)
+      raise ArgumentError, 'Struct element value_type must be a Type' unless value_type.is_a?(Types::PAnyType)
+
+      # TODO: Should have stricter name rule
+      if key_type.is_a?(String)
+        raise ArgumentError, 'Struct element key cannot be an empty String' if key_type.empty?
+        key_type = string(key_type)
+        # Must make key optional if the value can be Undef
+        key_type = optional(key_type) if tc.assignable?(value_type, @undef_t)
+      else
+        # assert that the key type is one of String[1], NotUndef[String[1]] and Optional[String[1]]
+        case key_type
+        when Types::PNotUndefType
+          # We can loose the NotUndef wrapper here since String[1] isn't optional anyway
+          key_type = key_type.type
+          s = key_type
+        when Types::POptionalType
+          s = key_type.optional_type
+        else
+          s = key_type
+        end
+        unless (s.is_a?(Puppet::Pops::Types::PStringType) || s.is_a?(Puppet::Pops::Types::PEnumType)) && s.values.size == 1 && !s.values[0].empty?
+          raise ArgumentError, 'Unable to extract a non-empty literal string from Struct member key type' if key_type.empty?
+        end
+      end
+      elem = Types::PStructElement.new
+      elem.key_type = key_type
+      elem.value_type = value_type
+      elem
+    end
+    t
+  end
+
+  def self.tuple(*types)
+    t = Types::PTupleType.new
+    types.each {|elem| t.addTypes(type_of(elem)) }
+    t
+  end
+
+  # Produces the Boolean type
+  # @api public
+  #
+  def self.boolean()
+    Types::PBooleanType.new()
+  end
+
+  # Produces the Any type
+  # @api public
+  #
+  def self.any()
+    Types::PAnyType.new()
+  end
+
+  # Produces the Regexp type
+  # @param pattern [Regexp, String, nil] (nil) The regular expression object or
+  #   a regexp source string, or nil for bare type
+  # @api public
+  #
+  def self.regexp(pattern = nil)
+    t = Types::PRegexpType.new()
+    if pattern
+      t.pattern = pattern.is_a?(Regexp) ? pattern.inspect[1..-2] : pattern
+    end
+    t.regexp() unless pattern.nil? # compile pattern to catch errors
+    t
+  end
+
+  def self.pattern(*regular_expressions)
+    t = Types::PPatternType.new()
+    regular_expressions.each do |re|
+      case re
+      when String
+        re_T = Types::PRegexpType.new()
+        re_T.pattern = re
+        re_T.regexp()  # compile it to catch errors
+        t.addPatterns(re_T)
+
+      when Regexp
+        re_T = Types::PRegexpType.new()
+        # Regep.to_s includes options user did not enter and does not escape source
+        # to work either as a string or as a // regexp. The inspect method does a better
+        # job, but includes the //
+        re_T.pattern = re.inspect[1..-2]
+        t.addPatterns(re_T)
+
+      when Types::PRegexpType
+        t.addPatterns(re.copy)
+
+      when Types::PPatternType
+        re.patterns.each do |p|
+          t.addPatterns(p.copy)
+        end
+
+     else
+       raise ArgumentError, "Only String, Regexp, Pattern-Type, and Regexp-Type are allowed: got '#{re.class}"
+      end
+    end
+    t
+  end
+
+  # Produces the Literal type
+  # @api public
+  #
+  def self.scalar()
+    Types::PScalarType.new()
+  end
+
+  # Produces a CallableType matching all callables
+  # @api public
+  #
+  def self.all_callables()
+    return Puppet::Pops::Types::PCallableType.new
+  end
+
+  # Produces a Callable type with one signature without support for a block
+  # Use #with_block, or #with_optional_block to add a block to the callable
+  # If no parameters are given, the Callable will describe a signature
+  # that does not accept parameters. To create a Callable that matches all callables
+  # use {#all_callables}.
+  #
+  # The params is a list of types, where the three last entries may be
+  # optionally followed by min, max count, and a Callable which is taken as the
+  # block_type.
+  # If neither min or max are specified the parameters must match exactly.
+  # A min < params.size means that the difference are optional.
+  # If max > params.size means that the last type repeats.
+  # if max is :default, the max value is unbound (infinity).
+  #
+  # Params are given as a sequence of arguments to {#type_of}.
+  #
+  def self.callable(*params)
+    if Puppet::Pops::Types::TypeCalculator.is_kind_of_callable?(params.last)
+      last_callable = true
+    end
+    block_t = last_callable ? params.pop : nil
+
+    # compute a size_type for the signature based on the two last parameters
+    if is_range_parameter?(params[-2]) && is_range_parameter?(params[-1])
+      size_type = range(params[-2], params[-1])
+      params = params[0, params.size - 2]
+    elsif is_range_parameter?(params[-1])
+      size_type = range(params[-1], :default)
+      params = params[0, params.size - 1]
+    end
+
+    types = params.map {|p| type_of(p) }
+
+    # If the specification requires types, and none were given, a Unit type is used
+    if types.empty? && !size_type.nil? && size_type.range[1] > 0
+      types << Types::PUnitType.new
+    end
+    # create a signature
+    callable_t = Types::PCallableType.new()
+    tuple_t = tuple(*types)
+    tuple_t.size_type = size_type unless size_type.nil?
+    callable_t.param_types = tuple_t
+
+    callable_t.block_type = block_t
+    callable_t
+  end
+
+  def self.with_block(callable, *block_params)
+    callable.block_type = callable(*block_params)
+    callable
+  end
+
+  def self.with_optional_block(callable, *block_params)
+    callable.block_type = optional(callable(*block_params))
+    callable
+  end
+
+  # Produces the abstract type Collection
+  # @api public
+  #
+  def self.collection()
+    Types::PCollectionType.new()
+  end
+
+  # Produces the Data type
+  # @api public
+  #
+  def self.data()
+    Types::PDataType.new()
+  end
+
+  # Creates an instance of the Undef type
+  # @api public
+  def self.undef()
+    Types::PUndefType.new()
+  end
+
+  # Creates an instance of the Default type
+  # @api public
+  def self.default()
+    Types::PDefaultType.new()
+  end
+
+  # Produces an instance of the abstract type PCatalogEntryType
+  def self.catalog_entry()
+    Types::PCatalogEntryType.new()
+  end
+
+  # Produces a PResourceType with a String type_name A PResourceType with a nil
+  # or empty name is compatible with any other PResourceType.  A PResourceType
+  # with a given name is only compatible with a PResourceType with the same
+  # name.  (There is no resource-type subtyping in Puppet (yet)).
+  #
+  def self.resource(type_name = nil, title = nil)
+    type = Types::PResourceType.new()
+    type_name = type_name.type_name if type_name.is_a?(Types::PResourceType)
+    type_name = type_name.downcase unless type_name.nil?
+    type.type_name = type_name
+    unless type_name.nil? || type_name =~ Puppet::Pops::Patterns::CLASSREF
+      raise ArgumentError, "Illegal type name '#{type.type_name}'"
+    end
+    if type_name.nil? && !title.nil?
+      raise ArgumentError, "The type name cannot be nil, if title is given"
+    end
+    type.title = title
+    type
+  end
+
+  # Produces PHostClassType with a string class_name.  A PHostClassType with
+  # nil or empty name is compatible with any other PHostClassType.  A
+  # PHostClassType with a given name is only compatible with a PHostClassType
+  # with the same name.
+  #
+  def self.host_class(class_name = nil)
+    type = Types::PHostClassType.new()
+    unless class_name.nil?
+      type.class_name = class_name.sub(/^::/, '')
+    end
+    type
+  end
+
+  # Produces a type for Array[o] where o is either a type, or an instance for
+  # which a type is inferred.
+  # @api public
+  #
+  def self.array_of(o)
+    type = Types::PArrayType.new()
+    type.element_type = type_of(o)
+    type
+  end
+
+  # Produces a type for Hash[Scalar, o] where o is either a type, or an
+  # instance for which a type is inferred.
+  # @api public
+  #
+  def self.hash_of(value, key = scalar())
+    type = Types::PHashType.new()
+    type.key_type = type_of(key)
+    type.element_type = type_of(value)
+    type
+  end
+
+  # Produces a type for Array[Data]
+  # @api public
+  #
+  def self.array_of_data()
+    type = Types::PArrayType.new()
+    type.element_type = data()
+    type
+  end
+
+  # Produces a type for Hash[Scalar, Data]
+  # @api public
+  #
+  def self.hash_of_data()
+    type = Types::PHashType.new()
+    type.key_type = scalar()
+    type.element_type = data()
+    type
+  end
+
+  # Produces a type for NotUndef[T]
+  # The given 'inst_type' can be a string in which case it will be converted into
+  # the type String[inst_type].
+  #
+  # @param inst_type [Type,String] the type to qualify
+  # @return [Puppet::Pops::Types::PNotUndefType] the NotUndef type
+  #
+  # @api public
+  #
+  def self.not_undef(inst_type = nil)
+    type = Types::PNotUndefType.new()
+    inst_type = string(inst_type) if inst_type.is_a?(String)
+    type.type = inst_type
+    type
+  end
+
+  # Produces a type for Type[T]
+  # @api public
+  #
+  def self.type_type(inst_type = nil)
+    type = Types::PType.new()
+    type.type = inst_type
+    type
+  end
+
+  # Produce a type corresponding to the class of given unless given is a
+  # String, Class or a PAnyType.  When a String is given this is taken as
+  # a classname.
+  #
+  def self.type_of(o)
+    if o.is_a?(Class)
+      @type_calculator.type(o)
+    elsif o.is_a?(Types::PAnyType)
+      o
+    elsif o.is_a?(String)
+      Types::PRuntimeType.new(:runtime => :ruby, :runtime_type_name => o)
+    else
+      @type_calculator.infer_generic(o)
+    end
+  end
+
+  # Produces a type for a class or infers a type for something that is not a
+  # class
+  # @note
+  #   To get the type for the class' class use `TypeCalculator.infer(c)`
+  #
+  # @overload ruby(o)
+  #   @param o [Class] produces the type corresponding to the class (e.g.
+  #     Integer becomes PIntegerType)
+  # @overload ruby(o)
+  #   @param o [Object] produces the type corresponding to the instance class
+  #     (e.g. 3 becomes PIntegerType)
+  #
+  # @api public
+  #
+  def self.ruby(o)
+    if o.is_a?(Class)
+      @type_calculator.type(o)
+    else
+      Types::PRuntimeType.new(:runtime => :ruby, :runtime_type_name => o.class.name)
+    end
+  end
+
+  # Generic creator of a RuntimeType["ruby"] - allows creating the Ruby type
+  # with nil name, or String name.  Also see ruby(o) which performs inference,
+  # or mapps a Ruby Class to its name.
+  #
+  def self.ruby_type(class_name = nil)
+    Types::PRuntimeType.new(:runtime => :ruby, :runtime_type_name => class_name)
+  end
+
+  # Generic creator of a RuntimeType - allows creating the type with nil or
+  # String runtime_type_name.  Also see ruby_type(o) and ruby(o).
+  #
+  def self.runtime(runtime=nil, runtime_type_name = nil)
+    runtime = runtime.to_sym if runtime.is_a?(String)
+    Types::PRuntimeType.new(:runtime => runtime, :runtime_type_name => runtime_type_name)
+  end
+
+  # Sets the accepted size range of a collection if something other than the
+  # default 0 to Infinity is wanted. The semantics for from/to are the same as
+  # for #range
+  #
+  def self.constrain_size(collection_t, from, to)
+    collection_t.size_type = range(from, to)
+    collection_t
+  end
+
+  # Returns true if the given type t is of valid range parameter type (integer
+  # or literal default).
+  def self.is_range_parameter?(t)
+    t.is_a?(Integer) || t == 'default' || :default == t
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/types/type_parser.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/types/type_parser.rb
new file mode 100644
index 0000000..4830370
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/types/type_parser.rb
@@ -0,0 +1,481 @@
+# This class provides parsing of Type Specification from a string into the Type
+# Model that is produced by the Puppet::Pops::Types::TypeFactory.
+#
+# The Type Specifications that are parsed are the same as the stringified forms
+# of types produced by the {Puppet::Pops::Types::TypeCalculator TypeCalculator}.
+#
+# @api public
+class Puppet::Pops::Types::TypeParser
+  # @api private
+  TYPES = Puppet::Pops::Types::TypeFactory
+
+  # @api public
+  def initialize
+    @parser = Puppet::Pops::Parser::Parser.new()
+    @type_transformer = Puppet::Pops::Visitor.new(nil, "interpret", 0, 0)
+    @undef_t = TYPES.undef
+  end
+
+  # Produces a *puppet type* based on the given string.
+  #
+  # @example
+  #     parser.parse('Integer')
+  #     parser.parse('Array[String]')
+  #     parser.parse('Hash[Integer, Array[String]]')
+  #
+  # @param string [String] a string with the type expressed in stringified form as produced by the 
+  #   {Puppet::Pops::Types::TypeCalculator#string TypeCalculator#string} method.
+  # @return [Puppet::Pops::Types::PAnyType] a specialization of the PAnyType representing the type.
+  #
+  # @api public
+  #
+  def parse(string)
+    # TODO: This state (@string) can be removed since the parse result of newer future parser
+    # contains a Locator in its SourcePosAdapter and the Locator keeps the string.
+    # This way, there is no difference between a parsed "string" and something that has been parsed
+    # earlier and fed to 'interpret'
+    #
+    @string = string
+    model = @parser.parse_string(@string)
+    if model
+      interpret(model.current)
+    else
+      raise_invalid_type_specification_error
+    end
+  end
+
+  # @api private
+  def interpret(ast)
+    result = @type_transformer.visit_this_0(self, ast)
+    result = result.body if result.is_a?(Puppet::Pops::Model::Program)
+    raise_invalid_type_specification_error unless result.is_a?(Puppet::Pops::Types::PAnyType)
+    result
+  end
+
+  # @api private
+  def interpret_any(ast)
+    @type_transformer.visit_this_0(self, ast)
+  end
+
+  # @api private
+  def interpret_Object(o)
+    raise_invalid_type_specification_error
+  end
+
+  # @api private
+  def interpret_Program(o)
+    interpret(o.body)
+  end
+
+  # @api private
+  def interpret_QualifiedName(o)
+    o.value
+  end
+
+  # @api private
+  def interpret_LiteralString(o)
+    o.value
+  end
+
+  def interpret_LiteralRegularExpression(o)
+    o.value
+  end
+
+  # @api private
+  def interpret_String(o)
+    o
+  end
+
+  # @api private
+  def interpret_LiteralDefault(o)
+    :default
+  end
+
+  # @api private
+  def interpret_LiteralInteger(o)
+    o.value
+  end
+
+  # @api private
+  def interpret_LiteralFloat(o)
+    o.value
+  end
+
+  # @api private
+  def interpret_LiteralHash(o)
+    result = {}
+    o.entries.each do |entry|
+      result[@type_transformer.visit_this_0(self, entry.key)] = @type_transformer.visit_this_0(self, entry.value)
+    end
+    result
+  end
+
+  # @api private
+  def interpret_QualifiedReference(name_ast)
+    case name_ast.value
+    when "integer"
+      TYPES.integer
+
+    when "float"
+      TYPES.float
+
+    when "numeric"
+        TYPES.numeric
+
+    when "string"
+      TYPES.string
+
+    when "enum"
+      TYPES.enum
+
+    when "boolean"
+      TYPES.boolean
+
+    when "pattern"
+      TYPES.pattern
+
+    when "regexp"
+      TYPES.regexp
+
+    when "data"
+      TYPES.data
+
+    when "array"
+      TYPES.array_of_data
+
+    when "hash"
+      TYPES.hash_of_data
+
+    when "class"
+      TYPES.host_class()
+
+    when "resource"
+      TYPES.resource()
+
+    when "collection"
+      TYPES.collection()
+
+    when "scalar"
+      TYPES.scalar()
+
+    when "catalogentry"
+      TYPES.catalog_entry()
+
+    when "undef"
+      TYPES.undef()
+
+    when "notundef"
+      TYPES.not_undef()
+
+    when "default"
+      TYPES.default()
+
+    when "any"
+      TYPES.any()
+
+    when "variant"
+      TYPES.variant()
+
+    when "optional"
+      TYPES.optional()
+
+    when "runtime"
+      TYPES.runtime()
+
+    when "type"
+      TYPES.type_type()
+
+    when "tuple"
+      TYPES.tuple()
+
+    when "struct"
+      TYPES.struct()
+
+    when "callable"
+      # A generic callable as opposed to one that does not accept arguments
+      TYPES.all_callables()
+
+    else
+      TYPES.resource(name_ast.value)
+    end
+  end
+
+  # @api private
+  def interpret_AccessExpression(parameterized_ast)
+    parameters = parameterized_ast.keys.collect { |param| interpret_any(param) }
+
+    unless parameterized_ast.left_expr.is_a?(Puppet::Pops::Model::QualifiedReference)
+      raise_invalid_type_specification_error
+    end
+
+    case parameterized_ast.left_expr.value
+    when "array"
+      case parameters.size
+      when 1
+      when 2
+        size_type =
+        if parameters[1].is_a?(Puppet::Pops::Types::PIntegerType)
+          parameters[1].copy
+        else
+          assert_range_parameter(parameters[1])
+          TYPES.range(parameters[1], :default)
+        end
+      when 3
+        assert_range_parameter(parameters[1])
+        assert_range_parameter(parameters[2])
+        size_type = TYPES.range(parameters[1], parameters[2])
+      else
+        raise_invalid_parameters_error("Array", "1 to 3", parameters.size)
+      end
+      assert_type(parameters[0])
+      t = TYPES.array_of(parameters[0])
+      t.size_type = size_type if size_type
+      t
+
+    when "hash"
+      result = case parameters.size
+      when 2
+        assert_type(parameters[0])
+        assert_type(parameters[1])
+        TYPES.hash_of(parameters[1], parameters[0])
+      when 3
+        size_type =
+        if parameters[2].is_a?(Puppet::Pops::Types::PIntegerType)
+          parameters[2].copy
+        else
+          assert_range_parameter(parameters[2])
+          TYPES.range(parameters[2], :default)
+        end
+        assert_type(parameters[0])
+        assert_type(parameters[1])
+        TYPES.hash_of(parameters[1], parameters[0])
+      when 4
+        assert_range_parameter(parameters[2])
+        assert_range_parameter(parameters[3])
+        size_type = TYPES.range(parameters[2], parameters[3])
+        assert_type(parameters[0])
+        assert_type(parameters[1])
+        TYPES.hash_of(parameters[1], parameters[0])
+      else
+        raise_invalid_parameters_error("Hash", "2 to 4", parameters.size)
+      end
+      result.size_type = size_type if size_type
+      result
+
+    when "collection"
+      size_type = case parameters.size
+      when 1
+        if parameters[0].is_a?(Puppet::Pops::Types::PIntegerType)
+          parameters[0].copy
+        else
+          assert_range_parameter(parameters[0])
+          TYPES.range(parameters[0], :default)
+        end
+      when 2
+        assert_range_parameter(parameters[0])
+        assert_range_parameter(parameters[1])
+        TYPES.range(parameters[0], parameters[1])
+      else
+        raise_invalid_parameters_error("Collection", "1 to 2", parameters.size)
+      end
+      result = TYPES.collection
+      result.size_type = size_type
+      result
+
+    when "class"
+      if parameters.size != 1
+        raise_invalid_parameters_error("Class", 1, parameters.size)
+      end
+      TYPES.host_class(parameters[0])
+
+    when "resource"
+      if parameters.size == 1
+        TYPES.resource(parameters[0])
+      elsif parameters.size != 2
+        raise_invalid_parameters_error("Resource", "1 or 2", parameters.size)
+      else
+        TYPES.resource(parameters[0], parameters[1])
+      end
+
+    when "regexp"
+      # 1 parameter being a string, or regular expression
+      raise_invalid_parameters_error("Regexp", "1", parameters.size) unless parameters.size == 1
+      TYPES.regexp(parameters[0])
+
+    when "enum"
+      # 1..m parameters being strings
+      raise_invalid_parameters_error("Enum", "1 or more", parameters.size) unless parameters.size >= 1
+      TYPES.enum(*parameters)
+
+    when "pattern"
+      # 1..m parameters being strings or regular expressions
+      raise_invalid_parameters_error("Pattern", "1 or more", parameters.size) unless parameters.size >= 1
+      TYPES.pattern(*parameters)
+
+    when "variant"
+      # 1..m parameters being strings or regular expressions
+      raise_invalid_parameters_error("Variant", "1 or more", parameters.size) unless parameters.size >= 1
+      TYPES.variant(*parameters)
+
+    when "tuple"
+      # 1..m parameters being types (last two optionally integer or literal default
+      raise_invalid_parameters_error("Tuple", "1 or more", parameters.size) unless parameters.size >= 1
+      length = parameters.size
+      if TYPES.is_range_parameter?(parameters[-2])
+        # min, max specification
+        min = parameters[-2]
+        min = (min == :default || min == 'default') ? 0 : min
+        assert_range_parameter(parameters[-1])
+        max = parameters[-1]
+        max = max == :default ? nil : max
+        parameters = parameters[0, length-2]
+      elsif TYPES.is_range_parameter?(parameters[-1])
+        min = parameters[-1]
+        min = (min == :default || min == 'default') ? 0 : min
+        max = nil
+        parameters = parameters[0, length-1]
+      end
+      t = TYPES.tuple(*parameters)
+      if min || max
+        TYPES.constrain_size(t, min, max)
+      end
+      t
+
+    when "callable"
+      # 1..m parameters being types (last three optionally integer or literal default, and a callable)
+      TYPES.callable(*parameters)
+
+    when "struct"
+      # 1..m parameters being types (last two optionally integer or literal default
+      raise_invalid_parameters_error("Struct", "1", parameters.size) unless parameters.size == 1
+      h = parameters[0]
+      raise_invalid_type_specification_error unless h.is_a?(Hash)
+      TYPES.struct(h)
+
+    when "integer"
+      if parameters.size == 1
+        case parameters[0]
+        when Integer
+          TYPES.range(parameters[0], :default)
+        when :default
+          TYPES.integer # unbound
+        end
+      elsif parameters.size != 2
+        raise_invalid_parameters_error("Integer", "1 or 2", parameters.size)
+     else
+       TYPES.range(parameters[0] == :default ? nil : parameters[0], parameters[1] == :default ? nil : parameters[1])
+     end
+
+    when "float"
+      if parameters.size == 1
+        case parameters[0]
+        when Integer, Float
+          TYPES.float_range(parameters[0], :default)
+        when :default
+          TYPES.float # unbound
+        end
+      elsif parameters.size != 2
+        raise_invalid_parameters_error("Float", "1 or 2", parameters.size)
+     else
+       TYPES.float_range(parameters[0] == :default ? nil : parameters[0], parameters[1] == :default ? nil : parameters[1])
+     end
+
+    when "string"
+      size_type =
+      case parameters.size
+      when 1
+        if parameters[0].is_a?(Puppet::Pops::Types::PIntegerType)
+          parameters[0].copy
+        else
+          assert_range_parameter(parameters[0])
+          TYPES.range(parameters[0], :default)
+        end
+      when 2
+        assert_range_parameter(parameters[0])
+        assert_range_parameter(parameters[1])
+        TYPES.range(parameters[0], parameters[1])
+      else
+        raise_invalid_parameters_error("String", "1 to 2", parameters.size)
+      end
+      result = TYPES.string
+      result.size_type = size_type
+      result
+
+    when "optional"
+      if parameters.size != 1
+        raise_invalid_parameters_error("Optional", 1, parameters.size)
+      end
+      param = parameters[0]
+      assert_type(param) unless param.is_a?(String)
+      TYPES.optional(param)
+
+    when "any", "data", "catalogentry", "boolean", "scalar", "undef", "numeric", "default"
+      raise_unparameterized_type_error(parameterized_ast.left_expr)
+
+    when "notundef"
+      case parameters.size
+      when 0
+        TYPES.not_undef
+      when 1
+        param = parameters[0]
+        assert_type(param) unless param.is_a?(String)
+        TYPES.not_undef(param)
+      else
+        raise_invalid_parameters_error("NotUndef", "0 to 1", parameters.size)
+      end
+
+    when "type"
+      if parameters.size != 1
+        raise_invalid_parameters_error("Type", 1, parameters.size)
+      end
+      assert_type(parameters[0])
+      TYPES.type_type(parameters[0])
+
+    when "runtime"
+      raise_invalid_parameters_error("Runtime", "2", parameters.size) unless parameters.size == 2
+      TYPES.runtime(*parameters)
+
+    else
+      # It is a resource such a File['/tmp/foo']
+      type_name = parameterized_ast.left_expr.value
+      if parameters.size != 1
+        raise_invalid_parameters_error(type_name.capitalize, 1, parameters.size)
+      end
+      TYPES.resource(type_name, parameters[0])
+    end
+  end
+
+  private
+
+  def assert_type(t)
+    raise_invalid_type_specification_error unless t.is_a?(Puppet::Pops::Types::PAnyType)
+    true
+  end
+
+  def assert_range_parameter(t)
+    raise_invalid_type_specification_error unless TYPES.is_range_parameter?(t)
+  end
+
+  def raise_invalid_type_specification_error
+    raise Puppet::ParseError,
+      "The expression <#{@string}> is not a valid type specification."
+  end
+
+  def raise_invalid_parameters_error(type, required, given)
+    raise Puppet::ParseError,
+      "Invalid number of type parameters specified: #{type} requires #{required}, #{given} provided"
+  end
+
+  def raise_unparameterized_type_error(ast)
+    raise Puppet::ParseError, "Not a parameterized type <#{original_text_of(ast)}>"
+  end
+
+  def raise_unknown_type_error(ast)
+    raise Puppet::ParseError, "Unknown type <#{original_text_of(ast)}>"
+  end
+
+  def original_text_of(ast)
+    position = Puppet::Pops::Adapters::SourcePosAdapter.adapt(ast)
+    position.extract_text()
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/types/types.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/types/types.rb
new file mode 100644
index 0000000..b6cf500
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/types/types.rb
@@ -0,0 +1,406 @@
+require 'rgen/metamodel_builder'
+
+# The Types model is a model of Puppet Language types.
+# It consists of two parts; the meta-model expressed using RGen (in types_meta.rb) and this file which
+# mixes in the implementation.
+#
+# @api public
+#
+module Puppet::Pops
+  require 'puppet/pops/types/types_meta'
+
+  # TODO: See PUP-2978 for possible performance optimization
+
+  # Mix in implementation part of the Bindings Module
+  module Types
+    # Used as end in a range
+    INFINITY = 1.0 / 0.0
+    NEGATIVE_INFINITY = -INFINITY
+
+    class TypeModelObject < RGen::MetamodelBuilder::MMBase
+      include Puppet::Pops::Visitable
+      include Puppet::Pops::Adaptable
+      include Puppet::Pops::Containment
+    end
+
+    class PAnyType < TypeModelObject
+      module ClassModule
+        # Produce a deep copy of the type
+        def copy
+          Marshal.load(Marshal.dump(self))
+        end
+
+        def hash
+          self.class.hash
+        end
+
+        def ==(o)
+          self.class == o.class
+        end
+
+        alias eql? ==
+
+        def to_s
+          Puppet::Pops::Types::TypeCalculator.string(self)
+        end
+      end
+    end
+
+    class PNotUndefType < PAnyType
+      module ClassModule
+        def hash
+          [self.class, type].hash
+        end
+
+        def ==(o)
+          self.class == o.class && type == o.type
+        end
+      end
+    end
+
+    class PType < PAnyType
+      module ClassModule
+        def hash
+          [self.class, type].hash
+        end
+
+        def ==(o)
+          self.class == o.class && type == o.type
+        end
+      end
+    end
+
+    class PDataType < PAnyType
+      module ClassModule
+        def ==(o)
+          self.class == o.class ||
+            o.class == PVariantType && o == Puppet::Pops::Types::TypeCalculator.data_variant()
+        end
+      end
+    end
+
+    class PVariantType < PAnyType
+      module ClassModule
+
+        def hash
+          [self.class, Set.new(self.types)].hash
+        end
+
+        def ==(o)
+          (self.class == o.class && Set.new(types) == Set.new(o.types)) ||
+            (o.class == PDataType && self == Puppet::Pops::Types::TypeCalculator.data_variant())
+        end
+      end
+    end
+
+    class PEnumType < PScalarType
+      module ClassModule
+        def hash
+          [self.class, Set.new(self.values)].hash
+        end
+
+        def ==(o)
+          self.class == o.class && Set.new(values) == Set.new(o.values)
+        end
+      end
+    end
+
+    class PIntegerType < PNumericType
+      module ClassModule
+        # The integer type is enumerable when it defines a range
+        include Enumerable
+
+        # Returns Float.Infinity if one end of the range is unbound
+        def size
+          return INFINITY if from.nil? || to.nil?
+          1+(to-from).abs
+        end
+
+        # Returns the range as an array ordered so the smaller number is always first.
+        # The number may be Infinity or -Infinity.
+        def range
+          f = from || NEGATIVE_INFINITY
+          t = to || INFINITY
+          [f, t]
+        end
+
+        # Returns Enumerator if no block is given
+        # Returns self if size is infinity (does not yield)
+        def each
+          return self.to_enum unless block_given?
+          return nil if from.nil? || to.nil?
+          from.upto(to) {|x| yield x }
+        end
+
+        def hash
+          [self.class, from, to].hash
+        end
+
+        def ==(o)
+          self.class == o.class && from == o.from && to == o.to
+        end
+      end
+    end
+
+    class PFloatType < PNumericType
+      module ClassModule
+        def hash
+          [self.class, from, to].hash
+        end
+
+        def ==(o)
+          self.class == o.class && from == o.from && to == o.to
+        end
+      end
+    end
+
+    class PStringType < PScalarType
+      module ClassModule
+
+        def hash
+          [self.class, self.size_type, Set.new(self.values)].hash
+        end
+
+        def ==(o)
+          self.class == o.class && self.size_type == o.size_type && Set.new(values) == Set.new(o.values)
+        end
+      end
+    end
+
+    class PRegexpType < PScalarType
+      module ClassModule
+        def regexp_derived
+          @_regexp = Regexp.new(pattern) unless @_regexp && @_regexp.source == pattern
+          @_regexp
+        end
+
+        def hash
+          [self.class, pattern].hash
+        end
+
+        def ==(o)
+          self.class == o.class && pattern == o.pattern
+        end
+      end
+    end
+
+    class PPatternType < PScalarType
+      module ClassModule
+
+        def hash
+          [self.class, Set.new(patterns)].hash
+        end
+
+        def ==(o)
+          self.class == o.class && Set.new(patterns) == Set.new(o.patterns)
+        end
+      end
+    end
+
+    class PCollectionType < PAnyType
+      module ClassModule
+        # Returns an array with from (min) size to (max) size
+        def size_range
+          return [0, INFINITY] if size_type.nil?
+          f = size_type.from || 0
+          t = size_type.to || INFINITY
+          [f, t]
+        end
+
+        def hash
+          [self.class, element_type, size_type].hash
+        end
+
+        def ==(o)
+          self.class == o.class && element_type == o.element_type && size_type == o.size_type
+        end
+      end
+    end
+
+    class PStructElement < TypeModelObject
+      module ClassModule
+        def hash
+          [self.class, value_type, key_type].hash
+        end
+
+        def name
+          k = key_type
+          k = k.optional_type if k.is_a?(POptionalType)
+          k.values[0]
+        end
+
+        def ==(o)
+          self.class == o.class && value_type == o.value_type && key_type == o.key_type
+        end
+      end
+    end
+
+
+    class PStructType < PAnyType
+      module ClassModule
+        def hashed_elements_derived
+          @_hashed ||= elements.reduce({}) {|memo, e| memo[e.name] = e; memo }
+          @_hashed
+        end
+
+        def clear_hashed_elements
+          @_hashed = nil
+        end
+
+        def hash
+          [self.class, Set.new(elements)].hash
+        end
+
+        def ==(o)
+          self.class == o.class && hashed_elements == o.hashed_elements
+        end
+      end
+    end
+
+    class PTupleType < PAnyType
+      module ClassModule
+        # Returns the number of elements accepted [min, max] in the tuple
+        def size_range
+          types_size = types.size
+          size_type.nil? ? [types_size, types_size] : size_type.range
+        end
+
+        # Returns the number of accepted occurrences [min, max] of the last type in the tuple
+        # The defaults is [1,1]
+        #
+        def repeat_last_range
+          types_size = types.size
+          if size_type.nil?
+            return [1, 1]
+          end
+          from, to = size_type.range()
+          min = from - (types_size-1)
+          min = min <= 0 ? 0 : min
+          max = to - (types_size-1)
+          [min, max]
+        end
+
+        def hash
+          [self.class, size_type, Set.new(types)].hash
+        end
+
+        def ==(o)
+          self.class == o.class && types == o.types && size_type == o.size_type
+        end
+      end
+    end
+
+    class PCallableType < PAnyType
+      module ClassModule
+        # Returns the number of accepted arguments [min, max]
+        def size_range
+          param_types.size_range
+        end
+
+        # Returns the number of accepted arguments for the last parameter type [min, max]
+        #
+        def last_range
+          param_types.repeat_last_range
+        end
+
+        # Range [0,0], [0,1], or [1,1] for the block
+        #
+        def block_range
+          case block_type
+          when Puppet::Pops::Types::POptionalType
+            [0,1]
+          when Puppet::Pops::Types::PVariantType, Puppet::Pops::Types::PCallableType
+            [1,1]
+          else
+            [0,0]
+          end
+        end
+
+        def hash
+          [self.class, Set.new(param_types), block_type].hash
+        end
+
+        def ==(o)
+          self.class == o.class && args_type == o.args_type && block_type == o.block_type
+        end
+      end
+    end
+
+    class PArrayType < PCollectionType
+      module ClassModule
+        def hash
+          [self.class, self.element_type, self.size_type].hash
+        end
+
+        def ==(o)
+          self.class == o.class && self.element_type == o.element_type && self.size_type == o.size_type
+        end
+      end
+    end
+
+    class PHashType < PCollectionType
+      module ClassModule
+        def hash
+          [self.class, key_type, self.element_type, self.size_type].hash
+        end
+
+        def ==(o)
+          self.class        == o.class         &&
+          key_type          == o.key_type      &&
+          self.element_type == o.element_type  &&
+          self.size_type    == o.size_type
+        end
+
+        def is_the_empty_hash?
+          size_type.is_a?(PIntegerType) && size_type.from == 0 && size_type.to == 0 && key_type.is_a?(PUndefType) && element_type.is_a?(PUndefType)
+        end
+      end
+    end
+
+    class PRuntimeType < PAnyType
+      module ClassModule
+        def hash
+          [self.class, runtime, runtime_type_name].hash
+        end
+
+        def ==(o)
+          self.class == o.class && runtime == o.runtime && runtime_type_name == o.runtime_type_name 
+        end
+      end
+    end
+
+    class PHostClassType < PCatalogEntryType
+      module ClassModule
+        def hash
+          [self.class, class_name].hash
+        end
+        def ==(o)
+          self.class == o.class && class_name == o.class_name
+        end
+      end
+    end
+
+    class PResourceType < PCatalogEntryType
+      module ClassModule
+        def hash
+          [self.class, type_name, title].hash
+        end
+        def ==(o)
+          self.class == o.class && type_name == o.type_name && title == o.title
+        end
+      end
+    end
+
+    class POptionalType < PAnyType
+      module ClassModule
+        def hash
+          [self.class, optional_type].hash
+        end
+
+        def ==(o)
+          self.class == o.class && optional_type == o.optional_type
+        end
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/types/types_meta.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/types/types_meta.rb
new file mode 100644
index 0000000..8394190
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/types/types_meta.rb
@@ -0,0 +1,234 @@
+require 'rgen/metamodel_builder'
+
+# The Types model is a model of Puppet Language types.
+#
+# The exact relationship between types is not visible in this model wrt. the PDataType which is an abstraction
+# of Scalar, Array[Data], and Hash[Scalar, Data] nested to any depth. This means it is not possible to
+# infer the type by simply looking at the inheritance hierarchy. The {Puppet::Pops::Types::TypeCalculator} should
+# be used to answer questions about types. The {Puppet::Pops::Types::TypeFactory} should be used to create an instance
+# of a type whenever one is needed.
+#
+# The implementation of the Types model contains methods that are required for the type objects to behave as
+# expected when comparing them and using them as keys in hashes. (No other logic is, or should be included directly in
+# the model's classes).
+#
+# @api public
+#
+module Puppet::Pops::Types
+  extend RGen::MetamodelBuilder::ModuleExtension
+
+  class TypeModelObject < RGen::MetamodelBuilder::MMBase
+    abstract
+  end
+
+  # Base type for all types except {Puppet::Pops::Types::PType PType}, the type of types.
+  # @api public
+  #
+  class PAnyType < TypeModelObject
+  end
+
+  # A type that is assignable from the same types as its contained `type` except the
+  # types assignable from {Puppet::Pops::Types::PUndefType}
+  #
+  # @api public
+  #
+  class PNotUndefType < PAnyType
+    contains_one_uni 'type', PAnyType
+  end
+
+  # The type of types.
+  # @api public
+  #
+  class PType < PAnyType
+    contains_one_uni 'type', PAnyType
+  end
+
+  # @api public
+  #
+  class PUndefType < PAnyType
+  end
+
+
+  # A type private to the type system that describes "ignored type" - i.e. "I am what you are"
+  # @api private
+  #
+  class  PUnitType < PAnyType
+  end
+
+  # @api public
+  #
+  class PDefaultType < PAnyType
+  end
+
+  # A flexible data type, being assignable to its subtypes as well as PArrayType and PHashType with element type assignable to PDataType.
+  #
+  # @api public
+  #
+  class PDataType < PAnyType
+  end
+
+  # A flexible type describing an any? of other types
+  # @api public
+  #
+  class PVariantType < PAnyType
+    contains_many_uni 'types', PAnyType, :lowerBound => 1
+  end
+
+  # Type that is PDataType compatible, but is not a PCollectionType.
+  # @api public
+  #
+  class PScalarType < PAnyType
+  end
+
+  # A string type describing the set of strings having one of the given values
+  # @api public
+  #
+  class PEnumType < PScalarType
+    has_many_attr 'values', String, :lowerBound => 1
+  end
+
+  # @api public
+  #
+  class PNumericType < PScalarType
+  end
+
+  # @api public
+  #
+  class PIntegerType < PNumericType
+    has_attr 'from', Integer, :lowerBound => 0
+    has_attr 'to', Integer, :lowerBound => 0
+  end
+
+  # @api public
+  #
+  class PFloatType < PNumericType
+    has_attr 'from', Float, :lowerBound => 0
+    has_attr 'to', Float, :lowerBound => 0
+  end
+
+  # @api public
+  #
+  class PStringType < PScalarType
+    has_many_attr 'values', String, :lowerBound => 0, :upperBound => -1, :unique => true
+    contains_one_uni 'size_type', PIntegerType
+  end
+
+  # @api public
+  #
+  class PRegexpType < PScalarType
+    has_attr 'pattern', String, :lowerBound => 1
+    has_attr 'regexp', Object, :derived => true
+  end
+
+  # Represents a subtype of String that narrows the string to those matching the patterns
+  # If specified without a pattern it is basically the same as the String type.
+  #
+  # @api public
+  #
+  class PPatternType < PScalarType
+    contains_many_uni 'patterns', PRegexpType
+  end
+
+  # @api public
+  #
+  class PBooleanType < PScalarType
+  end
+
+  # @api public
+  #
+  class PCollectionType < PAnyType
+    contains_one_uni 'element_type', PAnyType
+    contains_one_uni 'size_type', PIntegerType
+  end
+
+  # @api public
+  #
+  class PStructElement < TypeModelObject
+    # key_type must be either String[1] or Optional[String[1]] and the String[1] must
+    # have a values collection with exactly one element
+    contains_one_uni 'key_type', PAnyType, :lowerBound => 1
+    contains_one_uni 'value_type', PAnyType
+  end
+
+  # @api public
+  #
+  class PStructType < PAnyType
+    contains_many_uni 'elements', PStructElement, :lowerBound => 1
+    has_attr 'hashed_elements', Object, :derived => true
+  end
+
+  # @api public
+  #
+  class PTupleType < PAnyType
+    contains_many_uni 'types', PAnyType, :lowerBound => 1
+    # If set, describes min and max required of the given types - if max > size of
+    # types, the last type entry repeats
+    #
+    contains_one_uni 'size_type', PIntegerType, :lowerBound => 0
+  end
+
+  # @api public
+  #
+  class PCallableType < PAnyType
+    # Types of parameters as a Tuple with required/optional count, or an Integer with min (required), max count
+    contains_one_uni 'param_types', PAnyType, :lowerBound => 1
+
+    # Although being an abstract type reference, only Callable, or all Callables wrapped in
+    # Optional or Variant are supported
+    # If not set, the meaning is that block is not supported.
+    #
+    contains_one_uni 'block_type', PAnyType, :lowerBound => 0
+  end
+
+  # @api public
+  #
+  class PArrayType < PCollectionType
+  end
+
+  # @api public
+  #
+  class PHashType < PCollectionType
+    contains_one_uni 'key_type', PAnyType
+  end
+
+  RuntimeEnum = RGen::MetamodelBuilder::DataTypes::Enum.new(
+    :name => 'RuntimeEnum',
+    :literals => [:'ruby', ])
+
+  # @api public
+  #
+  class PRuntimeType < PAnyType
+    has_attr 'runtime', RuntimeEnum, :lowerBound => 1
+    has_attr 'runtime_type_name', String
+  end
+
+  # Abstract representation of a type that can be placed in a Catalog.
+  # @api public
+  #
+  class PCatalogEntryType < PAnyType
+  end
+
+  # Represents a (host-) class in the Puppet Language.
+  # @api public
+  #
+  class PHostClassType < PCatalogEntryType
+    has_attr 'class_name', String
+  end
+
+  # Represents a Resource Type in the Puppet Language
+  # @api public
+  #
+  class PResourceType < PCatalogEntryType
+    has_attr 'type_name', String
+    has_attr 'title', String
+  end
+
+  # Represents a type that accept PUndefType instead of the type parameter
+  # required_type - is a short hand for Variant[T, Undef]
+  # @api public
+  #
+  class POptionalType < PAnyType
+    contains_one_uni 'optional_type', PAnyType
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/utils.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/utils.rb
new file mode 100644
index 0000000..69085ce
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/utils.rb
@@ -0,0 +1,142 @@
+# Provides utility methods
+module Puppet::Pops::Utils
+  # Can the given o be converted to numeric? (or is numeric already)
+  # Accepts a leading '::'
+  # Returns a boolean if the value is numeric
+  # If testing if value can be converted it is more efficient to call {#to_n} or {#to_n_with_radix} directly
+  # and check if value is nil.
+  def self.is_numeric?(o)
+    case o
+    when Numeric
+      true
+    else
+      !!Puppet::Pops::Patterns::NUMERIC.match(relativize_name(o.to_s))
+    end
+  end
+
+  # Convert a match from Puppet::Pops::Patterns::NUMERIC to floating point value if
+  # possible
+  def self.match_to_fp(match)
+    if match[5].to_s.length > 0
+      # Use default radix (default is decimal == 10) for floats
+      # Do not convert a value that is 0 raised to 10^somevalue to float - the value is always 0
+      # i.e. 0000.0e1, 0e1, 0.0000e1
+      if Integer(match[4]) == 0 && match[5] =~ /\A\.?0*[eE].*\z/
+        nil
+      else
+        fp_value = Float(match[2])
+        if fp_value != Puppet::Pops::Types::TypeCalculator::TheInfinity
+          match[1] == '-' ? -fp_value : fp_value
+        else
+          nil
+        end
+      end
+    end
+  end
+
+  # To Numeric with radix, or nil if not a number.
+  # If the value is already Numeric it is returned verbatim with a radix of 10.
+  # @param o [String, Number] a string containing a number in octal, hex, integer (decimal) or floating point form
+  #   with optional sign +/-
+  # @return [Array<Number, Integer>, nil] array with converted number and radix, or nil if not possible to convert
+  # @api public
+  #
+  def self.to_n_with_radix o
+    begin
+      case o
+      when String
+        match = Puppet::Pops::Patterns::NUMERIC.match(relativize_name(o))
+        if !match
+          nil
+        elsif match[5].to_s.length > 0
+          fp_value = match_to_fp(match)
+          fp_value.nil? ? nil : [fp_value, 10]
+        else
+          # Set radix (default is decimal == 10)
+          radix = 10
+          if match[3].to_s.length > 0
+            radix = 16
+          elsif match[4].to_s.length > 1 && match[4][0,1] == '0'
+            radix = 8
+          end
+          # Ruby 1.8.7 does not have a second argument to Kernel method that creates an
+          # integer from a string, it relies on the prefix 0x, 0X, 0 (and unsupported in puppet binary 'b')
+          # We have the correct string here, match[2] is safe to parse without passing on radix
+          match[1] == '-' ? [-Integer(match[2]), radix] : [Integer(match[2]), radix]
+        end
+      when Numeric
+        # Impossible to calculate radix, assume decimal
+        [o, 10]
+      else
+        nil
+      end
+    rescue ArgumentError
+      nil
+    end
+  end
+
+  # To Numeric (or already numeric)
+  # Returns nil if value is not numeric, else an Integer or Float. A String may have an optional sign.
+  #
+  # A leading '::' is accepted (and ignored)
+  #
+  def self.to_n o
+    begin
+      case o
+      when String
+        match = Puppet::Pops::Patterns::NUMERIC.match(relativize_name(o))
+        if !match
+          nil
+        elsif match[5].to_s.length > 0
+          match_to_fp(match)
+        else
+          match[1] == '-' ? -Integer(match[2]) : Integer(match[2])
+        end
+      when Numeric
+        o
+      else
+        nil
+      end
+    rescue ArgumentError
+      nil
+    end
+  end
+
+  # is the name absolute (i.e. starts with ::)
+  def self.is_absolute? name
+    name.start_with? "::"
+  end
+
+  def self.name_to_segments name
+    name.split("::")
+  end
+
+  def self.relativize_name name
+    is_absolute?(name) ? name[2..-1] : name
+  end
+
+  # Finds an existing adapter for o or for one of its containers, or nil, if none of the containers
+  # was adapted with the given adapter.
+  # This method can only be used with objects that respond to `:eContainer`.
+  # with true.
+  #
+  # @see #find_closest_positioned
+  #
+  def self.find_adapter(o, adapter)
+    return nil if o.nil? || (o.is_a?(Array) && o.empty?)
+    a = adapter.get(o)
+    return a if a
+    return find_adapter(o.eContainer, adapter)
+  end
+
+  # Finds the closest positioned Puppet::Pops::Model::Positioned object, or object decorated with
+  # a SourcePosAdapter, and returns
+  # a SourcePosAdapter for the first found, or nil if not found.
+  #
+  def self.find_closest_positioned(o)
+    return nil if o.nil? || o.is_a?(Puppet::Pops::Model::Program) || (o.is_a?(Array) && o.empty?)
+    return find_adapter(o, Puppet::Pops::Adapters::SourcePosAdapter) unless o.is_a?(Puppet::Pops::Model::Positioned)
+    o.offset.nil? ? find_closest_positioned(o.eContainer) : Puppet::Pops::Adapters::SourcePosAdapter.adapt(o)
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/validation.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/validation.rb
new file mode 100644
index 0000000..570d42f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/validation.rb
@@ -0,0 +1,455 @@
+# A module with base functionality for validation of a model.
+#
+# * **Factory** - an abstract factory implementation that makes it easier to create a new validation factory.
+# * **SeverityProducer** - produces a severity (:error, :warning, :ignore) for a given Issue
+# * **DiagnosticProducer** - produces a Diagnostic which binds an Issue to an occurrence of that issue
+# * **Acceptor** - the receiver/sink/collector of computed diagnostics
+# * **DiagnosticFormatter** - produces human readable output for a Diagnostic
+#
+module Puppet::Pops::Validation
+
+  # This class is an abstract base implementation of a _model validation factory_ that creates a validator instance
+  # and associates it with a fully configured DiagnosticProducer.
+  #
+  # A _validator_ is responsible for validating a model. There may be different versions of validation available
+  # for one and the same model; e.g. different semantics for different puppet versions, or different types of
+  # validation configuration depending on the context/type of validation that should be performed (static, vs. runtime, etc.).
+  #
+  # This class is abstract and must be subclassed. The subclass must implement the methods
+  # {#label_provider} and {#checker}. It is also expected that the sublcass will override
+  # the severity_producer and configure the issues that should be reported as errors (i.e. if they should be ignored, produce
+  # a warning, or a deprecation warning).
+  #
+  # @abstract Subclass must implement {#checker}, and {#label_provider}
+  # @api public
+  #
+  class Factory
+
+    # Produces a validator with the given acceptor as the recipient of produced diagnostics.
+    # The acceptor is where detected issues are received (and typically collected).
+    #
+    # @param acceptor [Acceptor] the acceptor is the receiver of all detected issues
+    # @return [#validate] a validator responding to `validate(model)`
+    #
+    # @api public
+    #
+    def validator(acceptor)
+      checker(diagnostic_producer(acceptor))
+    end
+
+    # Produces the diagnostics producer to use given an acceptor of issues.
+    #
+    # @param acceptor [Acceptor] the acceptor is the receiver of all detected issues
+    # @return [DiagnosticProducer] a detector of issues
+    #
+    # @api public
+    #
+    def diagnostic_producer(acceptor)
+      Puppet::Pops::Validation::DiagnosticProducer.new(acceptor, severity_producer(), label_provider())
+    end
+
+    # Produces the SeverityProducer to use
+    # Subclasses should implement and add specific overrides
+    #
+    # @return [SeverityProducer] a severity producer producing error, warning or ignore per issue
+    #
+    # @api public
+    #
+    def severity_producer
+      Puppet::Pops::Validation::SeverityProducer.new
+    end
+
+    # Produces the checker to use.
+    #
+    # @abstract
+    #
+    # @api public
+    #
+    def checker(diagnostic_producer)
+      raise NoMethodError, "checker"
+    end
+
+    # Produces the label provider to use.
+    #
+    # @abstract
+    #
+    # @api public
+    #
+    def label_provider
+      raise NoMethodError, "label_provider"
+    end
+  end
+
+  # Decides on the severity of a given issue.
+  # The produced severity is one of `:error`, `:warning`, or `:ignore`.
+  # By default, a severity of `:error` is produced for all issues. To configure the severity
+  # of an issue call `#severity=(issue, level)`.
+  #
+  # @return [Symbol] a symbol representing the severity `:error`, `:warning`, or `:ignore`
+  #
+  # @api public
+  #
+  class SeverityProducer
+    @@severity_hash = {:ignore => true, :warning => true, :error => true, :deprecation => true }
+
+    # Creates a new instance where all issues are diagnosed as :error unless overridden.
+    # @param [Symbol] specifies default severity if :error is not wanted as the default
+    # @api public
+    #
+    def initialize(default_severity = :error)
+      # If diagnose is not set, the default is returned by the block
+      @severities = Hash.new default_severity
+    end
+
+    # Returns the severity of the given issue.
+    # @return [Symbol] severity level :error, :warning, or :ignore
+    # @api public
+    #
+    def severity(issue)
+      assert_issue(issue)
+      @severities[issue]
+    end
+
+    # @see {#severity}
+    # @api public
+    #
+    def [] issue
+      severity issue
+    end
+
+    # Override a default severity with the given severity level.
+    #
+    # @param issue [Puppet::Pops::Issues::Issue] the issue for which to set severity
+    # @param level [Symbol] the severity level (:error, :warning, or :ignore).
+    # @api public
+    #
+    def []=(issue, level)
+      raise Puppet::DevError.new("Attempt to set validation severity for something that is not an Issue. (Got #{issue.class})") unless issue.is_a? Puppet::Pops::Issues::Issue
+      raise Puppet::DevError.new("Illegal severity level: #{option}") unless @@severity_hash[level]
+      raise Puppet::DevError.new("Attempt to demote the hard issue '#{issue.issue_code}' to #{level}") unless issue.demotable? || level == :error
+      @severities[issue] = level
+    end
+
+    # Returns `true` if the issue should be reported or not.
+    # @return [Boolean] this implementation returns true for errors and warnings
+    #
+    # @api public
+    #
+    def should_report? issue
+      diagnose = @severities[issue]
+      diagnose == :error || diagnose == :warning || diagnose == :deprecation
+    end
+
+    # Checks if the given issue is valid.
+    # @api private
+    #
+    def assert_issue issue
+      raise Puppet::DevError.new("Attempt to get validation severity for something that is not an Issue. (Got #{issue.class})") unless issue.is_a? Puppet::Pops::Issues::Issue
+    end
+
+    # Checks if the given severity level is valid.
+    # @api private
+    #
+    def assert_severity level
+      raise Puppet::DevError.new("Illegal severity level: #{option}") unless @@severity_hash[level]
+    end
+  end
+
+  # A producer of diagnostics.
+  # An producer of diagnostics is given each issue occurrence as they are found by a diagnostician/validator. It then produces
+  # a Diagnostic, which it passes on to a configured Acceptor.
+  #
+  # This class exists to aid a diagnostician/validator which will typically first check if a particular issue
+  # will be accepted at all (before checking for an occurrence of the issue; i.e. to perform check avoidance for expensive checks).
+  # A validator passes an instance of Issue, the semantic object (the "culprit"), a hash with arguments, and an optional
+  # exception. The semantic object is used to determine the location of the occurrence of the issue (file/line), and it
+  # sets keys in the given argument hash that may be used in the formatting of the issue message.
+  #
+  class DiagnosticProducer
+
+    # A producer of severity for a given issue
+    # @return [SeverityProducer]
+    #
+    attr_reader :severity_producer
+
+    # A producer of labels for objects involved in the issue
+    # @return [LabelProvider]
+    #
+    attr_reader :label_provider
+    # Initializes this producer.
+    #
+    # @param acceptor [Acceptor] a sink/collector of diagnostic results
+    # @param severity_producer [SeverityProducer] the severity producer to use to determine severity of a given issue
+    # @param label_provider [LabelProvider] a provider of model element type to human readable label
+    #
+    def initialize(acceptor, severity_producer, label_provider)
+      @acceptor           = acceptor
+      @severity_producer  = severity_producer
+      @label_provider     = label_provider
+    end
+
+    def accept(issue, semantic, arguments={}, except=nil)
+      return unless will_accept? issue
+
+      # Set label provider unless caller provided a special label provider
+      arguments[:label]    ||= @label_provider
+      arguments[:semantic] ||= semantic
+
+      # A detail message is always provided, but is blank by default.
+      # TODO: this support is questionable, it requires knowledge that :detail is special
+      arguments[:detail] ||= ''
+
+      source_pos = Puppet::Pops::Utils.find_closest_positioned(semantic)
+      file = source_pos ? source_pos.locator.file : nil
+
+      severity = @severity_producer.severity(issue)
+      @acceptor.accept(Diagnostic.new(severity, issue, file, source_pos, arguments, except))
+    end
+
+    def will_accept? issue
+      @severity_producer.should_report? issue
+    end
+  end
+
+  class Diagnostic
+    attr_reader :severity
+    attr_reader :issue
+    attr_reader :arguments
+    attr_reader :exception
+    attr_reader :file
+    attr_reader :source_pos
+    def initialize severity, issue, file, source_pos, arguments={}, exception=nil
+      @severity = severity
+      @issue = issue
+      @file = file
+      @source_pos = source_pos
+      @arguments = arguments
+      # TODO: Currently unused, the intention is to provide more information (stack backtrace, etc.) when
+      # debugging or similar - this to catch internal problems reported as higher level issues.
+      @exception = exception
+    end
+
+    # Two diagnostics are considered equal if the have the same issue, location and severity
+    # (arguments and exception are ignored)
+    #
+    def ==(o)
+      self.class            == o.class             &&
+        same_position?(o)                          &&
+        issue.issue_code    == o.issue.issue_code  &&
+        file                == o.file              &&
+        severity            == o.severity
+    end
+    alias eql? ==
+
+    # Position is equal if the diagnostic is not located or if referring to the same offset
+    def same_position?(o)
+      source_pos.nil? && o.source_pos.nil? || source_pos.offset == o.source_pos.offset
+    end
+    private :same_position?
+
+    def hash
+      @hash ||= [file, source_pos.offset, issue.issue_code, severity].hash
+    end
+  end
+
+  # Formats a diagnostic for output.
+  # Produces a diagnostic output typical for a compiler (suitable for interpretation by tools)
+  # The format is:
+  # `file:line:pos: Message`, where pos, line and file are included if available.
+  #
+  class DiagnosticFormatter
+    def format diagnostic
+      "#{loc(diagnostic)} #{format_severity(diagnostic)}#{format_message(diagnostic)}"
+    end
+
+    def format_message diagnostic
+      diagnostic.issue.format(diagnostic.arguments)
+    end
+
+    # This produces "Deprecation notice: " prefix if the diagnostic has :deprecation severity, otherwise "".
+    # The idea is that all other diagnostics are emitted with the methods Puppet.err (or an exception), and
+    # Puppet.warning.
+    # @note Note that it is not a good idea to use Puppet.deprecation_warning as it is for internal deprecation.
+    #
+    def format_severity diagnostic
+      diagnostic.severity == :deprecation ? "Deprecation notice: " : ""
+    end
+
+    def format_location diagnostic
+      file = diagnostic.file
+      file = (file.is_a?(String) && file.empty?) ? nil : file
+      line = pos = nil
+      if diagnostic.source_pos
+        line = diagnostic.source_pos.line
+        pos = diagnostic.source_pos.pos
+      end
+      if file && line && pos
+        "#{file}:#{line}:#{pos}:"
+      elsif file && line
+        "#{file}:#{line}:"
+      elsif file
+        "#{file}:"
+      else
+        ""
+      end
+    end
+  end
+
+  # Produces a diagnostic output in the "puppet style", where the location is appended with an "at ..." if the
+  # location is known.
+  #
+  class DiagnosticFormatterPuppetStyle < DiagnosticFormatter
+    def format diagnostic
+      if (location = format_location diagnostic) != ""
+        "#{format_severity(diagnostic)}#{format_message(diagnostic)}#{location}"
+      else
+        format_message(diagnostic)
+      end
+    end
+
+    # The somewhat (machine) unusable format in current use by puppet.
+    # have to be used here for backwards compatibility.
+    def format_location diagnostic
+      file = diagnostic.file
+      file = (file.is_a?(String) && file.empty?) ? nil : file
+      line = pos = nil
+      if diagnostic.source_pos
+        line = diagnostic.source_pos.line
+        pos = diagnostic.source_pos.pos
+      end
+
+      if file && line && pos
+        " at #{file}:#{line}:#{pos}"
+      elsif file and line
+        " at #{file}:#{line}"
+      elsif line && pos
+        " at line #{line}:#{pos}"
+      elsif line
+        " at line #{line}"
+      elsif file
+        " in #{file}"
+      else
+        ""
+      end
+    end
+  end
+
+  # An acceptor of diagnostics.
+  # An acceptor of diagnostics is given each issue as they are found by a diagnostician/validator. An
+  # acceptor can collect all found issues, or decide to collect a few and then report, or give up as the first issue
+  # if found.
+  # This default implementation collects all diagnostics in the order they are produced, and can then
+  # answer questions about what was diagnosed.
+  #
+  class Acceptor
+
+    # All diagnostic in the order they were issued
+    attr_reader :diagnostics
+
+    # The number of :warning severity issues + number of :deprecation severity issues
+    attr_reader :warning_count
+
+    # The number of :error severity issues
+    attr_reader :error_count
+    # Initializes this diagnostics acceptor.
+    # By default, the acceptor is configured with a default severity producer.
+    # @param severity_producer [SeverityProducer] the severity producer to use to determine severity of an issue
+    #
+    # TODO add semantic_label_provider
+    #
+    def initialize()
+      @diagnostics = []
+      @error_count = 0
+      @warning_count = 0
+    end
+
+    # Returns true when errors have been diagnosed.
+    def errors?
+      @error_count > 0
+    end
+
+    # Returns true when warnings have been diagnosed.
+    def warnings?
+      @warning_count > 0
+    end
+
+    # Returns true when errors and/or warnings have been diagnosed.
+    def errors_or_warnings?
+      errors? || warnings?
+    end
+
+    # Returns the diagnosed errors in the order thwy were reported.
+    def errors
+      @diagnostics.select {|d| d.severity == :error }
+    end
+
+    # Returns the diagnosed warnings in the order thwy were reported.
+    # (This includes :warning and :deprecation severity)
+    def warnings
+      @diagnostics.select {|d| d.severity == :warning || d.severity == :deprecation }
+    end
+
+    def errors_and_warnings
+      @diagnostics.select {|d| d.severity != :ignore }
+    end
+
+    # Returns the ignored diagnostics in the order thwy were reported (if reported at all)
+    def ignored
+      @diagnostics.select {|d| d.severity == :ignore }
+    end
+
+    # Add a diagnostic, or all diagnostics from another acceptor to the set of diagnostics
+    # @param diagnostic [Puppet::Pops::Validation::Diagnostic, Puppet::Pops::Validation::Acceptor] diagnostic(s) that should be accepted
+    def accept(diagnostic)
+      if diagnostic.is_a?(Acceptor)
+        diagnostic.diagnostics.each {|d| self.send(d.severity, d)}
+      else
+        self.send(diagnostic.severity, diagnostic)
+      end
+    end
+
+    # Prunes the contain diagnostics by removing those for which the given block returns true.
+    # The internal statistics is updated as a consequence of removing.
+    # @return [Array<Puppet::Pops::Validation::Diagnostic, nil] the removed set of diagnostics or nil if nothing was removed
+    #
+    def prune(&block)
+      removed = []
+      @diagnostics.delete_if do |d|
+        if should_remove = yield(d)
+          removed << d
+        end
+        should_remove
+      end
+      removed.each do |d|
+        case d.severity
+        when :error
+          @error_count -= 1
+        when :warning
+          @warning_count -= 1
+        # there is not ignore_count
+        end
+      end
+      removed.empty? ? nil : removed
+    end
+
+    private
+
+    def ignore diagnostic
+      @diagnostics << diagnostic
+    end
+
+    def error diagnostic
+      @diagnostics << diagnostic
+      @error_count += 1
+    end
+
+    def warning diagnostic
+      @diagnostics << diagnostic
+      @warning_count += 1
+    end
+
+    def deprecation diagnostic
+      warning diagnostic
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/validation/checker4_0.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/validation/checker4_0.rb
new file mode 100644
index 0000000..de10ff7
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/validation/checker4_0.rb
@@ -0,0 +1,812 @@
+# A Validator validates a model.
+#
+# Validation is performed on each model element in isolation. Each method should validate the model element's state
+# but not validate its referenced/contained elements except to check their validity in their respective role.
+# The intent is to drive the validation with a tree iterator that visits all elements in a model.
+#
+#
+# TODO: Add validation of multiplicities - this is a general validation that can be checked for all
+#       Model objects via their metamodel. (I.e an extra call to multiplicity check in polymorph check).
+#       This is however mostly valuable when validating model to model transformations, and is therefore T.B.D
+#
+class Puppet::Pops::Validation::Checker4_0
+  Issues = Puppet::Pops::Issues
+  Model = Puppet::Pops::Model
+
+  attr_reader :acceptor
+  attr_reader :migration_checker
+
+  # Initializes the validator with a diagnostics producer. This object must respond to
+  # `:will_accept?` and `:accept`.
+  #
+  def initialize(diagnostics_producer)
+    @@check_visitor       ||= Puppet::Pops::Visitor.new(nil, "check", 0, 0)
+    @@rvalue_visitor      ||= Puppet::Pops::Visitor.new(nil, "rvalue", 0, 0)
+    @@hostname_visitor    ||= Puppet::Pops::Visitor.new(nil, "hostname", 1, 2)
+    @@assignment_visitor  ||= Puppet::Pops::Visitor.new(nil, "assign", 0, 1)
+    @@query_visitor       ||= Puppet::Pops::Visitor.new(nil, "query", 0, 0)
+    @@top_visitor         ||= Puppet::Pops::Visitor.new(nil, "top", 1, 1)
+    @@relation_visitor    ||= Puppet::Pops::Visitor.new(nil, "relation", 0, 0)
+    @@idem_visitor        ||= Puppet::Pops::Visitor.new(self, "idem", 0, 0)
+
+    @acceptor = diagnostics_producer
+
+    # Use null migration checker unless given in context
+    @migration_checker ||= (Puppet.lookup(:migration_checker) { Puppet::Pops::Migration::MigrationChecker.new() })
+  end
+
+  # Validates the entire model by visiting each model element and calling `check`.
+  # The result is collected (or acted on immediately) by the configured diagnostic provider/acceptor
+  # given when creating this Checker.
+  #
+  def validate(model)
+    # tree iterate the model, and call check for each element
+    check(model)
+    model.eAllContents.each {|m| check(m) }
+  end
+
+  # Performs regular validity check
+  def check(o)
+    @@check_visitor.visit_this_0(self, o)
+  end
+
+  # Performs check if this is a vaid hostname expression
+  # @param single_feature_name [String, nil] the name of a single valued hostname feature of the value's container. e.g. 'parent'
+  def hostname(o, semantic, single_feature_name = nil)
+    @@hostname_visitor.visit_this_2(self, o, semantic, single_feature_name)
+  end
+
+  # Performs check if this is valid as a query
+  def query(o)
+    @@query_visitor.visit_this_0(self, o)
+  end
+
+  # Performs check if this is valid as a relationship side
+  def relation(o)
+    @@relation_visitor.visit_this_0(self, o)
+  end
+
+  # Performs check if this is valid as a rvalue
+  def rvalue(o)
+    @@rvalue_visitor.visit_this_0(self, o)
+  end
+
+  # Performs check if this is valid as a container of a definition (class, define, node)
+  def top(o, definition)
+    @@top_visitor.visit_this_1(self, o, definition)
+  end
+
+  # Checks the LHS of an assignment (is it assignable?).
+  # If args[0] is true, assignment via index is checked.
+  #
+  def assign(o, via_index = false)
+    @@assignment_visitor.visit_this_1(self, o, via_index)
+  end
+
+  # Checks if the expression has side effect ('idem' is latin for 'the same', here meaning that the evaluation state
+  # is known to be unchanged after the expression has been evaluated). The result is not 100% authoritative for
+  # negative answers since analysis of function behavior is not possible.
+  # @return [Boolean] true if expression is known to have no effect on evaluation state
+  #
+  def idem(o)
+    @@idem_visitor.visit_this_0(self, o)
+  end
+
+  # Returns the last expression in a block, or the expression, if that expression is idem
+  def ends_with_idem(o)
+    if o.is_a?(Puppet::Pops::Model::BlockExpression)
+      last = o.statements[-1]
+      idem(last) ? last : nil
+    else
+      idem(o) ? o : nil
+    end
+  end
+
+  #---ASSIGNMENT CHECKS
+
+  def assign_VariableExpression(o, via_index)
+    varname_string = varname_to_s(o.expr)
+    if varname_string =~ Puppet::Pops::Patterns::NUMERIC_VAR_NAME
+      acceptor.accept(Issues::ILLEGAL_NUMERIC_ASSIGNMENT, o, :varname => varname_string)
+    end
+    # Can not assign to something in another namespace (i.e. a '::' in the name is not legal)
+    if acceptor.will_accept? Issues::CROSS_SCOPE_ASSIGNMENT
+      if varname_string =~ /::/
+        acceptor.accept(Issues::CROSS_SCOPE_ASSIGNMENT, o, :name => varname_string)
+      end
+    end
+    # TODO: Could scan for reassignment of the same variable if done earlier in the same container
+    #       Or if assigning to a parameter (more work).
+    # TODO: Investigate if there are invalid cases for += assignment
+  end
+
+  def assign_AccessExpression(o, via_index)
+    # Are indexed assignments allowed at all ? $x[x] = '...'
+    if acceptor.will_accept? Issues::ILLEGAL_INDEXED_ASSIGNMENT
+      acceptor.accept(Issues::ILLEGAL_INDEXED_ASSIGNMENT, o)
+    else
+      # Then the left expression must be assignable-via-index
+      assign(o.left_expr, true)
+    end
+  end
+
+  def assign_Object(o, via_index)
+    # Can not assign to anything else (differentiate if this is via index or not)
+    # i.e. 10 = 'hello' vs. 10['x'] = 'hello' (the root is reported as being in error in both cases)
+    #
+    acceptor.accept(via_index ? Issues::ILLEGAL_ASSIGNMENT_VIA_INDEX : Issues::ILLEGAL_ASSIGNMENT, o)
+  end
+
+  #---CHECKS
+
+  def check_Object(o)
+  end
+
+  def check_Factory(o)
+    check(o.current)
+  end
+
+  def check_AccessExpression(o)
+    # Only min range is checked, all other checks are RT checks as they depend on the resulting type
+    # of the LHS.
+    if o.keys.size < 1
+      acceptor.accept(Issues::MISSING_INDEX, o)
+    end
+  end
+
+  def check_AssignmentExpression(o)
+    case o.operator
+    when :'='
+      assign(o.left_expr)
+      rvalue(o.right_expr)
+    when :'+=', :'-='
+      acceptor.accept(Issues::APPENDS_DELETES_NO_LONGER_SUPPORTED, o, {:operator => o.operator})
+    else
+      acceptor.accept(Issues::UNSUPPORTED_OPERATOR, o, {:operator => o.operator})
+    end
+  end
+
+  # Checks that operation with :+> is contained in a ResourceOverride or Collector.
+  #
+  # Parent of an AttributeOperation can be one of:
+  # * CollectExpression
+  # * ResourceOverride
+  # * ResourceBody (ILLEGAL this is a regular resource expression)
+  # * ResourceDefaults (ILLEGAL)
+  #
+  def check_AttributeOperation(o)
+    if o.operator == :'+>'
+      # Append operator use is constrained
+      parent = o.eContainer
+      unless parent.is_a?(Model::CollectExpression) || parent.is_a?(Model::ResourceOverrideExpression)
+        acceptor.accept(Issues::ILLEGAL_ATTRIBUTE_APPEND, o, {:name=>o.attribute_name, :parent=>parent})
+      end
+    end
+    rvalue(o.value_expr)
+  end
+
+  def check_AttributesOperation(o)
+    # Append operator use is constrained
+    parent1 = o.eContainer
+    case parent1
+    when Model::AbstractResource
+    when Model::CollectExpression
+    else
+      # protect against just testing a snippet that has no parent, error message will be a bit strange
+      # but it is not for a real program.
+      parent2 = parent1.nil? ? o : parent1.eContainer
+      unless parent2.is_a?(Model::AbstractResource)
+        acceptor.accept(Issues::UNSUPPORTED_OPERATOR_IN_CONTEXT, parent2, :operator=>'* =>')
+      end
+    end
+    rvalue(o.expr)
+  end
+
+  def check_BinaryExpression(o)
+    rvalue(o.left_expr)
+    rvalue(o.right_expr)
+  end
+
+  def check_BlockExpression(o)
+    o.statements[0..-2].each do |statement|
+      if idem(statement)
+        acceptor.accept(Issues::IDEM_EXPRESSION_NOT_LAST, statement)
+        break # only flag the first
+      end
+    end
+    migration_checker.report_array_last_in_block(o.statements[-1])
+  end
+
+  def check_CallNamedFunctionExpression(o)
+    case o.functor_expr
+    when Puppet::Pops::Model::QualifiedName
+      # ok
+      nil
+    when Puppet::Pops::Model::RenderStringExpression
+      # helpful to point out this easy to make Epp error
+      acceptor.accept(Issues::ILLEGAL_EPP_PARAMETERS, o)
+    else
+      acceptor.accept(Issues::ILLEGAL_EXPRESSION, o.functor_expr, {:feature=>'function name', :container => o})
+    end
+  end
+
+  def check_EppExpression(o)
+    if o.eContainer.is_a?(Puppet::Pops::Model::LambdaExpression)
+      internal_check_no_capture(o.eContainer, o)
+      internal_check_parameter_name_uniqueness(o.eContainer)
+    end
+  end
+
+  def check_MethodCallExpression(o)
+    unless o.functor_expr.is_a? Model::QualifiedName
+      acceptor.accept(Issues::ILLEGAL_EXPRESSION, o.functor_expr, :feature => 'function name', :container => o)
+    end
+  end
+
+  def check_CaseExpression(o)
+    rvalue(o.test)
+    # There should only be one LiteralDefault case option value
+    # TODO: Implement this check
+  end
+
+  def check_CaseOption(o)
+    o.values.each { |v| rvalue(v) }
+  end
+
+  def check_CollectExpression(o)
+    unless o.type_expr.is_a? Model::QualifiedReference
+      acceptor.accept(Issues::ILLEGAL_EXPRESSION, o.type_expr, :feature=> 'type name', :container => o)
+    end
+
+    # If a collect expression tries to collect exported resources and storeconfigs is not on
+    # then it will not work... This was checked in the parser previously. This is a runtime checking
+    # thing as opposed to a language thing.
+    if acceptor.will_accept?(Issues::RT_NO_STORECONFIGS) && o.query.is_a?(Model::ExportedQuery)
+      acceptor.accept(Issues::RT_NO_STORECONFIGS, o)
+    end
+  end
+
+  # Only used for function names, grammar should not be able to produce something faulty, but
+  # check anyway if model is created programatically (it will fail in transformation to AST for sure).
+  def check_NamedAccessExpression(o)
+    name = o.right_expr
+    unless name.is_a? Model::QualifiedName
+      acceptor.accept(Issues::ILLEGAL_EXPRESSION, name, :feature=> 'function name', :container => o.eContainer)
+    end
+  end
+
+  RESERVED_TYPE_NAMES = {
+    'type' => true,
+    'any' => true,
+    'unit' => true,
+    'scalar' => true,
+    'boolean' => true,
+    'numeric' => true,
+    'integer' => true,
+    'float' => true,
+    'collection' => true,
+    'array' => true,
+    'hash' => true,
+    'tuple' => true,
+    'struct' => true,
+    'variant' => true,
+    'optional' => true,
+    'enum' => true,
+    'regexp' => true,
+    'pattern' => true,
+    'runtime' => true,
+  }
+
+  FUTURE_RESERVED_WORDS = {
+    'application' => true,
+    'produces' => true,
+    'consumes' => true
+  }
+
+  # for 'class', 'define', and function
+  def check_NamedDefinition(o)
+    top(o.eContainer, o)
+    if o.name !~ Puppet::Pops::Patterns::CLASSREF
+      acceptor.accept(Issues::ILLEGAL_DEFINITION_NAME, o, {:name=>o.name})
+    end
+
+    if RESERVED_TYPE_NAMES[o.name()]
+      acceptor.accept(Issues::RESERVED_TYPE_NAME, o, {:name => o.name})
+    end
+
+    # This is perhaps not ideal but it's very difficult to pass a ReservedWord through
+    # the mechanism that creates qualified names (namestack, namepop etc.)
+    if FUTURE_RESERVED_WORDS[o.name]
+      acceptor.accept(Issues::FUTURE_RESERVED_WORD, o, {:word => o.name})
+    end
+
+    if violator = ends_with_idem(o.body)
+      acceptor.accept(Issues::IDEM_NOT_ALLOWED_LAST, violator, {:container => o})
+    end
+  end
+
+  def check_HostClassDefinition(o)
+    check_NamedDefinition(o)
+    internal_check_no_capture(o)
+    internal_check_parameter_name_uniqueness(o)
+    internal_check_reserved_params(o)
+  end
+
+  def check_ResourceTypeDefinition(o)
+    check_NamedDefinition(o)
+    internal_check_no_capture(o)
+    internal_check_parameter_name_uniqueness(o)
+    internal_check_reserved_params(o)
+  end
+
+  def internal_check_capture_last(o)
+    accepted_index = o.parameters.size() -1
+    o.parameters.each_with_index do |p, index|
+      if p.captures_rest && index != accepted_index
+        acceptor.accept(Issues::CAPTURES_REST_NOT_LAST, p, {:param_name => p.name})
+      end
+    end
+  end
+
+  def internal_check_no_capture(o, container = o)
+    o.parameters.each do |p|
+      if p.captures_rest
+        acceptor.accept(Issues::CAPTURES_REST_NOT_SUPPORTED, p, {:container => container, :param_name => p.name})
+      end
+    end
+  end
+
+  RESERVED_PARAMETERS = {
+    'name' => true,
+    'title' => true,
+  }
+
+  def internal_check_reserved_params(o)
+    o.parameters.each do |p|
+      if RESERVED_PARAMETERS[p.name]
+        acceptor.accept(Issues::RESERVED_PARAMETER, p, {:container => o, :param_name => p.name})
+      end
+    end
+  end
+
+  def internal_check_parameter_name_uniqueness(o)
+    unique = Set.new
+    o.parameters.each do |p|
+      acceptor.accept(Issues::DUPLICATE_PARAMETER, p, {:param_name => p.name}) unless unique.add?(p.name)
+    end
+  end
+
+  def check_IfExpression(o)
+    rvalue(o.test)
+  end
+
+  def check_KeyedEntry(o)
+    rvalue(o.key)
+    rvalue(o.value)
+    # In case there are additional things to forbid than non-rvalues
+    # acceptor.accept(Issues::ILLEGAL_EXPRESSION, o.key, :feature => 'hash key', :container => o.eContainer)
+  end
+
+  def check_LambdaExpression(o)
+    internal_check_capture_last(o)
+  end
+
+  def check_LiteralList(o)
+    o.values.each {|v| rvalue(v) }
+  end
+
+  def check_LiteralFloat(o)
+    migration_checker.report_ambiguous_float(o)
+  end
+
+  def check_LiteralInteger(o)
+    migration_checker.report_ambiguous_integer(o)
+  end
+
+  def check_NodeDefinition(o)
+    # Check that hostnames are valid hostnames (or regular expressions)
+    hostname(o.host_matches, o)
+    hostname(o.parent, o, 'parent') unless o.parent.nil?
+    top(o.eContainer, o)
+    if violator = ends_with_idem(o.body)
+      acceptor.accept(Issues::IDEM_NOT_ALLOWED_LAST, violator, {:container => o})
+    end
+    unless o.parent.nil?
+      acceptor.accept(Issues::ILLEGAL_NODE_INHERITANCE, o.parent)
+    end
+  end
+
+  # No checking takes place - all expressions using a QualifiedName need to check. This because the
+  # rules are slightly different depending on the container (A variable allows a numeric start, but not
+  # other names). This means that (if the lexer/parser so chooses) a QualifiedName
+  # can be anything when it represents a Bare Word and evaluates to a String.
+  #
+  def check_QualifiedName(o)
+  end
+
+  # Checks that the value is a valid UpperCaseWord (a CLASSREF), and optionally if it contains a hypen.
+  # DOH: QualifiedReferences are created with LOWER CASE NAMES at parse time
+  def check_QualifiedReference(o)
+    # Is this a valid qualified name?
+    if o.value !~ Puppet::Pops::Patterns::CLASSREF
+      acceptor.accept(Issues::ILLEGAL_CLASSREF, o, {:name=>o.value})
+    end
+  end
+
+  def check_QueryExpression(o)
+    query(o.expr) if o.expr  # is optional
+  end
+
+  def relation_Object(o)
+    rvalue(o)
+  end
+
+  def relation_CollectExpression(o); end
+
+  def relation_RelationshipExpression(o); end
+
+  def check_Parameter(o)
+    if o.name =~ /^(?:0x)?[0-9]+$/
+      acceptor.accept(Issues::ILLEGAL_NUMERIC_PARAMETER, o, :name => o.name)
+    end
+
+    unless o.name =~ Puppet::Pops::Patterns::PARAM_NAME
+      acceptor.accept(Issues::ILLEGAL_PARAM_NAME, o, :name => o.name)
+    end
+  end
+
+  #relationship_side: resource
+  #  | resourceref
+  #  | collection
+  #  | variable
+  #  | quotedtext
+  #  | selector
+  #  | casestatement
+  #  | hasharrayaccesses
+
+  def check_RelationshipExpression(o)
+    relation(o.left_expr)
+    relation(o.right_expr)
+  end
+
+  def check_ResourceExpression(o)
+    # The expression for type name cannot be statically checked - this is instead done at runtime
+    # to enable better error message of the result of the expression rather than the static instruction.
+    # (This can be revised as there are static constructs that are illegal, but require updating many
+    # tests that expect the detailed reporting).
+  end
+
+  def check_ResourceBody(o)
+    seenUnfolding = false
+    o.operations.each do |ao|
+      if ao.is_a?(Puppet::Pops::Model::AttributesOperation)
+        if seenUnfolding
+          acceptor.accept(Issues::MULTIPLE_ATTRIBUTES_UNFOLD, ao)
+        else
+          seenUnfolding = true
+        end
+      end
+    end
+  end
+
+  def check_ResourceDefaultsExpression(o)
+    if o.form && o.form != :regular
+      acceptor.accept(Issues::NOT_VIRTUALIZEABLE, o)
+    end
+  end
+
+  def check_ResourceOverrideExpression(o)
+    if o.form && o.form != :regular
+      acceptor.accept(Issues::NOT_VIRTUALIZEABLE, o)
+    end
+  end
+
+  def check_ReservedWord(o)
+    if o.future
+      acceptor.accept(Issues::FUTURE_RESERVED_WORD, o, :word => o.word)
+    else
+      acceptor.accept(Issues::RESERVED_WORD, o, :word => o.word)
+    end
+  end
+
+  def check_SelectorExpression(o)
+    rvalue(o.left_expr)
+  end
+
+  def check_SelectorEntry(o)
+    rvalue(o.matching_expr)
+  end
+
+  def check_UnaryExpression(o)
+    rvalue(o.expr)
+  end
+
+  def check_UnlessExpression(o)
+    rvalue(o.test)
+    # TODO: Unless may not have an else part that is an IfExpression (grammar denies this though)
+  end
+
+  # Checks that variable is either strictly 0, or a non 0 starting decimal number, or a valid VAR_NAME
+  def check_VariableExpression(o)
+    # The expression must be a qualified name or an integer
+    name_expr = o.expr
+    return if name_expr.is_a?(Model::LiteralInteger)
+    if !name_expr.is_a?(Model::QualifiedName)
+      acceptor.accept(Issues::ILLEGAL_EXPRESSION, o, :feature => 'name', :container => o)
+    else
+      # name must be either a decimal string value, or a valid NAME
+      name = o.expr.value
+      if name[0,1] =~ /[0-9]/
+        unless name =~ Puppet::Pops::Patterns::NUMERIC_VAR_NAME
+          acceptor.accept(Issues::ILLEGAL_NUMERIC_VAR_NAME, o, :name => name)
+        end
+      else
+        unless name =~ Puppet::Pops::Patterns::VAR_NAME
+          acceptor.accept(Issues::ILLEGAL_VAR_NAME, o, :name => name)
+        end
+      end
+    end
+  end
+
+  #--- HOSTNAME CHECKS
+
+  # Transforms Array of host matching expressions into a (Ruby) array of AST::HostName
+  def hostname_Array(o, semantic, single_feature_name)
+    if single_feature_name
+      acceptor.accept(Issues::ILLEGAL_EXPRESSION, o, {:feature=>single_feature_name, :container=>semantic})
+    end
+    o.each {|x| hostname(x, semantic, false) }
+  end
+
+  def hostname_String(o, semantic, single_feature_name)
+    # The 3.x checker only checks for illegal characters - if matching /[^-\w.]/ the name is invalid,
+    # but this allows pathological names like "a..b......c", "----"
+    # TODO: Investigate if more illegal hostnames should be flagged.
+    #
+    if o =~ Puppet::Pops::Patterns::ILLEGAL_HOSTNAME_CHARS
+      acceptor.accept(Issues::ILLEGAL_HOSTNAME_CHARS, semantic, :hostname => o)
+    end
+  end
+
+  def hostname_LiteralValue(o, semantic, single_feature_name)
+    hostname_String(o.value.to_s, o, single_feature_name)
+  end
+
+  def hostname_ConcatenatedString(o, semantic, single_feature_name)
+    # Puppet 3.1. only accepts a concatenated string without interpolated expressions
+    if the_expr = o.segments.index {|s| s.is_a?(Model::TextExpression) }
+      acceptor.accept(Issues::ILLEGAL_HOSTNAME_INTERPOLATION, o.segments[the_expr].expr)
+    elsif o.segments.size() != 1
+      # corner case, bad model, concatenation of several plain strings
+      acceptor.accept(Issues::ILLEGAL_HOSTNAME_INTERPOLATION, o)
+    else
+      # corner case, may be ok, but lexer may have replaced with plain string, this is
+      # here if it does not
+      hostname_String(o.segments[0], o.segments[0], false)
+    end
+  end
+
+  def hostname_QualifiedName(o, semantic, single_feature_name)
+    hostname_String(o.value.to_s, o, single_feature_name)
+  end
+
+  def hostname_QualifiedReference(o, semantic, single_feature_name)
+    hostname_String(o.value.to_s, o, single_feature_name)
+  end
+
+  def hostname_LiteralNumber(o, semantic, single_feature_name)
+    # always ok
+  end
+
+  def hostname_LiteralDefault(o, semantic, single_feature_name)
+    # always ok
+  end
+
+  def hostname_LiteralRegularExpression(o, semantic, single_feature_name)
+    # always ok
+  end
+
+  def hostname_Object(o, semantic, single_feature_name)
+    acceptor.accept(Issues::ILLEGAL_EXPRESSION, o, {:feature=> single_feature_name || 'hostname', :container=>semantic})
+  end
+
+  #---QUERY CHECKS
+
+  # Anything not explicitly allowed is flagged as error.
+  def query_Object(o)
+    acceptor.accept(Issues::ILLEGAL_QUERY_EXPRESSION, o)
+  end
+
+  # Puppet AST only allows == and !=
+  #
+  def query_ComparisonExpression(o)
+    acceptor.accept(Issues::ILLEGAL_QUERY_EXPRESSION, o) unless [:'==', :'!='].include? o.operator
+  end
+
+  # Allows AND, OR, and checks if left/right are allowed in query.
+  def query_BooleanExpression(o)
+    query o.left_expr
+    query o.right_expr
+  end
+
+  def query_ParenthesizedExpression(o)
+    query(o.expr)
+  end
+
+  def query_VariableExpression(o); end
+
+  def query_QualifiedName(o); end
+
+  def query_LiteralNumber(o); end
+
+  def query_LiteralString(o); end
+
+  def query_LiteralBoolean(o); end
+
+  #---RVALUE CHECKS
+
+  # By default, all expressions are reported as being rvalues
+  # Implement specific rvalue checks for those that are not.
+  #
+  def rvalue_Expression(o); end
+
+  def rvalue_CollectExpression(o)         ; acceptor.accept(Issues::NOT_RVALUE, o) ; end
+
+  def rvalue_Definition(o)                ; acceptor.accept(Issues::NOT_RVALUE, o) ; end
+
+  def rvalue_NodeDefinition(o)            ; acceptor.accept(Issues::NOT_RVALUE, o) ; end
+
+  def rvalue_UnaryExpression(o)           ; rvalue o.expr                 ; end
+
+  #---TOP CHECK
+
+  def top_NilClass(o, definition)
+    # ok, reached the top, no more parents
+  end
+
+  def top_Object(o, definition)
+    # fail, reached a container that is not top level
+    acceptor.accept(Issues::NOT_TOP_LEVEL, definition)
+  end
+
+  def top_BlockExpression(o, definition)
+    # ok, if this is a block representing the body of a class, or is top level
+    top o.eContainer, definition
+  end
+
+  def top_HostClassDefinition(o, definition)
+    # ok, stop scanning parents
+  end
+
+  def top_Program(o, definition)
+    # ok
+  end
+
+  # A LambdaExpression is a BlockExpression, and this method is needed to prevent the polymorph method for BlockExpression
+  # to accept a lambda.
+  # A lambda can not iteratively create classes, nodes or defines as the lambda does not have a closure.
+  #
+  def top_LambdaExpression(o, definition)
+    # fail, stop scanning parents
+    acceptor.accept(Issues::NOT_TOP_LEVEL, definition)
+  end
+
+  #--IDEM CHECK
+  def idem_Object(o)
+    false
+  end
+
+  def idem_Nop(o)
+    true
+  end
+
+  def idem_NilClass(o)
+    true
+  end
+
+  def idem_Literal(o)
+    true
+  end
+
+  def idem_LiteralList(o)
+    true
+  end
+
+  def idem_LiteralHash(o)
+    true
+  end
+
+  def idem_Factory(o)
+    idem(o.current)
+  end
+
+  def idem_AccessExpression(o)
+    true
+  end
+
+  def idem_BinaryExpression(o)
+    true
+  end
+
+  def idem_RelationshipExpression(o)
+    # Always side effect
+    false
+  end
+
+  def idem_AssignmentExpression(o)
+    # Always side effect
+    false
+  end
+
+  # Handles UnaryMinusExpression, NotExpression, VariableExpression
+  def idem_UnaryExpression(o)
+    true
+  end
+
+  # Allow (no-effect parentheses) to be used around a productive expression
+  def idem_ParenthesizedExpression(o)
+    idem(o.expr)
+  end
+
+  def idem_RenderExpression(o)
+    false
+  end
+
+  def idem_RenderStringExpression(o)
+    false
+  end
+
+  def idem_BlockExpression(o)
+    # productive if there is at least one productive expression
+    ! o.statements.any? {|expr| !idem(expr) }
+  end
+
+  # Returns true even though there may be interpolated expressions that have side effect.
+  # Report as idem anyway, as it is very bad design to evaluate an interpolated string for its
+  # side effect only.
+  def idem_ConcatenatedString(o)
+    true
+  end
+
+  # Heredoc is just a string, but may contain interpolated string (which may have side effects).
+  # This is still bad design and should be reported as idem.
+  def idem_HeredocExpression(o)
+    true
+  end
+
+  # May technically have side effects inside the Selector, but this is bad design - treat as idem
+  def idem_SelectorExpression(o)
+    true
+  end
+
+  def idem_IfExpression(o)
+    [o.test, o.then_expr, o.else_expr].all? {|e| idem(e) }
+  end
+
+  # Case expression is idem, if test, and all options are idem
+  def idem_CaseExpression(o)
+    return false if !idem(o.test)
+    ! o.options.any? {|opt| !idem(opt) }
+  end
+
+  # An option is idem if values and the then_expression are idem
+  def idem_CaseOption(o)
+    return false if o.values.any? { |value| !idem(value) }
+    idem(o.then_expr)
+  end
+
+  #--- NON POLYMORPH, NON CHECKING CODE
+
+  # Produces string part of something named, or nil if not a QualifiedName or QualifiedReference
+  #
+  def varname_to_s(o)
+    case o
+    when Model::QualifiedName
+      o.value
+    when Model::QualifiedReference
+      o.value
+    else
+      nil
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/validation/validator_factory_4_0.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/validation/validator_factory_4_0.rb
new file mode 100644
index 0000000..fe7acc5
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/validation/validator_factory_4_0.rb
@@ -0,0 +1,32 @@
+# Configures validation suitable for 4.0
+#
+class Puppet::Pops::Validation::ValidatorFactory_4_0 < Puppet::Pops::Validation::Factory
+  Issues = Puppet::Pops::Issues
+
+  # Produces the checker to use
+  def checker diagnostic_producer
+    Puppet::Pops::Validation::Checker4_0.new(diagnostic_producer)
+  end
+
+  # Produces the label provider to use
+  def label_provider
+    Puppet::Pops::Model::ModelLabelProvider.new()
+  end
+
+  # Produces the severity producer to use
+  def severity_producer
+    p = super
+
+    # Configure each issue that should **not** be an error
+    #
+    # Validate as per the current runtime configuration
+    p[Issues::RT_NO_STORECONFIGS_EXPORT]    = Puppet[:storeconfigs] ? :ignore : :warning
+    p[Issues::RT_NO_STORECONFIGS]           = Puppet[:storeconfigs] ? :ignore : :warning
+
+    p[Issues::FUTURE_RESERVED_WORD]          = :deprecation
+
+    p[Issues::NAME_WITH_HYPHEN]              = :error
+    p[Issues::EMPTY_RESOURCE_SPECIALIZATION] = :ignore
+    p
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/visitable.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/visitable.rb
new file mode 100644
index 0000000..2f72e37
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/visitable.rb
@@ -0,0 +1,6 @@
+# Visitable is a mix-in module that makes a class visitable by a Visitor
+module Puppet::Pops::Visitable
+  def accept(visitor, *arguments)
+    visitor.visit(self, *arguments)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/visitor.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/visitor.rb
new file mode 100644
index 0000000..baae887
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/pops/visitor.rb
@@ -0,0 +1,89 @@
+# A Visitor performs delegation to a given receiver based on the configuration of the Visitor.
+# A new visitor is created with a given receiver, a method prefix, min, and max argument counts.
+# e.g.
+#   vistor = Visitor.new(self, "visit_from", 1, 1)
+# will make the visitor call "self.visit_from_CLASS(x)" where CLASS is resolved to the given
+# objects class, or one of is ancestors, the first class for which there is an implementation of
+# a method will be selected.
+#
+# Raises RuntimeError if there are too few or too many arguments, or if the receiver is not
+# configured to handle a given visiting object.
+#
+class Puppet::Pops::Visitor
+  attr_reader :receiver, :message, :min_args, :max_args, :cache
+  def initialize(receiver, message, min_args=0, max_args=nil)
+    raise ArgumentError.new("min_args must be >= 0") if min_args < 0
+    raise ArgumentError.new("max_args must be >= min_args or nil") if max_args && max_args < min_args
+
+    @receiver = receiver
+    @message = message
+    @min_args = min_args
+    @max_args = max_args
+    @cache = Hash.new
+  end
+
+  # Visit the configured receiver
+  def visit(thing, *args)
+    visit_this(@receiver, thing, *args)
+  end
+
+  # Visit an explicit receiver
+  def visit_this(receiver, thing, *args)
+    raise "Visitor Error: Too few arguments passed. min = #{@min_args}" unless args.length >= @min_args
+    if @max_args
+      raise "Visitor Error: Too many arguments passed. max = #{@max_args}" unless args.length <= @max_args
+    end
+    if method_name = @cache[thing.class]
+      return receiver.send(method_name, thing, *args)
+    else
+      thing.class.ancestors().each do |ancestor|
+        method_name = :"#{@message}_#{ancestor.name.split(/::/).last}"
+        next unless receiver.respond_to?(method_name, true)
+        @cache[thing.class] = method_name
+        return receiver.send(method_name, thing, *args)
+      end
+    end
+    raise "Visitor Error: the configured receiver (#{receiver.class}) can't handle instance of: #{thing.class}"
+  end
+
+  # Visit an explicit receiver with 0 args
+  # (This is ~30% faster than calling the general method)
+  #
+  def visit_this_0(receiver, thing)
+    if method_name = @cache[thing.class]
+      return receiver.send(method_name, thing)
+    end
+    visit_this(receiver, thing)
+  end
+
+  # Visit an explicit receiver with 1 args
+  # (This is ~30% faster than calling the general method)
+  #
+  def visit_this_1(receiver, thing, arg)
+    if method_name = @cache[thing.class]
+      return receiver.send(method_name, thing, arg)
+    end
+    visit_this(receiver, thing, arg)
+  end
+
+  # Visit an explicit receiver with 2 args
+  # (This is ~30% faster than calling th general method)
+  #
+  def visit_this_2(receiver, thing, arg1, arg2)
+    if method_name = @cache[thing.class]
+      return receiver.send(method_name, thing, arg1, arg2)
+    end
+    visit_this(receiver, thing, arg1, arg2)
+  end
+
+  # Visit an explicit receiver with 3 args
+  # (This is ~30% faster than calling the general method)
+  #
+  def visit_this_3(receiver, thing, arg1, arg2, arg3)
+    if method_name = @cache[thing.class]
+      return receiver.send(method_name, thing, arg1, arg2, arg3)
+    end
+    visit_this(receiver, thing, arg1, arg2, arg3)
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/property.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/property.rb
new file mode 100644
index 0000000..841f867
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/property.rb
@@ -0,0 +1,617 @@
+# The virtual base class for properties, which are the self-contained building
+# blocks for actually doing work on the system.
+
+require 'puppet'
+require 'puppet/parameter'
+
+# The Property class is the implementation of a resource's attributes of _property_ kind.
+# A Property is a specialized Resource Type Parameter that has both an 'is' (current) state, and
+# a 'should' (wanted state). However, even if this is conceptually true, the current _is_ value is
+# obtained by asking the associated provider for the value, and hence it is not actually part of a
+# property's state, and only available when a provider has been selected and can obtain the value (i.e. when
+# running on an agent).
+#
+# A Property (also in contrast to a parameter) is intended to describe a managed attribute of
+# some system entity, such as the name or mode of a file.
+#
+# The current value _(is)_ is read and written with the methods {#retrieve} and {#set}, and the wanted
+# value _(should)_ is read and written with the methods {#value} and {#value=} which delegate to
+# {#should} and {#should=}, i.e. when a property is used like any other parameter, it is the _should_ value
+# that is operated on.
+#
+# All resource type properties in the puppet system are derived from this class.
+#
+# The intention is that new parameters are created by using the DSL method {Puppet::Type.newproperty}.
+#
+# @abstract
+# @note Properties of Types are expressed using subclasses of this class. Such a class describes one
+#   named property of a particular Type (as opposed to describing a type of property in general). This
+#   limits the use of one (concrete) property class instance to occur only once for a given type's inheritance
+#   chain. An instance of a Property class is the value holder of one instance of the resource type (e.g. the
+#   mode of a file resource instance).
+#   A Property class may server as the superclass _(parent)_ of another; e.g. a Size property that describes
+#   handling of measurements such as kb, mb, gb. If a type requires two different size measurements it requires
+#   one concrete class per such measure; e.g. MinSize (:parent => Size), and MaxSize (:parent => Size).
+#
+# @todo Describe meta-parameter shadowing. This concept can not be understood by just looking at the descriptions
+#   of the methods involved.
+#
+# @see Puppet::Type
+# @see Puppet::Parameter
+#
+# @api public
+#
+class Puppet::Property < Puppet::Parameter
+  require 'puppet/property/ensure'
+
+  # Returns the original wanted value(s) _(should)_ unprocessed by munging/unmunging.
+  # The original values are set by {#value=} or {#should=}.
+  # @return (see #should)
+  #
+  attr_reader :shouldorig
+
+  # The noop mode for this property.
+  # By setting a property's noop mode to `true`, any management of this property is inhibited. Calculation
+  # and reporting still takes place, but if a change of the underlying managed entity's state
+  # should take place it will not be carried out. This noop
+  # setting overrides the overall `Puppet[:noop]` mode as well as the noop mode in the _associated resource_
+  #
+  attr_writer :noop
+
+  class << self
+    # @todo Figure out what this is used for. Can not find any logic in the puppet code base that
+    #   reads or writes this attribute.
+    # ??? Probably Unused
+    attr_accessor :unmanaged
+
+    # @return [Symbol] The name of the property as given when the property was created.
+    #
+    attr_reader :name
+
+    # @!attribute [rw] array_matching
+    # @comment note that $#46; is a period - char code require to not terminate sentence.
+    # The `is` vs&#46; `should` array matching mode; `:first`, or `:all`.
+    #
+    # @comment there are two blank chars after the symbols to cause a break - do not remove these.
+    # * `:first`
+    #   This is primarily used for single value properties. When matched against an array of values
+    #   a match is true if the `is` value matches any of the values in the `should` array. When the `is` value
+    #   is also an array, the matching is performed against the entire array as the `is` value.
+    # * `:all`
+    #   : This is primarily used for multi-valued properties. When matched against an array of
+    #     `should` values, the size of `is` and `should` must be the same, and all values in `is` must match
+    #     a value in `should`.
+    #
+    # @note The semantics of these modes are implemented by the method {#insync?}. That method is the default
+    #   implementation and it has a backwards compatible behavior that imposes additional constraints
+    #   on what constitutes a positive match. A derived property may override that method.
+    # @return [Symbol] (:first) the mode in which matching is performed
+    # @see #insync?
+    # @dsl type
+    # @api public
+    #
+    def array_matching
+      @array_matching ||= :first
+    end
+
+    # @comment This is documented as an attribute - see the {array_matching} method.
+    #
+    def array_matching=(value)
+      value = value.intern if value.is_a?(String)
+      raise ArgumentError, "Supported values for Property#array_matching are 'first' and 'all'" unless [:first, :all].include?(value)
+      @array_matching = value
+    end
+  end
+
+  # Looks up a value's name among valid values, to enable option lookup with result as a key.
+  # @param name [Object] the parameter value to match against valid values (names).
+  # @return {Symbol, Regexp} a value matching predicate
+  # @api private
+  #
+  def self.value_name(name)
+    if value = value_collection.match?(name)
+      value.name
+    end
+  end
+
+  # Returns the value of the given option (set when a valid value with the given "name" was defined).
+  # @param name [Symbol, Regexp] the valid value predicate as returned by {value_name}
+  # @param option [Symbol] the name of the wanted option
+  # @return [Object] value of the option
+  # @raise [NoMethodError] if the option is not supported
+  # @todo Guessing on result of passing a non supported option (it performs send(option)).
+  # @api private
+  #
+  def self.value_option(name, option)
+    if value = value_collection.value(name)
+      value.send(option)
+    end
+  end
+
+  # Defines a new valid value for this property.
+  # A valid value is specified as a literal (typically a Symbol), but can also be
+  # specified with a Regexp.
+  #
+  # @param name [Symbol, Regexp] a valid literal value, or a regexp that matches a value
+  # @param options [Hash] a hash with options
+  # @option options [Symbol] :event The event that should be emitted when this value is set.
+  # @todo Option :event original comment says "event should be returned...", is "returned" the correct word
+  #   to use?
+  # @option options [Symbol] :call When to call any associated block. The default value is `:instead` which
+  #   means that the block should be called instead of the provider. In earlier versions (before 20081031) it
+  #   was possible to specify a value of `:before` or `:after` for the purpose of calling
+  #   both the block and the provider. Use of these deprecated options will now raise an exception later
+  #   in the process when the _is_ value is set (see #set).
+  # @option options [Symbol] :invalidate_refreshes Indicates a change on this property should invalidate and
+  #   remove any scheduled refreshes (from notify or subscribe) targeted at the same resource. For example, if
+  #   a change in this property takes into account any changes that a scheduled refresh would have performed,
+  #   then the scheduled refresh would be deleted.
+  # @option options [Object] any Any other option is treated as a call to a setter having the given
+  #   option name (e.g. `:required_features` calls `required_features=` with the option's value as an
+  #   argument).
+  # @todo The original documentation states that the option `:method` will set the name of the generated
+  #   setter method, but this is not implemented. Is the documentatin or the implementation in error?
+  #   (The implementation is in Puppet::Parameter::ValueCollection#new_value).
+  # @todo verify that the use of :before and :after have been deprecated (or rather - never worked, and
+  #   was never in use. (This means, that the option :call could be removed since calls are always :instead).
+  #
+  # @dsl type
+  # @api public
+  def self.newvalue(name, options = {}, &block)
+    value = value_collection.newvalue(name, options, &block)
+
+    define_method(value.method, &value.block) if value.method and value.block
+    value
+  end
+
+  # Calls the provider setter method for this property with the given value as argument.
+  # @return [Object] what the provider returns when calling a setter for this property's name
+  # @raise [Puppet::Error] when the provider can not handle this property.
+  # @see #set
+  # @api private
+  #
+  def call_provider(value)
+      method = self.class.name.to_s + "="
+      unless provider.respond_to? method
+        self.fail "The #{provider.class.name} provider can not handle attribute #{self.class.name}"
+      end
+      provider.send(method, value)
+  end
+
+  # Sets the value of this property to the given value by calling the dynamically created setter method associated with the "valid value" referenced by the given name.
+  # @param name [Symbol, Regexp] a valid value "name" as returned by {value_name}
+  # @param value [Object] the value to set as the value of the property
+  # @raise [Puppet::DevError] if there was no method to call
+  # @raise [Puppet::Error] if there were problems setting the value
+  # @raise [Puppet::ResourceError] if there was a problem setting the value and it was not raised
+  #   as a Puppet::Error. The original exception is wrapped and logged.
+  # @todo The check for a valid value option called `:method` does not seem to be fully supported
+  #   as it seems that this option is never consulted when the method is dynamically created. Needs to
+  #   be investigated. (Bug, or documentation needs to be changed).
+  # @see #set
+  # @api private
+  #
+  def call_valuemethod(name, value)
+    if method = self.class.value_option(name, :method) and self.respond_to?(method)
+      begin
+        self.send(method)
+      rescue Puppet::Error
+        raise
+      rescue => detail
+        error = Puppet::ResourceError.new("Could not set '#{value}' on #{self.class.name}: #{detail}", @resource.line, @resource.file, detail)
+        error.set_backtrace detail.backtrace
+        Puppet.log_exception(detail, error.message)
+        raise error
+      end
+    elsif block = self.class.value_option(name, :block)
+      # FIXME It'd be better here to define a method, so that
+      # the blocks could return values.
+      self.instance_eval(&block)
+    else
+      devfail "Could not find method for value '#{name}'"
+    end
+  end
+
+  # Formats a message for a property change from the given `current_value` to the given `newvalue`.
+  # @return [String] a message describing the property change.
+  # @note If called with equal values, this is reported as a change.
+  # @raise [Puppet::DevError] if there were issues formatting the message
+  #
+  def change_to_s(current_value, newvalue)
+    begin
+      if current_value == :absent
+        return "defined '#{name}' as #{self.class.format_value_for_display should_to_s(newvalue)}"
+      elsif newvalue == :absent or newvalue == [:absent]
+        return "undefined '#{name}' from #{self.class.format_value_for_display is_to_s(current_value)}"
+      else
+        return "#{name} changed #{self.class.format_value_for_display is_to_s(current_value)} to #{self.class.format_value_for_display should_to_s(newvalue)}"
+      end
+    rescue Puppet::Error, Puppet::DevError
+      raise
+    rescue => detail
+      message = "Could not convert change '#{name}' to string: #{detail}"
+      Puppet.log_exception(detail, message)
+      raise Puppet::DevError, message, detail.backtrace
+    end
+  end
+
+  # Produces the name of the event to use to describe a change of this property's value.
+  # The produced event name is either the event name configured for this property, or a generic
+  # event based on the name of the property with suffix `_changed`, or if the property is
+  # `:ensure`, the name of the resource type and one of the suffixes `_created`, `_removed`, or `_changed`.
+  # @return [String] the name of the event that describes the change
+  #
+  def event_name
+    value = self.should
+
+    event_name = self.class.value_option(value, :event) and return event_name
+
+    name == :ensure or return (name.to_s + "_changed").to_sym
+
+    return (resource.type.to_s + case value
+    when :present; "_created"
+    when :absent; "_removed"
+    else
+      "_changed"
+    end).to_sym
+  end
+
+  # Produces an event describing a change of this property.
+  # In addition to the event attributes set by the resource type, this method adds:
+  #
+  # * `:name` - the event_name
+  # * `:desired_value` - a.k.a _should_ or _wanted value_
+  # * `:property` - reference to this property
+  # * `:source_description` - the _path_ (?? See todo)
+  # * `:invalidate_refreshes` - if scheduled refreshes should be invalidated
+  #
+  # @todo What is the intent of this method? What is the meaning of the :source_description passed in the
+  #   options to the created event?
+  # @return [Puppet::Transaction::Event] the created event
+  # @see Puppet::Type#event
+  def event
+    attrs = { :name => event_name, :desired_value => should, :property => self, :source_description => path }
+    if should and value = self.class.value_collection.match?(should)
+      attrs[:invalidate_refreshes] = true if value.invalidate_refreshes
+    end
+    resource.event attrs
+  end
+
+  # @todo What is this?
+  # What is this used for?
+  attr_reader :shadow
+
+  # Initializes a Property the same way as a Parameter and handles the special case when a property is shadowing a meta-parameter.
+  # @todo There is some special initialization when a property is not a metaparameter but
+  #   Puppet::Type.metaparamclass(for this class's name) is not nil - if that is the case a
+  #   setup_shadow is performed for that class.
+  #
+  # @param hash [Hash] options passed to the super initializer {Puppet::Parameter#initialize}
+  # @note New properties of a type should be created via the DSL method {Puppet::Type.newproperty}.
+  # @see Puppet::Parameter#initialize description of Parameter initialize options.
+  # @api private
+  def initialize(hash = {})
+    super
+
+    if ! self.metaparam? and klass = Puppet::Type.metaparamclass(self.class.name)
+      setup_shadow(klass)
+    end
+  end
+
+  # Determines whether the property is in-sync or not in a way that is protected against missing value.
+  # @note If the wanted value _(should)_ is not defined or is set to a non-true value then this is
+  #   a state that can not be fixed and the property is reported to be in sync.
+  # @return [Boolean] the protected result of `true` or the result of calling {#insync?}.
+  #
+  # @api private
+  # @note Do not override this method.
+  #
+  def safe_insync?(is)
+    # If there is no @should value, consider the property to be in sync.
+    return true unless @should
+
+    # Otherwise delegate to the (possibly derived) insync? method.
+    insync?(is)
+  end
+
+  # Protects against override of the {#safe_insync?} method.
+  # @raise [RuntimeError] if the added method is `:safe_insync?`
+  # @api private
+  #
+  def self.method_added(sym)
+    raise "Puppet::Property#safe_insync? shouldn't be overridden; please override insync? instead" if sym == :safe_insync?
+  end
+
+  # Checks if the current _(is)_ value is in sync with the wanted _(should)_ value.
+  # The check if the two values are in sync is controlled by the result of {#match_all?} which
+  # specifies a match of `:first` or `:all`). The matching of the _is_ value against the entire _should_ value
+  # or each of the _should_ values (as controlled by {#match_all?} is performed by {#property_matches?}.
+  #
+  # A derived property typically only needs to override the {#property_matches?} method, but may also
+  # override this method if there is a need to have more control over the array matching logic.
+  #
+  # @note The array matching logic in this method contains backwards compatible logic that performs the
+  #   comparison in `:all` mode by checking equality and equality of _is_ against _should_ converted to array of String,
+  #   and that the lengths are equal, and in `:first` mode by checking if one of the _should_ values
+  #   is included in the _is_ values. This means that the _is_ value needs to be carefully arranged to
+  #   match the _should_.
+  # @todo The implementation should really do return is.zip(@should).all? {|a, b| property_matches?(a, b) }
+  #   instead of using equality check and then check against an array with converted strings.
+  # @param is [Object] The current _(is)_ value to check if it is in sync with the wanted _(should)_ value(s)
+  # @return [Boolean] whether the values are in sync or not.
+  # @raise [Puppet::DevError] if wanted value _(should)_ is not an array.
+  # @api public
+  #
+  def insync?(is)
+    self.devfail "#{self.class.name}'s should is not array" unless @should.is_a?(Array)
+
+    # an empty array is analogous to no should values
+    return true if @should.empty?
+
+    # Look for a matching value, either for all the @should values, or any of
+    # them, depending on the configuration of this property.
+    if match_all? then
+      # Emulate Array#== using our own comparison function.
+      # A non-array was not equal to an array, which @should always is.
+      return false unless is.is_a? Array
+
+      # If they were different lengths, they are not equal.
+      return false unless is.length == @should.length
+
+      # Finally, are all the elements equal?  In order to preserve the
+      # behaviour of previous 2.7.x releases, we need to impose some fun rules
+      # on "equality" here.
+      #
+      # Specifically, we need to implement *this* comparison: the two arrays
+      # are identical if the is values are == the should values, or if the is
+      # values are == the should values, stringified.
+      #
+      # This does mean that property equality is not commutative, and will not
+      # work unless the `is` value is carefully arranged to match the should.
+      return (is == @should or is == @should.map(&:to_s))
+
+      # When we stop being idiots about this, and actually have meaningful
+      # semantics, this version is the thing we actually want to do.
+      #
+      # return is.zip(@should).all? {|a, b| property_matches?(a, b) }
+    else
+      return @should.any? {|want| property_matches?(is, want) }
+    end
+  end
+
+  # Checks if the given current and desired values are equal.
+  # This default implementation performs this check in a backwards compatible way where
+  # the equality of the two values is checked, and then the equality of current with desired
+  # converted to a string.
+  #
+  # A derived implementation may override this method to perform a property specific equality check.
+  #
+  # The intent of this method is to provide an equality check suitable for checking if the property
+  # value is in sync or not. It is typically called from {#insync?}.
+  #
+  def property_matches?(current, desired)
+    # This preserves the older Puppet behaviour of doing raw and string
+    # equality comparisons for all equality.  I am not clear this is globally
+    # desirable, but at least it is not a breaking change. --daniel 2011-11-11
+    current == desired or current == desired.to_s
+  end
+
+  # Produces a pretty printing string for the given value.
+  # This default implementation simply returns the given argument. A derived implementation
+  # may perform property specific pretty printing when the _is_ and _should_ values are not
+  # already in suitable form.
+  # @return [String] a pretty printing string
+  def is_to_s(currentvalue)
+    currentvalue
+  end
+
+  # Emits a log message at the log level specified for the associated resource.
+  # The log entry is associated with this property.
+  # @param msg [String] the message to log
+  # @return [void]
+  #
+  def log(msg)
+    Puppet::Util::Log.create(
+      :level   => resource[:loglevel],
+      :message => msg,
+      :source  => self
+    )
+  end
+
+  # @return [Boolean] whether the {array_matching} mode is set to `:all` or not
+  def match_all?
+    self.class.array_matching == :all
+  end
+
+  # (see Puppet::Parameter#munge)
+  # If this property is a meta-parameter shadow, the shadow's munge is also called.
+  # @todo Incomprehensible ! The concept of "meta-parameter-shadowing" needs to be explained.
+  #
+  def munge(value)
+    self.shadow.munge(value) if self.shadow
+
+    super
+  end
+
+  # @return [Symbol] the name of the property as stated when the property was created.
+  # @note A property class (just like a parameter class) describes one specific property and
+  #   can only be used once within one type's inheritance chain.
+  def name
+    self.class.name
+  end
+
+  # @return [Boolean] whether this property is in noop mode or not.
+  # Returns whether this property is in noop mode or not; if a difference between the
+  # _is_ and _should_ values should be acted on or not.
+  # The noop mode is a transitive setting. The mode is checked in this property, then in
+  # the _associated resource_ and finally in Puppet[:noop].
+  # @todo This logic is different than Parameter#noop in that the resource noop mode overrides
+  #   the property's mode - in parameter it is the other way around. Bug or feature?
+  #
+  def noop
+    # This is only here to make testing easier.
+    if @resource.respond_to?(:noop?)
+      @resource.noop?
+    else
+      if defined?(@noop)
+        @noop
+      else
+        Puppet[:noop]
+      end
+    end
+  end
+
+  # Retrieves the current value _(is)_ of this property from the provider.
+  # This implementation performs this operation by calling a provider method with the
+  # same name as this property (i.e. if the property name is 'gid', a call to the
+  # 'provider.gid' is expected to return the current value.
+  # @return [Object] what the provider returns as the current value of the property
+  #
+  def retrieve
+    provider.send(self.class.name)
+  end
+
+  # Sets the current _(is)_ value of this property.
+  # The value is set using the provider's setter method for this property ({#call_provider}) if nothing
+  # else has been specified. If the _valid value_ for the given value defines a `:call` option with the
+  # value `:instead`, the
+  # value is set with {#call_valuemethod} which invokes a block specified for the valid value.
+  #
+  # @note In older versions (before 20081031) it was possible to specify the call types `:before` and `:after`
+  #   which had the effect that both the provider method and the _valid value_ block were called.
+  #   This is no longer supported.
+  #
+  # @param value [Object] the value to set as the value of this property
+  # @return [Object] returns what {#call_valuemethod} or {#call_provider} returns
+  # @raise [Puppet::Error] when the provider setter should be used but there is no provider set in the _associated
+  #  resource_
+  # @raise [Puppet::DevError] when a deprecated call form was specified (e.g. `:before` or `:after`).
+  # @api public
+  #
+  def set(value)
+    # Set a name for looking up associated options like the event.
+    name = self.class.value_name(value)
+
+    call = self.class.value_option(name, :call) || :none
+
+    if call == :instead
+      call_valuemethod(name, value)
+    elsif call == :none
+      # They haven't provided a block, and our parent does not have
+      # a provider, so we have no idea how to handle this.
+      self.fail "#{self.class.name} cannot handle values of type #{value.inspect}" unless @resource.provider
+      call_provider(value)
+    else
+      # LAK:NOTE 20081031 This is a change in behaviour -- you could
+      # previously specify :call => [;before|:after], which would call
+      # the setter *in addition to* the block.  I'm convinced this
+      # was never used, and it makes things unecessarily complicated.
+      # If you want to specify a block and still call the setter, then
+      # do so in the block.
+      devfail "Cannot use obsolete :call value '#{call}' for property '#{self.class.name}'"
+    end
+  end
+
+  # Sets up a shadow property for a shadowing meta-parameter.
+  # This construct allows the creation of a property with the
+  # same name as a meta-parameter. The metaparam will only be stored as a shadow.
+  # @param klass [Class<inherits Puppet::Parameter>] the class of the shadowed meta-parameter
+  # @return [Puppet::Parameter] an instance of the given class (a parameter or property)
+  #
+  def setup_shadow(klass)
+    @shadow = klass.new(:resource => self.resource)
+  end
+
+  # Returns the wanted _(should)_ value of this property.
+  # If the _array matching mode_ {#match_all?} is true, an array of the wanted values in unmunged format
+  # is returned, else the first value in the array of wanted values in unmunged format is returned.
+  # @return [Array<Object>, Object, nil] Array of values if {#match_all?} else a single value, or nil if there are no
+  #   wanted values.
+  # @raise [Puppet::DevError] if the wanted value is non nil and not an array
+  #
+  # @note This method will potentially return different values than the original values as they are
+  #   converted via munging/unmunging. If the original values are wanted, call {#shouldorig}.
+  #
+  # @see #shouldorig
+  # @api public
+  #
+  def should
+    return nil unless defined?(@should)
+
+    self.devfail "should for #{self.class.name} on #{resource.name} is not an array" unless @should.is_a?(Array)
+
+    if match_all?
+      return @should.collect { |val| self.unmunge(val) }
+    else
+      return self.unmunge(@should[0])
+    end
+  end
+
+  # Sets the wanted _(should)_ value of this property.
+  # If the given value is not already an Array, it will be wrapped in one before being set.
+  # This method also sets the cached original _should_ values returned by {#shouldorig}.
+  #
+  # @param values [Array<Object>, Object] the value(s) to set as the wanted value(s)
+  # @raise [StandardError] when validation of a value fails (see {#validate}).
+  # @api public
+  #
+  def should=(values)
+    values = [values] unless values.is_a?(Array)
+
+    @shouldorig = values
+
+    values.each { |val| validate(val) }
+    @should = values.collect { |val| self.munge(val) }
+  end
+
+  # Formats the given newvalue (following _should_ type conventions) for inclusion in a string describing a change.
+  # @return [String] Returns the given newvalue in string form with space separated entries if it is an array.
+  # @see #change_to_s
+  #
+  def should_to_s(newvalue)
+    [newvalue].flatten.join(" ")
+  end
+
+  # Synchronizes the current value _(is)_ and the wanted value _(should)_ by calling {#set}.
+  # @raise [Puppet::DevError] if {#should} is nil
+  # @todo The implementation of this method is somewhat inefficient as it computes the should
+  #  array twice.
+  def sync
+    devfail "Got a nil value for should" unless should
+    set(should)
+  end
+
+  # Asserts that the given value is valid.
+  # If the developer uses a 'validate' hook, this method will get overridden.
+  # @raise [Exception] if the value is invalid, or value can not be handled.
+  # @return [void]
+  # @api private
+  #
+  def unsafe_validate(value)
+    super
+    validate_features_per_value(value)
+  end
+
+  # Asserts that all required provider features are present for the given property value.
+  # @raise [ArgumentError] if a required feature is not present
+  # @return [void]
+  # @api private
+  #
+  def validate_features_per_value(value)
+    if features = self.class.value_option(self.class.value_name(value), :required_features)
+      features = Array(features)
+      needed_features = features.collect { |f| f.to_s }.join(", ")
+      raise ArgumentError, "Provider must have features '#{needed_features}' to set '#{self.class.name}' to '#{value}'" unless provider.satisfies?(features)
+    end
+  end
+
+  # @return [Object, nil] Returns the wanted _(should)_ value of this property.
+  def value
+    self.should
+  end
+
+  # (see #should=)
+  def value=(values)
+    self.should = values
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/property/boolean.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/property/boolean.rb
new file mode 100644
index 0000000..bd21a2e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/property/boolean.rb
@@ -0,0 +1,7 @@
+require 'puppet/coercion'
+
+class Puppet::Property::Boolean < Puppet::Property
+  def unsafe_munge(value)
+    Puppet::Coercion.boolean(value)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/property/ensure.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/property/ensure.rb
new file mode 100644
index 0000000..c87c3fa
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/property/ensure.rb
@@ -0,0 +1,105 @@
+require 'puppet/property'
+
+# This property is automatically added to any {Puppet::Type} that responds
+# to the methods 'exists?', 'create', and 'destroy'.
+#
+# Ensure defaults to having the wanted _(should)_ value `:present`.
+#
+# @api public
+#
+class Puppet::Property::Ensure < Puppet::Property
+  @name = :ensure
+
+  def self.defaultvalues
+    newvalue(:present) do
+      if @resource.provider and @resource.provider.respond_to?(:create)
+        @resource.provider.create
+      else
+        @resource.create
+      end
+      nil # return nil so the event is autogenerated
+    end
+
+    newvalue(:absent) do
+      if @resource.provider and @resource.provider.respond_to?(:destroy)
+        @resource.provider.destroy
+      else
+        @resource.destroy
+      end
+      nil # return nil so the event is autogenerated
+    end
+
+    defaultto do
+      if @resource.managed?
+        :present
+      else
+        nil
+      end
+    end
+
+    # This doc will probably get overridden
+    @doc ||= "The basic property that the resource should be in."
+  end
+
+  def self.inherited(sub)
+    # Add in the two properties that everyone will have.
+    sub.class_eval do
+    end
+  end
+
+  def change_to_s(currentvalue, newvalue)
+    begin
+      if currentvalue == :absent or currentvalue.nil?
+        return "created"
+      elsif newvalue == :absent
+        return "removed"
+      else
+        return "#{self.name} changed '#{self.is_to_s(currentvalue)}' to '#{self.should_to_s(newvalue)}'"
+      end
+    rescue Puppet::Error, Puppet::DevError
+      raise
+    rescue => detail
+      raise Puppet::DevError, "Could not convert change #{self.name} to string: #{detail}", detail.backtrace
+    end
+  end
+
+  # Retrieves the _is_ value for the ensure property.
+  # The existence of the resource is checked by first consulting the provider (if it responds to
+  # `:exists`), and secondly the resource. A a value of `:present` or `:absent` is returned
+  # depending on if the managed entity exists or not.
+  #
+  # @return [Symbol] a value of `:present` or `:absent` depending on if it exists or not
+  # @raise [Puppet::DevError] if neither the provider nor the resource responds to `:exists`
+  #
+  def retrieve
+    # XXX This is a problem -- whether the object exists or not often
+    # depends on the results of other properties, yet we're the first property
+    # to get checked, which means that those other properties do not have
+    # @is values set.  This seems to be the source of quite a few bugs,
+    # although they're mostly logging bugs, not functional ones.
+    if prov = @resource.provider and prov.respond_to?(:exists?)
+      result = prov.exists?
+    elsif @resource.respond_to?(:exists?)
+      result = @resource.exists?
+    else
+      raise Puppet::DevError, "No ability to determine if #{@resource.class.name} exists"
+    end
+    if result
+      return :present
+    else
+      return :absent
+    end
+  end
+
+  # If they're talking about the thing at all, they generally want to
+  # say it should exist.
+  #defaultto :present
+  defaultto do
+    if @resource.managed?
+      :present
+    else
+      nil
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/property/keyvalue.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/property/keyvalue.rb
new file mode 100644
index 0000000..3f604d8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/property/keyvalue.rb
@@ -0,0 +1,95 @@
+require 'puppet/property'
+
+module Puppet
+  class Property
+    # This subclass of {Puppet::Property} manages string key value pairs.
+    # In order to use this property:
+    #
+    # * the _should_ value must be an array of key-value pairs separated by the 'separator'
+    # * the retrieve method should return a hash with the keys as symbols
+    # @note **IMPORTANT**: In order for this property to work there must also be a 'membership' parameter
+    #   The class that inherits from property should override that method with the symbol for the membership
+    # @todo The node with an important message is not very clear.
+    #
+    class KeyValue < Property
+
+      def hash_to_key_value_s(hash)
+        hash.select { |k,v| true }.map { |pair| pair.join(separator) }.join(delimiter)
+      end
+
+      def should_to_s(should_value)
+        hash_to_key_value_s(should_value)
+      end
+
+      def is_to_s(current_value)
+        hash_to_key_value_s(current_value)
+      end
+
+      def membership
+        :key_value_membership
+      end
+
+      def inclusive?
+        @resource[membership] == :inclusive
+      end
+
+      def hashify(key_value_array)
+        #turns string array into a hash
+        key_value_array.inject({}) do |hash, key_value|
+          tmp = key_value.split(separator)
+          hash[tmp[0].intern] = tmp[1]
+          hash
+        end
+      end
+
+      def process_current_hash(current)
+        return {} if current == :absent
+
+        #inclusive means we are managing everything so if it isn't in should, its gone
+        current.each_key { |key| current[key] = nil } if inclusive?
+        current
+      end
+
+      def should
+        return nil unless @should
+
+        members = hashify(@should)
+        current = process_current_hash(retrieve)
+
+        #shared keys will get overwritten by members
+        current.merge(members)
+      end
+
+      # @return [String] Returns a default separator of "="
+      def separator
+        "="
+      end
+
+      # @return [String] Returns a default delimiter of ";"
+      def delimiter
+        ";"
+      end
+
+      # Retrieves the key-hash from the provider by invoking its method named the same as this property.
+      # @return [Hash] the hash from the provider, or `:absent`
+      #
+      def retrieve
+        #ok, some 'convention' if the keyvalue property is named properties, provider should implement a properties method
+        if key_hash = provider.send(name) and key_hash != :absent
+          return key_hash
+        else
+          return :absent
+        end
+      end
+
+      # Returns true if there is no _is_ value, else returns if _is_ is equal to _should_ using == as comparison.
+      # @return [Boolean] whether the property is in sync or not.
+      #
+      def insync?(is)
+        return true unless is
+
+        (is == self.should)
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/property/list.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/property/list.rb
new file mode 100644
index 0000000..82dde3e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/property/list.rb
@@ -0,0 +1,78 @@
+require 'puppet/property'
+
+module Puppet
+  class Property
+    # This subclass of {Puppet::Property} manages an unordered list of values.
+    # For an ordered list see {Puppet::Property::OrderedList}.
+    #
+    class List < Property
+
+      def should_to_s(should_value)
+        #just return the should value
+        should_value
+      end
+
+      def is_to_s(currentvalue)
+        if currentvalue == :absent
+          return "absent"
+        else
+          return currentvalue.join(delimiter)
+        end
+      end
+
+      def membership
+        :membership
+      end
+
+      def add_should_with_current(should, current)
+        should += current if current.is_a?(Array)
+        should.uniq
+      end
+
+      def inclusive?
+        @resource[membership] == :inclusive
+      end
+
+      #dearrayify was motivated because to simplify the implementation of the OrderedList property
+      def dearrayify(array)
+        array.sort.join(delimiter)
+      end
+
+      def should
+        return nil unless @should
+
+        members = @should
+        #inclusive means we are managing everything so if it isn't in should, its gone
+        members = add_should_with_current(members, retrieve) if ! inclusive?
+
+        dearrayify(members)
+      end
+
+      def delimiter
+        ","
+      end
+
+      def retrieve
+        #ok, some 'convention' if the list property is named groups, provider should implement a groups method
+        if provider and tmp = provider.send(name) and tmp != :absent
+          return tmp.split(delimiter)
+        else
+          return :absent
+        end
+      end
+
+      def prepare_is_for_comparison(is)
+        if is == :absent
+          is = []
+        end
+        dearrayify(is)
+      end
+
+      def insync?(is)
+        return true unless is
+
+        (prepare_is_for_comparison(is) == self.should)
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/property/ordered_list.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/property/ordered_list.rb
new file mode 100644
index 0000000..28c5651
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/property/ordered_list.rb
@@ -0,0 +1,29 @@
+require 'puppet/property/list'
+
+module Puppet
+  class Property
+    # This subclass of {Puppet::Property} manages an ordered list of values.
+    # The maintained order is the order defined by the 'current' set of values (i.e. the
+    # original order is not disrupted). Any additions are added after the current values
+    # in their given order).
+    #
+    # For an unordered list see {Puppet::Property::List}.
+    #
+    class OrderedList < List
+
+      def add_should_with_current(should, current)
+        if current.is_a?(Array)
+          #tricky trick
+          #Preserve all the current items in the list
+          #but move them to the back of the line
+          should = should + (current - should)
+        end
+        should
+      end
+
+      def dearrayify(array)
+        array.join(delimiter)
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider.rb
new file mode 100644
index 0000000..fe98e69
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider.rb
@@ -0,0 +1,651 @@
+# A Provider is an implementation of the actions that manage resources (of some type) on a system.
+# This class is the base class for all implementation of a Puppet Provider.
+#
+# Concepts:
+#--
+# * **Confinement** - confinement restricts providers to only be applicable under certain conditions.
+#    It is possible to confine a provider several different ways:
+#    * the included {#confine} method which provides filtering on fact, feature, existence of files, or a free form
+#      predicate.
+#    * the {commands} method that filters on the availability of given system commands.
+# * **Property hash** - the important instance variable `@property_hash` contains all current state values
+#   for properties (it is lazily built). It is important that these values are managed appropriately in the
+#   methods {instances}, {prefetch}, and in methods that alters the current state (those that change the
+#   lifecycle (creates, destroys), or alters some value reflected backed by a property).
+# * **Flush** - is a hook that is called once per resource when everything has been applied. The intent is
+#   that an implementation may defer modification of the current state typically done in property setters
+#   and instead record information that allows flush to perform the changes more efficiently.
+# * **Execution Methods** -  The execution methods provides access to execution of arbitrary commands.
+#   As a convenience execution methods are available on both the instance and the class of a provider since a
+#   lot of provider logic switch between these contexts fairly freely.
+# * **System Entity/Resource** - this documentation uses the term "system entity" for system resources to make
+#   it clear if talking about a resource on the system being managed (e.g. a file in the file system)
+#   or about a description of such a resource (e.g. a Puppet Resource).
+# * **Resource Type** - this is an instance of Type that describes a classification of instances of Resource (e.g.
+#   the `File` resource type describes all instances of `file` resources).
+#   (The term is used to contrast with "type" in general, and specifically to contrast with the implementation
+#   class of Resource or a specific Type).
+#
+# @note An instance of a Provider is associated with one resource.
+#
+# @note Class level methods are only called once to configure the provider (when the type is created), and not
+#   for each resource the provider is operating on.
+#   The instance methods are however called for each resource.
+#
+# @api public
+#
+class Puppet::Provider
+  include Puppet::Util
+  include Puppet::Util::Errors
+  include Puppet::Util::Warnings
+  extend Puppet::Util::Warnings
+
+  require 'puppet/confiner'
+  require 'puppet/provider/command'
+
+  extend Puppet::Confiner
+
+  Puppet::Util.logmethods(self, true)
+
+  class << self
+    # Include the util module so we have access to things like 'which'
+    include Puppet::Util, Puppet::Util::Docs
+    include Puppet::Util::Logging
+
+    # @return [String] The name of the provider
+    attr_accessor :name
+
+    #
+    # @todo Original = _"The source parameter exists so that providers using the same
+    #   source can specify this, so reading doesn't attempt to read the
+    #   same package multiple times."_ This seems to be a package type specific attribute. Is this really
+    #   used?
+    #
+    # @return [???] The source is WHAT?
+    attr_writer :source
+
+    # @todo Original = _"LAK 2007-05-09: Keep the model stuff around for backward compatibility"_
+    #   Is this really needed? The comment about backwards compatibility was made in 2007.
+    #
+    # @return [???] A model kept for backwards compatibility.
+    # @api private
+    # @deprecated This attribute is available for backwards compatibility reasons.
+    attr_reader :model
+
+    # @todo What is this type? A reference to a Puppet::Type ?
+    # @return [Puppet::Type] the resource type (that this provider is ... WHAT?)
+    #
+    attr_accessor :resource_type
+
+    # @!attribute [r] doc
+    #   The (full) documentation for this provider class. The documentation for the provider class itself
+    #   should be set with the DSL method {desc=}. Setting the documentation with with {doc=} has the same effect
+    #   as setting it with {desc=} (only the class documentation part is set). In essence this means that
+    #   there is no getter for the class documentation part (since the getter returns the full
+    #   documentation when there are additional contributors).
+    #
+    #   @return [String] Returns the full documentation for the provider.
+    # @see Puppet::Utils::Docs
+    # @comment This is puzzling ... a write only doc attribute??? The generated setter never seems to be
+    #   used, instead the instance variable @doc is set in the `desc` method. This seems wrong. It is instead
+    #   documented as a read only attribute (to get the full documentation). Also see doc below for
+    #   desc.
+    # @!attribute [w] desc
+    #   Sets the documentation of this provider class. (The full documentation is read via the
+    #   {doc} attribute).
+    #
+    #   @dsl type
+    #
+    attr_writer :doc
+  end
+
+  # @todo original = _"LAK 2007-05-09: Keep the model stuff around for backward compatibility"_, why is it
+  #   both here (instance) and at class level? Is this a different model?
+  # @return [???] model is WHAT?
+  attr_reader :model
+
+  # @return [???] This resource is what? Is an instance of a provider attached to one particular Puppet::Resource?
+  #
+  attr_accessor :resource
+
+  # Convenience methods - see class method with the same name.
+  # @see execute
+  # @return (see execute)
+  def execute(*args)
+    Puppet::Util::Execution.execute(*args)
+  end
+
+  # (see Puppet::Util::Execution.execute)
+  def self.execute(*args)
+    Puppet::Util::Execution.execute(*args)
+  end
+
+  # Convenience methods - see class method with the same name.
+  # @see execpipe
+  # @return (see execpipe)
+  def execpipe(*args, &block)
+    Puppet::Util::Execution.execpipe(*args, &block)
+  end
+
+  # (see Puppet::Util::Execution.execpipe)
+  def self.execpipe(*args, &block)
+    Puppet::Util::Execution.execpipe(*args, &block)
+  end
+
+  # Convenience methods - see class method with the same name.
+  # @see execfail
+  # @return (see execfail)
+  def execfail(*args)
+    Puppet::Util::Execution.execfail(*args)
+  end
+
+  # (see Puppet::Util::Execution.execfail)
+  def self.execfail(*args)
+    Puppet::Util::Execution.execfail(*args)
+  end
+
+  # Returns the absolute path to the executable for the command referenced by the given name.
+  # @raise [Puppet::DevError] if the name does not reference an existing command.
+  # @return [String] the absolute path to the found executable for the command
+  # @see which
+  # @api public
+  def self.command(name)
+    name = name.intern
+
+    if defined?(@commands) and command = @commands[name]
+      # nothing
+    elsif superclass.respond_to? :command and command = superclass.command(name)
+      # nothing
+    else
+      raise Puppet::DevError, "No command #{name} defined for provider #{self.name}"
+    end
+
+    which(command)
+  end
+
+  # Confines this provider to be suitable only on hosts where the given commands are present.
+  # Also see {Puppet::Confiner#confine} for other types of confinement of a provider by use of other types of
+  # predicates.
+  #
+  # @note It is preferred if the commands are not entered with absolute paths as this allows puppet
+  #   to search for them using the PATH variable.
+  #
+  # @param command_specs [Hash{String => String}] Map of name to command that the provider will
+  #   be executing on the system. Each command is specified with a name and the path of the executable.
+  # @return [void]
+  # @see optional_commands
+  # @api public
+  #
+  def self.commands(command_specs)
+    command_specs.each do |name, path|
+      has_command(name, path)
+    end
+  end
+
+  # Defines optional commands.
+  # Since Puppet 2.7.8 this is typically not needed as evaluation of provider suitability
+  # is lazy (when a resource is evaluated) and the absence of commands
+  # that will be present after other resources have been applied no longer needs to be specified as
+  # optional.
+  # @param [Hash{String => String}] hash Named commands that the provider will
+  #   be executing on the system. Each command is specified with a name and the path of the executable.
+  # (@see #has_command)
+  # @see commands
+  # @api public
+  def self.optional_commands(hash)
+    hash.each do |name, target|
+      has_command(name, target) do
+        is_optional
+      end
+    end
+  end
+
+  # Creates a convenience method for invocation of a command.
+  #
+  # This generates a Provider method that allows easy execution of the command. The generated
+  # method may take arguments that will be passed through to the executable as the command line arguments
+  # when it is invoked.
+  #
+  # @example Use it like this:
+  #   has_command(:echo, "/bin/echo")
+  #   def some_method
+  #     echo("arg 1", "arg 2")
+  #   end
+  # @comment the . . .  below is intentional to avoid the three dots to become an illegible ellipsis char.
+  # @example . . . or like this
+  #   has_command(:echo, "/bin/echo") do
+  #     is_optional
+  #     environment :HOME => "/var/tmp", :PWD => "/tmp"
+  #   end
+  #
+  # @param name [Symbol] The name of the command (will become the name of the generated method that executes the command)
+  # @param path [String] The path to the executable for the command
+  # @yield [ ] A block that configures the command (see {Puppet::Provider::Command})
+  # @comment a yield [ ] produces {|| ...} in the signature, do not remove the space.
+  # @note the name ´has_command´ looks odd in an API context, but makes more sense when seen in the internal
+  #   DSL context where a Provider is declaratively defined.
+  # @api public
+  #
+  def self.has_command(name, path, &block)
+    name = name.intern
+    command = CommandDefiner.define(name, path, self, &block)
+
+    @commands[name] = command.executable
+
+    # Now define the class and instance methods.
+    create_class_and_instance_method(name) do |*args|
+      return command.execute(*args)
+    end
+  end
+
+  # Internal helper class when creating commands - undocumented.
+  # @api private
+  class CommandDefiner
+    private_class_method :new
+
+    def self.define(name, path, confiner, &block)
+      definer = new(name, path, confiner)
+      definer.instance_eval(&block) if block
+      definer.command
+    end
+
+    def initialize(name, path, confiner)
+      @name = name
+      @path = path
+      @optional = false
+      @confiner = confiner
+      @custom_environment = {}
+    end
+
+    def is_optional
+      @optional = true
+    end
+
+    def environment(env)
+      @custom_environment = @custom_environment.merge(env)
+    end
+
+    def command
+      if not @optional
+        @confiner.confine :exists => @path, :for_binary => true
+      end
+
+      Puppet::Provider::Command.new(@name, @path, Puppet::Util, Puppet::Util::Execution, { :failonfail => true, :combine => true, :custom_environment => @custom_environment })
+    end
+  end
+
+  # @return [Boolean] Return whether the given feature has been declared or not.
+  def self.declared_feature?(name)
+    defined?(@declared_features) and @declared_features.include?(name)
+  end
+
+  # @return [Boolean] Returns whether this implementation satisfies all of the default requirements or not.
+  #   Returns false if there is no matching defaultfor
+  # @see Provider.defaultfor
+  #
+  def self.default?
+    default_match ? true : false
+  end
+
+  # Look through the array of defaultfor hashes and return the first match.
+  # @return [Hash<{String => Object}>] the matching hash specified by a defaultfor
+  # @see Provider.defaultfor
+  # @api private
+  def self.default_match
+    @defaults.find do |default|
+      default.all? do |key, values|
+        case key
+          when :feature
+            feature_match(values)
+          else
+            fact_match(key, values)
+        end
+      end
+    end
+  end
+
+  def self.fact_match(fact, values)
+    values = [values] unless values.is_a? Array
+    values.map! { |v| v.to_s.downcase.intern }
+
+    if fval = Facter.value(fact).to_s and fval != ""
+      fval = fval.to_s.downcase.intern
+
+      values.include?(fval)
+    else
+      false
+    end
+  end
+
+  def self.feature_match(value)
+    Puppet.features.send(value.to_s + "?")
+  end
+
+  # Sets a facts filter that determine which of several suitable providers should be picked by default.
+  # This selection only kicks in if there is more than one suitable provider.
+  # To filter on multiple facts the given hash may contain more than one fact name/value entry.
+  # The filter picks the provider if all the fact/value entries match the current set of facts. (In case
+  # there are still more than one provider after this filtering, the first found is picked).
+  # @param hash [Hash<{String => Object}>] hash of fact name to fact value.
+  # @return [void]
+  #
+  def self.defaultfor(hash)
+    @defaults << hash
+  end
+
+  # @return [Integer] Returns a numeric specificity for this provider based on how many requirements it has
+  #  and number of _ancestors_. The higher the number the more specific the provider.
+  # The number of requirements is based on the hash size of the matching {Provider.defaultfor}.
+  #
+  # The _ancestors_ is the Ruby Module::ancestors method and the number of classes returned is used
+  # to boost the score. The intent is that if two providers are equal, but one is more "derived" than the other
+  # (i.e. includes more classes), it should win because it is more specific).
+  # @note Because of how this value is
+  #   calculated there could be surprising side effects if a provider included an excessive amount of classes.
+  #
+  def self.specificity
+    # This strange piece of logic attempts to figure out how many parent providers there
+    # are to increase the score. What is will actually do is count all classes that Ruby Module::ancestors
+    # returns (which can be other classes than those the parent chain) - in a way, an odd measure of the
+    # complexity of a provider).
+    match = default_match
+    length = match ? match.length : 0
+    (length * 100) + ancestors.select { |a| a.is_a? Class }.length
+  end
+
+  # Initializes defaults and commands (i.e. clears them).
+  # @return [void]
+  def self.initvars
+    @defaults = []
+    @commands = {}
+  end
+
+  # Returns a list of system resources (entities) this provider may/can manage.
+  # This is a query mechanism that lists entities that the provider may manage on a given system. It is
+  # is directly used in query services, but is also the foundation for other services; prefetching, and
+  # purging.
+  #
+  # As an example, a package provider lists all installed packages. (In contrast, the File provider does
+  # not list all files on the file-system as that would make execution incredibly slow). An implementation
+  # of this method should be made if it is possible to quickly (with a single system call) provide all
+  # instances.
+  #
+  # An implementation of this method should only cache the values of properties
+  # if they are discovered as part of the process for finding existing resources.
+  # Resource properties that require additional commands (than those used to determine existence/identity)
+  # should be implemented in their respective getter method. (This is important from a performance perspective;
+  # it may be expensive to compute, as well as wasteful as all discovered resources may perhaps not be managed).
+  #
+  # An implementation may return an empty list (naturally with the effect that it is not possible to query
+  # for manageable entities).
+  #
+  # By implementing this method, it is possible to use the `resources´ resource type to specify purging
+  # of all non managed entities.
+  #
+  # @note The returned instances are instance of some subclass of Provider, not resources.
+  # @return [Array<Puppet::Provider>] a list of providers referencing the system entities
+  # @abstract this method must be implemented by a subclass and this super method should never be called as it raises an exception.
+  # @raise [Puppet::DevError] Error indicating that the method should have been implemented by subclass.
+  # @see prefetch
+  def self.instances
+    raise Puppet::DevError, "Provider #{self.name} has not defined the 'instances' class method"
+  end
+
+  # Creates the methods for a given command.
+  # @api private
+  # @deprecated Use {commands}, {optional_commands}, or {has_command} instead. This was not meant to be part of a public API
+  def self.make_command_methods(name)
+    Puppet.deprecation_warning "Provider.make_command_methods is deprecated; use Provider.commands or Provider.optional_commands instead for creating command methods"
+
+    # Now define a method for that command
+    unless singleton_class.method_defined?(name)
+      meta_def(name) do |*args|
+        # This might throw an ExecutionFailure, but the system above
+        # will catch it, if so.
+        command = Puppet::Provider::Command.new(name, command(name), Puppet::Util, Puppet::Util::Execution)
+        return command.execute(*args)
+      end
+
+      # And then define an instance method that just calls the class method.
+      # We need both, so both instances and classes can easily run the commands.
+      unless method_defined?(name)
+        define_method(name) do |*args|
+          self.class.send(name, *args)
+        end
+      end
+    end
+  end
+
+  # Creates getter- and setter- methods for each property supported by the resource type.
+  # Call this method to generate simple accessors for all properties supported by the
+  # resource type. These simple accessors lookup and sets values in the property hash.
+  # The generated methods may be overridden by more advanced implementations if something
+  # else than a straight forward getter/setter pair of methods is required.
+  # (i.e. define such overriding methods after this method has been called)
+  #
+  # An implementor of a provider that makes use of `prefetch` and `flush` can use this method since it uses
+  # the internal `@property_hash` variable to store values. An implementation would then update the system
+  # state on a call to `flush` based on the current values in the `@property_hash`.
+  #
+  # @return [void]
+  #
+  def self.mk_resource_methods
+    [resource_type.validproperties, resource_type.parameters].flatten.each do |attr|
+      attr = attr.intern
+      next if attr == :name
+      define_method(attr) do
+        if @property_hash[attr].nil?
+          :absent
+        else
+          @property_hash[attr]
+        end
+      end
+
+      define_method(attr.to_s + "=") do |val|
+        @property_hash[attr] = val
+      end
+    end
+  end
+
+  self.initvars
+
+  # This method is used to generate a method for a command.
+  # @return [void]
+  # @api private
+  #
+  def self.create_class_and_instance_method(name, &block)
+    unless singleton_class.method_defined?(name)
+      meta_def(name, &block)
+    end
+
+    unless method_defined?(name)
+      define_method(name) do |*args|
+        self.class.send(name, *args)
+      end
+    end
+  end
+  private_class_method :create_class_and_instance_method
+
+  # @return [String] Returns the data source, which is the provider name if no other source has been set.
+  # @todo Unclear what "the source" is used for?
+  def self.source
+    @source ||= self.name
+  end
+
+  # Returns true if the given attribute/parameter is supported by the provider.
+  # The check is made that the parameter is a valid parameter for the resource type, and then
+  # if all its required features (if any) are supported by the provider.
+  #
+  # @param param [Class, Puppet::Parameter] the parameter class, or a parameter instance
+  # @return [Boolean] Returns whether this provider supports the given parameter or not.
+  # @raise [Puppet::DevError] if the given parameter is not valid for the resource type
+  #
+  def self.supports_parameter?(param)
+    if param.is_a?(Class)
+      klass = param
+    else
+      unless klass = resource_type.attrclass(param)
+        raise Puppet::DevError, "'#{param}' is not a valid parameter for #{resource_type.name}"
+      end
+    end
+    return true unless features = klass.required_features
+
+    !!satisfies?(*features)
+  end
+
+#    def self.to_s
+#        unless defined?(@str)
+#            if self.resource_type
+#                @str = "#{resource_type.name} provider #{self.name}"
+#            else
+#                @str = "unattached provider #{self.name}"
+#            end
+#        end
+#        @str
+#    end
+
+  dochook(:defaults) do
+    if @defaults.length > 0
+      return @defaults.collect do |d|
+        "Default for " + d.collect do |f, v|
+          "`#{f}` == `#{[v].flatten.join(', ')}`"
+        end.sort.join(" and ") + "."
+      end.join(" ")
+    end
+  end
+
+  dochook(:commands) do
+    if @commands.length > 0
+      return "Required binaries: " + @commands.collect do |n, c|
+        "`#{c}`"
+      end.sort.join(", ") + "."
+    end
+  end
+
+  dochook(:features) do
+    if features.length > 0
+      return "Supported features: " + features.collect do |f|
+        "`#{f}`"
+      end.sort.join(", ") + "."
+    end
+  end
+
+  # Clears this provider instance to allow GC to clean up.
+  def clear
+    @resource = nil
+    @model = nil
+  end
+
+  # (see command)
+  def command(name)
+    self.class.command(name)
+  end
+
+  # Returns the value of a parameter value, or `:absent` if it is not defined.
+  # @param param [Puppet::Parameter] the parameter to obtain the value of
+  # @return [Object] the value of the parameter or `:absent` if not defined.
+  #
+  def get(param)
+    @property_hash[param.intern] || :absent
+  end
+
+  # Creates a new provider that is optionally initialized from a resource or a hash of properties.
+  # If no argument is specified, a new non specific provider is initialized. If a resource is given
+  # it is remembered for further operations. If a hash is used it becomes the internal `@property_hash`
+  # structure of the provider - this hash holds the current state property values of system entities
+  # as they are being discovered by querying or other operations (typically getters).
+  #
+  # @todo The use of a hash as a parameter needs a better exaplanation; why is this done? What is the intent?
+  # @param resource [Puppet::Resource, Hash] optional resource or hash
+  #
+  def initialize(resource = nil)
+    if resource.is_a?(Hash)
+      # We don't use a duplicate here, because some providers (ParsedFile, at least)
+      # use the hash here for later events.
+      @property_hash = resource
+    elsif resource
+      @resource = resource
+      # LAK 2007-05-09: Keep the model stuff around for backward compatibility
+      @model = resource
+      @property_hash = {}
+    else
+      @property_hash = {}
+    end
+  end
+
+  # Returns the name of the resource this provider is operating on.
+  # @return [String] the name of the resource instance (e.g. the file path of a File).
+  # @raise [Puppet::DevError] if no resource is set, or no name defined.
+  #
+  def name
+    if n = @property_hash[:name]
+      return n
+    elsif self.resource
+      resource.name
+    else
+      raise Puppet::DevError, "No resource and no name in property hash in #{self.class.name} instance"
+    end
+  end
+
+  # Sets the given parameters values as the current values for those parameters.
+  # Other parameters are unchanged.
+  # @param [Array<Puppet::Parameter>] params the parameters with values that should be set
+  # @return [void]
+  #
+  def set(params)
+    params.each do |param, value|
+      @property_hash[param.intern] = value
+    end
+  end
+
+  # @return [String] Returns a human readable string with information about the resource and the provider.
+  def to_s
+    "#{@resource}(provider=#{self.class.name})"
+  end
+
+  # Makes providers comparable.
+  include Comparable
+  # Compares this provider against another provider.
+  # Comparison is only possible with another provider (no other class).
+  # The ordering is based on the class name of the two providers.
+  #
+  # @return [-1,0,+1, nil] A comparison result -1, 0, +1 if this is before other, equal or after other. Returns
+  #   nil oif not comparable to other.
+  # @see Comparable
+  def <=>(other)
+    # We can only have ordering against other providers.
+    return nil unless other.is_a? Puppet::Provider
+    # Otherwise, order by the providers class name.
+    return self.class.name <=> other.class.name
+  end
+
+  # @comment Document prefetch here as it does not exist anywhere else (called from transaction if implemented)
+  # @!method self.prefetch(resource_hash)
+  # @abstract A subclass may implement this - it is not implemented in the Provider class
+  # This method may be implemented by a provider in order to pre-fetch resource properties.
+  # If implemented it should set the provider instance of the managed resources to a provider with the
+  # fetched state (i.e. what is returned from the {instances} method).
+  # @param resources_hash [Hash<{String => Puppet::Resource}>] map from name to resource of resources to prefetch
+  # @return [void]
+  # @api public
+
+  # @comment Document post_resource_eval here as it does not exist anywhere else (called from transaction if implemented)
+  # @!method self.post_resource_eval()
+  # @since 3.4.0
+  # @api public
+  # @abstract A subclass may implement this - it is not implemented in the Provider class
+  # This method may be implemented by a provider in order to perform any
+  # cleanup actions needed.  It will be called at the end of the transaction if
+  # any resources in the catalog make use of the provider, regardless of
+  # whether the resources are changed or not and even if resource failures occur.
+  # @return [void]
+
+  # @comment Document flush here as it does not exist anywhere (called from transaction if implemented)
+  # @!method flush()
+  # @abstract A subclass may implement this - it is not implemented in the Provider class
+  # This method may be implemented by a provider in order to flush properties that has not been individually
+  # applied to the managed entity's current state.
+  # @return [void]
+  # @api public
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/aixobject.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/aixobject.rb
new file mode 100644
index 0000000..53132a4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/aixobject.rb
@@ -0,0 +1,392 @@
+#
+# Common code for AIX providers. This class implements basic structure for
+# AIX resources.
+# Author::    Hector Rivas Gandara <keymon@gmail.com>
+#
+class Puppet::Provider::AixObject < Puppet::Provider
+  desc "Generic AIX resource provider"
+
+  # The real provider must implement these functions.
+  def lscmd( _value = @resource[:name] )
+    raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: Base AixObject provider doesn't implement lscmd"
+  end
+
+  def addcmd( _extra_attrs = [] )
+    raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: Base AixObject provider doesn't implement addcmd"
+  end
+
+  def modifycmd( _attributes_hash = {} )
+    raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: Base AixObject provider doesn't implement modifycmd"
+  end
+
+  def deletecmd
+    raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: Base AixObject provider doesn't implement deletecmd"
+  end
+
+  # Valid attributes to be managed by this provider.
+  # It is a list of hashes
+  #  :aix_attr      AIX command attribute name
+  #  :puppet_prop   Puppet propertie name
+  #  :to            Optional. Method name that adapts puppet property to aix command value.
+  #  :from          Optional. Method to adapt aix command line value to puppet property. Optional
+  class << self
+    attr_accessor :attribute_mapping
+  end
+
+  # Mapping from Puppet property to AIX attribute.
+  def self.attribute_mapping_to
+    if ! @attribute_mapping_to
+      @attribute_mapping_to = {}
+      attribute_mapping.each { |elem|
+        attribute_mapping_to[elem[:puppet_prop]] = {
+          :key => elem[:aix_attr],
+          :method => elem[:to]
+        }
+      }
+    end
+    @attribute_mapping_to
+  end
+
+  # Mapping from AIX attribute to Puppet property.
+  def self.attribute_mapping_from
+    if ! @attribute_mapping_from
+      @attribute_mapping_from = {}
+      attribute_mapping.each { |elem|
+        attribute_mapping_from[elem[:aix_attr]] = {
+          :key => elem[:puppet_prop],
+          :method => elem[:from]
+        }
+      }
+    end
+    @attribute_mapping_from
+  end
+
+  # This functions translates a key and value using the given mapping.
+  # Mapping can be nil (no translation) or a hash with this format
+  # {:key => new_key, :method => translate_method}
+  # It returns a list with the pair [key, value]
+  def translate_attr(key, value, mapping)
+    return [key, value] unless mapping
+    return nil unless mapping[key]
+
+    if mapping[key][:method]
+      new_value = method(mapping[key][:method]).call(value)
+    else
+      new_value = value
+    end
+    [mapping[key][:key], new_value]
+  end
+
+  # Loads an AIX attribute (key=value) and stores it in the given hash with
+  # puppet semantics. It translates the pair using the given mapping.
+  #
+  # This operation works with each property one by one,
+  # subclasses must reimplement this if more complex operations are needed
+  def load_attribute(key, value, mapping, objectinfo)
+    if mapping.nil?
+      objectinfo[key] = value
+    elsif mapping[key].nil?
+      # is not present in mapping, ignore it.
+      true
+    elsif mapping[key][:method].nil?
+      objectinfo[mapping[key][:key]] = value
+    elsif
+      objectinfo[mapping[key][:key]] = method(mapping[key][:method]).call(value)
+    end
+
+    return objectinfo
+  end
+
+  # Gets the given command line argument for the given key and value,
+  # using the given mapping to translate key and value.
+  # All the objectinfo hash (@resource or @property_hash) is passed.
+  #
+  # This operation works with each property one by one,
+  # and default behaviour is return the arguments as key=value pairs.
+  # Subclasses must reimplement this if more complex operations/arguments
+  # are needed
+  #
+  def get_arguments(key, value, mapping, objectinfo)
+    if mapping.nil?
+      new_key = key
+      new_value = value
+    elsif mapping[key].nil?
+      # is not present in mapping, ignore it.
+      new_key = nil
+      new_value = nil
+    elsif mapping[key][:method].nil?
+      new_key = mapping[key][:key]
+      new_value = value
+    elsif
+      new_key = mapping[key][:key]
+      new_value = method(mapping[key][:method]).call(value)
+    end
+
+    # convert it to string
+    new_value = Array(new_value).join(',')
+
+    if new_key
+      return [ "#{new_key}=#{new_value}" ]
+    else
+      return []
+    end
+  end
+
+  # Convert the provider properties (hash) to AIX command arguments
+  # (list of strings)
+  # This function will translate each value/key and generate the argument using
+  # the get_arguments function.
+  def hash2args(hash, mapping=self.class.attribute_mapping_to)
+    return "" unless hash
+    arg_list = []
+    hash.each {|key, val|
+      arg_list += self.get_arguments(key, val, mapping, hash)
+    }
+    arg_list
+  end
+
+  # Parse AIX command attributes from the output of an AIX command, that
+  # which format is a list of space separated of key=value pairs:
+  # "uid=100 groups=a,b,c".
+  # It returns a hash.
+  #
+  # If a mapping is provided, the keys are translated as defined in the
+  # mapping hash. And only values included in mapping will be added
+  #
+  # NOTE: it will ignore the items not including '='
+  def parse_attr_list(str, mapping=self.class.attribute_mapping_from)
+    properties = {}
+    attrs = []
+    if str.nil? or (attrs = str.split()).empty?
+      return nil
+    end
+
+    attrs.each { |i|
+      if i.include? "=" # Ignore if it does not include '='
+        (key_str, val) = i.split('=')
+        # Check the key
+        if key_str.nil? or key_str.empty?
+          info "Empty key in string 'i'?"
+          continue
+        end
+        key_str.strip!
+        key = key_str.to_sym
+        val.strip! if val
+
+        properties = self.load_attribute(key, val, mapping, properties)
+      end
+    }
+    properties.empty? ? nil : properties
+  end
+
+  # Parse AIX command output in a colon separated list of attributes,
+  # This function is useful to parse the output of commands like lsfs -c:
+  #   #MountPoint:Device:Vfs:Nodename:Type:Size:Options:AutoMount:Acct
+  #   /:/dev/hd4:jfs2::bootfs:557056:rw:yes:no
+  #   /home:/dev/hd1:jfs2:::2129920:rw:yes:no
+  #   /usr:/dev/hd2:jfs2::bootfs:9797632:rw:yes:no
+  #
+  # If a mapping is provided, the keys are translated as defined in the
+  # mapping hash. And only values included in mapping will be added
+  def parse_colon_list(str, key_list, mapping=self.class.attribute_mapping_from)
+    properties = {}
+    attrs = []
+    if str.nil? or (attrs = str.split(':')).empty?
+      return nil
+    end
+
+    attrs.each { |val|
+      key = key_list.shift.downcase.to_sym
+      properties = self.load_attribute(key, val, mapping, properties)
+    }
+    properties.empty? ? nil : properties
+  end
+
+  # Default parsing function for AIX commands.
+  # It will choose the method depending of the first line.
+  # For the colon separated list it will:
+  #  1. Get keys from first line.
+  #  2. Parse next line.
+  def parse_command_output(output, mapping=self.class.attribute_mapping_from)
+    lines = output.split("\n")
+    # if it begins with #something:... is a colon separated list.
+    if lines[0] =~ /^#.*:/
+      self.parse_colon_list(lines[1], lines[0][1..-1].split(':'), mapping)
+    else
+      self.parse_attr_list(lines[0], mapping)
+    end
+  end
+
+  # Retrieve all the information of an existing resource.
+  # It will execute 'lscmd' command and parse the output, using the mapping
+  # 'attribute_mapping_from' to translate the keys and values.
+  def getinfo(refresh = false)
+    if @objectinfo.nil? or refresh == true
+      # Execute lsuser, split all attributes and add them to a dict.
+      begin
+        output = execute(self.lscmd)
+        @objectinfo = self.parse_command_output(output)
+        # All attributtes without translation
+        @objectosinfo = self.parse_command_output(output, nil)
+      rescue Puppet::ExecutionFailure => detail
+        # Print error if needed. FIXME: Do not check the user here.
+        Puppet.debug "aix.getinfo(): Could not find #{@resource.class.name} #{@resource.name}: #{detail}"
+      end
+    end
+    @objectinfo
+  end
+
+  # Like getinfo, but it will not use the mapping to translate the keys and values.
+  # It might be usefult to retrieve some raw information.
+  def getosinfo(refresh = false)
+    if @objectosinfo.nil? or refresh == true
+      getinfo(refresh)
+    end
+    @objectosinfo || Hash.new
+  end
+
+
+  # List all elements of given type. It works for colon separated commands and
+  # list commands.
+  # It returns a list of names.
+  def self.list_all
+    names = []
+    begin
+      output = execute([self.command(:list), 'ALL'])
+
+      output = output.split("\n").select{ |line| line != /^#/ }
+
+      output.each do |line|
+        name = line.split(/[ :]/)[0]
+        names << name if not name.empty?
+      end
+    rescue Puppet::ExecutionFailure => detail
+      # Print error if needed
+      Puppet.debug "aix.list_all(): Could not get all resources of type #{@resource.class.name}: #{detail}"
+    end
+    names
+  end
+
+
+  #-------------
+  # Provider API
+  # ------------
+
+  # Clear out the cached values.
+  def flush
+    @property_hash.clear if @property_hash
+    @objectinfo.clear if @objectinfo
+  end
+
+  # Check that the user exists
+  def exists?
+    !!getinfo(true) # !! => converts to bool
+  end
+
+  # Return all existing instances
+  # The method for returning a list of provider instances.  Note that it returns
+  # providers, preferably with values already filled in, not resources.
+  def self.instances
+    objects=[]
+    list_all.each { |entry|
+      objects << new(:name => entry, :ensure => :present)
+    }
+    objects
+  end
+
+  #- **ensure**
+  #    The basic state that the object should be in.  Valid values are
+  #    `present`, `absent`, `role`.
+  # From ensurable: exists?, create, delete
+  def ensure
+    if exists?
+      :present
+    else
+      :absent
+    end
+  end
+
+  # Create a new instance of the resource
+  def create
+    if exists?
+      info "already exists"
+      # The object already exists
+      return nil
+    end
+
+    begin
+      execute(self.addcmd)
+    rescue Puppet::ExecutionFailure => detail
+      raise Puppet::Error, "Could not create #{@resource.class.name} #{@resource.name}: #{detail}", detail.backtrace
+    end
+  end
+
+  # Delete this instance of the resource
+  def delete
+    unless exists?
+      info "already absent"
+      # the object already doesn't exist
+      return nil
+    end
+
+    begin
+      execute(self.deletecmd)
+    rescue Puppet::ExecutionFailure => detail
+      raise Puppet::Error, "Could not delete #{@resource.class.name} #{@resource.name}: #{detail}", detail.backtrace
+    end
+  end
+
+  #--------------------------------
+  # Call this method when the object is initialized.
+  # It creates getter/setter methods for each property our resource type supports.
+  # If setter or getter already defined it will not be overwritten
+  def self.mk_resource_methods
+    [resource_type.validproperties, resource_type.parameters].flatten.each do |prop|
+      next if prop == :ensure
+      define_method(prop) { get(prop) || :absent} unless public_method_defined?(prop)
+      define_method(prop.to_s + "=") { |*vals| set(prop, *vals) } unless public_method_defined?(prop.to_s + "=")
+    end
+  end
+
+  # Define the needed getters and setters as soon as we know the resource type
+  def self.resource_type=(resource_type)
+    super
+    mk_resource_methods
+  end
+
+  # Retrieve a specific value by name.
+  def get(param)
+    (hash = getinfo(false)) ? hash[param] : nil
+  end
+
+  # Set a property.
+  def set(param, value)
+    @property_hash[param.intern] = value
+
+    if getinfo().nil?
+      # This is weird...
+      raise Puppet::Error, "Trying to update parameter '#{param}' to '#{value}' for a resource that does not exists #{@resource.class.name} #{@resource.name}: #{detail}"
+    end
+    if value == getinfo()[param.to_sym]
+      return
+    end
+
+    #self.class.validate(param, value)
+    if cmd = modifycmd({param =>value})
+      begin
+        execute(cmd)
+      rescue Puppet::ExecutionFailure  => detail
+        raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}", detail.backtrace
+      end
+    end
+
+    # Refresh de info.
+    getinfo(true)
+  end
+
+  def initialize(resource)
+    super
+    @objectinfo = nil
+    @objectosinfo = nil
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/augeas/augeas.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/augeas/augeas.rb
new file mode 100644
index 0000000..5f11c34
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/augeas/augeas.rb
@@ -0,0 +1,509 @@
+#
+#   Copyright 2011 Bryan Kearney <bkearney@redhat.com>
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+require 'augeas' if Puppet.features.augeas?
+require 'strscan'
+require 'puppet/util'
+require 'puppet/util/diff'
+require 'puppet/util/package'
+
+Puppet::Type.type(:augeas).provide(:augeas) do
+  include Puppet::Util
+  include Puppet::Util::Diff
+  include Puppet::Util::Package
+
+  confine :feature => :augeas
+
+  has_features :parse_commands, :need_to_run?,:execute_changes
+
+  SAVE_NOOP = "noop"
+  SAVE_OVERWRITE = "overwrite"
+  SAVE_NEWFILE = "newfile"
+  SAVE_BACKUP = "backup"
+
+  COMMANDS = {
+    "set" => [ :path, :string ],
+    "setm" => [ :path, :string, :string ],
+    "rm" => [ :path ],
+    "clear" => [ :path ],
+    "clearm" => [ :path, :string ],
+    "mv" => [ :path, :path ],
+    "insert" => [ :string, :string, :path ],
+    "get" => [ :path, :comparator, :string ],
+    "defvar" => [ :string, :path ],
+    "defnode" => [ :string, :path, :string ],
+    "match" => [ :path, :glob ],
+    "size" => [:comparator, :int],
+    "include" => [:string],
+    "not_include" => [:string],
+    "==" => [:glob],
+    "!=" => [:glob]
+  }
+
+  COMMANDS["ins"] = COMMANDS["insert"]
+  COMMANDS["remove"] = COMMANDS["rm"]
+  COMMANDS["move"] = COMMANDS["mv"]
+
+  attr_accessor :aug
+
+  # Extracts an 2 dimensional array of commands which are in the
+  # form of command path value.
+  # The input can be
+  # - A string with one command
+  # - A string with many commands per line
+  # - An array of strings.
+  def parse_commands(data)
+    context = resource[:context]
+    # Add a trailing / if it is not there
+    if (context.length > 0)
+      context << "/" if context[-1, 1] != "/"
+    end
+
+    data = data.split($/) if data.is_a?(String)
+    data = data.flatten
+    args = []
+    data.each do |line|
+      line.strip!
+      next if line.nil? || line.empty?
+      argline = []
+      sc = StringScanner.new(line)
+      cmd = sc.scan(/\w+|==|!=/)
+      formals = COMMANDS[cmd]
+      fail("Unknown command #{cmd}") unless formals
+      argline << cmd
+      narg = 0
+      formals.each do |f|
+        sc.skip(/\s+/)
+        narg += 1
+        if f == :path
+          start = sc.pos
+          nbracket = 0
+          inSingleTick = false
+          inDoubleTick = false
+          begin
+            sc.skip(/([^\]\[\s\\'"]|\\.)+/)
+            ch = sc.getch
+            nbracket += 1 if ch == "["
+            nbracket -= 1 if ch == "]"
+            inSingleTick = !inSingleTick if ch == "'"
+            inDoubleTick = !inDoubleTick if ch == "\""
+            fail("unmatched [") if nbracket < 0
+          end until ((nbracket == 0 && !inSingleTick && !inDoubleTick && (ch =~ /\s/)) || sc.eos?)
+            len = sc.pos - start
+            len -= 1 unless sc.eos?
+          unless p = sc.string[start, len]
+            fail("missing path argument #{narg} for #{cmd}")
+          end
+          # Rip off any ticks if they are there.
+          p = p[1, (p.size - 2)] if p[0,1] == "'" || p[0,1] == "\""
+          p.chomp!("/")
+          if p[0,1] != '$' && p[0,1] != "/"
+            argline << context + p
+          else
+            argline << p
+          end
+        elsif f == :string
+          delim = sc.peek(1)
+          if delim == "'" || delim == "\""
+            sc.getch
+            argline << sc.scan(/([^\\#{delim}]|(\\.))*/)
+            sc.getch
+          else
+            argline << sc.scan(/[^\s]+/)
+          end
+          fail("missing string argument #{narg} for #{cmd}") unless argline[-1]
+        elsif f == :comparator
+          argline << sc.scan(/(==|!=|=~|<=|>=|<|>)/)
+          unless argline[-1]
+            puts sc.rest
+            fail("invalid comparator for command #{cmd}")
+          end
+        elsif f == :int
+          argline << sc.scan(/\d+/).to_i
+        elsif f== :glob
+          argline << sc.rest
+        end
+      end
+      args << argline
+    end
+    args
+  end
+
+
+  def open_augeas
+    unless @aug
+      flags = Augeas::NONE
+      flags = Augeas::TYPE_CHECK if resource[:type_check] == :true
+
+      if resource[:incl]
+        flags |= Augeas::NO_MODL_AUTOLOAD
+      else
+        flags |= Augeas::NO_LOAD
+      end
+
+      root = resource[:root]
+      load_path = get_load_path(resource)
+      debug("Opening augeas with root #{root}, lens path #{load_path}, flags #{flags}")
+      @aug = Augeas::open(root, load_path,flags)
+
+      debug("Augeas version #{get_augeas_version} is installed") if versioncmp(get_augeas_version, "0.3.6") >= 0
+
+      # Optimize loading if the context is given and it's a simple path,
+      # requires the glob function from Augeas 0.8.2 or up
+      glob_avail = !aug.match("/augeas/version/pathx/functions/glob").empty?
+      opt_ctx = resource[:context].match("^/files/[^'\"\\[\\]]+$") if resource[:context]
+
+      restricted = false
+      if resource[:incl]
+        aug.set("/augeas/load/Xfm/lens", resource[:lens])
+        aug.set("/augeas/load/Xfm/incl", resource[:incl])
+        restricted_metadata = "/augeas//error"
+      elsif glob_avail and opt_ctx
+        # Optimize loading if the context is given, requires the glob function
+        # from Augeas 0.8.2 or up
+        ctx_path = resource[:context].sub(/^\/files(.*?)\/?$/, '\1/')
+        load_path = "/augeas/load/*['%s' !~ glob(incl) + regexp('/.*')]" % ctx_path
+
+        if aug.match(load_path).size < aug.match("/augeas/load/*").size
+          aug.rm(load_path)
+          restricted_metadata = "/augeas/files#{ctx_path}/error"
+        else
+          # This will occur if the context is less specific than any glob
+          debug("Unable to optimize files loaded by context path, no glob matches")
+        end
+      end
+      aug.load
+      print_load_errors(restricted_metadata)
+    end
+    @aug
+  end
+
+  def close_augeas
+    if @aug
+      @aug.close
+      debug("Closed the augeas connection")
+      @aug = nil
+    end
+  end
+
+  def is_numeric?(s)
+    case s
+    when Fixnum
+      true
+    when String
+      s.match(/\A[+-]?\d+?(\.\d+)?\Z/n) == nil ? false : true
+    else
+      false
+    end
+  end
+
+  # Used by the need_to_run? method to process get filters. Returns
+  # true if there is a match, false if otherwise
+  # Assumes a syntax of get /files/path [COMPARATOR] value
+  def process_get(cmd_array)
+    return_value = false
+
+    #validate and tear apart the command
+    fail ("Invalid command: #{cmd_array.join(" ")}") if cmd_array.length < 4
+    cmd = cmd_array.shift
+    path = cmd_array.shift
+    comparator = cmd_array.shift
+    arg = cmd_array.join(" ")
+
+    #check the value in augeas
+    result = @aug.get(path) || ''
+
+    if ['<', '<=', '>=', '>'].include? comparator and is_numeric?(result) and
+                                                      is_numeric?(arg)
+      resultf = result.to_f
+      argf = arg.to_f
+      return_value = (resultf.send(comparator, argf))
+    elsif comparator == "!="
+      return_value = (result != arg)
+    elsif comparator == "=~"
+      regex = Regexp.new(arg)
+      return_value = (result =~ regex)
+    else
+      return_value = (result.send(comparator, arg))
+    end
+    !!return_value
+  end
+
+  # Used by the need_to_run? method to process match filters. Returns
+  # true if there is a match, false if otherwise
+  def process_match(cmd_array)
+    return_value = false
+
+    #validate and tear apart the command
+    fail("Invalid command: #{cmd_array.join(" ")}") if cmd_array.length < 3
+    cmd = cmd_array.shift
+    path = cmd_array.shift
+
+    # Need to break apart the clause
+    clause_array = parse_commands(cmd_array.shift)[0]
+    verb = clause_array.shift
+
+    #Get the values from augeas
+    result = @aug.match(path) || []
+    fail("Error trying to match path '#{path}'") if (result == -1)
+
+    # Now do the work
+    case verb
+    when "size"
+      fail("Invalid command: #{cmd_array.join(" ")}") if clause_array.length != 2
+      comparator = clause_array.shift
+      arg = clause_array.shift
+      case comparator
+      when "!="
+        return_value = !(result.size.send(:==, arg))
+      else
+        return_value = (result.size.send(comparator, arg))
+      end
+    when "include"
+      arg = clause_array.shift
+      return_value = result.include?(arg)
+    when "not_include"
+      arg = clause_array.shift
+      return_value = !result.include?(arg)
+    when "=="
+      begin
+        arg = clause_array.shift
+        new_array = eval arg
+        return_value = (result == new_array)
+      rescue
+        fail("Invalid array in command: #{cmd_array.join(" ")}")
+      end
+    when "!="
+      begin
+        arg = clause_array.shift
+        new_array = eval arg
+        return_value = (result != new_array)
+      rescue
+        fail("Invalid array in command: #{cmd_array.join(" ")}")
+      end
+    end
+    !!return_value
+  end
+
+  # Generate lens load paths from user given paths and local pluginsync dir
+  def get_load_path(resource)
+    load_path = []
+
+    # Permits colon separated strings or arrays
+    if resource[:load_path]
+      load_path = [resource[:load_path]].flatten
+      load_path.map! { |path| path.split(/:/) }
+      load_path.flatten!
+    end
+
+    if Puppet::FileSystem.exist?("#{Puppet[:libdir]}/augeas/lenses")
+      load_path << "#{Puppet[:libdir]}/augeas/lenses"
+    end
+
+    load_path.join(":")
+  end
+
+  def get_augeas_version
+    @aug.get("/augeas/version") || ""
+  end
+
+  def set_augeas_save_mode(mode)
+    @aug.set("/augeas/save", mode)
+  end
+
+  def print_load_errors(path)
+    errors = @aug.match("/augeas//error")
+    unless errors.empty?
+      if path && !@aug.match(path).empty?
+        warning("Loading failed for one or more files, see debug for /augeas//error output")
+      else
+        debug("Loading failed for one or more files, output from /augeas//error:")
+      end
+    end
+    print_errors(errors)
+  end
+
+  def print_put_errors
+    errors = @aug.match("/augeas//error[. = 'put_failed']")
+    debug("Put failed on one or more files, output from /augeas//error:") unless errors.empty?
+    print_errors(errors)
+  end
+
+  def print_errors(errors)
+    errors.each do |errnode|
+      error = @aug.get(errnode)
+      debug("#{errnode} = #{error}") unless error.nil?
+      @aug.match("#{errnode}/*").each do |subnode|
+        subvalue = @aug.get(subnode)
+        debug("#{subnode} = #{subvalue}")
+      end
+    end
+  end
+
+  # Determines if augeas actually needs to run.
+  def need_to_run?
+    force = resource[:force]
+    return_value = true
+    begin
+      open_augeas
+      filter = resource[:onlyif]
+      unless filter == ""
+        cmd_array = parse_commands(filter)[0]
+        command = cmd_array[0];
+        begin
+          case command
+          when "get"; return_value = process_get(cmd_array)
+          when "match"; return_value = process_match(cmd_array)
+          end
+        rescue SystemExit,NoMemoryError
+          raise
+        rescue Exception => e
+          fail("Error sending command '#{command}' with params #{cmd_array[1..-1].inspect}/#{e.message}")
+        end
+      end
+
+      unless force
+        # If we have a verison of augeas which is at least 0.3.6 then we
+        # can make the changes now and see if changes were made.
+        if return_value and versioncmp(get_augeas_version, "0.3.6") >= 0
+          debug("Will attempt to save and only run if files changed")
+          # Execute in NEWFILE mode so we can show a diff
+          set_augeas_save_mode(SAVE_NEWFILE)
+          do_execute_changes
+          save_result = @aug.save
+          unless save_result
+            print_put_errors
+            fail("Saving failed, see debug")
+          end
+
+          saved_files = @aug.match("/augeas/events/saved")
+          if saved_files.size > 0
+            root = resource[:root].sub(/^\/$/, "")
+            saved_files.map! {|key| @aug.get(key).sub(/^\/files/, root) }
+            saved_files.uniq.each do |saved_file|
+              if Puppet[:show_diff] && @resource[:show_diff]
+                self.send(@resource[:loglevel], "\n" + diff(saved_file, saved_file + ".augnew"))
+              end
+              File.delete(saved_file + ".augnew")
+            end
+            debug("Files changed, should execute")
+            return_value = true
+          else
+            debug("Skipping because no files were changed")
+            return_value = false
+          end
+        end
+      end
+    ensure
+      if not return_value or resource.noop? or not save_result
+        close_augeas
+      end
+    end
+    return_value
+  end
+
+  def execute_changes
+    # Workaround Augeas bug where changing the save mode doesn't trigger a
+    # reload of the previously saved file(s) when we call Augeas#load
+    @aug.match("/augeas/events/saved").each do |file|
+      @aug.rm("/augeas#{@aug.get(file)}/mtime")
+    end
+
+    # Reload augeas, and execute the changes for real
+    set_augeas_save_mode(SAVE_OVERWRITE) if versioncmp(get_augeas_version, "0.3.6") >= 0
+    @aug.load
+    do_execute_changes
+    unless @aug.save
+      print_put_errors
+      fail("Save failed, see debug")
+    end
+
+    :executed
+  ensure
+    close_augeas
+  end
+
+  # Actually execute the augeas changes.
+  def do_execute_changes
+    commands = parse_commands(resource[:changes])
+    commands.each do |cmd_array|
+      fail("invalid command #{cmd_array.join[" "]}") if cmd_array.length < 2
+      command = cmd_array[0]
+      cmd_array.shift
+      begin
+        case command
+          when "set"
+            debug("sending command '#{command}' with params #{cmd_array.inspect}")
+            rv = aug.set(cmd_array[0], cmd_array[1])
+            fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv)
+          when "setm"
+            if aug.respond_to?(command)
+              debug("sending command '#{command}' with params #{cmd_array.inspect}")
+              rv = aug.setm(cmd_array[0], cmd_array[1], cmd_array[2])
+              fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1)
+            else
+              fail("command '#{command}' not supported in installed version of ruby-augeas")
+            end
+          when "rm", "remove"
+            debug("sending command '#{command}' with params #{cmd_array.inspect}")
+            rv = aug.rm(cmd_array[0])
+            fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1)
+          when "clear"
+            debug("sending command '#{command}' with params #{cmd_array.inspect}")
+            rv = aug.clear(cmd_array[0])
+            fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv)
+          when "clearm"
+            # Check command exists ... doesn't currently in ruby-augeas 0.4.1
+            if aug.respond_to?(command)
+              debug("sending command '#{command}' with params #{cmd_array.inspect}")
+              rv = aug.clearm(cmd_array[0], cmd_array[1])
+              fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv)
+            else
+              fail("command '#{command}' not supported in installed version of ruby-augeas")
+            end
+          when "insert", "ins"
+            label = cmd_array[0]
+            where = cmd_array[1]
+            path = cmd_array[2]
+            case where
+              when "before"; before = true
+              when "after"; before = false
+              else fail("Invalid value '#{where}' for where param")
+            end
+            debug("sending command '#{command}' with params #{[label, where, path].inspect}")
+            rv = aug.insert(path, label, before)
+            fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1)
+          when "defvar"
+            debug("sending command '#{command}' with params #{cmd_array.inspect}")
+            rv = aug.defvar(cmd_array[0], cmd_array[1])
+            fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv)
+          when "defnode"
+            debug("sending command '#{command}' with params #{cmd_array.inspect}")
+            rv = aug.defnode(cmd_array[0], cmd_array[1], cmd_array[2])
+            fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv)
+          when "mv", "move"
+            debug("sending command '#{command}' with params #{cmd_array.inspect}")
+            rv = aug.mv(cmd_array[0], cmd_array[1])
+            fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1)
+          else fail("Command '#{command}' is not supported")
+        end
+      rescue SystemExit,NoMemoryError
+        raise
+      rescue Exception => e
+        fail("Error sending command '#{command}' with params #{cmd_array.inspect}/#{e.message}")
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/cisco.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/cisco.rb
new file mode 100644
index 0000000..918982f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/cisco.rb
@@ -0,0 +1,9 @@
+require 'puppet/util/network_device/cisco/device'
+require 'puppet/provider/network_device'
+
+# This is the base class of all prefetched cisco device providers
+class Puppet::Provider::Cisco < Puppet::Provider::NetworkDevice
+  def self.device(url)
+    Puppet::Util::NetworkDevice::Cisco::Device.new(url)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/command.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/command.rb
new file mode 100644
index 0000000..d737c27
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/command.rb
@@ -0,0 +1,25 @@
+# A command that can be executed on the system
+class Puppet::Provider::Command
+  attr_reader :executable
+  attr_reader :name
+
+  # @param [String] name A way of referencing the name
+  # @param [String] executable The path to the executable file
+  # @param resolver An object for resolving the executable to an absolute path (usually Puppet::Util)
+  # @param executor An object for performing the actual execution of the command (usually Puppet::Util::Execution)
+  # @param [Hash] options Extra options to be used when executing (see Puppet::Util::Execution#execute)
+  def initialize(name, executable, resolver, executor, options = {})
+    @name = name
+    @executable = executable
+    @resolver = resolver
+    @executor = executor
+    @options = options
+  end
+
+  # @param args [Array<String>] Any command line arguments to pass to the executable
+  # @return The output from the command
+  def execute(*args)
+    resolved_executable = @resolver.which(@executable) or raise Puppet::Error, "Command #{@name} is missing"
+    @executor.execute([resolved_executable] + args, @options)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/computer/computer.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/computer/computer.rb
new file mode 100644
index 0000000..dd055be
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/computer/computer.rb
@@ -0,0 +1,20 @@
+require 'puppet/provider/nameservice/directoryservice'
+
+Puppet::Type.type(:computer).provide :directoryservice, :parent => Puppet::Provider::NameService::DirectoryService do
+  desc "Computer object management using DirectoryService on OS X.
+  Note that these are distinctly different kinds of objects to 'hosts',
+  as they require a MAC address and can have all sorts of policy attached to
+  them.
+
+  This provider only manages Computer objects in the local directory service
+  domain, not in remote directories.
+
+  If you wish to manage /etc/hosts on Mac OS X, then simply use the host
+  type as per other platforms."
+
+  confine :operatingsystem => :darwin
+  defaultfor :operatingsystem => :darwin
+
+  # hurray for abstraction. The nameservice directoryservice provider can
+  # handle everything we need. super.
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/confine.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/confine.rb
new file mode 100644
index 0000000..4804465
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/confine.rb
@@ -0,0 +1,6 @@
+# Confines have been moved out of the provider as they are also used for other things.
+# This provides backwards compatibility for people still including this old location.
+require 'puppet/provider'
+require 'puppet/confine'
+
+Puppet::Provider::Confine = Puppet::Confine
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/cron/crontab.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/cron/crontab.rb
new file mode 100644
index 0000000..a59fd23
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/cron/crontab.rb
@@ -0,0 +1,260 @@
+require 'puppet/provider/parsedfile'
+
+Puppet::Type.type(:cron).provide(:crontab, :parent => Puppet::Provider::ParsedFile, :default_target => ENV["USER"] || "root") do
+  commands :crontab => "crontab"
+
+  text_line :comment, :match => %r{^\s*#}, :post_parse => proc { |record|
+    record[:name] = $1 if record[:line] =~ /Puppet Name: (.+)\s*$/
+  }
+
+  text_line :blank, :match => %r{^\s*$}
+
+  text_line :environment, :match => %r{^\s*\w+=}
+
+  def self.filetype
+  tabname = case Facter.value(:osfamily)
+            when "Solaris"
+              :suntab
+            when "AIX"
+              :aixtab
+            else
+              :crontab
+            end
+
+    Puppet::Util::FileType.filetype(tabname)
+  end
+
+  self::TIME_FIELDS = [:minute, :hour, :monthday, :month, :weekday]
+
+  record_line :crontab,
+    :fields     => %w{time command},
+    :match      => %r{^\s*(@\w+|\S+\s+\S+\s+\S+\s+\S+\s+\S+)\s+(.+)$},
+    :absent     => '*',
+    :block_eval => :instance do
+
+    def post_parse(record)
+      time = record.delete(:time)
+      if match = /@(\S+)/.match(time)
+        # is there another way to access the constant?
+        Puppet::Type::Cron::ProviderCrontab::TIME_FIELDS.each { |f| record[f] = :absent }
+        record[:special] = match.captures[0]
+      elsif match = /(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/.match(time)
+        record[:special] = :absent
+        Puppet::Type::Cron::ProviderCrontab::TIME_FIELDS.zip(match.captures).each do |field,value|
+          if value == self.absent
+            record[field] = :absent
+          else
+            record[field] = value.split(",")
+          end
+        end
+      else
+        raise Puppet::Error, "Line got parsed as a crontab entry but cannot be handled. Please file a bug with the contents of your crontab"
+      end
+      record
+    end
+
+    def pre_gen(record)
+      if record[:special] and record[:special] != :absent
+        record[:special] = "@#{record[:special]}"
+      end
+
+      Puppet::Type::Cron::ProviderCrontab::TIME_FIELDS.each do |field|
+        if vals = record[field] and vals.is_a?(Array)
+          record[field] = vals.join(",")
+        end
+      end
+      record
+    end
+
+    def to_line(record)
+      str = ""
+      record[:name] = nil if record[:unmanaged]
+      str = "# Puppet Name: #{record[:name]}\n" if record[:name]
+      if record[:environment] and record[:environment] != :absent
+        str += record[:environment].map {|line| "#{line}\n"}.join('')
+      end
+      if record[:special] and record[:special] != :absent
+        fields = [:special, :command]
+      else
+        fields = Puppet::Type::Cron::ProviderCrontab::TIME_FIELDS + [:command]
+      end
+      str += record.values_at(*fields).map do |field|
+        if field.nil? or field == :absent
+          self.absent
+        else
+          field
+        end
+      end.join(self.joiner)
+      str
+    end
+  end
+
+  def create
+    if resource.should(:command) then
+      super
+    else
+      resource.err "no command specified, cannot create"
+    end
+  end
+
+  # Look up a resource with a given name whose user matches a record target
+  #
+  # @api private
+  #
+  # @note This overrides the ParsedFile method for finding resources by name,
+  #   so that only records for a given user are matched to resources of the
+  #   same user so that orphaned records in other crontabs don't get falsely
+  #   matched (#2251)
+  #
+  # @param [Hash<Symbol, Object>] record
+  # @param [Array<Puppet::Resource>] resources
+  #
+  # @return [Puppet::Resource, nil] The resource if found, else nil
+  def self.resource_for_record(record, resources)
+    resource = super
+
+    if resource
+      target = resource[:target] || resource[:user]
+      if record[:target] == target
+        resource
+      end
+    end
+  end
+
+  # Return the header placed at the top of each generated file, warning
+  # users that modifying this file manually is probably a bad idea.
+  def self.header
+%{# HEADER: This file was autogenerated at #{Time.now} by puppet.
+# HEADER: While it can still be managed manually, it is definitely not recommended.
+# HEADER: Note particularly that the comments starting with 'Puppet Name' should
+# HEADER: not be deleted, as doing so could cause duplicate cron jobs.\n}
+  end
+
+  # Regex for finding one vixie cron header.
+  def self.native_header_regex
+    /# DO NOT EDIT THIS FILE.*?Cron version.*?vixie.*?\n/m
+  end
+
+  # If a vixie cron header is found, it should be dropped, cron will insert
+  # a new one in any case, so we need to avoid duplicates.
+  def self.drop_native_header
+    true
+  end
+
+  # See if we can match the record against an existing cron job.
+  def self.match(record, resources)
+    # if the record is named, do not even bother (#19876)
+    # except the resource name was implicitly generated (#3220)
+    return false if record[:name] and !record[:unmanaged]
+    resources.each do |name, resource|
+      # Match the command first, since it's the most important one.
+      next unless record[:target] == resource[:target]
+      next unless record[:command] == resource.value(:command)
+
+      # Now check the time fields
+      compare_fields = self::TIME_FIELDS + [:special]
+
+      matched = true
+      compare_fields.each do |field|
+        # If the resource does not manage a property (say monthday) it should
+        # always match. If it is the other way around (e.g. resource defines
+        # a should value for :special but the record does not have it, we do
+        # not match
+        next unless resource[field]
+        unless record.include?(field)
+          matched = false
+          break
+        end
+
+        if record_value = record[field] and resource_value = resource.value(field)
+          # The record translates '*' into absent in the post_parse hook and
+          # the resource type does exactly the opposite (alias :absent to *)
+          next if resource_value == '*' and record_value == :absent
+          next if resource_value == record_value
+        end
+        matched =false
+        break
+      end
+      return resource if matched
+    end
+    false
+  end
+
+  @name_index = 0
+
+  # Collapse name and env records.
+  def self.prefetch_hook(records)
+    name = nil
+    envs = nil
+    result = records.each { |record|
+      case record[:record_type]
+      when :comment
+        if record[:name]
+          name = record[:name]
+          record[:skip] = true
+
+          # Start collecting env values
+          envs = []
+        end
+      when :environment
+        # If we're collecting env values (meaning we're in a named cronjob),
+        # store the line and skip the record.
+        if envs
+          envs << record[:line]
+          record[:skip] = true
+        end
+      when :blank
+        # nothing
+      else
+        if name
+          record[:name] = name
+          name = nil
+        else
+          cmd_string = record[:command].gsub(/\s+/, "_")
+          index = ( @name_index += 1 )
+          record[:name] = "unmanaged:#{cmd_string}-#{ index.to_s }"
+          record[:unmanaged] = true
+        end
+        if envs.nil? or envs.empty?
+          record[:environment] = :absent
+        else
+          # Collect all of the environment lines, and mark the records to be skipped,
+          # since their data is included in our crontab record.
+          record[:environment] = envs
+
+          # And turn off env collection again
+          envs = nil
+        end
+      end
+    }.reject { |record| record[:skip] }
+    result
+  end
+
+  def self.to_file(records)
+    text = super
+    # Apparently Freebsd will "helpfully" add a new TZ line to every
+    # single cron line, but not in all cases (e.g., it doesn't do it
+    # on my machine).  This is my attempt to fix it so the TZ lines don't
+    # multiply.
+    if text =~ /(^TZ=.+\n)/
+      tz = $1
+      text.sub!(tz, '')
+      text = tz + text
+    end
+    text
+  end
+
+  def user=(user)
+    # we have to mark the target as modified first, to make sure that if
+    # we move a cronjob from userA to userB, userA's crontab will also
+    # be rewritten
+    mark_target_modified
+    @property_hash[:user] = user
+    @property_hash[:target] = user
+  end
+
+  def user
+    @property_hash[:user] || @property_hash[:target]
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/exec.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/exec.rb
new file mode 100644
index 0000000..6222864
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/exec.rb
@@ -0,0 +1,105 @@
+require 'puppet/provider'
+require 'puppet/util/execution'
+
+class Puppet::Provider::Exec < Puppet::Provider
+  include Puppet::Util::Execution
+
+  def run(command, check = false)
+    output = nil
+    status = nil
+    dir = nil
+
+    checkexe(command)
+
+    if dir = resource[:cwd]
+      unless File.directory?(dir)
+        if check
+          dir = nil
+        else
+          self.fail "Working directory '#{dir}' does not exist"
+        end
+      end
+    end
+
+    dir ||= Dir.pwd
+
+    debug "Executing#{check ? " check": ""} '#{command}'"
+    begin
+      # Do our chdir
+      Dir.chdir(dir) do
+        environment = {}
+
+        environment[:PATH] = resource[:path].join(File::PATH_SEPARATOR) if resource[:path]
+
+        if envlist = resource[:environment]
+          envlist = [envlist] unless envlist.is_a? Array
+          envlist.each do |setting|
+            if setting =~ /^(\w+)=((.|\n)+)$/
+              env_name = $1
+              value = $2
+              if environment.include?(env_name) || environment.include?(env_name.to_sym)
+                warning "Overriding environment setting '#{env_name}' with '#{value}'"
+              end
+              environment[env_name] = value
+            else
+              warning "Cannot understand environment setting #{setting.inspect}"
+            end
+          end
+        end
+
+        if Puppet.features.microsoft_windows?
+          exec_user = resource[:user]
+        # Etc.getpwuid() returns nil on Windows
+        elsif resource.current_username == resource[:user]
+          exec_user = nil
+        else
+          exec_user = resource[:user]
+        end
+
+        # Ruby 2.1 and later interrupt execution in a way that bypasses error
+        # handling by default. Passing Timeout::Error causes an exception to be
+        # raised that can be rescued inside of the block by cleanup routines.
+        #
+        # This is backwards compatible all the way to Ruby 1.8.7.
+        Timeout.timeout(resource[:timeout], Timeout::Error) do
+          # note that we are passing "false" for the "override_locale" parameter, which ensures that the user's
+          # default/system locale will be respected.  Callers may override this behavior by setting locale-related
+          # environment variables (LANG, LC_ALL, etc.) in their 'environment' configuration.
+          output = Puppet::Util::Execution.execute(command, :failonfail => false, :combine => true,
+                                  :uid => exec_user, :gid => resource[:group],
+                                  :override_locale => false,
+                                  :custom_environment => environment)
+        end
+        # The shell returns 127 if the command is missing.
+        if output.exitstatus == 127
+          raise ArgumentError, output
+        end
+
+      end
+    rescue Errno::ENOENT => detail
+      self.fail Puppet::Error, detail.to_s, detail
+    end
+
+    # Return output twice as processstatus was returned before, but only exitstatus was ever called.
+    # Output has the exitstatus on it so it is returned instead. This is here twice as changing this
+    #  would result in a change to the underlying API.
+    return output, output
+  end
+
+  def extractexe(command)
+    if command.is_a? Array
+      command.first
+    elsif match = /^"([^"]+)"|^'([^']+)'/.match(command)
+      # extract whichever of the two sides matched the content.
+      match[1] or match[2]
+    else
+      command.split(/ /)[0]
+    end
+  end
+
+  def validatecmd(command)
+    exe = extractexe(command)
+    # if we're not fully qualified, require a path
+    self.fail "'#{command}' is not qualified and no path was specified. Please qualify the command or specify a path." if !absolute_path?(exe) and resource[:path].nil?
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/exec/posix.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/exec/posix.rb
new file mode 100644
index 0000000..1b0ae56
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/exec/posix.rb
@@ -0,0 +1,48 @@
+require 'puppet/provider/exec'
+
+Puppet::Type.type(:exec).provide :posix, :parent => Puppet::Provider::Exec do
+  has_feature :umask
+  confine :feature => :posix
+  defaultfor :feature => :posix
+
+  desc <<-EOT
+    Executes external binaries directly, without passing through a shell or
+    performing any interpolation. This is a safer and more predictable way
+    to execute most commands, but prevents the use of globbing and shell
+    built-ins (including control logic like "for" and "if" statements).
+  EOT
+
+  # Verify that we have the executable
+  def checkexe(command)
+    exe = extractexe(command)
+
+    if File.expand_path(exe) == exe
+      if !Puppet::FileSystem.exist?(exe)
+        raise ArgumentError, "Could not find command '#{exe}'"
+      elsif !File.file?(exe)
+        raise ArgumentError, "'#{exe}' is a #{File.ftype(exe)}, not a file"
+      elsif !File.executable?(exe)
+        raise ArgumentError, "'#{exe}' is not executable"
+      end
+      return
+    end
+
+    if resource[:path]
+      Puppet::Util.withenv :PATH => resource[:path].join(File::PATH_SEPARATOR) do
+        return if which(exe)
+      end
+    end
+
+    # 'which' will only return the command if it's executable, so we can't
+    # distinguish not found from not executable
+    raise ArgumentError, "Could not find command '#{exe}'"
+  end
+
+  def run(command, check = false)
+    if resource[:umask]
+      Puppet::Util::withumask(resource[:umask]) { super(command, check) }
+    else
+      super(command, check)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/exec/shell.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/exec/shell.rb
new file mode 100644
index 0000000..3dbf75f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/exec/shell.rb
@@ -0,0 +1,25 @@
+Puppet::Type.type(:exec).provide :shell, :parent => :posix do
+  include Puppet::Util::Execution
+
+  confine :feature => :posix
+
+  desc <<-EOT
+    Passes the provided command through `/bin/sh`; only available on
+    POSIX systems. This allows the use of shell globbing and built-ins, and
+    does not require that the path to a command be fully-qualified. Although
+    this can be more convenient than the `posix` provider, it also means that
+    you need to be more careful with escaping; as ever, with great power comes
+    etc. etc.
+
+    This provider closely resembles the behavior of the `exec` type
+    in Puppet 0.25.x.
+  EOT
+
+  def run(command, check = false)
+    super(['/bin/sh', '-c', command], check)
+  end
+
+  def validatecmd(command)
+    true
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/exec/windows.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/exec/windows.rb
new file mode 100644
index 0000000..4c792af
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/exec/windows.rb
@@ -0,0 +1,55 @@
+require 'puppet/provider/exec'
+
+Puppet::Type.type(:exec).provide :windows, :parent => Puppet::Provider::Exec do
+
+  confine    :operatingsystem => :windows
+  defaultfor :operatingsystem => :windows
+
+  desc <<-'EOT'
+    Execute external binaries on Windows systems. As with the `posix`
+    provider, this provider directly calls the command with the arguments
+    given, without passing it through a shell or performing any interpolation.
+    To use shell built-ins --- that is, to emulate the `shell` provider on
+    Windows --- a command must explicitly invoke the shell:
+
+        exec {'echo foo':
+          command => 'cmd.exe /c echo "foo"',
+        }
+
+    If no extension is specified for a command, Windows will use the `PATHEXT`
+    environment variable to locate the executable.
+
+    **Note on PowerShell scripts:** PowerShell's default `restricted`
+    execution policy doesn't allow it to run saved scripts. To run PowerShell
+    scripts, specify the `remotesigned` execution policy as part of the
+    command:
+
+        exec { 'test':
+          path    => 'C:/Windows/System32/WindowsPowerShell/v1.0',
+          command => 'powershell -executionpolicy remotesigned -file C:/test.ps1',
+        }
+
+  EOT
+
+  # Verify that we have the executable
+  def checkexe(command)
+    exe = extractexe(command)
+
+    if absolute_path?(exe)
+      if !Puppet::FileSystem.exist?(exe)
+        raise ArgumentError, "Could not find command '#{exe}'"
+      elsif !File.file?(exe)
+        raise ArgumentError, "'#{exe}' is a #{File.ftype(exe)}, not a file"
+      end
+      return
+    end
+
+    if resource[:path]
+      Puppet::Util.withenv :PATH => resource[:path].join(File::PATH_SEPARATOR) do
+        return if which(exe)
+      end
+    end
+
+    raise ArgumentError, "Could not find command '#{exe}'"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/file/posix.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/file/posix.rb
new file mode 100644
index 0000000..0ce7d22
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/file/posix.rb
@@ -0,0 +1,136 @@
+Puppet::Type.type(:file).provide :posix do
+  desc "Uses POSIX functionality to manage file ownership and permissions."
+
+  confine :feature => :posix
+  has_features :manages_symlinks
+
+  include Puppet::Util::POSIX
+  include Puppet::Util::Warnings
+
+  require 'etc'
+
+  def uid2name(id)
+    return id.to_s if id.is_a?(Symbol) or id.is_a?(String)
+    return nil if id > Puppet[:maximum_uid].to_i
+
+    begin
+      user = Etc.getpwuid(id)
+    rescue TypeError, ArgumentError
+      return nil
+    end
+
+    if user.uid == ""
+      return nil
+    else
+      return user.name
+    end
+  end
+
+  # Determine if the user is valid, and if so, return the UID
+  def name2uid(value)
+    Integer(value) rescue uid(value) || false
+  end
+
+  def gid2name(id)
+    return id.to_s if id.is_a?(Symbol) or id.is_a?(String)
+    return nil if id > Puppet[:maximum_uid].to_i
+
+    begin
+      group = Etc.getgrgid(id)
+    rescue TypeError, ArgumentError
+      return nil
+    end
+
+    if group.gid == ""
+      return nil
+    else
+      return group.name
+    end
+  end
+
+  def name2gid(value)
+    Integer(value) rescue gid(value) || false
+  end
+
+  def owner
+    unless stat = resource.stat
+      return :absent
+    end
+
+    currentvalue = stat.uid
+
+    # On OS X, files that are owned by -2 get returned as really
+    # large UIDs instead of negative ones.  This isn't a Ruby bug,
+    # it's an OS X bug, since it shows up in perl, too.
+    if currentvalue > Puppet[:maximum_uid].to_i
+      self.warning "Apparently using negative UID (#{currentvalue}) on a platform that does not consistently handle them"
+      currentvalue = :silly
+    end
+
+    currentvalue
+  end
+
+  def owner=(should)
+    # Set our method appropriately, depending on links.
+    if resource[:links] == :manage
+      method = :lchown
+    else
+      method = :chown
+    end
+
+    begin
+      File.send(method, should, nil, resource[:path])
+    rescue => detail
+      raise Puppet::Error, "Failed to set owner to '#{should}': #{detail}", detail.backtrace
+    end
+  end
+
+  def group
+    return :absent unless stat = resource.stat
+
+    currentvalue = stat.gid
+
+    # On OS X, files that are owned by -2 get returned as really
+    # large GIDs instead of negative ones.  This isn't a Ruby bug,
+    # it's an OS X bug, since it shows up in perl, too.
+    if currentvalue > Puppet[:maximum_uid].to_i
+      self.warning "Apparently using negative GID (#{currentvalue}) on a platform that does not consistently handle them"
+      currentvalue = :silly
+    end
+
+    currentvalue
+  end
+
+  def group=(should)
+    # Set our method appropriately, depending on links.
+    if resource[:links] == :manage
+      method = :lchown
+    else
+      method = :chown
+    end
+
+    begin
+      File.send(method, nil, should, resource[:path])
+    rescue => detail
+      raise Puppet::Error, "Failed to set group to '#{should}': #{detail}", detail.backtrace
+    end
+  end
+
+  def mode
+    if stat = resource.stat
+      return (stat.mode & 007777).to_s(8)
+    else
+      return :absent
+    end
+  end
+
+  def mode=(value)
+    begin
+      File.chmod(value.to_i(8), resource[:path])
+    rescue => detail
+      error = Puppet::Error.new("failed to set mode #{mode} on #{resource[:path]}: #{detail.message}")
+      error.set_backtrace detail.backtrace
+      raise error
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/file/windows.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/file/windows.rb
new file mode 100644
index 0000000..c0ef68c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/file/windows.rb
@@ -0,0 +1,104 @@
+Puppet::Type.type(:file).provide :windows do
+  desc "Uses Microsoft Windows functionality to manage file ownership and permissions."
+
+  confine :operatingsystem => :windows
+  has_feature :manages_symlinks if Puppet.features.manages_symlinks?
+
+  include Puppet::Util::Warnings
+
+  if Puppet.features.microsoft_windows?
+    require 'puppet/util/windows'
+    include Puppet::Util::Windows::Security
+  end
+
+  # Determine if the account is valid, and if so, return the UID
+  def name2id(value)
+    Puppet::Util::Windows::SID.name_to_sid(value)
+  end
+
+  # If it's a valid SID, get the name. Otherwise, it's already a name,
+  # so just return it.
+  def id2name(id)
+    if Puppet::Util::Windows::SID.valid_sid?(id)
+      Puppet::Util::Windows::SID.sid_to_name(id)
+    else
+      id
+    end
+  end
+
+  # We use users and groups interchangeably, so use the same methods for both
+  # (the type expects different methods, so we have to oblige).
+  alias :uid2name :id2name
+  alias :gid2name :id2name
+
+  alias :name2gid :name2id
+  alias :name2uid :name2id
+
+  def owner
+    return :absent unless resource.stat
+    get_owner(resource[:path])
+  end
+
+  def owner=(should)
+    begin
+      set_owner(should, resolved_path)
+    rescue => detail
+      raise Puppet::Error, "Failed to set owner to '#{should}': #{detail}", detail.backtrace
+    end
+  end
+
+  def group
+    return :absent unless resource.stat
+    get_group(resource[:path])
+  end
+
+  def group=(should)
+    begin
+      set_group(should, resolved_path)
+    rescue => detail
+      raise Puppet::Error, "Failed to set group to '#{should}': #{detail}", detail.backtrace
+    end
+  end
+
+  def mode
+    if resource.stat
+      mode = get_mode(resource[:path])
+      mode ? mode.to_s(8) : :absent
+    else
+      :absent
+    end
+  end
+
+  def mode=(value)
+    begin
+      set_mode(value.to_i(8), resource[:path])
+    rescue => detail
+      error = Puppet::Error.new("failed to set mode #{mode} on #{resource[:path]}: #{detail.message}")
+      error.set_backtrace detail.backtrace
+      raise error
+    end
+    :file_changed
+  end
+
+  def validate
+    if [:owner, :group, :mode].any?{|p| resource[p]} and !supports_acl?(resource[:path])
+      resource.fail("Can only manage owner, group, and mode on filesystems that support Windows ACLs, such as NTFS")
+    end
+  end
+
+  attr_reader :file
+  private
+  def file
+    @file ||= Puppet::FileSystem.pathname(resource[:path])
+  end
+
+  def resolved_path
+    path = file()
+    # under POSIX, :manage means use lchown - i.e. operate on the link
+    return path.to_s if resource[:links] == :manage
+
+    # otherwise, use chown -- that will resolve the link IFF it is a link
+    # otherwise it will operate on the path
+    Puppet::FileSystem.symlink?(path) ? Puppet::FileSystem.readlink(path) : path.to_s
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/group/aix.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/group/aix.rb
new file mode 100644
index 0000000..1722748
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/group/aix.rb
@@ -0,0 +1,141 @@
+#
+# Group Puppet provider for AIX. It uses standard commands to manage groups:
+#  mkgroup, rmgroup, lsgroup, chgroup
+#
+# Author::    Hector Rivas Gandara <keymon@gmail.com>
+#
+require 'puppet/provider/aixobject'
+
+Puppet::Type.type(:group).provide :aix, :parent => Puppet::Provider::AixObject do
+  desc "Group management for AIX."
+
+  # This will the default provider for this platform
+  defaultfor :operatingsystem => :aix
+  confine :operatingsystem => :aix
+
+  # Provider features
+  has_features :manages_aix_lam
+  has_features :manages_members
+
+  # Commands that manage the element
+  commands :list      => "/usr/sbin/lsgroup"
+  commands :add       => "/usr/bin/mkgroup"
+  commands :delete    => "/usr/sbin/rmgroup"
+  commands :modify    => "/usr/bin/chgroup"
+
+  # Group attributes to ignore
+  def self.attribute_ignore
+    []
+  end
+
+  # AIX attributes to properties mapping.
+  #
+  # Valid attributes to be managed by this provider.
+  # It is a list with of hash
+  #  :aix_attr      AIX command attribute name
+  #  :puppet_prop   Puppet propertie name
+  #  :to            Method to adapt puppet property to aix command value. Optional.
+  #  :from          Method to adapt aix command value to puppet property. Optional
+  self.attribute_mapping = [
+    #:name => :name,
+    {:aix_attr => :id,       :puppet_prop => :gid },
+    {:aix_attr => :users,    :puppet_prop => :members,
+      :from => :users_from_attr},
+    {:aix_attr => :attributes, :puppet_prop => :attributes},
+  ]
+
+  #--------------
+  # Command definition
+
+  # Return the IA module arguments based on the resource param ia_load_module
+  def get_ia_module_args
+    if @resource[:ia_load_module]
+      ["-R", @resource[:ia_load_module].to_s]
+    else
+      []
+    end
+  end
+
+  def lscmd(value=@resource[:name])
+    [self.class.command(:list)] +
+      self.get_ia_module_args +
+      [ value]
+  end
+
+  def lsallcmd()
+    lscmd("ALL")
+  end
+
+  def addcmd(extra_attrs = [])
+    # Here we use the @resource.to_hash to get the list of provided parameters
+    # Puppet does not call to self.<parameter>= method if it does not exists.
+    #
+    # It gets an extra list of arguments to add to the user.
+    [self.class.command(:add) ] +
+      self.get_ia_module_args +
+      self.hash2args(@resource.to_hash) +
+      extra_attrs + [@resource[:name]]
+  end
+
+  def modifycmd(hash = property_hash)
+    args = self.hash2args(hash)
+    return nil if args.empty?
+
+    [self.class.command(:modify)] +
+      self.get_ia_module_args +
+      args + [@resource[:name]]
+  end
+
+  def deletecmd
+    [self.class.command(:delete)] +
+      self.get_ia_module_args +
+      [@resource[:name]]
+  end
+
+
+  #--------------
+  # Overwrite get_arguments to add the attributes arguments
+  def get_arguments(key, value, mapping, objectinfo)
+    # In the case of attributes, return a list of key=vlaue
+    if key == :attributes
+      raise Puppet::Error, "Attributes must be a list of pairs key=value on #{@resource.class.name}[#{@resource.name}]" \
+        unless value and value.is_a? Hash
+      return value.select { |k,v| true }.map { |pair| pair.join("=") }
+    end
+    super(key, value, mapping, objectinfo)
+  end
+
+  def filter_attributes(hash)
+    # Return only not managed attributtes.
+    hash.select {
+        |k,v| !self.class.attribute_mapping_from.include?(k) and
+                !self.class.attribute_ignore.include?(k)
+      }.inject({}) {
+        |hash, array| hash[array[0]] = array[1]; hash
+      }
+  end
+
+  def attributes
+    filter_attributes(getosinfo(false))
+  end
+
+  def attributes=(attr_hash)
+    #self.class.validate(param, value)
+    param = :attributes
+    cmd = modifycmd({param => filter_attributes(attr_hash)})
+    if cmd
+      begin
+        execute(cmd)
+      rescue Puppet::ExecutionFailure  => detail
+        raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}", detail.backtrace
+      end
+    end
+  end
+
+  # Force convert users it a list.
+  def users_from_attr(value)
+    (value.is_a? String) ? value.split(',') : value
+  end
+
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/group/directoryservice.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/group/directoryservice.rb
new file mode 100644
index 0000000..e112848
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/group/directoryservice.rb
@@ -0,0 +1,12 @@
+require 'puppet/provider/nameservice/directoryservice'
+
+Puppet::Type.type(:group).provide :directoryservice, :parent => Puppet::Provider::NameService::DirectoryService do
+  desc "Group management using DirectoryService on OS X.
+
+  "
+
+  commands :dscl => "/usr/bin/dscl"
+  confine :operatingsystem => :darwin
+  defaultfor :operatingsystem => :darwin
+  has_feature :manages_members
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/group/groupadd.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/group/groupadd.rb
new file mode 100644
index 0000000..f345bdc
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/group/groupadd.rb
@@ -0,0 +1,85 @@
+require 'puppet/provider/nameservice/objectadd'
+require 'puppet/util/libuser'
+
+Puppet::Type.type(:group).provide :groupadd, :parent => Puppet::Provider::NameService::ObjectAdd do
+  desc "Group management via `groupadd` and its ilk. The default for most platforms.
+
+  "
+
+  commands :add => "groupadd", :delete => "groupdel", :modify => "groupmod"
+
+  has_feature :system_groups unless %w{HP-UX Solaris}.include? Facter.value(:operatingsystem)
+
+  verify :gid, "GID must be an integer" do |value|
+    value.is_a? Integer
+  end
+
+  optional_commands :localadd => "lgroupadd"
+  has_feature :libuser if Puppet.features.libuser?
+
+  def exists?
+    return !!localgid if @resource.forcelocal?
+    super
+  end
+
+  def gid
+    return localgid if @resource.forcelocal?
+    get(:gid)
+  end
+
+  def findgroup(key, value)
+    group_file = "/etc/group"
+    group_keys = ['group_name', 'password', 'gid', 'user_list']
+    index = group_keys.index(key)
+    File.open(group_file) do |f|
+      f.each_line do |line|
+         group = line.split(":")
+         if group[index] == value
+             f.close
+             return group
+         end
+      end
+    end
+    false
+  end
+
+  def localgid
+    group = findgroup('group_name', resource[:name])
+    return group[2] if group
+    false
+  end
+
+  def check_allow_dup
+    # We have to manually check for duplicates when using libuser
+    # because by default duplicates are allowed.  This check is
+    # to ensure consistent behaviour of the useradd provider when
+    # using both useradd and luseradd
+    if not @resource.allowdupe? and @resource.forcelocal?
+       if @resource.should(:gid) and findgroup('gid', @resource.should(:gid).to_s)
+           raise(Puppet::Error, "GID #{@resource.should(:gid).to_s} already exists, use allowdupe to force group creation")
+       end
+    elsif @resource.allowdupe? and not @resource.forcelocal?
+       return ["-o"]
+    end
+    []
+  end
+
+  def addcmd
+    if @resource.forcelocal?
+      cmd = [command(:localadd)]
+      @custom_environment = Puppet::Util::Libuser.getenv
+    else
+      cmd = [command(:add)]
+    end
+
+    if gid = @resource.should(:gid)
+      unless gid == :absent
+        cmd << flag(:gid) << gid
+      end
+    end
+    cmd += check_allow_dup
+    cmd << "-r" if @resource.system? and self.class.system_groups?
+    cmd << @resource[:name]
+    cmd
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/group/ldap.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/group/ldap.rb
new file mode 100644
index 0000000..01ba43d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/group/ldap.rb
@@ -0,0 +1,45 @@
+require 'puppet/provider/ldap'
+
+Puppet::Type.type(:group).provide :ldap, :parent => Puppet::Provider::Ldap do
+  desc "Group management via LDAP.
+
+    This provider requires that you have valid values for all of the
+    LDAP-related settings in `puppet.conf`, including `ldapbase`.  You will
+    almost definitely need settings for `ldapuser` and `ldappassword` in order
+    for your clients to write to LDAP.
+
+    Note that this provider will automatically generate a GID for you if you do
+    not specify one, but it is a potentially expensive operation, as it
+    iterates across all existing groups to pick the appropriate next one."
+
+  confine :feature => :ldap, :false => (Puppet[:ldapuser] == "")
+
+  # We're mapping 'members' here because we want to make it
+  # easy for the ldap user provider to manage groups.  This
+  # way it can just use the 'update' method in the group manager,
+  # whereas otherwise it would need to replicate that code.
+  manages(:posixGroup).at("ou=Groups").and.maps :name => :cn, :gid => :gidNumber, :members => :memberUid
+
+  # Find the next gid after the current largest gid.
+  provider = self
+  manager.generates(:gidNumber).with do
+    largest = 500
+    if existing = provider.manager.search
+        existing.each do |hash|
+        next unless value = hash[:gid]
+        num = value[0].to_i
+        largest = num if num > largest
+      end
+    end
+    largest + 1
+  end
+
+  # Convert a group name to an id.
+  def self.name2id(group)
+    return nil unless result = manager.search("cn=#{group}") and result.length > 0
+
+    # Only use the first result.
+    group = result[0]
+    group[:gid][0]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/group/pw.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/group/pw.rb
new file mode 100644
index 0000000..96b0199
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/group/pw.rb
@@ -0,0 +1,49 @@
+require 'puppet/provider/nameservice/pw'
+
+Puppet::Type.type(:group).provide :pw, :parent => Puppet::Provider::NameService::PW do
+  desc "Group management via `pw` on FreeBSD and DragonFly BSD."
+
+  commands :pw => "pw"
+  has_features :manages_members
+
+  defaultfor :operatingsystem => [:freebsd, :dragonfly]
+  confine    :operatingsystem => [:freebsd, :dragonfly]
+
+  options :members, :flag => "-M", :method => :mem
+
+  verify :gid, "GID must be an integer" do |value|
+    value.is_a? Integer
+  end
+
+  def addcmd
+    cmd = [command(:pw), "groupadd", @resource[:name]]
+
+    if gid = @resource.should(:gid)
+      unless gid == :absent
+        cmd << flag(:gid) << gid
+      end
+    end
+
+    if members = @resource.should(:members)
+      unless members == :absent
+        if members.is_a?(Array)
+          members = members.join(",")
+        end
+        cmd << "-M" << members
+      end
+    end
+
+    cmd << "-o" if @resource.allowdupe?
+
+    cmd
+  end
+
+  def modifycmd(param, value)
+    # members may be an array, need a comma separated list
+    if param == :members and value.is_a?(Array)
+      value = value.join(",")
+    end
+    super(param, value)
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/group/windows_adsi.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/group/windows_adsi.rb
new file mode 100644
index 0000000..e4472da
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/group/windows_adsi.rb
@@ -0,0 +1,107 @@
+require 'puppet/util/windows'
+
+Puppet::Type.type(:group).provide :windows_adsi do
+  desc "Local group management for Windows. Group members can be both users and groups.
+    Additionally, local groups can contain domain users."
+
+  defaultfor :operatingsystem => :windows
+  confine    :operatingsystem => :windows
+
+  has_features :manages_members
+
+  def initialize(value={})
+    super(value)
+    @deleted = false
+  end
+
+  def members_insync?(current, should)
+    return false unless current
+
+    # By comparing account SIDs we don't have to worry about case
+    # sensitivity, or canonicalization of account names.
+
+    # Cannot use munge of the group property to canonicalize @should
+    # since the default array_matching comparison is not commutative
+
+    # dupes automatically weeded out when hashes built
+    current_users = Puppet::Util::Windows::ADSI::Group.name_sid_hash(current)
+    specified_users = Puppet::Util::Windows::ADSI::Group.name_sid_hash(should)
+
+    if @resource[:auth_membership]
+      current_users == specified_users
+    else
+      return true if specified_users.empty?
+      (specified_users.keys.to_a & current_users.keys.to_a) == specified_users.keys.to_a
+    end
+  end
+
+  def members_to_s(users)
+    return '' if users.nil? or !users.kind_of?(Array)
+    users = users.map do |user_name|
+      sid = Puppet::Util::Windows::SID.name_to_sid_object(user_name)
+      if !sid
+        resource.debug("#{user_name} (unresolvable to SID)")
+        next user_name
+      end
+
+      if sid.account =~ /\\/
+        account, _ = Puppet::Util::Windows::ADSI::User.parse_name(sid.account)
+      else
+        account = sid.account
+      end
+      resource.debug("#{sid.domain}\\#{account} (#{sid.to_s})")
+      "#{sid.domain}\\#{account}"
+    end
+    return users.join(',')
+  end
+
+  def member_valid?(user_name)
+    ! Puppet::Util::Windows::SID.name_to_sid_object(user_name).nil?
+  end
+
+  def group
+    @group ||= Puppet::Util::Windows::ADSI::Group.new(@resource[:name])
+  end
+
+  def members
+    group.members
+  end
+
+  def members=(members)
+    group.set_members(members, @resource[:auth_membership])
+  end
+
+  def create
+    @group = Puppet::Util::Windows::ADSI::Group.create(@resource[:name])
+    @group.commit
+
+    self.members = @resource[:members]
+  end
+
+  def exists?
+    Puppet::Util::Windows::ADSI::Group.exists?(@resource[:name])
+  end
+
+  def delete
+    Puppet::Util::Windows::ADSI::Group.delete(@resource[:name])
+
+    @deleted = true
+  end
+
+  # Only flush if we created or modified a group, not deleted
+  def flush
+    @group.commit if @group && !@deleted
+  end
+
+  def gid
+    Puppet::Util::Windows::SID.name_to_sid(@resource[:name])
+  end
+
+  def gid=(value)
+    fail "gid is read-only"
+  end
+
+  def self.instances
+    Puppet::Util::Windows::ADSI::Group.map { |g| new(:ensure => :present, :name => g.name) }
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/host/parsed.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/host/parsed.rb
new file mode 100644
index 0000000..c51dd53
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/host/parsed.rb
@@ -0,0 +1,44 @@
+require 'puppet/provider/parsedfile'
+
+hosts = nil
+case Facter.value(:osfamily)
+when "Solaris"; hosts = "/etc/inet/hosts"
+when "windows"
+  require 'win32/resolv'
+  hosts = Win32::Resolv.get_hosts_path
+else
+  hosts = "/etc/hosts"
+end
+
+
+Puppet::Type.type(:host).provide(:parsed,:parent => Puppet::Provider::ParsedFile,
+  :default_target => hosts,:filetype => :flat) do
+  confine :exists => hosts
+
+  text_line :comment, :match => /^#/
+  text_line :blank, :match => /^\s*$/
+
+  record_line :parsed, :fields => %w{ip name host_aliases comment},
+    :optional => %w{host_aliases comment},
+    :match    => /^(\S+)\s+(\S+)\s*(.*?)?(?:\s*#\s*(.*))?$/,
+    :post_parse => proc { |hash|
+      # An absent comment should match "comment => ''"
+      hash[:comment] = '' if hash[:comment].nil? or hash[:comment] == :absent
+      unless hash[:host_aliases].nil? or hash[:host_aliases] == :absent
+        hash[:host_aliases].gsub!(/\s+/,' ') # Change delimiter
+      end
+    },
+    :to_line  => proc { |hash|
+      [:ip, :name].each do |n|
+        raise ArgumentError, "#{n} is a required attribute for hosts" unless hash[n] and hash[n] != :absent
+      end
+      str = "#{hash[:ip]}\t#{hash[:name]}"
+      if hash.include? :host_aliases and !hash[:host_aliases].nil? and hash[:host_aliases] != :absent
+        str += "\t#{hash[:host_aliases]}"
+      end
+      if hash.include? :comment and !hash[:comment].empty?
+        str += "\t# #{hash[:comment]}"
+      end
+      str
+    }
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/interface/cisco.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/interface/cisco.rb
new file mode 100644
index 0000000..a0f82c7
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/interface/cisco.rb
@@ -0,0 +1,27 @@
+require 'puppet/provider/cisco'
+
+Puppet::Type.type(:interface).provide :cisco, :parent => Puppet::Provider::Cisco do
+
+  desc "Cisco switch/router provider for interface."
+
+  mk_resource_methods
+
+  def self.lookup(device, name)
+    interface = nil
+    device.command do |dev|
+      interface = dev.interface(name)
+    end
+    interface
+  end
+
+  def initialize(device, *args)
+    super
+  end
+
+  def flush
+    device.command do |dev|
+      dev.new_interface(name).update(former_properties, properties)
+    end
+    super
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/ldap.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/ldap.rb
new file mode 100644
index 0000000..412a921
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/ldap.rb
@@ -0,0 +1,137 @@
+require 'puppet/provider'
+
+# The base class for LDAP providers.
+class Puppet::Provider::Ldap < Puppet::Provider
+  require 'puppet/util/ldap/manager'
+
+  class << self
+    attr_reader :manager
+  end
+
+  # Look up all instances at our location.  Yay.
+  def self.instances
+    return [] unless list = manager.search
+
+    list.collect { |entry| new(entry) }
+  end
+
+  # Specify the ldap manager for this provider, which is
+  # used to figure out how we actually interact with ldap.
+  def self.manages(*args)
+    @manager = Puppet::Util::Ldap::Manager.new
+    @manager.manages(*args)
+
+    # Set up our getter/setter methods.
+    mk_resource_methods
+    @manager
+  end
+
+  # Query all of our resources from ldap.
+  def self.prefetch(resources)
+    resources.each do |name, resource|
+      if result = manager.find(name)
+        result[:ensure] = :present
+        resource.provider = new(result)
+      else
+        resource.provider = new(:ensure => :absent)
+      end
+    end
+  end
+
+  def manager
+    self.class.manager
+  end
+
+  def create
+    @property_hash[:ensure] = :present
+    self.class.resource_type.validproperties.each do |property|
+      if val = resource.should(property)
+        if property.to_s == 'gid'
+          self.gid = val
+        else
+          @property_hash[property] = val
+        end
+      end
+    end
+  end
+
+  def delete
+    @property_hash[:ensure] = :absent
+  end
+
+  def exists?
+    @property_hash[:ensure] != :absent
+  end
+
+  # Apply our changes to ldap, yo.
+  def flush
+    # Just call the manager's update() method.
+    @property_hash.delete(:groups)
+    @ldap_properties.delete(:groups)
+    manager.update(name, ldap_properties, properties)
+    @property_hash.clear
+    @ldap_properties.clear
+  end
+
+  def initialize(*args)
+    raise(Puppet::DevError, "No LDAP Configuration defined for #{self.class}") unless self.class.manager
+    raise(Puppet::DevError, "Invalid LDAP Configuration defined for #{self.class}") unless self.class.manager.valid?
+    super
+
+    @property_hash = @property_hash.inject({}) do |result, ary|
+      param, values = ary
+
+      # Skip any attributes we don't manage.
+      next result unless self.class.resource_type.valid_parameter?(param)
+
+      paramclass = self.class.resource_type.attrclass(param)
+
+      unless values.is_a?(Array)
+        result[param] = values
+        next result
+      end
+
+      # Only use the first value if the attribute class doesn't manage
+      # arrays of values.
+      if paramclass.superclass == Puppet::Parameter or paramclass.array_matching == :first
+        result[param] = values[0]
+      else
+        result[param] = values
+      end
+      result
+    end
+
+    # Make a duplicate, so that we have a copy for comparison
+    # at the end.
+    @ldap_properties = @property_hash.dup
+  end
+
+  # Return the current state of ldap.
+  def ldap_properties
+    @ldap_properties.dup
+  end
+
+  # Return (and look up if necessary) the desired state.
+  def properties
+    if @property_hash.empty?
+      @property_hash = query || {:ensure => :absent}
+      @property_hash[:ensure] = :absent if @property_hash.empty?
+    end
+    @property_hash.dup
+  end
+
+  # Collect the current attributes from ldap.  Returns
+  # the results, but also stores the attributes locally,
+  # so we have something to compare against when we update.
+  # LAK:NOTE This is normally not used, because we rely on prefetching.
+  def query
+    # Use the module function.
+    unless attributes = manager.find(name)
+      @ldap_properties = {}
+      return nil
+    end
+
+    @ldap_properties = attributes
+    @ldap_properties.dup
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/macauthorization/macauthorization.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/macauthorization/macauthorization.rb
new file mode 100644
index 0000000..ad431d2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/macauthorization/macauthorization.rb
@@ -0,0 +1,309 @@
+require 'facter'
+require 'facter/util/plist'
+require 'puppet'
+require 'tempfile'
+
+Puppet::Type.type(:macauthorization).provide :macauthorization, :parent => Puppet::Provider do
+
+  desc "Manage Mac OS X authorization database rules and rights.
+
+  "
+
+  commands :security => "/usr/bin/security"
+  commands :sw_vers => "/usr/bin/sw_vers"
+
+  confine :operatingsystem => :darwin
+
+  # This should be confined based on macosx_productversion
+  # but puppet resource doesn't make the facts available and
+  # that interface is heavily used with this provider.
+  if Puppet::FileSystem.exist?("/usr/bin/sw_vers")
+    product_version = sw_vers "-productVersion"
+
+    confine :true => unless /^10\.[0-4]/.match(product_version)
+      true
+    end
+  end
+
+  defaultfor :operatingsystem => :darwin
+
+  AuthDB = "/etc/authorization"
+
+  @rights = {}
+  @rules = {}
+  @parsed_auth_db = {}
+  @comment = ""  # Not implemented yet. Is there any real need to?
+
+  # This map exists due to the use of hyphens and reserved words in
+  # the authorization schema.
+  PuppetToNativeAttributeMap = {  :allow_root => "allow-root",
+    :authenticate_user => "authenticate-user",
+    :auth_class => "class",
+    :k_of_n => "k-of-n",
+    :session_owner => "session-owner", }
+
+  class << self
+    attr_accessor :parsed_auth_db
+    attr_accessor :rights
+    attr_accessor :rules
+    attr_accessor :comments  # Not implemented yet.
+
+    def prefetch(resources)
+      self.populate_rules_rights
+    end
+
+    def instances
+      if self.parsed_auth_db == {}
+        self.prefetch(nil)
+      end
+      self.parsed_auth_db.collect do |k,v|
+        new(:name => k)
+      end
+    end
+
+    def populate_rules_rights
+      auth_plist = Plist::parse_xml(AuthDB)
+      raise Puppet::Error.new("Cannot parse: #{AuthDB}") if not auth_plist
+      self.rights = auth_plist["rights"].dup
+      self.rules = auth_plist["rules"].dup
+      self.parsed_auth_db = self.rights.dup
+      self.parsed_auth_db.merge!(self.rules.dup)
+    end
+
+  end
+
+  # standard required provider instance methods
+
+  def initialize(resource)
+    if self.class.parsed_auth_db == {}
+      self.class.prefetch(resource)
+    end
+    super
+  end
+
+
+  def create
+    # we just fill the @property_hash in here and let the flush method
+    # deal with it rather than repeating code.
+    new_values = {}
+    validprops = Puppet::Type.type(resource.class.name).validproperties
+    validprops.each do |prop|
+      next if prop == :ensure
+      if value = resource.should(prop) and value != ""
+        new_values[prop] = value
+      end
+    end
+    @property_hash = new_values.dup
+  end
+
+  def destroy
+    # We explicitly delete here rather than in the flush method.
+    case resource[:auth_type]
+    when :right
+      destroy_right
+    when :rule
+      destroy_rule
+    else
+      raise Puppet::Error.new("Must specify auth_type when destroying.")
+    end
+  end
+
+  def exists?
+    !!self.class.parsed_auth_db.has_key?(resource[:name])
+  end
+
+
+  def flush
+    # deletion happens in the destroy methods
+    if resource[:ensure] != :absent
+      case resource[:auth_type]
+      when :right
+        flush_right
+      when :rule
+        flush_rule
+      else
+        raise Puppet::Error.new("flush requested for unknown type.")
+      end
+      @property_hash.clear
+    end
+  end
+
+
+  # utility methods below
+
+  def destroy_right
+    security "authorizationdb", :remove, resource[:name]
+  end
+
+  def destroy_rule
+    authdb = Plist::parse_xml(AuthDB)
+    authdb_rules = authdb["rules"].dup
+    if authdb_rules[resource[:name]]
+      begin
+        authdb["rules"].delete(resource[:name])
+        Plist::Emit.save_plist(authdb, AuthDB)
+      rescue Errno::EACCES => e
+        raise Puppet::Error.new("Error saving #{AuthDB}: #{e}", e)
+      end
+    end
+  end
+
+  def flush_right
+    # first we re-read the right just to make sure we're in sync for
+    # values that weren't specified in the manifest. As we're supplying
+    # the whole plist when specifying the right it seems safest to be
+    # paranoid given the low cost of quering the db once more.
+    cmds = []
+    cmds << :security << "authorizationdb" << "read" << resource[:name]
+    output = execute(cmds, :failonfail => false, :combine => false)
+    current_values = Plist::parse_xml(output)
+    current_values ||= {}
+    specified_values = convert_plist_to_native_attributes(@property_hash)
+
+    # take the current values, merge the specified values to obtain a
+    # complete description of the new values.
+    new_values = current_values.merge(specified_values)
+    set_right(resource[:name], new_values)
+  end
+
+  def flush_rule
+    authdb = Plist::parse_xml(AuthDB)
+    authdb_rules = authdb["rules"].dup
+    current_values = {}
+    current_values = authdb_rules[resource[:name]] if authdb_rules[resource[:name]]
+    specified_values = convert_plist_to_native_attributes(@property_hash)
+    new_values = current_values.merge(specified_values)
+    set_rule(resource[:name], new_values)
+  end
+
+  def set_right(name, values)
+    # Both creates and modifies rights as it simply overwrites them.
+    # The security binary only allows for writes using stdin, so we
+    # dump the values to a tempfile.
+    values = convert_plist_to_native_attributes(values)
+    tmp = Tempfile.new('puppet_macauthorization')
+    begin
+      Plist::Emit.save_plist(values, tmp.path)
+      cmds = []
+      cmds << :security << "authorizationdb" << "write" << name
+      execute(cmds, :failonfail => false, :combine => false, :stdinfile => tmp.path.to_s)
+    rescue Errno::EACCES => e
+      raise Puppet::Error.new("Cannot save right to #{tmp.path}: #{e}", e)
+    ensure
+      tmp.close
+      tmp.unlink
+    end
+  end
+
+  def set_rule(name, values)
+    # Both creates and modifies rules as it overwrites the entry in the
+    # rules dictionary.  Unfortunately the security binary doesn't
+    # support modifying rules at all so we have to twiddle the whole
+    # plist... :( See Apple Bug #6386000
+    values = convert_plist_to_native_attributes(values)
+    authdb = Plist::parse_xml(AuthDB)
+    authdb["rules"][name] = values
+
+    begin
+      Plist::Emit.save_plist(authdb, AuthDB)
+    rescue
+      raise Puppet::Error.new("Error writing to: #{AuthDB}")
+    end
+  end
+
+  def convert_plist_to_native_attributes(propertylist)
+    # This mainly converts the keys from the puppet attributes to the
+    # 'native' ones, but also enforces that the keys are all Strings
+    # rather than Symbols so that any merges of the resultant Hash are
+    # sane. The exception is booleans, where we coerce to a proper bool
+    # if they come in as a symbol.
+    newplist = {}
+    propertylist.each_pair do |key, value|
+      next if key == :ensure     # not part of the auth db schema.
+      next if key == :auth_type  # not part of the auth db schema.
+      case value
+      when true, :true
+        value = true
+      when false, :false
+        value = false
+      end
+      new_key = key
+      if PuppetToNativeAttributeMap.has_key?(key)
+        new_key = PuppetToNativeAttributeMap[key].to_s
+      elsif not key.is_a?(String)
+        new_key = key.to_s
+      end
+      newplist[new_key] = value
+    end
+    newplist
+  end
+
+  def retrieve_value(resource_name, attribute)
+    # We set boolean values to symbols when retrieving values
+    raise Puppet::Error.new("Cannot find #{resource_name} in auth db") if not self.class.parsed_auth_db.has_key?(resource_name)
+
+    if PuppetToNativeAttributeMap.has_key?(attribute)
+      native_attribute = PuppetToNativeAttributeMap[attribute]
+    else
+      native_attribute = attribute.to_s
+    end
+
+    if self.class.parsed_auth_db[resource_name].has_key?(native_attribute)
+      value = self.class.parsed_auth_db[resource_name][native_attribute]
+      case value
+      when true, :true
+        value = :true
+      when false, :false
+        value = :false
+      end
+
+      @property_hash[attribute] = value
+      return value
+    else
+      @property_hash.delete(attribute)
+      return ""  # so ralsh doesn't display it.
+    end
+  end
+
+
+  # property methods below
+  #
+  # We define them all dynamically apart from auth_type which is a special
+  # case due to not being in the actual authorization db schema.
+
+  properties = [  :allow_root, :authenticate_user, :auth_class, :comment,
+    :group, :k_of_n, :mechanisms, :rule, :session_owner,
+    :shared, :timeout, :tries ]
+
+  properties.each do |field|
+    define_method(field.to_s) do
+      retrieve_value(resource[:name], field)
+    end
+
+    define_method(field.to_s + "=") do |value|
+      @property_hash[field] = value
+    end
+  end
+
+  def auth_type
+    if resource.should(:auth_type) != nil
+      return resource.should(:auth_type)
+    elsif self.exists?
+      # this is here just for ralsh, so it can work out what type it is.
+      if self.class.rights.has_key?(resource[:name])
+        return :right
+      elsif self.class.rules.has_key?(resource[:name])
+        return :rule
+      else
+        raise Puppet::Error.new("#{resource[:name]} is unknown type.")
+      end
+    else
+      raise Puppet::Error.new("auth_type required for new resources.")
+    end
+  end
+
+  def auth_type=(value)
+    @property_hash[:auth_type] = value
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/mailalias/aliases.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/mailalias/aliases.rb
new file mode 100644
index 0000000..87ee5b4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/mailalias/aliases.rb
@@ -0,0 +1,39 @@
+require 'puppet/provider/parsedfile'
+
+Puppet::Type.type(:mailalias).provide(
+  :aliases,
+  :parent => Puppet::Provider::ParsedFile,
+  :default_target => "/etc/aliases",
+  :filetype => :flat
+) do
+  text_line :comment, :match => /^#/
+  text_line :blank, :match => /^\s*$/
+
+  record_line :aliases, :fields => %w{name recipient}, :separator => /\s*:\s*/, :block_eval => :instance do
+    def post_parse(record)
+      record[:recipient] = record[:recipient].split(/\s*,\s*/).collect { |d| d.gsub(/^['"]|['"]$/, '') }
+      record
+    end
+
+    def process(line)
+      ret = {}
+      records = line.split(':',2)
+      ret[:name] = records[0].strip
+      ret[:recipient] = records[1].strip
+      ret
+    end
+
+    def to_line(record)
+      dest = record[:recipient].collect do |d|
+        # Quote aliases that have non-alpha chars
+        if d =~ /[^-\w@.]/
+          '"%s"' % d
+        else
+          d
+        end
+      end.join(",")
+      "#{record[:name]}: #{dest}"
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/maillist/mailman.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/maillist/mailman.rb
new file mode 100644
index 0000000..e070a25
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/maillist/mailman.rb
@@ -0,0 +1,108 @@
+require 'puppet/provider/parsedfile'
+
+Puppet::Type.type(:maillist).provide(:mailman) do
+  if [ "CentOS", "RedHat", "Fedora" ].any? { |os|  Facter.value(:operatingsystem) == os }
+    commands :list_lists => "/usr/lib/mailman/bin/list_lists", :rmlist => "/usr/lib/mailman/bin/rmlist", :newlist => "/usr/lib/mailman/bin/newlist"
+    commands :mailman => "/usr/lib/mailman/mail/mailman"
+  else
+    # This probably won't work for non-Debian installs, but this path is sure not to be in the PATH.
+    commands :list_lists => "list_lists", :rmlist => "rmlist", :newlist => "newlist"
+    commands :mailman => "/var/lib/mailman/mail/mailman"
+  end
+
+  mk_resource_methods
+
+  # Return a list of existing mailman instances.
+  def self.instances
+    list_lists('--bare').
+      split("\n").
+      collect { |line| new(:ensure => :present, :name => line.strip) }
+  end
+
+  # Prefetch our list list, yo.
+  def self.prefetch(lists)
+    instances.each do |prov|
+      if list = lists[prov.name] || lists[prov.name.downcase]
+        list.provider = prov
+      end
+    end
+  end
+
+  def aliases
+    mailman = self.class.command(:mailman)
+    name = self.name.downcase
+    aliases = {name => "| #{mailman} post #{name}"}
+    %w{admin bounces confirm join leave owner request subscribe unsubscribe}.each do |address|
+      aliases["#{name}-#{address}"] = "| #{mailman} #{address} #{name}"
+    end
+    aliases
+  end
+
+  # Create the list.
+  def create
+    args = []
+    if val = @resource[:mailserver]
+      args << "--emailhost" << val
+    end
+    if val = @resource[:webserver]
+      args << "--urlhost" << val
+    end
+
+    args << self.name
+    if val = @resource[:admin]
+      args << val
+    else
+      raise ArgumentError, "Mailman lists require an administrator email address"
+    end
+    if val = @resource[:password]
+      args << val
+    else
+      raise ArgumentError, "Mailman lists require an administrator password"
+    end
+    newlist(*args)
+  end
+
+  # Delete the list.
+  def destroy(purge = false)
+    args = []
+    args << "--archives" if purge
+    args << self.name
+    rmlist(*args)
+  end
+
+  # Does our list exist already?
+  def exists?
+    properties[:ensure] != :absent
+  end
+
+  # Clear out the cached values.
+  def flush
+    @property_hash.clear
+  end
+
+  # Look up the current status.
+  def properties
+    if @property_hash.empty?
+      @property_hash = query || {:ensure => :absent}
+      @property_hash[:ensure] = :absent if @property_hash.empty?
+    end
+    @property_hash.dup
+  end
+
+  # Remove the list and its archives.
+  def purge
+    destroy(true)
+  end
+
+  # Pull the current state of the list from the full list.  We're
+  # getting some double entendre here....
+  def query
+    self.class.instances.each do |list|
+      if list.name == self.name or list.name.downcase == self.name
+        return list.properties
+      end
+    end
+    nil
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/mcx/mcxcontent.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/mcx/mcxcontent.rb
new file mode 100644
index 0000000..d6c8714
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/mcx/mcxcontent.rb
@@ -0,0 +1,172 @@
+require 'tempfile'
+
+Puppet::Type.type(:mcx).provide :mcxcontent, :parent => Puppet::Provider do
+
+  desc "MCX Settings management using DirectoryService on OS X.
+
+  This provider manages the entire MCXSettings attribute available
+  to some directory services nodes.  This management is 'all or nothing'
+  in that discrete application domain key value pairs are not managed
+  by this provider.
+
+  It is recommended to use WorkGroup Manager to configure Users, Groups,
+  Computers, or ComputerLists, then use 'ralsh mcx' to generate a puppet
+  manifest from the resulting configuration.
+
+  Original Author: Jeff McCune (mccune.jeff@gmail.com)
+
+"
+
+  # This provides a mapping of puppet types to DirectoryService
+  # type strings.
+  TypeMap = {
+    :user => "Users",
+    :group => "Groups",
+    :computer => "Computers",
+    :computerlist => "ComputerLists",
+  }
+
+  class MCXContentProviderException < Exception
+
+  end
+
+  commands :dscl => "/usr/bin/dscl"
+  confine :operatingsystem => :darwin
+  defaultfor :operatingsystem => :darwin
+
+  def self.instances
+    mcx_list = []
+    TypeMap.keys.each do |ds_type|
+      ds_path = "/Local/Default/#{TypeMap[ds_type]}"
+      output = dscl 'localhost', '-list', ds_path
+      member_list = output.split
+      member_list.each do |ds_name|
+        content = mcxexport(ds_type, ds_name)
+        if content.empty?
+          Puppet.debug "/#{TypeMap[ds_type]}/#{ds_name} has no MCX data."
+        else
+          # This node has MCX data.
+
+          mcx_list << self.new(
+            :name => "/#{TypeMap[ds_type]}/#{ds_name}",
+            :ds_type => ds_type,
+            :ds_name => ds_name,
+            :content => content
+          )
+        end
+      end
+    end
+    mcx_list
+  end
+
+  def self.mcxexport(ds_type, ds_name)
+    ds_t = TypeMap[ds_type]
+    ds_n = ds_name.to_s
+    ds_path = "/Local/Default/#{ds_t}/#{ds_n}"
+    dscl 'localhost', '-mcxexport', ds_path
+  end
+
+
+  def create
+    self.content=(resource[:content])
+  end
+
+  def destroy
+    ds_parms = get_dsparams
+    ds_t = TypeMap[ds_parms[:ds_type]]
+    ds_n = ds_parms[:ds_name].to_s
+    ds_path = "/Local/Default/#{ds_t}/#{ds_n}"
+
+    dscl 'localhost', '-mcxdelete', ds_path
+  end
+
+  def exists?
+    begin
+      has_mcx?
+    rescue Puppet::ExecutionFailure
+      return false
+    end
+  end
+
+  def content
+    ds_parms = get_dsparams
+
+    self.class.mcxexport(ds_parms[:ds_type], ds_parms[:ds_name])
+  end
+
+  def content=(value)
+    # dscl localhost -mcximport
+    ds_parms = get_dsparams
+
+    mcximport(ds_parms[:ds_type], ds_parms[:ds_name], resource[:content])
+  end
+
+  private
+
+  def has_mcx?
+    !content.empty?
+  end
+
+  def mcximport(ds_type, ds_name, val)
+    ds_t = TypeMap[ds_type]
+    ds_path = "/Local/Default/#{ds_t}/#{ds_name}"
+
+    if has_mcx?
+      Puppet.debug "Removing MCX from #{ds_path}"
+      dscl 'localhost', '-mcxdelete', ds_path
+    end
+
+    tmp = Tempfile.new('puppet_mcx')
+    begin
+      tmp << val
+      tmp.flush
+      Puppet.debug "Importing MCX into #{ds_path}"
+      dscl 'localhost', '-mcximport', ds_path, tmp.path
+    ensure
+      tmp.close
+      tmp.unlink
+    end
+  end
+
+  # Given the resource name string, parse ds_type out.
+  def parse_type(name)
+    ds_type = name.split('/')[1]
+    unless ds_type
+      raise MCXContentProviderException,
+      "Coult not parse ds_type from resource name '#{name}'.  Specify with ds_type parameter."
+    end
+    # De-pluralize and downcase.
+    ds_type = ds_type.chop.downcase.to_sym
+    unless TypeMap.key? ds_type
+      raise MCXContentProviderException,
+      "Coult not parse ds_type from resource name '#{name}'.  Specify with ds_type parameter."
+    end
+    ds_type
+  end
+
+  # Given the resource name string, parse ds_name out.
+  def parse_name(name)
+    ds_name = name.split('/')[2]
+    unless ds_name
+      raise MCXContentProviderException,
+      "Could not parse ds_name from resource name '#{name}'.  Specify with ds_name parameter."
+    end
+    ds_name
+  end
+
+  # Gather ds_type and ds_name from resource or parse it out of the name.
+  def get_dsparams
+    ds_type = resource[:ds_type]
+    ds_type ||= parse_type(resource[:name])
+    raise MCXContentProviderException unless TypeMap.keys.include? ds_type.to_sym
+
+    ds_name = resource[:ds_name]
+    ds_name ||= parse_name(resource[:name])
+
+    {
+      :ds_type => ds_type.to_sym,
+      :ds_name => ds_name,
+    }
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/mount.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/mount.rb
new file mode 100644
index 0000000..0f3bc10
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/mount.rb
@@ -0,0 +1,58 @@
+require 'puppet'
+
+# A module just to store the mount/unmount methods.  Individual providers
+# still need to add the mount commands manually.
+module Puppet::Provider::Mount
+  # This only works when the mount point is synced to the fstab.
+  def mount
+    args = []
+
+    # In general we do not have to pass mountoptions because we always
+    # flush /etc/fstab before attempting to mount. But old code suggests
+    # that MacOS always needs the mount options to be explicitly passed to
+    # the mount command
+    if Facter.value(:kernel) == 'Darwin'
+      args << "-o" << self.options if self.options and self.options != :absent
+    end
+    args << resource[:name]
+
+    mountcmd(*args)
+    case get(:ensure)
+    when :absent; set(:ensure => :ghost)
+    when :unmounted; set(:ensure => :mounted)
+    end
+  end
+
+  def remount
+    info "Remounting"
+    if resource[:remounts] == :true
+      mountcmd "-o", "remount", resource[:name]
+    elsif ["FreeBSD", "DragonFly", "OpenBSD"].include?(Facter.value(:operatingsystem))
+      if self.options && !self.options.empty?
+        options = self.options + ",update"
+      else
+        options = "update"
+      end
+      mountcmd "-o", options, resource[:name]
+    else
+      unmount
+      mount
+    end
+  end
+
+  # This only works when the mount point is synced to the fstab.
+  def unmount
+    umount(resource[:name])
+
+    # Update property hash for future queries (e.g. refresh is called)
+    case get(:ensure)
+    when :mounted; set(:ensure => :unmounted)
+    when :ghost; set(:ensure => :absent)
+    end
+  end
+
+  # Is the mount currently mounted?
+  def mounted?
+    [:mounted, :ghost].include?(get(:ensure))
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/mount/parsed.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/mount/parsed.rb
new file mode 100644
index 0000000..c7cc288
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/mount/parsed.rb
@@ -0,0 +1,266 @@
+require 'puppet/provider/parsedfile'
+require 'puppet/provider/mount'
+
+fstab = nil
+case Facter.value(:osfamily)
+when "Solaris"; fstab = "/etc/vfstab"
+when "AIX"; fstab = "/etc/filesystems"
+else
+  fstab = "/etc/fstab"
+end
+
+Puppet::Type.type(:mount).provide(
+  :parsed,
+  :parent => Puppet::Provider::ParsedFile,
+  :default_target => fstab,
+  :filetype => :flat
+) do
+  include Puppet::Provider::Mount
+
+  commands :mountcmd => "mount", :umount => "umount"
+
+  case Facter.value(:osfamily)
+  when "Solaris"
+    @fields = [:device, :blockdevice, :name, :fstype, :pass, :atboot, :options]
+  else
+    @fields = [:device, :name, :fstype, :options, :dump, :pass]
+  end
+
+  if Facter.value(:osfamily) == "AIX"
+    # * is the comment character on AIX /etc/filesystems
+    text_line :comment, :match => /^\s*\*/
+  else
+    text_line :comment, :match => /^\s*#/
+  end
+  text_line :blank, :match => /^\s*$/
+
+  optional_fields  = @fields - [:device, :name, :blockdevice]
+  mandatory_fields = @fields - optional_fields
+
+  # fstab will ignore lines that have fewer than the mandatory number of columns,
+  # so we should, too.
+  field_pattern = '(\s*(?>\S+))'
+  text_line :incomplete, :match => /^(?!#{field_pattern}{#{mandatory_fields.length}})/
+
+  case Facter.value(:osfamily)
+  when "AIX"
+    # The only field that is actually ordered is :name. See `man filesystems` on AIX
+    @fields = [:name, :account, :boot, :check, :dev, :free, :mount, :nodename,
+               :options, :quota, :size, :type, :vfs, :vol, :log]
+    self.line_separator = "\n"
+    # Override lines and use scan instead of split, because we DON'T want to
+    # remove the separators
+    def self.lines(text)
+      lines = text.split("\n")
+      filesystem_stanza = false
+      filesystem_index = 0
+      ret = Array.new
+      lines.each_with_index do |line,i|
+        if line.match(%r{^\S+:})
+          # Begin new filesystem stanza and save the index
+          ret[filesystem_index] = filesystem_stanza.join("\n") if filesystem_stanza
+          filesystem_stanza = Array(line)
+          filesystem_index = i
+          # Eat the preceeding blank line
+          ret[i-1] = nil if i > 0 and ret[i-1] and ret[i-1].match(%r{^\s*$})
+          nil
+        elsif line.match(%r{^(\s*\*.*|\s*)$})
+          # Just a comment or blank line; add in place
+          ret[i] = line
+        else
+          # Non-comments or blank lines must be part of a stanza
+          filesystem_stanza << line
+        end
+      end
+      # Add the final stanza to the return
+      ret[filesystem_index] = filesystem_stanza.join("\n") if filesystem_stanza
+      ret = ret.compact.flatten
+      ret.reject { |line| line.match(/^\* HEADER/) }
+    end
+    def self.header
+      super.gsub(/^#/,'*')
+    end
+
+    record_line self.name,
+      :fields    => @fields,
+      :separator => /\n/,
+      :block_eval => :instance do
+
+      def post_parse(result)
+        property_map = {
+          :dev      => :device,
+          :nodename => :nodename,
+          :options  => :options,
+          :vfs      => :fstype,
+        }
+        # Result is modified in-place instead of being returned; icky!
+        memo = result.dup
+        result.clear
+        # Save the line for later, just in case it is unparsable
+        result[:line] = @fields.collect do |field|
+          memo[field] if memo[field] != :absent
+        end.compact.join("\n")
+        result[:record_type] = memo[:record_type]
+        special_options = Array.new
+        result[:name] = memo[:name].sub(%r{:\s*$},'').strip
+        memo.each do |_,k_v|
+          if k_v and k_v.is_a?(String) and k_v.match("=")
+            attr_name, attr_value = k_v.split("=",2).map(&:strip)
+            if attr_map_name = property_map[attr_name.to_sym]
+              # These are normal "options" options (see `man filesystems`)
+              result[attr_map_name] = attr_value
+            else
+              # These /etc/filesystem attributes have no mount resource simile,
+              # so are added to the "options" property for puppet's sake
+              special_options << "#{attr_name}=#{attr_value}"
+            end
+            if result[:nodename]
+              result[:device] = "#{result[:nodename]}:#{result[:device]}"
+              result.delete(:nodename)
+            end
+          end
+        end
+        result[:options] = [result[:options],special_options.sort].flatten.compact.join(',')
+        if ! result[:device]
+          result[:device] = :absent
+          Puppet.err "Prefetch: Mount[#{result[:name]}]: Field 'device' is missing"
+        end
+        if ! result[:fstype]
+          result[:fstype] = :absent
+          Puppet.err "Prefetch: Mount[#{result[:name]}]: Field 'fstype' is missing"
+        end
+      end
+      def to_line(result)
+        output = Array.new
+        output << "#{result[:name]}:"
+        if result[:device] and result[:device].match(%r{^/})
+          output << "\tdev\t\t= #{result[:device]}"
+        elsif result[:device] and result[:device] != :absent
+          if ! result[:device].match(%{^.+:/})
+            # Just skip this entry; it was malformed to begin with
+            Puppet.err "Mount[#{result[:name]}]: Field 'device' must be in the format of <absolute path> or <host>:<absolute path>"
+            return result[:line]
+          end
+          nodename, path = result[:device].split(":")
+          output << "\tdev\t\t= #{path}"
+          output << "\tnodename\t= #{nodename}"
+        else
+          # Just skip this entry; it was malformed to begin with
+          Puppet.err "Mount[#{result[:name]}]: Field 'device' is required"
+          return result[:line]
+        end
+        if result[:fstype] and result[:fstype] != :absent
+          output << "\tvfs\t\t= #{result[:fstype]}"
+        else
+          # Just skip this entry; it was malformed to begin with
+          Puppet.err "Mount[#{result[:name]}]: Field 'device' is required"
+          return result[:line]
+        end
+        if result[:options]
+          options = result[:options].split(',')
+          special_options = options.select do |x|
+            x.match('=') and
+              ["account", "boot", "check", "free", "mount", "size", "type",
+               "vol", "log", "quota"].include? x.split('=').first
+          end
+          options = options - special_options
+          special_options.sort.each do |x|
+            k, v = x.split("=")
+            output << "\t#{k}\t\t= #{v}"
+          end
+          output << "\toptions\t\t= #{options.join(",")}" unless options.empty?
+        end
+        if result[:line] and result[:line].split("\n").sort == output.sort
+          return "\n#{result[:line]}"
+        else
+          return "\n#{output.join("\n")}"
+        end
+      end
+    end
+  else
+    record_line self.name, :fields => @fields, :separator => /\s+/, :joiner => "\t", :optional => optional_fields
+  end
+
+  # Every entry in fstab is :unmounted until we can prove different
+  def self.prefetch_hook(target_records)
+    target_records.collect do |record|
+      record[:ensure] = :unmounted if record[:record_type] == :parsed
+      record
+    end
+  end
+
+  def self.instances
+    providers = super
+    mounts = mountinstances.dup
+
+    # Update fstab entries that are mounted
+    providers.each do |prov|
+      if mounts.delete({:name => prov.get(:name), :mounted => :yes}) then
+        prov.set(:ensure => :mounted)
+      end
+    end
+
+    # Add mounts that are not in fstab but mounted
+    mounts.each do |mount|
+      providers << new(:ensure => :ghost, :name => mount[:name])
+    end
+    providers
+  end
+
+  def self.prefetch(resources = nil)
+    # Get providers for all resources the user defined and that match
+    # a record in /etc/fstab.
+    super
+    # We need to do two things now:
+    # - Update ensure from :unmounted to :mounted if the resource is mounted
+    # - Check for mounted devices that are not in fstab and
+    #   set ensure to :ghost (if the user wants to add an entry
+    #   to fstab we need to know if the device was mounted before)
+    mountinstances.each do |hash|
+      if mount = resources[hash[:name]]
+        case mount.provider.get(:ensure)
+        when :absent  # Mount not in fstab
+          mount.provider.set(:ensure => :ghost)
+        when :unmounted # Mount in fstab
+          mount.provider.set(:ensure => :mounted)
+        end
+      end
+    end
+  end
+
+  def self.mountinstances
+    # XXX: Will not work for mount points that have spaces in path (does fstab support this anyways?)
+    regex = case Facter.value(:osfamily)
+      when "Darwin"
+        / on (?:\/private\/var\/automount)?(\S*)/
+      when "Solaris", "HP-UX"
+        /^(\S*) on /
+      when "AIX"
+        /^(?:\S*\s+\S+\s+)(\S+)/
+      else
+        / on (\S*)/
+    end
+    instances = []
+    mount_output = mountcmd.split("\n")
+    if mount_output.length >= 2 and mount_output[1] =~ /^[- \t]*$/
+      # On some OSes (e.g. AIX) mount output begins with a header line
+      # followed by a line consisting of dashes and whitespace.
+      # Discard these two lines.
+      mount_output[0..1] = []
+    end
+    mount_output.each do |line|
+      if match = regex.match(line) and name = match.captures.first
+        instances << {:name => name, :mounted => :yes} # Only :name is important here
+      else
+        raise Puppet::Error, "Could not understand line #{line} from mount output"
+      end
+    end
+    instances
+  end
+
+  def flush
+    needs_mount = @property_hash.delete(:needs_mount)
+    super
+    mount if needs_mount
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/naginator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/naginator.rb
new file mode 100644
index 0000000..731c555
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/naginator.rb
@@ -0,0 +1,63 @@
+require 'puppet'
+require 'puppet/provider/parsedfile'
+require 'puppet/external/nagios'
+
+# The base class for all Naginator providers.
+class Puppet::Provider::Naginator < Puppet::Provider::ParsedFile
+  NAME_STRING = "## --PUPPET_NAME-- (called '_naginator_name' in the manifest)"
+  # Retrieve the associated class from Nagios::Base.
+  def self.nagios_type
+    unless @nagios_type
+      name = resource_type.name.to_s.sub(/^nagios_/, '')
+      unless @nagios_type = Nagios::Base.type(name.to_sym)
+        raise Puppet::DevError, "Could not find nagios type '#{name}'"
+      end
+
+      # And add our 'ensure' settings, since they aren't a part of
+      # Naginator by default
+      @nagios_type.send(:attr_accessor, :ensure, :target, :on_disk)
+    end
+    @nagios_type
+  end
+
+  def self.parse(text)
+      Nagios::Parser.new.parse(text.gsub(NAME_STRING, "_naginator_name"))
+  rescue => detail
+      raise Puppet::Error, "Could not parse configuration for #{resource_type.name}: #{detail}", detail.backtrace
+  end
+
+  def self.to_file(records)
+    header + records.collect { |record|
+        # Remap the TYPE_name or _naginator_name params to the
+        # name if the record is a template (register == 0)
+        if record.to_s =~ /register\s+0/
+            record.to_s.sub("_naginator_name", "name").sub(record.type.to_s + "_name", "name")
+        else
+            record.to_s.sub("_naginator_name", NAME_STRING)
+        end
+    }.join("\n")
+  end
+
+  def self.skip_record?(record)
+    false
+  end
+
+  def self.valid_attr?(klass, attr_name)
+    nagios_type.parameters.include?(attr_name)
+  end
+
+  def initialize(resource = nil)
+    if resource.is_a?(Nagios::Base)
+      # We don't use a duplicate here, because some providers (ParsedFile, at least)
+      # use the hash here for later events.
+      @property_hash = resource
+    elsif resource
+      @resource = resource if resource
+      # LAK 2007-05-09: Keep the model stuff around for backward compatibility
+      @model = resource
+      @property_hash = self.class.nagios_type.new
+    else
+      @property_hash = self.class.nagios_type.new
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/nameservice.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/nameservice.rb
new file mode 100644
index 0000000..5bf1f4d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/nameservice.rb
@@ -0,0 +1,292 @@
+require 'puppet'
+
+# This is the parent class of all NSS classes.  They're very different in
+# their backend, but they're pretty similar on the front-end.  This class
+# provides a way for them all to be as similar as possible.
+class Puppet::Provider::NameService < Puppet::Provider
+  class << self
+    def autogen_default(param)
+      defined?(@autogen_defaults) ? @autogen_defaults[param.intern] : nil
+    end
+
+    def autogen_defaults(hash)
+      @autogen_defaults ||= {}
+      hash.each do |param, value|
+        @autogen_defaults[param.intern] = value
+      end
+    end
+
+    def initvars
+      @checks = {}
+      @options = {}
+      super
+    end
+
+    def instances
+      objects = []
+      listbyname do |name|
+        objects << new(:name => name, :ensure => :present)
+      end
+
+      objects
+    end
+
+    def option(name, option)
+      name = name.intern if name.is_a? String
+      (defined?(@options) and @options.include? name and @options[name].include? option) ? @options[name][option] : nil
+    end
+
+    def options(name, hash)
+      raise Puppet::DevError, "#{name} is not a valid attribute for #{resource_type.name}" unless resource_type.valid_parameter?(name)
+      @options ||= {}
+      @options[name] ||= {}
+
+      # Set options individually, so we can call the options method
+      # multiple times.
+      hash.each do |param, value|
+        @options[name][param] = value
+      end
+    end
+
+    # List everything out by name.  Abstracted a bit so that it works
+    # for both users and groups.
+    def listbyname
+      names = []
+      Etc.send("set#{section()}ent")
+      begin
+        while ent = Etc.send("get#{section()}ent")
+          names << ent.name
+          yield ent.name if block_given?
+        end
+      ensure
+        Etc.send("end#{section()}ent")
+      end
+
+      names
+    end
+
+    def resource_type=(resource_type)
+      super
+      @resource_type.validproperties.each do |prop|
+        next if prop == :ensure
+        define_method(prop) { get(prop) || :absent} unless public_method_defined?(prop)
+        define_method(prop.to_s + "=") { |*vals| set(prop, *vals) } unless public_method_defined?(prop.to_s + "=")
+      end
+    end
+
+    # This is annoying, but there really aren't that many options,
+    # and this *is* built into Ruby.
+    def section
+      unless resource_type
+        raise Puppet::DevError,
+          "Cannot determine Etc section without a resource type"
+      end
+
+      if @resource_type.name == :group
+        "gr"
+      else
+        "pw"
+      end
+    end
+
+    def validate(name, value)
+      name = name.intern if name.is_a? String
+      if @checks.include? name
+        block = @checks[name][:block]
+        raise ArgumentError, "Invalid value #{value}: #{@checks[name][:error]}" unless block.call(value)
+      end
+    end
+
+    def verify(name, error, &block)
+      name = name.intern if name.is_a? String
+      @checks[name] = {:error => error, :block => block}
+    end
+
+    private
+
+    def op(property)
+      @ops[property.name] || ("-#{property.name}")
+    end
+  end
+
+  # Autogenerate a value.  Mostly used for uid/gid, but also used heavily
+  # with DirectoryServices, because DirectoryServices is stupid.
+  def autogen(field)
+    field = field.intern
+    id_generators = {:user => :uid, :group => :gid}
+    if id_generators[@resource.class.name] == field
+      return self.class.autogen_id(field, @resource.class.name)
+    else
+      if value = self.class.autogen_default(field)
+        return value
+      elsif respond_to?("autogen_#{field}")
+        return send("autogen_#{field}")
+      else
+        return nil
+      end
+    end
+  end
+
+  # Autogenerate either a uid or a gid.  This is not very flexible: we can
+  # only generate one field type per class, and get kind of confused if asked
+  # for both.
+  def self.autogen_id(field, resource_type)
+    # Figure out what sort of value we want to generate.
+    case resource_type
+    when :user;   database = :passwd;  method = :uid
+    when :group;  database = :group;   method = :gid
+    else
+      raise Puppet::DevError, "Invalid resource name #{resource}"
+    end
+
+    # Initialize from the data set, if needed.
+    unless @prevauto
+      # Sadly, Etc doesn't return an enumerator, it just invokes the block
+      # given, or returns the first record from the database.  There is no
+      # other, more convenient enumerator for these, so we fake one with this
+      # loop.  Thanks, Ruby, for your awesome abstractions. --daniel 2012-03-23
+      highest = []
+      Etc.send(database) {|entry| highest << entry.send(method) }
+      highest = highest.reject {|x| x > 65000 }.max
+
+      @prevauto = highest || 1000
+    end
+
+    # ...and finally increment and return the next value.
+    @prevauto += 1
+  end
+
+  def create
+    if exists?
+      info "already exists"
+      # The object already exists
+      return nil
+    end
+
+    begin
+      execute(self.addcmd, {:failonfail => true, :combine => true, :custom_environment => @custom_environment})
+      if feature?(:manages_password_age) && (cmd = passcmd)
+        execute(cmd)
+      end
+    rescue Puppet::ExecutionFailure => detail
+      raise Puppet::Error, "Could not create #{@resource.class.name} #{@resource.name}: #{detail}", detail.backtrace
+    end
+  end
+
+  def delete
+    unless exists?
+      info "already absent"
+      # the object already doesn't exist
+      return nil
+    end
+
+    begin
+      execute(self.deletecmd)
+    rescue Puppet::ExecutionFailure => detail
+      raise Puppet::Error, "Could not delete #{@resource.class.name} #{@resource.name}: #{detail}", detail.backtrace
+    end
+  end
+
+  def ensure
+    if exists?
+      :present
+    else
+      :absent
+    end
+  end
+
+  # Does our object exist?
+  def exists?
+    !!getinfo(true)
+  end
+
+  # Retrieve a specific value by name.
+  def get(param)
+    (hash = getinfo(false)) ? unmunge(param, hash[param]) : nil
+  end
+
+  def munge(name, value)
+    if block = self.class.option(name, :munge) and block.is_a? Proc
+      block.call(value)
+    else
+      value
+    end
+  end
+
+  def unmunge(name, value)
+    if block = self.class.option(name, :unmunge) and block.is_a? Proc
+      block.call(value)
+    else
+      value
+    end
+  end
+
+  # Retrieve what we can about our object
+  def getinfo(refresh)
+    if @objectinfo.nil? or refresh == true
+      @etcmethod ||= ("get" + self.class.section.to_s + "nam").intern
+      begin
+        @objectinfo = Etc.send(@etcmethod, @resource[:name])
+      rescue ArgumentError
+        @objectinfo = nil
+      end
+    end
+
+    # Now convert our Etc struct into a hash.
+    @objectinfo ? info2hash(@objectinfo) : nil
+  end
+
+  # The list of all groups the user is a member of.  Different
+  # user mgmt systems will need to override this method.
+  def groups
+    groups = []
+
+    # Reset our group list
+    Etc.setgrent
+
+    user = @resource[:name]
+
+    # Now iterate across all of the groups, adding each one our
+    # user is a member of
+    while group = Etc.getgrent
+      members = group.mem
+
+      groups << group.name if members.include? user
+    end
+
+    # We have to close the file, so each listing is a separate
+    # reading of the file.
+    Etc.endgrent
+
+    groups.join(",")
+  end
+
+  # Convert the Etc struct into a hash.
+  def info2hash(info)
+    hash = {}
+    self.class.resource_type.validproperties.each do |param|
+      method = posixmethod(param)
+      hash[param] = info.send(posixmethod(param)) if info.respond_to? method
+    end
+
+    hash
+  end
+
+  def initialize(resource)
+    super
+    @custom_environment = {}
+    @objectinfo = nil
+  end
+
+  def set(param, value)
+    self.class.validate(param, value)
+    cmd = modifycmd(param, munge(param, value))
+    raise Puppet::DevError, "Nameservice command must be an array" unless cmd.is_a?(Array)
+    begin
+      execute(cmd)
+    rescue Puppet::ExecutionFailure => detail
+      raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}", detail.backtrace
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/nameservice/directoryservice.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/nameservice/directoryservice.rb
new file mode 100644
index 0000000..9f31089
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/nameservice/directoryservice.rb
@@ -0,0 +1,588 @@
+require 'puppet'
+require 'puppet/provider/nameservice'
+require 'facter/util/plist'
+require 'fileutils'
+
+class Puppet::Provider::NameService::DirectoryService < Puppet::Provider::NameService
+  # JJM: Dive into the singleton_class
+  class << self
+    # JJM: This allows us to pass information when calling
+    #      Puppet::Type.type
+    #  e.g. Puppet::Type.type(:user).provide :directoryservice, :ds_path => "Users"
+    #  This is referenced in the get_ds_path class method
+    attr_writer :ds_path
+    attr_writer :macosx_version_major
+  end
+
+  initvars
+
+  commands :dscl => "/usr/bin/dscl"
+  commands :dseditgroup => "/usr/sbin/dseditgroup"
+  commands :sw_vers => "/usr/bin/sw_vers"
+  commands :plutil => '/usr/bin/plutil'
+  confine :operatingsystem => :darwin
+  defaultfor :operatingsystem => :darwin
+
+
+  # JJM 2007-07-25: This map is used to map NameService attributes to their
+  #     corresponding DirectoryService attribute names.
+  #     See: http://images.apple.com/server/docs.Open_Directory_v10.4.pdf
+  # JJM: Note, this is de-coupled from the Puppet::Type, and must
+  #     be actively maintained.  There may also be collisions with different
+  #     types (Users, Groups, Mounts, Hosts, etc...)
+  def ds_to_ns_attribute_map; self.class.ds_to_ns_attribute_map; end
+  def self.ds_to_ns_attribute_map
+    {
+      'RecordName' => :name,
+      'PrimaryGroupID' => :gid,
+      'NFSHomeDirectory' => :home,
+      'UserShell' => :shell,
+      'UniqueID' => :uid,
+      'RealName' => :comment,
+      'Password' => :password,
+      'GeneratedUID' => :guid,
+      'IPAddress'    => :ip_address,
+      'ENetAddress'  => :en_address,
+      'GroupMembership' => :members,
+    }
+  end
+
+  # JJM The same table as above, inverted.
+  def ns_to_ds_attribute_map; self.class.ns_to_ds_attribute_map end
+  def self.ns_to_ds_attribute_map
+    @ns_to_ds_attribute_map ||= ds_to_ns_attribute_map.invert
+  end
+
+  def self.password_hash_dir
+    '/var/db/shadow/hash'
+  end
+
+  def self.users_plist_dir
+    '/var/db/dslocal/nodes/Default/users'
+  end
+
+  def self.instances
+    # JJM Class method that provides an array of instance objects of this
+    #     type.
+    # JJM: Properties are dependent on the Puppet::Type we're managine.
+    type_property_array = [:name] + @resource_type.validproperties
+
+    # Create a new instance of this Puppet::Type for each object present
+    #    on the system.
+    list_all_present.collect do |name_string|
+      self.new(single_report(name_string, *type_property_array))
+    end
+  end
+
+  def self.get_ds_path
+    # JJM: 2007-07-24 This method dynamically returns the DS path we're concerned with.
+    #      For example, if we're working with an user type, this will be /Users
+    #      with a group type, this will be /Groups.
+    #   @ds_path is an attribute of the class itself.
+    return @ds_path if defined?(@ds_path)
+    # JJM: "Users" or "Groups" etc ...  (Based on the Puppet::Type)
+    #       Remember this is a class method, so self.class is Class
+    #       Also, @resource_type seems to be the reference to the
+    #       Puppet::Type this class object is providing for.
+    @resource_type.name.to_s.capitalize + "s"
+  end
+
+  def self.get_macosx_version_major
+    return @macosx_version_major if defined?(@macosx_version_major)
+    begin
+      product_version_major = Facter.value(:macosx_productversion_major)
+
+      fail("#{product_version_major} is not supported by the directoryservice provider") if %w{10.0 10.1 10.2 10.3 10.4}.include?(product_version_major)
+      @macosx_version_major = product_version_major
+      return @macosx_version_major
+    rescue Puppet::ExecutionFailure => detail
+      fail("Could not determine OS X version: #{detail}")
+    end
+  end
+
+
+  def self.list_all_present
+    # JJM: List all objects of this Puppet::Type already present on the system.
+    begin
+      dscl_output = execute(get_exec_preamble("-list"))
+    rescue Puppet::ExecutionFailure
+      fail("Could not get #{@resource_type.name} list from DirectoryService")
+    end
+    dscl_output.split("\n")
+  end
+
+  def self.parse_dscl_plist_data(dscl_output)
+    Plist.parse_xml(dscl_output)
+  end
+
+  def self.generate_attribute_hash(input_hash, *type_properties)
+    attribute_hash = {}
+    input_hash.keys.each do |key|
+      ds_attribute = key.sub("dsAttrTypeStandard:", "")
+      next unless (ds_to_ns_attribute_map.keys.include?(ds_attribute) and type_properties.include? ds_to_ns_attribute_map[ds_attribute])
+      ds_value = input_hash[key]
+      case ds_to_ns_attribute_map[ds_attribute]
+        when :members
+          ds_value = ds_value # only members uses arrays so far
+        when :gid, :uid
+          # OS X stores objects like uid/gid as strings.
+          # Try casting to an integer for these cases to be
+          # consistent with the other providers and the group type
+          # validation
+          begin
+            ds_value = Integer(ds_value[0])
+          rescue ArgumentError
+            ds_value = ds_value[0]
+          end
+        else ds_value = ds_value[0]
+      end
+      attribute_hash[ds_to_ns_attribute_map[ds_attribute]] = ds_value
+    end
+
+    # NBK: need to read the existing password here as it's not actually
+    # stored in the user record. It is stored at a path that involves the
+    # UUID of the user record for non-Mobile local acccounts.
+    # Mobile Accounts are out of scope for this provider for now
+    attribute_hash[:password] = self.get_password(attribute_hash[:guid], attribute_hash[:name]) if @resource_type.validproperties.include?(:password) and Puppet.features.root?
+    attribute_hash
+  end
+
+  def self.single_report(resource_name, *type_properties)
+    # JJM 2007-07-24:
+    #     Given a the name of an object and a list of properties of that
+    #     object, return all property values in a hash.
+    #
+    #     This class method returns nil if the object doesn't exist
+    #     Otherwise, it returns a hash of the object properties.
+
+    all_present_str_array = list_all_present
+
+    # NBK: shortcut the process if the resource is missing
+    return nil unless all_present_str_array.include? resource_name
+
+    dscl_vector = get_exec_preamble("-read", resource_name)
+    begin
+      dscl_output = execute(dscl_vector)
+    rescue Puppet::ExecutionFailure
+      fail("Could not get report.  command execution failed.")
+    end
+
+    # (#11593) Remove support for OS X 10.4 and earlier
+    fail_if_wrong_version
+    dscl_plist = self.parse_dscl_plist_data(dscl_output)
+
+    self.generate_attribute_hash(dscl_plist, *type_properties)
+  end
+
+  def self.fail_if_wrong_version
+    if (Puppet::Util::Package.versioncmp(self.get_macosx_version_major, '10.5') == -1)
+      fail("Puppet does not support OS X versions < 10.5")
+    end
+  end
+
+  def self.get_exec_preamble(ds_action, resource_name = nil)
+    # JJM 2007-07-24
+    #     DSCL commands are often repetitive and contain the same positional
+    #     arguments over and over. See http://developer.apple.com/documentation/Porting/Conceptual/PortingUnix/additionalfeatures/chapter_10_section_9.html
+    #     for an example of what I mean.
+    #     This method spits out proper DSCL commands for us.
+    #     We EXPECT name to be @resource[:name] when called from an instance object.
+
+    # (#11593) Remove support for OS X 10.4 and earlier
+    fail_if_wrong_version
+    command_vector = [ command(:dscl), "-plist", "." ]
+
+    # JJM: The actual action to perform.  See "man dscl"
+    #      Common actiosn: -create, -delete, -merge, -append, -passwd
+    command_vector << ds_action
+    # JJM: get_ds_path will spit back "Users" or "Groups",
+    # etc...  Depending on the Puppet::Type of our self.
+    if resource_name
+      command_vector << "/#{get_ds_path}/#{resource_name}"
+    else
+      command_vector << "/#{get_ds_path}"
+    end
+    # JJM:  This returns most of the preamble of the command.
+    #       e.g. 'dscl / -create /Users/mccune'
+    command_vector
+  end
+
+  def self.set_password(resource_name, guid, password_hash)
+    # Use Puppet::Util::Package.versioncmp() to catch the scenario where a
+    # version '10.10' would be < '10.7' with simple string comparison. This
+    # if-statement only executes if the current version is less-than 10.7
+    if (Puppet::Util::Package.versioncmp(get_macosx_version_major, '10.7') == -1)
+      password_hash_file = "#{password_hash_dir}/#{guid}"
+      begin
+        File.open(password_hash_file, 'w') { |f| f.write(password_hash)}
+      rescue Errno::EACCES => detail
+        fail("Could not write to password hash file: #{detail}")
+      end
+
+      # NBK: For shadow hashes, the user AuthenticationAuthority must contain a value of
+      # ";ShadowHash;". The LKDC in 10.5 makes this more interesting though as it
+      # will dynamically generate ;Kerberosv5;;username@LKDC:SHA1 attributes if
+      # missing. Thus we make sure we only set ;ShadowHash; if it is missing, and
+      # we can do this with the merge command. This allows people to continue to
+      # use other custom AuthenticationAuthority attributes without stomping on them.
+      #
+      # There is a potential problem here in that we're only doing this when setting
+      # the password, and the attribute could get modified at other times while the
+      # hash doesn't change and so this doesn't get called at all... but
+      # without switching all the other attributes to merge instead of create I can't
+      # see a simple enough solution for this that doesn't modify the user record
+      # every single time. This should be a rather rare edge case. (famous last words)
+
+      dscl_vector = self.get_exec_preamble("-merge", resource_name)
+      dscl_vector << "AuthenticationAuthority" << ";ShadowHash;"
+      begin
+        execute(dscl_vector)
+      rescue Puppet::ExecutionFailure => detail
+        fail("Could not set AuthenticationAuthority.")
+      end
+    else
+      # 10.7 uses salted SHA512 password hashes which are 128 characters plus
+      # an 8 character salt. Previous versions used a SHA1 hash padded with
+      # zeroes. If someone attempts to use a password hash that worked with
+      # a previous version of OX X, we will fail early and warn them.
+      if password_hash.length != 136
+        fail("OS X 10.7 requires a Salted SHA512 hash password of 136 characters. \
+             Please check your password and try again.")
+      end
+
+      if Puppet::FileSystem.exist?("#{users_plist_dir}/#{resource_name}.plist")
+        # If a plist already exists in /var/db/dslocal/nodes/Default/users, then
+        # we will need to extract the binary plist from the 'ShadowHashData'
+        # key, log the new password into the resultant plist's 'SALTED-SHA512'
+        # key, and then save the entire structure back.
+        users_plist = Plist::parse_xml(plutil( '-convert', 'xml1', '-o', '/dev/stdout', \
+                                       "#{users_plist_dir}/#{resource_name}.plist"))
+
+        # users_plist['ShadowHashData'][0].string is actually a binary plist
+        # that's nested INSIDE the user's plist (which itself is a binary
+        # plist). If we encounter a user plist that DOESN'T have a
+        # ShadowHashData field, create one.
+        if users_plist['ShadowHashData']
+          password_hash_plist = users_plist['ShadowHashData'][0].string
+          converted_hash_plist = convert_binary_to_xml(password_hash_plist)
+        else
+          users_plist['ShadowHashData'] = [StringIO.new]
+          converted_hash_plist = {'SALTED-SHA512' => StringIO.new}
+        end
+
+        # converted_hash_plist['SALTED-SHA512'].string expects a Base64 encoded
+        # string. The password_hash provided as a resource attribute is a
+        # hex value. We need to convert the provided hex value to a Base64
+        # encoded string to nest it in the converted hash plist.
+        converted_hash_plist['SALTED-SHA512'].string = \
+          password_hash.unpack('a2'*(password_hash.size/2)).collect { |i| i.hex.chr }.join
+
+        # Finally, we can convert the nested plist back to binary, embed it
+        # into the user's plist, and convert the resultant plist back to
+        # a binary plist.
+        changed_plist = convert_xml_to_binary(converted_hash_plist)
+        users_plist['ShadowHashData'][0].string = changed_plist
+        Plist::Emit.save_plist(users_plist, "#{users_plist_dir}/#{resource_name}.plist")
+        plutil('-convert', 'binary1', "#{users_plist_dir}/#{resource_name}.plist")
+      end
+    end
+  end
+
+  def self.get_password(guid, username)
+    # Use Puppet::Util::Package.versioncmp() to catch the scenario where a
+    # version '10.10' would be < '10.7' with simple string comparison. This
+    # if-statement only executes if the current version is less-than 10.7
+    if (Puppet::Util::Package.versioncmp(get_macosx_version_major, '10.7') == -1)
+      password_hash = nil
+      password_hash_file = "#{password_hash_dir}/#{guid}"
+      if Puppet::FileSystem.exist?(password_hash_file) and File.file?(password_hash_file)
+        fail("Could not read password hash file at #{password_hash_file}") if not File.readable?(password_hash_file)
+        f = File.new(password_hash_file)
+        password_hash = f.read
+        f.close
+      end
+      password_hash
+    else
+      if Puppet::FileSystem.exist?("#{users_plist_dir}/#{username}.plist")
+        # If a plist exists in /var/db/dslocal/nodes/Default/users, we will
+        # extract the binary plist from the 'ShadowHashData' key, decode the
+        # salted-SHA512 password hash, and then return it.
+        users_plist = Plist::parse_xml(plutil('-convert', 'xml1', '-o', '/dev/stdout', "#{users_plist_dir}/#{username}.plist"))
+        if users_plist['ShadowHashData']
+          # users_plist['ShadowHashData'][0].string is actually a binary plist
+          # that's nested INSIDE the user's plist (which itself is a binary
+          # plist).
+          password_hash_plist = users_plist['ShadowHashData'][0].string
+          converted_hash_plist = convert_binary_to_xml(password_hash_plist)
+
+          # converted_hash_plist['SALTED-SHA512'].string is a Base64 encoded
+          # string. The password_hash provided as a resource attribute is a
+          # hex value. We need to convert the Base64 encoded string to a
+          # hex value and provide it back to Puppet.
+          password_hash = converted_hash_plist['SALTED-SHA512'].string.unpack("H*")[0]
+          password_hash
+        end
+      end
+    end
+  end
+
+  # This method will accept a hash that has been returned from Plist::parse_xml
+  # and convert it to a binary plist (string value).
+  def self.convert_xml_to_binary(plist_data)
+    Puppet.debug('Converting XML plist to binary')
+    Puppet.debug('Executing: \'plutil -convert binary1 -o - -\'')
+    IO.popen('plutil -convert binary1 -o - -', 'r+') do |io|
+      io.write plist_data.to_plist
+      io.close_write
+      @converted_plist = io.read
+    end
+    @converted_plist
+  end
+
+  # This method will accept a binary plist (as a string) and convert it to a
+  # hash via Plist::parse_xml.
+  def self.convert_binary_to_xml(plist_data)
+    Puppet.debug('Converting binary plist to XML')
+    Puppet.debug('Executing: \'plutil -convert xml1 -o - -\'')
+    IO.popen('plutil -convert xml1 -o - -', 'r+') do |io|
+      io.write plist_data
+      io.close_write
+      @converted_plist = io.read
+    end
+    Puppet.debug('Converting XML values to a hash.')
+    @plist_hash = Plist::parse_xml(@converted_plist)
+    @plist_hash
+  end
+
+  # Unlike most other *nixes, OS X doesn't provide built in functionality
+  # for automatically assigning uids and gids to accounts, so we set up these
+  # methods for consumption by functionality like --mkusers
+  # By default we restrict to a reasonably sane range for system accounts
+  def self.next_system_id(id_type, min_id=20)
+    dscl_args = ['.', '-list']
+    if id_type == 'uid'
+      dscl_args << '/Users' << 'uid'
+    elsif id_type == 'gid'
+      dscl_args << '/Groups' << 'gid'
+    else
+      fail("Invalid id_type #{id_type}. Only 'uid' and 'gid' supported")
+    end
+    dscl_out = dscl(dscl_args)
+    # We're ok with throwing away negative uids here.
+    ids = dscl_out.split.compact.collect { |l| l.to_i if l.match(/^\d+$/) }
+    ids.compact!.sort! { |a,b| a.to_f <=> b.to_f }
+    # We're just looking for an unused id in our sorted array.
+    ids.each_index do |i|
+      next_id = ids[i] + 1
+      return next_id if ids[i+1] != next_id and next_id >= min_id
+    end
+  end
+
+
+  def ensure=(ensure_value)
+    super
+    # We need to loop over all valid properties for the type we're
+    # managing and call the method which sets that property value
+    # dscl can't create everything at once unfortunately.
+    if ensure_value == :present
+      @resource.class.validproperties.each do |name|
+        next if name == :ensure
+        # LAK: We use property.sync here rather than directly calling
+        # the settor method because the properties might do some kind
+        # of conversion.  In particular, the user gid property might
+        # have a string and need to convert it to a number
+        if @resource.should(name)
+          @resource.property(name).sync
+        elsif value = autogen(name)
+          self.send(name.to_s + "=", value)
+        else
+          next
+        end
+      end
+    end
+  end
+
+  def password=(passphrase)
+    exec_arg_vector = self.class.get_exec_preamble("-read", @resource.name)
+    exec_arg_vector << ns_to_ds_attribute_map[:guid]
+    begin
+      guid_output = execute(exec_arg_vector)
+      guid_plist = Plist.parse_xml(guid_output)
+      # Although GeneratedUID like all DirectoryService values can be multi-valued
+      # according to the schema, in practice user accounts cannot have multiple UUIDs
+      # otherwise Bad Things Happen, so we just deal with the first value.
+      guid = guid_plist["dsAttrTypeStandard:#{ns_to_ds_attribute_map[:guid]}"][0]
+      self.class.set_password(@resource.name, guid, passphrase)
+    rescue Puppet::ExecutionFailure => detail
+      fail("Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}")
+    end
+  end
+
+  # NBK: we override @parent.set as we need to execute a series of commands
+  # to deal with array values, rather than the single command nameservice.rb
+  # expects to be returned by modifycmd. Thus we don't bother defining modifycmd.
+
+  def set(param, value)
+    self.class.validate(param, value)
+    current_members = @property_value_cache_hash[:members]
+    if param == :members
+      # If we are meant to be authoritative for the group membership
+      # then remove all existing members who haven't been specified
+      # in the manifest.
+      remove_unwanted_members(current_members, value) if @resource[:auth_membership] and not current_members.nil?
+
+      # if they're not a member, make them one.
+      add_members(current_members, value)
+    else
+      exec_arg_vector = self.class.get_exec_preamble("-create", @resource[:name])
+      # JJM: The following line just maps the NS name to the DS name
+      #      e.g. { :uid => 'UniqueID' }
+      exec_arg_vector << ns_to_ds_attribute_map[param.intern]
+      # JJM: The following line sends the actual value to set the property to
+      exec_arg_vector << value.to_s
+      begin
+        execute(exec_arg_vector)
+      rescue Puppet::ExecutionFailure => detail
+        fail("Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}")
+      end
+    end
+  end
+
+  # NBK: we override @parent.create as we need to execute a series of commands
+  # to create objects with dscl, rather than the single command nameservice.rb
+  # expects to be returned by addcmd. Thus we don't bother defining addcmd.
+  def create
+    if exists?
+      info "already exists"
+      return nil
+    end
+
+    # NBK: First we create the object with a known guid so we can set the contents
+    # of the password hash if required
+    # Shelling out sucks, but for a single use case it doesn't seem worth
+    # requiring people install a UUID library that doesn't come with the system.
+    # This should be revisited if Puppet starts managing UUIDs for other platform
+    # user records.
+    guid = %x{/usr/bin/uuidgen}.chomp
+
+    exec_arg_vector = self.class.get_exec_preamble("-create", @resource[:name])
+    exec_arg_vector << ns_to_ds_attribute_map[:guid] << guid
+    begin
+      execute(exec_arg_vector)
+    rescue Puppet::ExecutionFailure => detail
+      fail("Could not set GeneratedUID for #{@resource.class.name} #{@resource.name}: #{detail}")
+    end
+
+    if value = @resource.should(:password) and value != ""
+      self.class.set_password(@resource[:name], guid, value)
+    end
+
+    # Now we create all the standard properties
+    Puppet::Type.type(@resource.class.name).validproperties.each do |property|
+      next if property == :ensure
+      value = @resource.should(property)
+      if property == :gid and value.nil?
+        value = self.class.next_system_id(id_type='gid')
+      end
+      if property == :uid and value.nil?
+        value = self.class.next_system_id(id_type='uid')
+      end
+      if value != "" and not value.nil?
+        if property == :members
+          add_members(nil, value)
+        else
+          exec_arg_vector = self.class.get_exec_preamble("-create", @resource[:name])
+          exec_arg_vector << ns_to_ds_attribute_map[property.intern]
+          next if property == :password  # skip setting the password here
+          exec_arg_vector << value.to_s
+          begin
+            execute(exec_arg_vector)
+          rescue Puppet::ExecutionFailure => detail
+            fail("Could not create #{@resource.class.name} #{@resource.name}: #{detail}")
+          end
+        end
+      end
+    end
+  end
+
+  def remove_unwanted_members(current_members, new_members)
+    current_members.each do |member|
+      if not new_members.flatten.include?(member)
+        cmd = [:dseditgroup, "-o", "edit", "-n", ".", "-d", member, @resource[:name]]
+        begin
+          execute(cmd)
+        rescue Puppet::ExecutionFailure => detail
+          # TODO: We're falling back to removing the member using dscl due to rdar://8481241
+          # This bug causes dseditgroup to fail to remove a member if that member doesn't exist
+          cmd = [:dscl, ".", "-delete", "/Groups/#{@resource.name}", "GroupMembership", member]
+          begin
+            execute(cmd)
+          rescue Puppet::ExecutionFailure => detail
+            fail("Could not remove #{member} from group: #{@resource.name}, #{detail}")
+          end
+        end
+      end
+    end
+  end
+
+  def add_members(current_members, new_members)
+    new_members.flatten.each do |new_member|
+      if current_members.nil? or not current_members.include?(new_member)
+        cmd = [:dseditgroup, "-o", "edit", "-n", ".", "-a", new_member, @resource[:name]]
+        begin
+          execute(cmd)
+        rescue Puppet::ExecutionFailure => detail
+          fail("Could not add #{new_member} to group: #{@resource.name}, #{detail}")
+        end
+      end
+    end
+  end
+
+  def deletecmd
+    # JJM: Like addcmd, only called when deleting the object itself
+    #    Note, this isn't used to delete properties of the object,
+    #    at least that's how I understand it...
+    self.class.get_exec_preamble("-delete", @resource[:name])
+  end
+
+  def getinfo(refresh = false)
+    # JJM 2007-07-24:
+    #      Override the getinfo method, which is also defined in nameservice.rb
+    #      This method returns and sets @infohash
+    # I'm not re-factoring the name "getinfo" because this method will be
+    # most likely called by nameservice.rb, which I didn't write.
+    if refresh or (! defined?(@property_value_cache_hash) or ! @property_value_cache_hash)
+      # JJM 2007-07-24: OK, there's a bit of magic that's about to
+      # happen... Let's see how strong my grip has become... =)
+      #
+      # self is a provider instance of some Puppet::Type, like
+      # Puppet::Type::User::ProviderDirectoryservice for the case of the
+      # user type and this provider.
+      #
+      # self.class looks like "user provider directoryservice", if that
+      # helps you ...
+      #
+      # self.class.resource_type is a reference to the Puppet::Type class,
+      # probably Puppet::Type::User or Puppet::Type::Group, etc...
+      #
+      # self.class.resource_type.validproperties is a class method,
+      # returning an Array of the valid properties of that specific
+      # Puppet::Type.
+      #
+      # So... something like [:comment, :home, :password, :shell, :uid,
+      # :groups, :ensure, :gid]
+      #
+      # Ultimately, we add :name to the list, delete :ensure from the
+      # list, then report on the remaining list. Pretty whacky, ehh?
+      type_properties = [:name] + self.class.resource_type.validproperties
+      type_properties.delete(:ensure) if type_properties.include? :ensure
+      type_properties << :guid  # append GeneratedUID so we just get the report here
+      @property_value_cache_hash = self.class.single_report(@resource[:name], *type_properties)
+      [:uid, :gid].each do |param|
+        @property_value_cache_hash[param] = @property_value_cache_hash[param].to_i if @property_value_cache_hash and @property_value_cache_hash.include?(param)
+      end
+    end
+    @property_value_cache_hash
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/nameservice/objectadd.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/nameservice/objectadd.rb
new file mode 100644
index 0000000..dbb9f30
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/nameservice/objectadd.rb
@@ -0,0 +1,33 @@
+require 'puppet/provider/nameservice'
+
+class Puppet::Provider::NameService
+class ObjectAdd < Puppet::Provider::NameService
+  def deletecmd
+    [command(:delete), @resource[:name]]
+  end
+
+  # Determine the flag to pass to our command.
+  def flag(name)
+    name = name.intern if name.is_a? String
+    self.class.option(name, :flag) || "-" + name.to_s[0,1]
+  end
+
+  def modifycmd(param, value)
+    cmd = [command(param.to_s =~ /password_.+_age/ ? :password : :modify)]
+    cmd << flag(param) << value
+    if @resource.allowdupe? && ((param == :uid) || (param == :gid and self.class.name == :groupadd))
+      cmd << "-o"
+    end
+    cmd << @resource[:name]
+
+    cmd
+  end
+
+  def posixmethod(name)
+    name = name.intern if name.is_a? String
+    method = self.class.option(name, :method) || name
+
+    method
+  end
+end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/nameservice/pw.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/nameservice/pw.rb
new file mode 100644
index 0000000..f774826
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/nameservice/pw.rb
@@ -0,0 +1,21 @@
+require 'puppet/provider/nameservice/objectadd'
+
+class Puppet::Provider::NameService
+class PW < ObjectAdd
+  def deletecmd
+    [command(:pw), "#{@resource.class.name.to_s}del", @resource[:name]]
+  end
+
+  def modifycmd(param, value)
+    cmd = [
+      command(:pw),
+      "#{@resource.class.name.to_s}mod",
+      @resource[:name],
+      flag(param),
+      munge(param, value)
+    ]
+    cmd
+  end
+end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/network_device.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/network_device.rb
new file mode 100644
index 0000000..46be279
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/network_device.rb
@@ -0,0 +1,68 @@
+
+# This is the base class of all prefetched network device provider
+class Puppet::Provider::NetworkDevice < Puppet::Provider
+
+  def self.device(url)
+    raise "This provider doesn't implement the necessary device method"
+  end
+
+  def self.lookup(device, name)
+    raise "This provider doesn't implement the necessary lookup method"
+  end
+
+  def self.prefetch(resources)
+    resources.each do |name, resource|
+      device = Puppet::Util::NetworkDevice.current || device(resource[:device_url])
+      if result = lookup(device, name)
+        result[:ensure] = :present
+        resource.provider = new(device, result)
+      else
+        resource.provider = new(device, :ensure => :absent)
+      end
+    end
+  end
+
+  def exists?
+    @property_hash[:ensure] != :absent
+  end
+
+  attr_accessor :device
+
+  def initialize(device, *args)
+    super(*args)
+
+    @device = device
+
+    # Make a duplicate, so that we have a copy for comparison
+    # at the end.
+    @properties = @property_hash.dup
+  end
+
+  def create
+    @property_hash[:ensure] = :present
+    self.class.resource_type.validproperties.each do |property|
+      if val = resource.should(property)
+        @property_hash[property] = val
+      end
+    end
+  end
+
+  def destroy
+    @property_hash[:ensure] = :absent
+  end
+
+  def flush
+    @property_hash.clear
+  end
+
+  def self.instances
+  end
+
+  def former_properties
+    @properties.dup
+  end
+
+  def properties
+    @property_hash.dup
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package.rb
new file mode 100644
index 0000000..88c6716
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package.rb
@@ -0,0 +1,52 @@
+class Puppet::Provider::Package < Puppet::Provider
+  # Prefetch our package list, yo.
+  def self.prefetch(packages)
+    instances.each do |prov|
+      if pkg = packages[prov.name]
+        pkg.provider = prov
+      end
+    end
+  end
+
+  # Clear out the cached values.
+  def flush
+    @property_hash.clear
+  end
+
+  # Look up the current status.
+  def properties
+    if @property_hash.empty?
+      @property_hash = query || {:ensure => :absent}
+      @property_hash[:ensure] = :absent if @property_hash.empty?
+    end
+    @property_hash.dup
+  end
+
+  def validate_source(value)
+    true
+  end
+
+  # Turns a array of options into flags to be passed to a command.
+  # The options can be passed as a string or hash. Note that passing a hash
+  # should only be used in case --foo=bar must be passed,
+  # which can be accomplished with:
+  #     install_options => [ { '--foo' => 'bar' } ]
+  # Regular flags like '--foo' must be passed as a string.
+  # @param options [Array]
+  # @return Concatenated list of options
+  # @api private
+  def join_options(options)
+    return unless options
+
+    options.collect do |val|
+      case val
+        when Hash
+          val.keys.sort.collect do |k|
+            "#{k}=#{val[k]}"
+          end
+        else
+          val
+      end
+    end.flatten
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/aix.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/aix.rb
new file mode 100644
index 0000000..ae54962
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/aix.rb
@@ -0,0 +1,152 @@
+require 'puppet/provider/package'
+require 'puppet/util/package'
+
+Puppet::Type.type(:package).provide :aix, :parent => Puppet::Provider::Package do
+  desc "Installation from an AIX software directory, using the AIX `installp`
+       command.  The `source` parameter is required for this provider, and should
+       be set to the absolute path (on the puppet agent machine) of a directory
+       containing one or more BFF package files.
+
+       The `installp` command will generate a table of contents file (named `.toc`)
+       in this directory, and the `name` parameter (or resource title) that you
+       specify for your `package` resource must match a package name that exists
+       in the `.toc` file.
+
+       Note that package downgrades are *not* supported; if your resource specifies
+       a specific version number and there is already a newer version of the package
+       installed on the machine, the resource will fail with an error message."
+
+  # The commands we are using on an AIX box are installed standard
+  # (except nimclient) nimclient needs the bos.sysmgt.nim.client fileset.
+  commands    :lslpp => "/usr/bin/lslpp",
+              :installp => "/usr/sbin/installp"
+
+  # AIX supports versionable packages with and without a NIM server
+  has_feature :versionable
+
+  confine  :operatingsystem => [ :aix ]
+  defaultfor :operatingsystem => :aix
+
+  attr_accessor   :latest_info
+
+  def self.srclistcmd(source)
+    [ command(:installp), "-L", "-d", source ]
+  end
+
+  def self.prefetch(packages)
+    raise Puppet::Error, "The aix provider can only be used by root" if Process.euid != 0
+
+    return unless packages.detect { |name, package| package.should(:ensure) == :latest }
+
+    sources = packages.collect { |name, package| package[:source] }.uniq
+
+    updates = {}
+    sources.each do |source|
+      execute(self.srclistcmd(source)).each_line do |line|
+        if line =~ /^[^#][^:]*:([^:]*):([^:]*)/
+          current = {}
+          current[:name]    = $1
+          current[:version] = $2
+          current[:source]  = source
+
+          if updates.key?(current[:name])
+            previous = updates[current[:name]]
+
+            updates[ current[:name] ] = current unless Puppet::Util::Package.versioncmp(previous[:version], current[:version]) == 1
+
+          else
+            updates[current[:name]] = current
+          end
+        end
+      end
+    end
+
+    packages.each do |name, package|
+      if info = updates[package[:name]]
+        package.provider.latest_info = info[0]
+      end
+    end
+  end
+
+  def uninstall
+    # Automatically process dependencies when installing/uninstalling
+    # with the -g option to installp.
+    installp "-gu", @resource[:name]
+
+    # installp will return an exit code of zero even if it didn't uninstall
+    # anything... so let's make sure it worked.
+    unless query().nil?
+      self.fail "Failed to uninstall package '#{@resource[:name]}'"
+    end
+  end
+
+  def install(useversion = true)
+    unless source = @resource[:source]
+      self.fail "A directory is required which will be used to find packages"
+    end
+
+    pkg = @resource[:name]
+
+    pkg += " #{@resource.should(:ensure)}" if (! @resource.should(:ensure).is_a? Symbol) and useversion
+
+    output = installp "-acgwXY", "-d", source, pkg
+
+    # If the package is superseded, it means we're trying to downgrade and we
+    # can't do that.
+    if output =~ /^#{Regexp.escape(@resource[:name])}\s+.*\s+Already superseded by.*$/
+      self.fail "aix package provider is unable to downgrade packages"
+    end
+  end
+
+  def self.pkglist(hash = {})
+    cmd = [command(:lslpp), "-qLc"]
+
+    if name = hash[:pkgname]
+      cmd << name
+    end
+
+    begin
+      list = execute(cmd).scan(/^[^#][^:]*:([^:]*):([^:]*)/).collect { |n,e|
+        { :name => n, :ensure => e, :provider => self.name }
+      }
+    rescue Puppet::ExecutionFailure => detail
+      if hash[:pkgname]
+        return nil
+      else
+        raise Puppet::Error, "Could not list installed Packages: #{detail}", detail.backtrace
+      end
+    end
+
+    if hash[:pkgname]
+      return list.shift
+    else
+      return list
+    end
+  end
+
+  def self.instances
+    pkglist.collect do |hash|
+      new(hash)
+    end
+  end
+
+  def latest
+    upd = latest_info
+
+    unless upd.nil?
+      return "#{upd[:version]}"
+    else
+      raise Puppet::DevError, "Tried to get latest on a missing package" if properties[:ensure] == :absent
+
+      return properties[:ensure]
+    end
+  end
+
+  def query
+    self.class.pkglist(:pkgname => @resource[:name])
+  end
+
+  def update
+    self.install(false)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/appdmg.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/appdmg.rb
new file mode 100644
index 0000000..46db070
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/appdmg.rb
@@ -0,0 +1,106 @@
+# Jeff McCune <mccune.jeff@gmail.com>
+# Changed to app.dmg by: Udo Waechter <root@zoide.net>
+# Mac OS X Package Installer which handles application (.app)
+# bundles inside an Apple Disk Image.
+#
+# Motivation: DMG files provide a true HFS file system
+# and are easier to manage.
+#
+# Note: the 'apple' Provider checks for the package name
+# in /L/Receipts.  Since we possibly install multiple apps's from
+# a single source, we treat the source .app.dmg file as the package name.
+# As a result, we store installed .app.dmg file names
+# in /var/db/.puppet_appdmg_installed_<name>
+
+require 'puppet/provider/package'
+Puppet::Type.type(:package).provide(:appdmg, :parent => Puppet::Provider::Package) do
+  desc "Package management which copies application bundles to a target."
+
+  confine :operatingsystem => :darwin
+
+  commands :hdiutil => "/usr/bin/hdiutil"
+  commands :curl => "/usr/bin/curl"
+  commands :ditto => "/usr/bin/ditto"
+
+  # JJM We store a cookie for each installed .app.dmg in /var/db
+  def self.instances_by_name
+    Dir.entries("/var/db").find_all { |f|
+      f =~ /^\.puppet_appdmg_installed_/
+    }.collect do |f|
+      name = f.sub(/^\.puppet_appdmg_installed_/, '')
+      yield name if block_given?
+      name
+    end
+  end
+
+  def self.instances
+    instances_by_name.collect do |name|
+      new(:name => name, :provider => :appdmg, :ensure => :installed)
+    end
+  end
+
+  def self.installapp(source, name, orig_source)
+    appname = File.basename(source);
+    ditto "--rsrc", source, "/Applications/#{appname}"
+    File.open("/var/db/.puppet_appdmg_installed_#{name}", "w") do |t|
+      t.print "name: '#{name}'\n"
+      t.print "source: '#{orig_source}'\n"
+    end
+  end
+
+  def self.installpkgdmg(source, name)
+    require 'open-uri'
+    require 'facter/util/plist'
+    cached_source = source
+    tmpdir = Dir.mktmpdir
+    begin
+      if %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} =~ cached_source
+        cached_source = File.join(tmpdir, name)
+        begin
+          curl "-o", cached_source, "-C", "-", "-k", "-L", "-s", "--url", source
+          Puppet.debug "Success: curl transfered [#{name}]"
+        rescue Puppet::ExecutionFailure
+          Puppet.debug "curl did not transfer [#{name}].  Falling back to slower open-uri transfer methods."
+          cached_source = source
+        end
+      end
+
+      open(cached_source) do |dmg|
+        xml_str = hdiutil "mount", "-plist", "-nobrowse", "-readonly", "-mountrandom", "/tmp", dmg.path
+          ptable = Plist::parse_xml xml_str
+          # JJM Filter out all mount-paths into a single array, discard the rest.
+          mounts = ptable['system-entities'].collect { |entity|
+            entity['mount-point']
+          }.select { |mountloc|; mountloc }
+          begin
+            mounts.each do |fspath|
+              Dir.entries(fspath).select { |f|
+                f =~ /\.app$/i
+              }.each do |pkg|
+                installapp("#{fspath}/#{pkg}", name, source)
+              end
+            end
+          ensure
+            hdiutil "eject", mounts[0]
+          end
+      end
+    ensure
+      FileUtils.remove_entry_secure(tmpdir, true)
+    end
+  end
+
+  def query
+    Puppet::FileSystem.exist?("/var/db/.puppet_appdmg_installed_#{@resource[:name]}") ? {:name => @resource[:name], :ensure => :present} : nil
+  end
+
+  def install
+    source = nil
+    unless source = @resource[:source]
+      self.fail "Mac OS X PKG DMG's must specify a package source."
+    end
+    unless name = @resource[:name]
+      self.fail "Mac OS X PKG DMG's must specify a package name."
+    end
+    self.class.installpkgdmg(source,name)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/apple.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/apple.rb
new file mode 100644
index 0000000..1d44c3e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/apple.rb
@@ -0,0 +1,47 @@
+require 'puppet/provider/package'
+
+# OS X Packaging sucks.  We can install packages, but that's about it.
+Puppet::Type.type(:package).provide :apple, :parent => Puppet::Provider::Package do
+  desc "Package management based on OS X's builtin packaging system.  This is
+    essentially the simplest and least functional package system in existence --
+    it only supports installation; no deletion or upgrades.  The provider will
+    automatically add the `.pkg` extension, so leave that off when specifying
+    the package name."
+
+  confine :operatingsystem => :darwin
+  commands :installer => "/usr/sbin/installer"
+
+  def self.instances
+    instance_by_name.collect do |name|
+      self.new(
+        :name     => name,
+        :provider => :apple,
+        :ensure   => :installed
+      )
+    end
+  end
+
+  def self.instance_by_name
+    Dir.entries("/Library/Receipts").find_all { |f|
+      f =~ /\.pkg$/
+    }.collect { |f|
+      name = f.sub(/\.pkg/, '')
+      yield name if block_given?
+
+      name
+    }
+  end
+
+  def query
+    Puppet::FileSystem.exist?("/Library/Receipts/#{@resource[:name]}.pkg") ? {:name => @resource[:name], :ensure => :present} : nil
+  end
+
+  def install
+    source = nil
+    unless source = @resource[:source]
+      self.fail "Mac OS X packages must specify a package source"
+    end
+
+    installer "-pkg", source, "-target", "/"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/apt.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/apt.rb
new file mode 100644
index 0000000..f43f514
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/apt.rb
@@ -0,0 +1,116 @@
+Puppet::Type.type(:package).provide :apt, :parent => :dpkg, :source => :dpkg do
+  # Provide sorting functionality
+  include Puppet::Util::Package
+
+  desc "Package management via `apt-get`.
+
+    This provider supports the `install_options` attribute, which allows command-line flags to be passed to apt-get.
+    These options should be specified as a string (e.g. '--flag'), a hash (e.g. {'--flag' => 'value'}),
+    or an array where each element is either a string or a hash."
+
+  has_feature :versionable, :install_options
+
+  commands :aptget => "/usr/bin/apt-get"
+  commands :aptcache => "/usr/bin/apt-cache"
+  commands :preseed => "/usr/bin/debconf-set-selections"
+
+  defaultfor :operatingsystem => [:debian, :ubuntu]
+
+  ENV['DEBIAN_FRONTEND'] = "noninteractive"
+
+  # disable common apt helpers to allow non-interactive package installs
+  ENV['APT_LISTBUGS_FRONTEND'] = "none"
+  ENV['APT_LISTCHANGES_FRONTEND'] = "none"
+
+  # A derivative of DPKG; this is how most people actually manage
+  # Debian boxes, and the only thing that differs is that it can
+  # install packages from remote sites.
+
+  def checkforcdrom
+    have_cdrom = begin
+                   !!(File.read("/etc/apt/sources.list") =~ /^[^#]*cdrom:/)
+                 rescue
+                   # This is basically pathological...
+                   false
+                 end
+
+    if have_cdrom and @resource[:allowcdrom] != :true
+      raise Puppet::Error,
+        "/etc/apt/sources.list contains a cdrom source; not installing.  Use 'allowcdrom' to override this failure."
+    end
+  end
+
+  # Install a package using 'apt-get'.  This function needs to support
+  # installing a specific version.
+  def install
+    self.run_preseed if @resource[:responsefile]
+    should = @resource[:ensure]
+
+    checkforcdrom
+    cmd = %w{-q -y}
+
+    if config = @resource[:configfiles]
+      if config == :keep
+        cmd << "-o" << 'DPkg::Options::=--force-confold'
+      else
+        cmd << "-o" << 'DPkg::Options::=--force-confnew'
+      end
+    end
+
+    str = @resource[:name]
+    case should
+    when true, false, Symbol
+      # pass
+    else
+      # Add the package version and --force-yes option
+      str += "=#{should}"
+      cmd << "--force-yes"
+    end
+
+    cmd += install_options if @resource[:install_options]
+    cmd << :install << str
+
+    aptget(*cmd)
+  end
+
+  # What's the latest package version available?
+  def latest
+    output = aptcache :policy,  @resource[:name]
+
+    if output =~ /Candidate:\s+(\S+)\s/
+      return $1
+    else
+      self.err "Could not find latest version"
+      return nil
+    end
+  end
+
+  #
+  # preseeds answers to dpkg-set-selection from the "responsefile"
+  #
+  def run_preseed
+    if response = @resource[:responsefile] and Puppet::FileSystem.exist?(response)
+      self.info("Preseeding #{response} to debconf-set-selections")
+
+      preseed response
+    else
+      self.info "No responsefile specified or non existant, not preseeding anything"
+    end
+  end
+
+  def uninstall
+    self.run_preseed if @resource[:responsefile]
+    aptget "-y", "-q", :remove, @resource[:name]
+  end
+
+  def purge
+    self.run_preseed if @resource[:responsefile]
+    aptget '-y', '-q', :remove, '--purge', @resource[:name]
+    # workaround a "bug" in apt, that already removed packages are not purged
+    super
+  end
+
+  def install_options
+    join_options(@resource[:install_options])
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/aptitude.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/aptitude.rb
new file mode 100644
index 0000000..d3ab0da
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/aptitude.rb
@@ -0,0 +1,29 @@
+Puppet::Type.type(:package).provide :aptitude, :parent => :apt, :source => :dpkg do
+  desc "Package management via `aptitude`."
+
+  has_feature :versionable
+
+  commands :aptitude => "/usr/bin/aptitude"
+  commands :aptcache => "/usr/bin/apt-cache"
+
+  ENV['DEBIAN_FRONTEND'] = "noninteractive"
+
+  def aptget(*args)
+    args.flatten!
+    # Apparently aptitude hasn't always supported a -q flag.
+    args.delete("-q") if args.include?("-q")
+    args.delete("--force-yes") if args.include?("--force-yes")
+    output = aptitude(*args)
+
+    # Yay, stupid aptitude doesn't throw an error when the package is missing.
+    if args.include?(:install) and output =~ /Couldn't find any package/
+      raise Puppet::Error.new(
+        "Could not find package #{self.name}"
+      )
+    end
+  end
+
+  def purge
+    aptitude '-y', 'purge', @resource[:name]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/aptrpm.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/aptrpm.rb
new file mode 100644
index 0000000..a244a96
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/aptrpm.rb
@@ -0,0 +1,83 @@
+Puppet::Type.type(:package).provide :aptrpm, :parent => :rpm, :source => :rpm do
+  # Provide sorting functionality
+  include Puppet::Util::Package
+
+  desc "Package management via `apt-get` ported to `rpm`."
+
+  has_feature :versionable
+
+  commands :aptget => "apt-get"
+  commands :aptcache => "apt-cache"
+  commands :rpm => "rpm"
+
+  if command('rpm')
+    confine :true => begin
+      rpm('-ql', 'rpm')
+      rescue Puppet::ExecutionFailure
+        false
+      else
+        true
+      end
+  end
+
+  # Install a package using 'apt-get'.  This function needs to support
+  # installing a specific version.
+  def install
+    should = @resource.should(:ensure)
+
+    str = @resource[:name]
+    case should
+    when true, false, Symbol
+      # pass
+    else
+      # Add the package version
+      str += "=#{should}"
+    end
+    cmd = %w{-q -y}
+
+    cmd << 'install' << str
+
+    aptget(*cmd)
+  end
+
+  # What's the latest package version available?
+  def latest
+    output = aptcache :showpkg,  @resource[:name]
+
+    if output =~ /Versions:\s*\n((\n|.)+)^$/
+      versions = $1
+      available_versions = versions.split(/\n/).collect { |version|
+        if version =~ /^([^\(]+)\(/
+          $1
+        else
+          self.warning "Could not match version '#{version}'"
+          nil
+        end
+      }.reject { |vers| vers.nil? }.sort { |a,b|
+        versioncmp(a,b)
+      }
+
+      if available_versions.length == 0
+        self.debug "No latest version"
+        print output if Puppet[:debug]
+      end
+
+      # Get the latest and greatest version number
+      return available_versions.pop
+    else
+      self.err "Could not match string"
+    end
+  end
+
+  def update
+    self.install
+  end
+
+  def uninstall
+    aptget "-y", "-q", 'remove', @resource[:name]
+  end
+
+  def purge
+    aptget '-y', '-q', 'remove', '--purge', @resource[:name]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/blastwave.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/blastwave.rb
new file mode 100644
index 0000000..27ce4d3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/blastwave.rb
@@ -0,0 +1,111 @@
+# Packaging using Blastwave's pkg-get program.
+Puppet::Type.type(:package).provide :blastwave, :parent => :sun, :source => :sun do
+  desc "Package management using Blastwave.org's `pkg-get` command on Solaris."
+  pkgget = "pkg-get"
+  pkgget = "/opt/csw/bin/pkg-get" if FileTest.executable?("/opt/csw/bin/pkg-get")
+
+  confine :osfamily => :solaris
+
+  commands :pkgget => pkgget
+
+  def pkgget_with_cat(*args)
+    Puppet::Util.withenv(:PAGER => "/usr/bin/cat") { pkgget(*args) }
+  end
+
+  def self.extended(mod)
+    unless command(:pkgget) != "pkg-get"
+      raise Puppet::Error,
+        "The pkg-get command is missing; blastwave packaging unavailable"
+    end
+
+    unless Puppet::FileSystem.exist?("/var/pkg-get/admin")
+      Puppet.notice "It is highly recommended you create '/var/pkg-get/admin'."
+      Puppet.notice "See /var/pkg-get/admin-fullauto"
+    end
+  end
+
+  def self.instances(hash = {})
+    blastlist(hash).collect do |bhash|
+      bhash.delete(:avail)
+      new(bhash)
+    end
+  end
+
+  # Turn our blastwave listing into a bunch of hashes.
+  def self.blastlist(hash)
+    command = ["-c"]
+
+    command << hash[:justme] if hash[:justme]
+
+    output = Puppet::Util.withenv(:PAGER => "/usr/bin/cat") { pkgget command }
+
+    list = output.split("\n").collect do |line|
+      next if line =~ /^#/
+      next if line =~ /^WARNING/
+      next if line =~ /localrev\s+remoterev/
+
+      blastsplit(line)
+    end.reject { |h| h.nil? }
+
+    if hash[:justme]
+      return list[0]
+    else
+      list.reject! { |h|
+        h[:ensure] == :absent
+      }
+      return list
+    end
+
+  end
+
+  # Split the different lines into hashes.
+  def self.blastsplit(line)
+    if line =~ /\s*(\S+)\s+((\[Not installed\])|(\S+))\s+(\S+)/
+      hash = {}
+      hash[:name] = $1
+      hash[:ensure] = if $2 == "[Not installed]"
+        :absent
+      else
+        $2
+      end
+      hash[:avail] = $5
+
+      hash[:avail] = hash[:ensure] if hash[:avail] == "SAME"
+
+      # Use the name method, so it works with subclasses.
+      hash[:provider] = self.name
+
+      return hash
+    else
+      Puppet.warning "Cannot match #{line}"
+      return nil
+    end
+  end
+
+  def install
+    pkgget_with_cat "-f", :install, @resource[:name]
+  end
+
+  # Retrieve the version from the current package file.
+  def latest
+    hash = self.class.blastlist(:justme => @resource[:name])
+    hash[:avail]
+  end
+
+  def query
+    if hash = self.class.blastlist(:justme => @resource[:name])
+      hash
+    else
+      {:ensure => :absent}
+    end
+  end
+
+  # Remove the old package, and install the new one
+  def update
+    pkgget_with_cat "-f", :upgrade, @resource[:name]
+  end
+
+  def uninstall
+    pkgget_with_cat "-f", :remove, @resource[:name]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/dpkg.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/dpkg.rb
new file mode 100644
index 0000000..49cacf6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/dpkg.rb
@@ -0,0 +1,165 @@
+require 'puppet/provider/package'
+
+Puppet::Type.type(:package).provide :dpkg, :parent => Puppet::Provider::Package do
+  desc "Package management via `dpkg`.  Because this only uses `dpkg`
+    and not `apt`, you must specify the source of any packages you want
+    to manage."
+
+  has_feature :holdable
+
+  commands :dpkg => "/usr/bin/dpkg"
+  commands :dpkg_deb => "/usr/bin/dpkg-deb"
+  commands :dpkgquery => "/usr/bin/dpkg-query"
+
+  # Performs a dpkgquery call with a pipe so that output can be processed
+  # inline in a passed block.
+  # @param args [Array<String>] any command line arguments to be appended to the command
+  # @param block expected to be passed on to execpipe
+  # @return whatever the block returns
+  # @see Puppet::Util::Execution.execpipe
+  # @api private
+  def self.dpkgquery_piped(*args, &block)
+    cmd = args.unshift(command(:dpkgquery))
+    Puppet::Util::Execution.execpipe(cmd, &block)
+  end
+
+  def self.instances
+    packages = []
+
+    # list out all of the packages
+    dpkgquery_piped('-W', '--showformat', self::DPKG_QUERY_FORMAT_STRING) do |pipe|
+      # now turn each returned line into a package object
+      pipe.each_line do |line|
+        if hash = parse_line(line)
+          packages << new(hash)
+        end
+      end
+    end
+
+    packages
+  end
+
+  private
+
+  # Note: self:: is required here to keep these constants in the context of what will
+  # eventually become this Puppet::Type::Package::ProviderDpkg class.
+  self::DPKG_QUERY_FORMAT_STRING = %Q{'${Status} ${Package} ${Version}\\n'}
+  self::FIELDS_REGEX = %r{^(\S+) +(\S+) +(\S+) (\S+) (\S*)$}
+  self::FIELDS= [:desired, :error, :status, :name, :ensure]
+
+  # @param line [String] one line of dpkg-query output
+  # @return [Hash,nil] a hash of FIELDS or nil if we failed to match
+  # @api private
+  def self.parse_line(line)
+    hash = nil
+
+    if match = self::FIELDS_REGEX.match(line)
+      hash = {}
+
+      self::FIELDS.zip(match.captures) do |field,value|
+        hash[field] = value
+      end
+
+      hash[:provider] = self.name
+
+      if hash[:status] == 'not-installed'
+        hash[:ensure] = :purged
+      elsif ['config-files', 'half-installed', 'unpacked', 'half-configured'].include?(hash[:status])
+        hash[:ensure] = :absent
+      end
+      hash[:ensure] = :held if hash[:desired] == 'hold'
+    else 
+      Puppet.debug("Failed to match dpkg-query line #{line.inspect}")
+    end
+
+    return hash
+  end
+
+  public
+
+  def install
+    unless file = @resource[:source]
+      raise ArgumentError, "You cannot install dpkg packages without a source"
+    end
+
+    args = []
+
+    # We always unhold when installing to remove any prior hold.
+    self.unhold
+
+    if @resource[:configfiles] == :keep
+      args << '--force-confold'
+    else
+      args << '--force-confnew'
+    end
+    args << '-i' << file
+
+    dpkg(*args)
+  end
+
+  def update
+    self.install
+  end
+
+  # Return the version from the package.
+  def latest
+    output = dpkg_deb "--show", @resource[:source]
+    matches = /^(\S+)\t(\S+)$/.match(output).captures
+    warning "source doesn't contain named package, but #{matches[0]}" unless matches[0].match( Regexp.escape(@resource[:name]) )
+    matches[1]
+  end
+
+  def query
+    hash = nil
+
+    # list out our specific package
+    begin
+      output = dpkgquery(
+        "-W",
+        "--showformat",
+        self.class::DPKG_QUERY_FORMAT_STRING,
+        @resource[:name]
+      )
+      hash = self.class.parse_line(output)
+    rescue Puppet::ExecutionFailure
+      # dpkg-query exits 1 if the package is not found.
+      return {:ensure => :purged, :status => 'missing', :name => @resource[:name], :error => 'ok'}
+    end
+
+    hash ||= {:ensure => :absent, :status => 'missing', :name => @resource[:name], :error => 'ok'}
+
+    if hash[:error] != "ok"
+      raise Puppet::Error.new(
+        "Package #{hash[:name]}, version #{hash[:ensure]} is in error state: #{hash[:error]}"
+      )
+    end
+
+    hash
+  end
+
+  def uninstall
+    dpkg "-r", @resource[:name]
+  end
+
+  def purge
+    dpkg "--purge", @resource[:name]
+  end
+
+  def hold
+    self.install
+    Tempfile.open('puppet_dpkg_set_selection') do |tmpfile|
+      tmpfile.write("#{@resource[:name]} hold\n")
+      tmpfile.flush
+      execute([:dpkg, "--set-selections"], :failonfail => false, :combine => false, :stdinfile => tmpfile.path.to_s)
+    end
+  end
+
+  def unhold
+    Tempfile.open('puppet_dpkg_set_selection') do |tmpfile|
+      tmpfile.write("#{@resource[:name]} install\n")
+      tmpfile.flush
+      execute([:dpkg, "--set-selections"], :failonfail => false, :combine => false, :stdinfile => tmpfile.path.to_s)
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/fink.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/fink.rb
new file mode 100644
index 0000000..6b49517
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/fink.rb
@@ -0,0 +1,79 @@
+Puppet::Type.type(:package).provide :fink, :parent => :dpkg, :source => :dpkg do
+  # Provide sorting functionality
+  include Puppet::Util::Package
+
+  desc "Package management via `fink`."
+
+  commands :fink => "/sw/bin/fink"
+  commands :aptget => "/sw/bin/apt-get"
+  commands :aptcache => "/sw/bin/apt-cache"
+  commands :dpkgquery => "/sw/bin/dpkg-query"
+
+  has_feature :versionable
+
+  # A derivative of DPKG; this is how most people actually manage
+  # Debian boxes, and the only thing that differs is that it can
+  # install packages from remote sites.
+
+  def finkcmd(*args)
+    fink(*args)
+  end
+
+  # Install a package using 'apt-get'.  This function needs to support
+  # installing a specific version.
+  def install
+    self.run_preseed if @resource[:responsefile]
+    should = @resource.should(:ensure)
+
+    str = @resource[:name]
+    case should
+    when true, false, Symbol
+      # pass
+    else
+      # Add the package version
+      str += "=#{should}"
+    end
+    cmd = %w{-b -q -y}
+
+    cmd << :install << str
+
+    finkcmd(cmd)
+  end
+
+  # What's the latest package version available?
+  def latest
+    output = aptcache :policy,  @resource[:name]
+
+    if output =~ /Candidate:\s+(\S+)\s/
+      return $1
+    else
+      self.err "Could not find latest version"
+      return nil
+    end
+  end
+
+  #
+  # preseeds answers to dpkg-set-selection from the "responsefile"
+  #
+  def run_preseed
+    if response = @resource[:responsefile] and Puppet::FileSystem.exist?(response)
+      self.info("Preseeding #{response} to debconf-set-selections")
+
+      preseed response
+    else
+      self.info "No responsefile specified or non existant, not preseeding anything"
+    end
+  end
+
+  def update
+    self.install
+  end
+
+  def uninstall
+    finkcmd "-y", "-q", :remove, @model[:name]
+  end
+
+  def purge
+    aptget '-y', '-q', 'remove', '--purge', @resource[:name]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/freebsd.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/freebsd.rb
new file mode 100644
index 0000000..adb72c6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/freebsd.rb
@@ -0,0 +1,47 @@
+Puppet::Type.type(:package).provide :freebsd, :parent => :openbsd do
+  desc "The specific form of package management on FreeBSD.  This is an
+    extremely quirky packaging system, in that it freely mixes between
+    ports and packages.  Apparently all of the tools are written in Ruby,
+    so there are plans to rewrite this support to directly use those
+    libraries."
+
+  commands :pkginfo => "/usr/sbin/pkg_info",
+    :pkgadd => "/usr/sbin/pkg_add",
+    :pkgdelete => "/usr/sbin/pkg_delete"
+
+  confine :operatingsystem => :freebsd
+
+  def self.listcmd
+    command(:pkginfo)
+  end
+
+  def install
+    if @resource[:source] =~ /\/$/
+      if @resource[:source] =~ /^(ftp|https?):/
+        Puppet::Util.withenv :PACKAGESITE => @resource[:source] do
+          pkgadd "-r", @resource[:name]
+        end
+      else
+        Puppet::Util.withenv :PKG_PATH => @resource[:source] do
+          pkgadd @resource[:name]
+        end
+      end
+    else
+      Puppet.warning "source is defined but does not have trailing slash, ignoring #{@resource[:source]}" if @resource[:source]
+      pkgadd "-r", @resource[:name]
+    end
+  end
+
+  def query
+    self.class.instances.each do |provider|
+      if provider.name == @resource.name
+        return provider.properties
+      end
+    end
+    nil
+  end
+
+  def uninstall
+    pkgdelete "#{@resource[:name]}-#{@resource.should(:ensure)}"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/gem.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/gem.rb
new file mode 100644
index 0000000..7cd61f4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/gem.rb
@@ -0,0 +1,135 @@
+require 'puppet/provider/package'
+require 'uri'
+
+# Ruby gems support.
+Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package do
+  desc "Ruby Gem support.  If a URL is passed via `source`, then that URL is used as the
+    remote gem repository; if a source is present but is not a valid URL, it will be
+    interpreted as the path to a local gem file.  If source is not present at all,
+    the gem will be installed from the default gem repositories.
+
+    This provider supports the `install_options` attribute, which allows command-line flags to be passed to the gem command.
+    These options should be specified as a string (e.g. '--flag'), a hash (e.g. {'--flag' => 'value'}),
+    or an array where each element is either a string or a hash."
+
+  has_feature :versionable, :install_options
+
+  commands :gemcmd => "gem"
+
+  def self.gemlist(options)
+    gem_list_command = [command(:gemcmd), "list"]
+
+    if options[:local]
+      gem_list_command << "--local"
+    else
+      gem_list_command << "--remote"
+    end
+    if options[:source]
+      gem_list_command << "--source" << options[:source]
+    end
+    if name = options[:justme]
+      gem_list_command << "^" + name + "$"
+    end
+
+    begin
+      list = execute(gem_list_command).lines.
+        map {|set| gemsplit(set) }.
+        reject {|x| x.nil? }
+    rescue Puppet::ExecutionFailure => detail
+      raise Puppet::Error, "Could not list gems: #{detail}", detail.backtrace
+    end
+
+    if options[:justme]
+      return list.shift
+    else
+      return list
+    end
+  end
+
+  def self.gemsplit(desc)
+    # `gem list` when output console has a line like:
+    # *** LOCAL GEMS ***
+    # but when it's not to the console that line
+    # and all blank lines are stripped
+    # so we don't need to check for them
+
+    if desc =~ /^(\S+)\s+\((.+)\)/
+      name = $1
+      versions = $2.split(/,\s*/)
+      {
+        :name     => name,
+        :ensure   => versions.map{|v| v.split[0]},
+        :provider => :gem
+      }
+    else
+      Puppet.warning "Could not match #{desc}" unless desc.chomp.empty?
+      nil
+    end
+  end
+
+  def self.instances(justme = false)
+    gemlist(:local => true).collect do |hash|
+      new(hash)
+    end
+  end
+
+  def install(useversion = true)
+    command = [command(:gemcmd), "install"]
+    command << "-v" << resource[:ensure] if (! resource[:ensure].is_a? Symbol) and useversion
+
+    if source = resource[:source]
+      begin
+        uri = URI.parse(source)
+      rescue => detail
+        self.fail Puppet::Error, "Invalid source '#{uri}': #{detail}", detail
+      end
+
+      case uri.scheme
+      when nil
+        # no URI scheme => interpret the source as a local file
+        command << source
+      when /file/i
+        command << uri.path
+      when 'puppet'
+        # we don't support puppet:// URLs (yet)
+        raise Puppet::Error.new("puppet:// URLs are not supported as gem sources")
+      else
+        # interpret it as a gem repository
+        command << "--source" << "#{source}" << resource[:name]
+      end
+    else
+      command << "--no-rdoc" << "--no-ri" << resource[:name]
+    end
+
+    command += install_options if resource[:install_options]
+
+    output = execute(command)
+    # Apparently some stupid gem versions don't exit non-0 on failure
+    self.fail "Could not install: #{output.chomp}" if output.include?("ERROR")
+  end
+
+  def latest
+    # This always gets the latest version available.
+    gemlist_options = {:justme => resource[:name]}
+    gemlist_options.merge!({:source => resource[:source]}) unless resource[:source].nil?
+    hash = self.class.gemlist(gemlist_options)
+
+    hash[:ensure][0]
+  end
+
+  def query
+    self.class.gemlist(:justme => resource[:name], :local => true)
+  end
+
+  def uninstall
+    gemcmd "uninstall", "-x", "-a", resource[:name]
+  end
+
+  def update
+    self.install(false)
+  end
+
+  def install_options
+    join_options(resource[:install_options])
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/hpux.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/hpux.rb
new file mode 100644
index 0000000..526f778
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/hpux.rb
@@ -0,0 +1,44 @@
+# HP-UX packaging.
+
+require 'puppet/provider/package'
+
+Puppet::Type.type(:package).provide :hpux, :parent => Puppet::Provider::Package do
+
+  desc "HP-UX's packaging system."
+
+  commands :swinstall => "/usr/sbin/swinstall",
+    :swlist => "/usr/sbin/swlist",
+    :swremove => "/usr/sbin/swremove"
+
+  confine :operatingsystem => "hp-ux"
+
+  defaultfor :operatingsystem => "hp-ux"
+
+  def self.instances
+    # TODO:  This is very hard on HP-UX!
+    []
+  end
+
+  # source and name are required
+  def install
+    raise ArgumentError, "source must be provided to install HP-UX packages" unless resource[:source]
+    args = standard_args + ["-s", resource[:source], resource[:name]]
+    swinstall(*args)
+  end
+
+  def query
+    swlist resource[:name]
+    {:ensure => :present}
+  rescue
+    {:ensure => :absent}
+  end
+
+  def uninstall
+    args = standard_args + [resource[:name]]
+    swremove(*args)
+  end
+
+  def standard_args
+    ["-x", "mount_all_filesystems=false"]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/macports.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/macports.rb
new file mode 100644
index 0000000..b410d6f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/macports.rb
@@ -0,0 +1,107 @@
+require 'puppet/provider/package'
+require 'puppet/provider/command'
+
+Puppet::Type.type(:package).provide :macports, :parent => Puppet::Provider::Package do
+  desc "Package management using MacPorts on OS X.
+
+    Supports MacPorts versions and revisions, but not variants.
+    Variant preferences may be specified using
+    [the MacPorts variants.conf file](http://guide.macports.org/chunked/internals.configuration-files.html#internals.configuration-files.variants-conf).
+
+    When specifying a version in the Puppet DSL, only specify the version, not the revision.
+    Revisions are only used internally for ensuring the latest version/revision of a port.
+  "
+
+  confine :operatingsystem => :darwin
+
+  has_command(:port, "/opt/local/bin/port") do
+    environment :HOME => "/opt/local"
+  end
+
+  has_feature :installable
+  has_feature :uninstallable
+  has_feature :upgradeable
+  has_feature :versionable
+
+
+  def self.parse_installed_query_line(line)
+    regex = /(\S+)\s+@(\S+)_(\d+).*\(active\)/
+    fields = [:name, :ensure, :revision]
+    hash_from_line(line, regex, fields)
+  end
+
+  def self.parse_info_query_line(line)
+    regex = /(\S+)\s+(\S+)/
+    fields = [:version, :revision]
+    hash_from_line(line, regex, fields)
+  end
+
+  def self.hash_from_line(line, regex, fields)
+    hash = {}
+    if match = regex.match(line)
+      fields.zip(match.captures) { |field, value|
+        hash[field] = value
+      }
+      hash[:provider] = self.name
+      return hash
+    end
+    nil
+  end
+
+  def self.instances
+    packages = []
+    port("-q", :installed).each_line do |line|
+      if hash = parse_installed_query_line(line)
+        packages << new(hash)
+      end
+    end
+    packages
+  end
+
+  def install
+    should = @resource.should(:ensure)
+    if [:latest, :installed, :present].include?(should)
+      output = port("-q", :install, @resource[:name])
+    else
+      output = port("-q", :install, @resource[:name], "@#{should}")
+    end
+    # MacPorts now correctly exits non-zero with appropriate errors in
+    # situations where a port cannot be found or installed.
+  end
+
+  def query
+    result = self.class.parse_installed_query_line(execute([command(:port), "-q", :installed, @resource[:name]], :failonfail => false, :combine => false))
+    return {} if result.nil?
+    return result
+  end
+
+  def latest
+    # We need both the version and the revision to be confident
+    # we've got the latest revision of a specific version
+    # Note we're still not doing anything with variants here.
+    info_line = execute([command(:port), "-q", :info, "--line", "--version", "--revision", @resource[:name]], :failonfail => false, :combine => false)
+    return nil if info_line == ""
+
+    if newest = self.class.parse_info_query_line(info_line)
+      current = query
+      # We're doing some fiddling behind the scenes here to cope with updated revisions.
+      # If we're already at the latest version/revision, then just return the version
+      # so the current and desired values match. Otherwise return version and revision
+      # to trigger an upgrade to the latest revision.
+      if newest[:version] == current[:ensure] and newest[:revision] == current[:revision]
+        return current[:ensure]
+      else
+        return "#{newest[:version]}_#{newest[:revision]}"
+      end
+    end
+    nil
+  end
+
+  def uninstall
+    port("-q", :uninstall, @resource[:name])
+  end
+
+  def update
+    install
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/msi.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/msi.rb
new file mode 100644
index 0000000..0edd024
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/msi.rb
@@ -0,0 +1,125 @@
+require 'puppet/provider/package'
+require 'puppet/util/windows'
+
+Puppet::Type.type(:package).provide(:msi, :parent => Puppet::Provider::Package) do
+  desc "Windows package management by installing and removing MSIs.
+
+    The `msi` provider is deprecated. Use the `windows` provider instead."
+
+  confine    :operatingsystem => :windows
+
+  has_feature :installable
+  has_feature :uninstallable
+  has_feature :install_options
+  has_feature :uninstall_options
+
+  class MsiPackage
+    extend Enumerable
+    include Puppet::Util::Windows::Registry
+    extend Puppet::Util::Windows::Registry
+
+    def self.installer
+      WIN32OLE.new("WindowsInstaller.Installer")
+    end
+
+    def self.each(&block)
+      inst = installer
+      inst.UILevel = 2
+
+      inst.Products.each do |guid|
+        # products may be advertised, installed in a different user
+        # context, etc, we only want to know about products currently
+        # installed in our context.
+        next unless inst.ProductState(guid) == 5
+
+        package = {
+          :name        => inst.ProductInfo(guid, 'ProductName'),
+          # although packages have a version, the provider isn't versionable,
+          # so we can't return a version
+          # :ensure      => inst.ProductInfo(guid, 'VersionString'),
+          :ensure      => :installed,
+          :provider    => :msi,
+          :productcode => guid,
+          :packagecode => inst.ProductInfo(guid, 'PackageCode')
+        }
+
+        yield package
+      end
+    end
+  end
+
+  def self.instances
+    []
+  end
+
+  def initialize(resource = nil)
+    Puppet.deprecation_warning "The `:msi` package provider is deprecated, use the `:windows` provider instead."
+    super(resource)
+  end
+
+  # Find first package whose PackageCode, e.g. {B2BE95D2-CD2C-46D6-8D27-35D150E58EC9},
+  # matches the resource name (case-insensitively due to hex) or the ProductName matches
+  # the resource name. The ProductName is not guaranteed to be unique, but the PackageCode
+  # should be if the package is authored correctly.
+  def query
+    MsiPackage.enum_for.find do |package|
+      resource[:name].casecmp(package[:packagecode]) == 0 || resource[:name] == package[:name]
+    end
+  end
+
+  def install
+    fail("The source parameter is required when using the MSI provider.") unless resource[:source]
+
+    # Unfortunately, we can't use the msiexec method defined earlier,
+    # because of the special quoting we need to do around the MSI
+    # properties to use.
+    command = ['msiexec.exe', '/qn', '/norestart', '/i', shell_quote(resource[:source]), install_options].flatten.compact.join(' ')
+    output = execute(command, :failonfail => false, :combine => true)
+
+    check_result(output.exitstatus)
+  end
+
+  def uninstall
+    fail("The productcode property is missing.") unless properties[:productcode]
+
+    command = ['msiexec.exe', '/qn', '/norestart', '/x', properties[:productcode], uninstall_options].flatten.compact.join(' ')
+    output = execute(command, :failonfail => false, :combine => true)
+
+    check_result(output.exitstatus)
+  end
+
+  # (Un)install may "fail" because the package requested a reboot, the system requested a
+  # reboot, or something else entirely. Reboot requests mean the package was installed
+  # successfully, but we warn since we don't have a good reboot strategy.
+  def check_result(hr)
+    operation = resource[:ensure] == :absent ? 'uninstall' : 'install'
+
+    # http://msdn.microsoft.com/en-us/library/windows/desktop/aa368542(v=vs.85).aspx
+    case hr
+    when 0
+      # yeah
+    when 1641
+      warning("The package #{operation}ed successfully and the system is rebooting now.")
+    when 3010
+      warning("The package #{operation}ed successfully, but the system must be rebooted.")
+    else
+      raise Puppet::Util::Windows::Error.new("Failed to #{operation}", hr)
+    end
+  end
+
+  def validate_source(value)
+    fail("The source parameter cannot be empty when using the MSI provider.") if value.empty?
+  end
+
+  def install_options
+    join_options(resource[:install_options])
+  end
+
+  def uninstall_options
+    join_options(resource[:uninstall_options])
+  end
+
+  def shell_quote(value)
+    value.include?(' ') ? %Q["#{value.gsub(/"/, '\"')}"] : value
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/nim.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/nim.rb
new file mode 100644
index 0000000..1869cf5
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/nim.rb
@@ -0,0 +1,280 @@
+require 'puppet/provider/package'
+require 'puppet/util/package'
+
+Puppet::Type.type(:package).provide :nim, :parent => :aix, :source => :aix do
+  desc "Installation from an AIX NIM LPP source.  The `source` parameter is required
+      for this provider, and should specify the name of a NIM `lpp_source` resource
+      that is visible to the puppet agent machine.  This provider supports the
+      management of both BFF/installp and RPM packages.
+
+      Note that package downgrades are *not* supported; if your resource specifies
+      a specific version number and there is already a newer version of the package
+      installed on the machine, the resource will fail with an error message."
+
+  # The commands we are using on an AIX box are installed standard
+  # (except nimclient) nimclient needs the bos.sysmgt.nim.client fileset.
+  commands    :nimclient  => "/usr/sbin/nimclient",
+              :lslpp      => "/usr/bin/lslpp",
+              :rpm        => "rpm"
+
+  # If NIM has not been configured, /etc/niminfo will not be present.
+  # However, we have no way of knowing if the NIM server is not configured
+  # properly.
+  confine  :exists => "/etc/niminfo"
+
+  has_feature :versionable
+
+  attr_accessor :latest_info
+
+
+
+  def self.srclistcmd(source)
+    [ command(:nimclient), "-o", "showres", "-a", "installp_flags=L", "-a", "resource=#{source}" ]
+  end
+
+  def uninstall
+    output = lslpp("-qLc", @resource[:name]).split(':')
+    # the 6th index in the colon-delimited output contains a " " for installp/BFF
+    # packages, and an "R" for RPMS.  (duh.)
+    pkg_type = output[6]
+
+    case pkg_type
+    when " "
+      installp "-gu", @resource[:name]
+    when "R"
+      rpm "-e", @resource[:name]
+    else
+      self.fail("Unrecognized AIX package type identifier: '#{pkg_type}'")
+    end
+
+    # installp will return an exit code of zero even if it didn't uninstall
+    # anything... so let's make sure it worked.
+    unless query().nil?
+      self.fail "Failed to uninstall package '#{@resource[:name]}'"
+    end
+  end
+
+  def install(useversion = true)
+    unless source = @resource[:source]
+      self.fail "An LPP source location is required in 'source'"
+    end
+
+    pkg = @resource[:name]
+
+    version_specified = (useversion and (! @resource.should(:ensure).is_a? Symbol))
+
+    # This is unfortunate for a couple of reasons.  First, because of a subtle
+    # difference in the command-line syntax for installing an RPM vs an
+    # installp/BFF package, we need to know ahead of time which type of
+    # package we're trying to install.  This means we have to execute an
+    # extra command.
+    #
+    # Second, the command is easiest to deal with and runs fastest if we
+    # pipe it through grep on the shell.  Unfortunately, the way that
+    # the provider `make_command_methods` metaprogramming works, we can't
+    # use that code path to execute the command (because it treats the arguments
+    # as an array of args that all apply to `nimclient`, which fails when you
+    # hit the `|grep`.)  So here we just call straight through to P::U.execute
+    # with a single string argument for the full command, rather than going
+    # through the metaprogrammed layer.  We could get rid of the grep and
+    # switch back to the metaprogrammed stuff, and just parse all of the output
+    # in Ruby... but we'd be doing an awful lot of unnecessary work.
+    showres_command = "/usr/sbin/nimclient -o showres -a resource=#{source} |/usr/bin/grep -p -E "
+    if (version_specified)
+      version = @resource.should(:ensure)
+      showres_command << "'#{Regexp.escape(pkg)}( |-)#{Regexp.escape(version)}'"
+    else
+      version = nil
+      showres_command << "'#{Regexp.escape(pkg)}'"
+    end
+    output = Puppet::Util.execute(showres_command)
+
+
+    if (version_specified)
+      package_type = determine_package_type(output, pkg, version)
+    else
+      package_type, version = determine_latest_version(output, pkg)
+    end
+
+    if (package_type == nil)
+      errmsg = "Unable to find package '#{pkg}' "
+      if (version_specified)
+        errmsg << "with version '#{version}' "
+      end
+      errmsg << "on lpp_source '#{source}'"
+      self.fail errmsg
+    end
+
+    # This part is a bit tricky.  If there are multiple versions of the
+    # package available, then `version` will be set to a value, and we'll need
+    # to add that value to our installation command.  However, if there is only
+    # one version of the package available, `version` will be set to `nil`, and
+    # we don't need to add the version string to the command.
+    if (version)
+      # Now we know if the package type is RPM or not, and we can adjust our
+      # `pkg` string for passing to the install command accordingly.
+      if (package_type == :rpm)
+        # RPM's expect a hyphen between the package name and the version number
+        version_separator = "-"
+      else
+        # installp/BFF packages expect a space between the package name and the
+        # version number.
+        version_separator = " "
+      end
+
+      pkg += version_separator + version
+    end
+
+    # NOTE: the installp flags here are ignored (but harmless) for RPMs
+    output = nimclient "-o", "cust", "-a", "installp_flags=acgwXY", "-a", "lpp_source=#{source}", "-a", "filesets=#{pkg}"
+
+    # If the package is superseded, it means we're trying to downgrade and we
+    # can't do that.
+    case package_type
+    when :installp
+      if output =~ /^#{Regexp.escape(@resource[:name])}\s+.*\s+Already superseded by.*$/
+        self.fail "NIM package provider is unable to downgrade packages"
+      end
+    when :rpm
+      if output =~ /^#{Regexp.escape(@resource[:name])}.* is superseded by.*$/
+        self.fail "NIM package provider is unable to downgrade packages"
+      end
+    end
+  end
+
+
+  private
+
+  ## UTILITY METHODS FOR PARSING `nimclient -o showres` output
+
+  # This makes me very sad.  These regexes seem pretty fragile, but
+  # I spent a lot of time trying to figure out a solution that didn't
+  # require parsing the `nimclient -o showres` output and was unable to
+  # do so.
+  self::HEADER_LINE_REGEX      = /^([^\s]+)\s+[^@]+@@(I|R):(\1)\s+[^\s]+$/
+  self::PACKAGE_LINE_REGEX     = /^.*@@(I|R):(.*)$/
+  self::RPM_PACKAGE_REGEX      = /^(.*)-(.*-\d+) \2$/
+  self::INSTALLP_PACKAGE_REGEX = /^(.*) (.*)$/
+
+  # Here is some sample output that shows what the above regexes will be up
+  # against:
+  # FOR AN INSTALLP PACKAGE:
+  #
+  #    mypackage.foo                                                           ALL  @@I:mypackage.foo _all_filesets
+  #    @ 1.2.3.1  MyPackage Runtime Environment                       @@I:mypackage.foo 1.2.3.1
+  #    + 1.2.3.4  MyPackage Runtime Environment                       @@I:mypackage.foo 1.2.3.4
+  #    + 1.2.3.8  MyPackage Runtime Environment                       @@I:mypackage.foo 1.2.3.8
+  #
+  # FOR AN RPM PACKAGE:
+  #
+  # mypackage.foo                                                                ALL  @@R:mypackage.foo _all_filesets
+  #   @@R:mypackage.foo-1.2.3-1 1.2.3-1
+  #   @@R:mypackage.foo-1.2.3-4 1.2.3-4
+  #   @@R:mypackage.foo-1.2.3-8 1.2.3-8
+
+
+  # Parse the output of a `nimclient -o showres` command.  Returns a two-dimensional
+  # hash, where the first-level keys are package names, the second-level keys are
+  # version number strings for all of the available version numbers for a package,
+  # and the values indicate the package type (:rpm / :installp)
+  def parse_showres_output(showres_output)
+    paragraphs = split_into_paragraphs(showres_output)
+    packages = {}
+    paragraphs.each do |para|
+      lines = para.split(/$/)
+      parse_showres_header_line(lines.shift)
+      lines.each do |l|
+        package, version, type = parse_showres_package_line(l)
+        packages[package] ||= {}
+        packages[package][version] = type
+      end
+    end
+    packages
+  end
+
+  # This method basically just splits the multi-line input string into chunks
+  # based on lines that contain nothing but whitespace.  It also strips any
+  # leading or trailing whitespace (including newlines) from the resulting
+  # strings and then returns them as an array.
+  def split_into_paragraphs(showres_output)
+    showres_output.split(/^\s*$/).map { |p| p.strip! }
+  end
+
+  def parse_showres_header_line(line)
+    # This method doesn't produce any meaningful output; it's basically just
+    # meant to validate that the header line for the package listing output
+    # looks sane, so we know we're dealing with the kind of output that we
+    # are capable of handling.
+    unless line.match(self.class::HEADER_LINE_REGEX)
+      self.fail "Unable to parse output from nimclient showres: line does not match expected package header format:\n'#{line}'"
+    end
+  end
+
+  def parse_installp_package_string(package_string)
+    unless match = package_string.match(self.class::INSTALLP_PACKAGE_REGEX)
+      self.fail "Unable to parse output from nimclient showres: package string does not match expected installp package string format:\n'#{package_string}'"
+    end
+    package_name = match.captures[0]
+    version = match.captures[1]
+    [package_name, version, :installp]
+  end
+
+  def parse_rpm_package_string(package_string)
+    unless match = package_string.match(self.class::RPM_PACKAGE_REGEX)
+      self.fail "Unable to parse output from nimclient showres: package string does not match expected rpm package string format:\n'#{package_string}'"
+    end
+    package_name = match.captures[0]
+    version = match.captures[1]
+    [package_name, version, :rpm]
+  end
+
+  def parse_showres_package_line(line)
+    unless match = line.match(self.class::PACKAGE_LINE_REGEX)
+      self.fail "Unable to parse output from nimclient showres: line does not match expected package line format:\n'#{line}'"
+    end
+
+    package_type_flag = match.captures[0]
+    package_string = match.captures[1]
+
+    case package_type_flag
+      when "I"
+        parse_installp_package_string(package_string)
+      when "R"
+        parse_rpm_package_string(package_string)
+      else
+        self.fail "Unrecognized package type specifier: '#{package_type_flag}' in package line:\n'#{line}'"
+    end
+  end
+
+  # Given a blob of output from `nimclient -o showres` and a package name,
+  # this method checks to see if there are multiple versions of the package
+  # available on the lpp_source.  If there are, the method returns
+  # [package_type, latest_version] (where package_type is one of :installp or :rpm).
+  # If there is only one version of the package available, it returns
+  # [package_type, nil], because the caller doesn't need to pass the version
+  # string to the command-line command if there is only one version available.
+  # If the package is not available at all, the method simply returns nil (instead
+  # of a tuple).
+  def determine_latest_version(showres_output, package_name)
+    packages = parse_showres_output(showres_output)
+    unless packages.has_key?(package_name)
+      return nil
+    end
+    if (packages[package_name].count == 1)
+      version = packages[package_name].keys[0]
+      return packages[package_name][version], nil
+    else
+      versions = packages[package_name].keys
+      latest_version = (versions.sort { |a, b| Puppet::Util::Package.versioncmp(b, a) })[0]
+      return packages[package_name][latest_version], latest_version
+    end
+  end
+
+  def determine_package_type(showres_output, package_name, version)
+    packages = parse_showres_output(showres_output)
+    unless (packages.has_key?(package_name) and packages[package_name].has_key?(version))
+      return nil
+    end
+    packages[package_name][version]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/openbsd.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/openbsd.rb
new file mode 100644
index 0000000..acf9b42
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/openbsd.rb
@@ -0,0 +1,228 @@
+require 'puppet/provider/package'
+
+# Packaging on OpenBSD.  Doesn't work anywhere else that I know of.
+Puppet::Type.type(:package).provide :openbsd, :parent => Puppet::Provider::Package do
+  desc "OpenBSD's form of `pkg_add` support.
+
+    This provider supports the `install_options` and `uninstall_options`
+    attributes, which allow command-line flags to be passed to pkg_add and pkg_delete.
+    These options should be specified as a string (e.g. '--flag'), a hash (e.g. {'--flag' => 'value'}),
+    or an array where each element is either a string or a hash."
+
+  commands :pkginfo   => "pkg_info",
+           :pkgadd    => "pkg_add",
+           :pkgdelete => "pkg_delete"
+
+  defaultfor :operatingsystem => :openbsd
+  confine :operatingsystem => :openbsd
+
+  has_feature :versionable
+  has_feature :install_options
+  has_feature :uninstall_options
+  has_feature :upgradeable
+
+  def self.instances
+    packages = []
+
+    begin
+      execpipe(listcmd) do |process|
+        # our regex for matching pkg_info output
+        regex = /^(.*)-(\d[^-]*)[-]?(\w*)(.*)$/
+        fields = [:name, :ensure, :flavor ]
+        hash = {}
+
+        # now turn each returned line into a package object
+        process.each_line { |line|
+          if match = regex.match(line.split[0])
+            fields.zip(match.captures) { |field,value|
+              hash[field] = value
+            }
+
+            hash[:provider] = self.name
+
+            packages << new(hash)
+            hash = {}
+          else
+            unless line =~ /Updating the pkgdb/
+              # Print a warning on lines we can't match, but move
+              # on, since it should be non-fatal
+              warning("Failed to match line #{line}")
+            end
+          end
+        }
+      end
+
+      return packages
+    rescue Puppet::ExecutionFailure
+      return nil
+    end
+  end
+
+  def self.listcmd
+    [command(:pkginfo), "-a"]
+  end
+
+  def latest
+    parse_pkgconf
+
+    if @resource[:source][-1,1] == ::File::SEPARATOR
+      e_vars = { 'PKG_PATH' => @resource[:source] }
+    else
+      e_vars = {}
+    end
+
+    if @resource[:flavor]
+      query = "#{@resource[:name]}--#{@resource[:flavor]}"
+    else
+      query = @resource[:name]
+    end
+
+    output = Puppet::Util.withenv(e_vars) {pkginfo "-Q", query}
+
+    if output.nil? or output.size == 0 or output =~ /Error from /
+      debug "Failed to query for #{resource[:name]}"
+      return properties[:ensure]
+    else
+      # Remove all fuzzy matches first.
+      output = output.split.select {|p| p =~ /^#{resource[:name]}-(\d[^-]*)[-]?(\w*)/ }.join
+      debug "pkg_info -Q for #{resource[:name]}: #{output}"
+    end
+
+    if output =~ /^#{resource[:name]}-(\d[^-]*)[-]?(\w*) \(installed\)$/
+      debug "Package is already the latest available"
+      return properties[:ensure]
+    else
+      match = /^(.*)-(\d[^-]*)[-]?(\w*)$/.match(output)
+      debug "Latest available for #{resource[:name]}: #{match[2]}"
+
+      if properties[:ensure].to_sym == :absent
+        return match[2]
+      end
+
+      vcmp = properties[:ensure].split('.').map{|s|s.to_i} <=> match[2].split('.').map{|s|s.to_i}
+      if vcmp > 0
+        debug "ensure: #{properties[:ensure]}"
+        # The locally installed package may actually be newer than what a mirror
+        # has. Log it at debug, but ignore it otherwise.
+        debug "Package #{resource[:name]} #{properties[:ensure]} newer then available #{match[2]}"
+        return properties[:ensure]
+      else
+        return match[2]
+      end
+    end
+  end
+
+  def update
+    self.install(true)
+  end
+
+  def parse_pkgconf
+    unless @resource[:source]
+      if Puppet::FileSystem.exist?("/etc/pkg.conf")
+        File.open("/etc/pkg.conf", "rb").readlines.each do |line|
+          if matchdata = line.match(/^installpath\s*=\s*(.+)\s*$/i)
+            @resource[:source] = matchdata[1]
+          elsif matchdata = line.match(/^installpath\s*\+=\s*(.+)\s*$/i)
+            if @resource[:source].nil?
+              @resource[:source] = matchdata[1]
+            else
+              @resource[:source] += ":" + matchdata[1]
+            end
+          end
+        end
+
+        unless @resource[:source]
+          raise Puppet::Error,
+          "No valid installpath found in /etc/pkg.conf and no source was set"
+        end
+      else
+        raise Puppet::Error,
+        "You must specify a package source or configure an installpath in /etc/pkg.conf"
+      end
+    end
+  end
+
+  def install(latest = false)
+    cmd = []
+
+    parse_pkgconf
+
+    if @resource[:source][-1,1] == ::File::SEPARATOR
+      e_vars = { 'PKG_PATH' => @resource[:source] }
+      # In case of a real update (i.e., the package already exists) then
+      # pkg_add(8) can handle the flavors. However, if we're actually
+      # installing with 'latest', we do need to handle the flavors.
+      # So we always need to handle flavors ourselves as to not break installs.
+      if latest and resource[:flavor]
+        full_name = "#{resource[:name]}--#{resource[:flavor]}"
+      elsif latest
+        # Don't depend on get_version for updates.
+        full_name = @resource[:name]
+      else
+        full_name = [ @resource[:name], get_version || @resource[:ensure], @resource[:flavor] ].join('-').chomp('-').chomp('-')
+      end
+    else
+      e_vars = {}
+      full_name = @resource[:source]
+    end
+
+    cmd << install_options
+    cmd << full_name
+
+    if latest
+      cmd.unshift('-rz')
+    end
+
+    Puppet::Util.withenv(e_vars) { pkgadd cmd.flatten.compact }
+  end
+
+  def get_version
+    execpipe([command(:pkginfo), "-I", @resource[:name]]) do |process|
+      # our regex for matching pkg_info output
+      regex = /^(.*)-(\d[^-]*)[-]?(\w*)(.*)$/
+      master_version = 0
+      version = -1
+
+      process.each_line do |line|
+        if match = regex.match(line.split[0])
+          # now we return the first version, unless ensure is latest
+          version = match.captures[1]
+          return version unless @resource[:ensure] == "latest"
+
+          master_version = version unless master_version > version
+        end
+      end
+
+      return master_version unless master_version == 0
+      return '' if version == -1
+      raise Puppet::Error, "#{version} is not available for this package"
+    end
+  rescue Puppet::ExecutionFailure
+    return nil
+  end
+
+  def query
+    # Search for the version info
+    if pkginfo(@resource[:name]) =~ /Information for (inst:)?#{@resource[:name]}-(\S+)/
+      return { :ensure => $2 }
+    else
+      return nil
+    end
+  end
+
+  def install_options
+    join_options(resource[:install_options])
+  end
+
+  def uninstall_options
+    join_options(resource[:uninstall_options])
+  end
+
+  def uninstall
+    pkgdelete uninstall_options.flatten.compact, @resource[:name]
+  end
+
+  def purge
+    pkgdelete "-c", "-q", @resource[:name]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/opkg.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/opkg.rb
new file mode 100644
index 0000000..439afeb
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/opkg.rb
@@ -0,0 +1,76 @@
+require 'puppet/provider/package'
+
+Puppet::Type.type(:package).provide :opkg, :source => :opkg, :parent => Puppet::Provider::Package do
+  desc "Opkg packaging support. Common on OpenWrt and OpenEmbedded platforms"
+
+  commands :opkg => "opkg"
+
+  confine     :operatingsystem => :openwrt
+  defaultfor  :operatingsystem => :openwrt
+
+  def self.instances
+    packages = []
+    execpipe("#{command(:opkg)} list-installed") do |process|
+      regex = %r{^(\S+) - (\S+)}
+      fields = [:name, :ensure]
+      hash = {}
+
+      process.each_line { |line|
+        if match = regex.match(line)
+          fields.zip(match.captures) { |field,value| hash[field] = value }
+          hash[:provider] = self.name
+          packages << new(hash)
+          hash = {}
+        else
+          warning("Failed to match line %s" % line)
+        end
+      }
+    end
+    packages
+  rescue Puppet::ExecutionFailure
+    return nil
+  end
+
+  def latest
+    output = opkg( "list", @resource[:name])
+    matches = /^(\S+) - (\S+)/.match(output).captures
+    matches[1]
+  end
+
+  def install
+    # OpenWrt package lists are ephemeral, make sure we have at least
+    # some entries in the list directory for opkg to use
+    opkg('update') if Dir.entries('/var/opkg-lists/').size <= 2
+
+    if @resource[:source]
+      opkg( '--force-overwrite', 'install', @resource[:source] )
+    else
+      opkg( '--force-overwrite', 'install', @resource[:name] )
+    end
+  end
+
+  def uninstall
+    opkg( 'remove', @resource[:name] )
+  end
+
+  def update
+    self.install
+  end
+
+  def query
+    # list out our specific package
+    output = opkg( 'list-installed', @resource[:name] )
+    if output =~ /^(\S+) - (\S+)/
+      return { :ensure => $2 }
+    end
+    nil
+  rescue Puppet::ExecutionFailure
+    return {
+      :ensure => :purged,
+      :status => 'missing',
+      :name => @resource[:name],
+      :error => 'ok',
+    }
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/pacman.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/pacman.rb
new file mode 100644
index 0000000..4ca356b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/pacman.rb
@@ -0,0 +1,234 @@
+require 'puppet/provider/package'
+require 'set'
+require 'uri'
+
+Puppet::Type.type(:package).provide :pacman, :parent => Puppet::Provider::Package do
+  desc "Support for the Package Manager Utility (pacman) used in Archlinux.
+
+  This provider supports the `install_options` attribute, which allows command-line flags to be passed to pacman.
+  These options should be specified as a string (e.g. '--flag'), a hash (e.g. {'--flag' => 'value'}),
+  or an array where each element is either a string or a hash."
+
+  commands :pacman => "/usr/bin/pacman"
+  # Yaourt is a common AUR helper which, if installed, we can use to query the AUR
+  commands :yaourt => "/usr/bin/yaourt" if Puppet::FileSystem.exist? '/usr/bin/yaourt'
+
+  confine     :operatingsystem => :archlinux
+  defaultfor  :operatingsystem => :archlinux
+  has_feature :install_options
+  has_feature :uninstall_options
+  has_feature :upgradeable
+
+  # If yaourt is installed, we can make use of it
+  def yaourt?
+    return Puppet::FileSystem.exist?('/usr/bin/yaourt')
+  end
+
+  # Install a package using 'pacman', or 'yaourt' if available.
+  # Installs quietly, without confirmation or progressbar, updates package
+  # list from servers defined in pacman.conf.
+  def install
+    if @resource[:source]
+      install_from_file
+    else
+      install_from_repo
+    end
+
+    unless self.query
+      raise Puppet::ExecutionFailure.new("Could not find package %s" % self.name)
+    end
+  end
+
+  def install_from_repo
+    if yaourt?
+      cmd = %w{--noconfirm}
+      cmd += install_options if @resource[:install_options]
+      cmd << "-S" << @resource[:name]
+      yaourt *cmd
+    else
+      cmd = %w{--noconfirm --noprogressbar}
+      cmd += install_options if @resource[:install_options]
+      cmd << "-Sy" << @resource[:name]
+      pacman *cmd
+    end
+  end
+  private :install_from_repo
+
+  def install_from_file
+    source = @resource[:source]
+    begin
+      source_uri = URI.parse source
+    rescue => detail
+      self.fail Puppet::Error, "Invalid source '#{source}': #{detail}", detail
+    end
+
+    source = case source_uri.scheme
+    when nil then source
+    when /https?/i then source
+    when /ftp/i then source
+    when /file/i then source_uri.path
+    when /puppet/i
+      fail "puppet:// URL is not supported by pacman"
+    else
+      fail "Source #{source} is not supported by pacman"
+    end
+    pacman "--noconfirm", "--noprogressbar", "-Sy"
+    pacman "--noconfirm", "--noprogressbar", "-U", source
+  end
+  private :install_from_file
+
+  def self.listcmd
+    [command(:pacman), "-Q"]
+  end
+
+  # Pacman has a concept of package groups as well.
+  # Package groups have no versions.
+  def self.listgroupcmd
+    [command(:pacman), "-Qg"]
+  end
+
+  # Get installed packages (pacman -Q)
+  def self.installedpkgs
+    packages = []
+    begin
+      execpipe(listcmd()) do |process|
+        # pacman -Q output is 'packagename version-rel'
+        regex = %r{^(\S+)\s(\S+)}
+        fields = [:name, :ensure]
+        hash = {}
+
+        process.each_line { |line|
+          if match = regex.match(line)
+            fields.zip(match.captures) { |field,value|
+              hash[field] = value
+            }
+
+            hash[:provider] = self.name
+
+            packages << new(hash)
+
+            hash = {}
+          else
+            warning("Failed to match line %s" % line)
+          end
+        }
+      end
+    rescue Puppet::ExecutionFailure
+      return nil
+    end
+    packages
+  end
+
+  # Get installed groups (pacman -Qg)
+  def self.installedgroups
+    packages = []
+    begin
+      execpipe(listgroupcmd()) do |process|
+        # pacman -Qg output is 'groupname packagename'
+        # Groups need to be deduplicated
+        groups = Set[]
+
+        process.each_line { |line|
+          groups.add(line.split[0])
+        }
+
+        groups.each { |line|
+          hash = {
+            :name   => line,
+            :ensure => "1", # Groups don't have versions, so ensure => latest
+                            # will still cause a reinstall.
+            :provider => self.name
+          }
+          packages << new(hash)
+        }
+      end
+    rescue Puppet::ExecutionFailure
+      return nil
+    end
+    packages
+  end
+
+  # Fetch the list of packages currently installed on the system.
+  def self.instances
+    packages = self.installedpkgs
+    groups   = self.installedgroups
+    result   = nil
+
+    if (!packages && !groups)
+      nil
+    elsif (packages && groups)
+      packages.concat(groups)
+    else
+      packages
+    end
+  end
+
+
+  # Because Archlinux is a rolling release based distro, installing a package
+  # should always result in the newest release.
+  def update
+    # Install in pacman can be used for update, too
+    self.install
+  end
+
+  # We rescue the main check from Pacman with a check on the AUR using yaourt, if installed
+  def latest
+    pacman "-Sy"
+    pacman_check = true   # Query the main repos first
+    begin
+      if pacman_check
+        output = pacman "-Sp", "--print-format", "%v", @resource[:name]
+        return output.chomp
+      else
+        output = yaourt "-Qma", @resource[:name]
+        output.split("\n").each do |line|
+          return line.split[1].chomp if line =~ /^aur/
+        end
+      end
+    rescue Puppet::ExecutionFailure
+      if pacman_check and self.yaourt?
+        pacman_check = false # now try the AUR
+        retry
+      else
+        raise
+      end
+    end
+  end
+
+  # Querys the pacman master list for information about the package.
+  def query
+    begin
+      output = pacman("-Qi", @resource[:name])
+
+      if output =~ /Version.*:\s(.+)/
+        return { :ensure => $1 }
+      end
+    rescue Puppet::ExecutionFailure
+      return {
+        :ensure => :purged,
+        :status => 'missing',
+        :name => @resource[:name],
+        :error => 'ok',
+      }
+    end
+    nil
+  end
+
+  # Removes a package from the system.
+  def uninstall
+    cmd = %w{--noconfirm --noprogressbar}
+    cmd += uninstall_options if @resource[:uninstall_options]
+    cmd << "-R" << @resource[:name]
+    pacman *cmd
+  end
+
+  private
+
+  def install_options
+    join_options(@resource[:install_options])
+  end
+
+  def uninstall_options
+    join_options(@resource[:uninstall_options])
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/pip.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/pip.rb
new file mode 100644
index 0000000..8e889a0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/pip.rb
@@ -0,0 +1,128 @@
+# Puppet package provider for Python's `pip` package management frontend.
+# <http://pip.openplans.org/>
+
+require 'puppet/provider/package'
+require 'xmlrpc/client'
+require 'puppet/util/http_proxy'
+
+Puppet::Type.type(:package).provide :pip,
+  :parent => ::Puppet::Provider::Package do
+
+  desc "Python packages via `pip`."
+
+  has_feature :installable, :uninstallable, :upgradeable, :versionable
+
+  # Parse lines of output from `pip freeze`, which are structured as
+  # _package_==_version_.
+  def self.parse(line)
+    if line.chomp =~ /^([^=]+)==([^=]+)$/
+      {:ensure => $2, :name => $1, :provider => name}
+    else
+      nil
+    end
+  end
+
+  # Return an array of structured information about every installed package
+  # that's managed by `pip` or an empty array if `pip` is not available.
+  def self.instances
+    packages = []
+    pip_cmd = which(cmd) or return []
+    execpipe "#{pip_cmd} freeze" do |process|
+      process.collect do |line|
+        next unless options = parse(line)
+        packages << new(options)
+      end
+    end
+    packages
+  end
+
+  def self.cmd
+    if Facter.value(:osfamily) == "RedHat" and Facter.value(:operatingsystemmajrelease).to_i < 7
+      "pip-python"
+    else
+      "pip"
+    end
+  end
+
+  # Return structured information about a particular package or `nil` if
+  # it is not installed or `pip` itself is not available.
+  def query
+    self.class.instances.each do |provider_pip|
+      return provider_pip.properties if @resource[:name].downcase == provider_pip.name.downcase
+    end
+    return nil
+  end
+
+  # Ask the PyPI API for the latest version number.  There is no local
+  # cache of PyPI's package list so this operation will always have to
+  # ask the web service.
+  def latest
+    http_proxy_host = Puppet::Util::HttpProxy.http_proxy_host
+    http_proxy_port = Puppet::Util::HttpProxy.http_proxy_port
+    if http_proxy_host && http_proxy_port
+      proxy = "#{http_proxy_host}:#{http_proxy_port}"
+    else
+      # nil is acceptable
+      proxy = http_proxy_host
+    end
+
+    client = XMLRPC::Client.new2("http://pypi.python.org/pypi", proxy)
+    client.http_header_extra = {"Content-Type" => "text/xml"}
+    client.timeout = 10
+    result = client.call("package_releases", @resource[:name])
+    result.first
+  rescue Timeout::Error => detail
+    raise Puppet::Error, "Timeout while contacting pypi.python.org: #{detail}", detail.backtrace
+  end
+
+  # Install a package.  The ensure parameter may specify installed,
+  # latest, a version number, or, in conjunction with the source
+  # parameter, an SCM revision.  In that case, the source parameter
+  # gives the fully-qualified URL to the repository.
+  def install
+    args = %w{install -q}
+    if @resource[:source]
+      if String === @resource[:ensure]
+        args << "#{@resource[:source]}@#{@resource[:ensure]}#egg=#{
+          @resource[:name]}"
+      else
+        args << "#{@resource[:source]}#egg=#{@resource[:name]}"
+      end
+    else
+      case @resource[:ensure]
+      when String
+        args << "#{@resource[:name]}==#{@resource[:ensure]}"
+      when :latest
+        args << "--upgrade" << @resource[:name]
+      else
+        args << @resource[:name]
+      end
+    end
+    lazy_pip *args
+  end
+
+  # Uninstall a package.  Uninstall won't work reliably on Debian/Ubuntu
+  # unless this issue gets fixed.
+  # <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=562544>
+  def uninstall
+    lazy_pip "uninstall", "-y", "-q", @resource[:name]
+  end
+
+  def update
+    install
+  end
+
+  # Execute a `pip` command.  If Puppet doesn't yet know how to do so,
+  # try to teach it and if even that fails, raise the error.
+  private
+  def lazy_pip(*args)
+    pip *args
+  rescue NoMethodError => e
+    if pathname = which(self.class.cmd)
+      self.class.commands :pip => pathname
+      pip *args
+    else
+      raise e, 'Could not locate the pip command.', e.backtrace
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/pkg.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/pkg.rb
new file mode 100644
index 0000000..db7c0a0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/pkg.rb
@@ -0,0 +1,201 @@
+require 'puppet/provider/package'
+
+Puppet::Type.type(:package).provide :pkg, :parent => Puppet::Provider::Package do
+  desc "OpenSolaris image packaging system. See pkg(5) for more information"
+  # http://docs.oracle.com/cd/E19963-01/html/820-6572/managepkgs.html
+  # A few notes before we start :
+  # Opensolaris pkg has two slightly different formats (as of now.)
+  # The first one is what is distributed with the Solaris 11 Express 11/10 dvd
+  # The latest one is what you get when you update package.
+  # To make things more interesting, pkg version just returns a sha sum.
+  # dvd:     pkg version => 052adf36c3f4
+  # updated: pkg version => 630e1ffc7a19
+  # Thankfully, solaris has not changed the commands to be used.
+  # TODO: We still have to allow packages to specify a preferred publisher.
+
+  has_feature :versionable
+
+  has_feature :upgradable
+
+  has_feature :holdable
+
+  commands :pkg => "/usr/bin/pkg"
+
+  confine :osfamily => :solaris
+
+  defaultfor :osfamily => :solaris, :kernelrelease => '5.11'
+
+  def self.instances
+    pkg(:list, '-H').split("\n").map{|l| new(parse_line(l))}
+  end
+
+  # The IFO flag field is just what it names, the first field can have ether
+  # i_nstalled or -, and second field f_rozen or -, and last
+  # o_bsolate or r_rename or -
+  # so this checks if the installed field is present, and also verifies that
+  # if not the field is -, else we dont know what we are doing and exit with
+  # out doing more damage.
+  def self.ifo_flag(flags)
+    (
+      case flags[0..0]
+      when 'i'
+        {:status => 'installed'}
+      when '-'
+        {:status => 'known'}
+      else
+        raise ArgumentError, 'Unknown format %s: %s[%s]' % [self.name, flags, flags[0..0]]
+      end
+    ).merge(
+      case flags[1..1]
+      when 'f'
+        {:ensure => 'held'}
+      when '-'
+        {}
+      else
+        raise ArgumentError, 'Unknown format %s: %s[%s]' % [self.name, flags, flags[1..1]]
+      end
+    )
+  end
+
+  # The UFOXI field is the field present in the older pkg
+  # (solaris 2009.06 - snv151a)
+  # similar to IFO, UFOXI is also an either letter or -
+  # u_pdate indicates that an update for the package is available.
+  # f_rozen(n/i) o_bsolete x_cluded(n/i) i_constrained(n/i)
+  # note that u_pdate flag may not be trustable due to constraints.
+  # so we dont rely on it
+  # Frozen was never implemented in UFOXI so skipping frozen here.
+  def self.ufoxi_flag(flags)
+    {}
+  end
+
+  # pkg state was present in the older version of pkg (with UFOXI) but is
+  # no longer available with the IFO field version. When it was present,
+  # it was used to indicate that a particular version was present (installed)
+  # and later versions were known. Note that according to the pkg man page,
+  # known never lists older versions of the package. So we can rely on this
+  # field to make sure that if a known is present, then the pkg is upgradable.
+  def self.pkg_state(state)
+    case state
+    when /installed/
+      {:status => 'installed'}
+    when /known/
+      {:status => 'known'}
+    else
+      raise ArgumentError, 'Unknown format %s: %s' % [self.name, state]
+    end
+  end
+
+  # Here is (hopefully) the only place we will have to deal with multiple
+  # formats of output for different pkg versions.
+  def self.parse_line(line)
+    (case line.chomp
+    # NAME (PUBLISHER)            VERSION           IFO  (new:630e1ffc7a19)
+    # system/core-os              0.5.11-0.169      i--
+    when /^(\S+) +(\S+) +(...)$/
+      {:name => $1, :ensure => $2}.merge ifo_flag($3)
+
+    # x11/wm/fvwm (fvwm.org)      2.6.1-3           i--
+    when /^(\S+) \((.+)\) +(\S+) +(...)$/
+      {:name => $1, :publisher => $2, :ensure => $3}.merge ifo_flag($4)
+
+    # NAME (PUBLISHER)                  VERSION          STATE      UFOXI (dvd:052adf36c3f4)
+    # SUNWcs                            0.5.11-0.126     installed  -----
+    when /^(\S+) +(\S+) +(\S+) +(.....)$/
+      {:name => $1, :ensure => $2}.merge pkg_state($3).merge(ufoxi_flag($4))
+
+    # web/firefox/plugin/flash (extra)  10.0.32.18-0.111 installed  -----
+    when /^(\S+) \((.+)\) +(\S+) +(\S+) +(.....)$/
+      {:name => $1, :publisher => $2, :ensure => $3}.merge pkg_state($4).merge(ufoxi_flag($5))
+
+    else
+      raise ArgumentError, 'Unknown line format %s: %s' % [self.name, line]
+    end).merge({:provider => self.name})
+  end
+
+  def hold
+    pkg(:freeze, @resource[:name])
+  end
+
+  def unhold
+    r = exec_cmd(command(:pkg), 'unfreeze', @resource[:name])
+    raise Puppet::Error, "Unable to unfreeze #{r[:out]}" unless [0,4].include? r[:exit]
+  end
+
+  # Return the version of the package. Note that the bug
+  # http://defect.opensolaris.org/bz/show_bug.cgi?id=19159%
+  # notes that we can't use -Ha for the same even though the manual page reads that way.
+  def latest
+    lines = pkg(:list, "-Hn", @resource[:name]).split("\n")
+
+    # remove certificate expiration warnings from the output, but report them
+    # Note: we'd like to use select! here to modify the lines array and avoid
+    #       the second select further down. But Solaris 11 comes with ruby 1.8.7
+    #       which doesn't support select!, so do this as two selects.
+    cert_warnings = lines.select { |line| line =~ /^Certificate/ }
+    if cert_warnings
+      Puppet.warning("pkg warning: #{cert_warnings}")
+    end
+
+    lst = lines.select { |line| line !~ /^Certificate/ }.map { |line| self.class.parse_line(line) }
+
+    # Now we know there is a newer version. But is that installable? (i.e are there any constraints?)
+    # return the first known we find. The only way that is currently available is to do a dry run of
+    # pkg update and see if could get installed (`pkg update -n res`).
+    known = lst.find {|p| p[:status] == 'known' }
+    return known[:ensure] if known and exec_cmd(command(:pkg), 'update', '-n', @resource[:name])[:exit].zero?
+
+    # If not, then return the installed, else nil
+    (lst.find {|p| p[:status] == 'installed' } || {})[:ensure]
+  end
+
+  # install the package and accept all licenses.
+  def install(nofail = false)
+    name = @resource[:name]
+    should = @resource[:ensure]
+    # always unhold if explicitly told to install/update
+    self.unhold
+    unless should.is_a? Symbol
+      name += "@#{should}"
+      is = self.query
+      unless is[:ensure].to_sym == :absent
+        self.uninstall if Puppet::Util::Package.versioncmp(should, is[:ensure]) < 0
+      end
+    end
+    r = exec_cmd(command(:pkg), 'install', '--accept', name)
+    return r if nofail
+    raise Puppet::Error, "Unable to update #{r[:out]}" if r[:exit] != 0
+  end
+
+  # uninstall the package. The complication comes from the -r_ecursive flag which is no longer
+  # present in newer package version.
+  def uninstall
+    cmd = [:uninstall]
+    case (pkg :version).chomp
+    when /052adf36c3f4/
+      cmd << '-r'
+    end
+    cmd << @resource[:name]
+    pkg cmd
+  end
+
+  # update the package to the latest version available
+  def update
+    r = install(true)
+    # 4 == /No updates available for this image./
+    return if [0,4].include? r[:exit]
+    raise Puppet::Error, "Unable to update #{r[:out]}"
+  end
+
+  # list a specific package
+  def query
+    r = exec_cmd(command(:pkg), 'list', '-H', @resource[:name])
+    return {:ensure => :absent, :name => @resource[:name]} if r[:exit] != 0
+    self.class.parse_line(r[:out])
+  end
+
+  def exec_cmd(*cmd)
+    output = Puppet::Util::Execution.execute(cmd, :failonfail => false, :combine => true)
+    {:out => output, :exit => $CHILD_STATUS.exitstatus}
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/pkgdmg.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/pkgdmg.rb
new file mode 100644
index 0000000..44c0922
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/pkgdmg.rb
@@ -0,0 +1,149 @@
+#
+# Motivation: DMG files provide a true HFS file system
+# and are easier to manage and .pkg bundles.
+#
+# Note: the 'apple' Provider checks for the package name
+# in /L/Receipts.  Since we install multiple pkg's from a single
+# source, we treat the source .pkg.dmg file as the package name.
+# As a result, we store installed .pkg.dmg file names
+# in /var/db/.puppet_pkgdmg_installed_<name>
+
+require 'puppet/provider/package'
+require 'facter/util/plist'
+require 'puppet/util/http_proxy'
+
+Puppet::Type.type(:package).provide :pkgdmg, :parent => Puppet::Provider::Package do
+  desc "Package management based on Apple's Installer.app and DiskUtility.app.
+
+    This provider works by checking the contents of a DMG image for Apple pkg or
+    mpkg files. Any number of pkg or mpkg files may exist in the root directory
+    of the DMG file system, and Puppet will install all of them. Subdirectories
+    are not checked for packages.
+
+    This provider can also accept plain .pkg (but not .mpkg) files in addition
+    to .dmg files.
+
+    Notes:
+
+    * The `source` attribute is mandatory. It must be either a local disk path
+      or an HTTP, HTTPS, or FTP URL to the package.
+    * The `name` of the resource must be the filename (without path) of the DMG file.
+    * When installing the packages from a DMG, this provider writes a file to
+      disk at `/var/db/.puppet_pkgdmg_installed_NAME`. If that file is present,
+      Puppet assumes all packages from that DMG are already installed.
+    * This provider is not versionable and uses DMG filenames to determine
+      whether a package has been installed. Thus, to install new a version of a
+      package, you must create a new DMG with a different filename."
+
+  confine :operatingsystem => :darwin
+  defaultfor :operatingsystem => :darwin
+  commands :installer => "/usr/sbin/installer"
+  commands :hdiutil => "/usr/bin/hdiutil"
+  commands :curl => "/usr/bin/curl"
+
+  # JJM We store a cookie for each installed .pkg.dmg in /var/db
+  def self.instance_by_name
+    Dir.entries("/var/db").find_all { |f|
+      f =~ /^\.puppet_pkgdmg_installed_/
+    }.collect do |f|
+      name = f.sub(/^\.puppet_pkgdmg_installed_/, '')
+      yield name if block_given?
+      name
+    end
+  end
+
+  def self.instances
+    instance_by_name.collect do |name|
+      new(:name => name, :provider => :pkgdmg, :ensure => :installed)
+    end
+  end
+
+  def self.installpkg(source, name, orig_source)
+    installer "-pkg", source, "-target", "/"
+    # Non-zero exit status will throw an exception.
+    File.open("/var/db/.puppet_pkgdmg_installed_#{name}", "w") do |t|
+      t.print "name: '#{name}'\n"
+      t.print "source: '#{orig_source}'\n"
+    end
+  end
+
+  def self.installpkgdmg(source, name)
+    http_proxy_host = Puppet::Util::HttpProxy.http_proxy_host
+    http_proxy_port = Puppet::Util::HttpProxy.http_proxy_port
+
+    unless source =~ /\.dmg$/i || source =~ /\.pkg$/i
+      raise Puppet::Error.new("Mac OS X PKG DMG's must specify a source string ending in .dmg or flat .pkg file")
+    end
+    require 'open-uri' # Dead code; this is never used. The File.open call 20-ish lines south of here used to be Kernel.open but changed in '09. -NF
+    cached_source = source
+    tmpdir = Dir.mktmpdir
+    ext = /(\.dmg|\.pkg)$/i.match(source)[0]
+    begin
+      if %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} =~ cached_source
+        cached_source = File.join(tmpdir, "#{name}#{ext}")
+        args = [ "-o", cached_source, "-C", "-", "-k", "-L", "-s", "--fail", "--url", source ]
+        if http_proxy_host and http_proxy_port
+          args << "--proxy" << "#{http_proxy_host}:#{http_proxy_port}"
+        elsif http_proxy_host and not http_proxy_port
+          args << "--proxy" << http_proxy_host
+        end
+      begin
+        curl *args
+          Puppet.debug "Success: curl transfered [#{name}] (via: curl #{args.join(" ")})"
+        rescue Puppet::ExecutionFailure
+          Puppet.debug "curl #{args.join(" ")} did not transfer [#{name}].  Falling back to local file." # This used to fall back to open-uri. -NF
+          cached_source = source
+        end
+      end
+
+      if source =~ /\.dmg$/i
+        # If you fix this to use open-uri again, you must update the docs above. -NF
+        File.open(cached_source) do |dmg|
+          xml_str = hdiutil "mount", "-plist", "-nobrowse", "-readonly", "-noidme", "-mountrandom", "/tmp", dmg.path
+          hdiutil_info = Plist::parse_xml(xml_str)
+          raise Puppet::Error.new("No disk entities returned by mount at #{dmg.path}") unless hdiutil_info.has_key?("system-entities")
+          mounts = hdiutil_info["system-entities"].collect { |entity|
+            entity["mount-point"]
+          }.compact
+          begin
+            mounts.each do |mountpoint|
+              Dir.entries(mountpoint).select { |f|
+                f =~ /\.m{0,1}pkg$/i
+              }.each do |pkg|
+                installpkg("#{mountpoint}/#{pkg}", name, source)
+              end
+            end
+          ensure
+            mounts.each do |mountpoint|
+              hdiutil "eject", mountpoint
+            end
+          end
+        end
+      else
+        installpkg(cached_source, name, source)
+      end
+    ensure
+      FileUtils.remove_entry_secure(tmpdir, true)
+    end
+  end
+
+  def query
+    if Puppet::FileSystem.exist?("/var/db/.puppet_pkgdmg_installed_#{@resource[:name]}")
+      Puppet.debug "/var/db/.puppet_pkgdmg_installed_#{@resource[:name]} found"
+      return {:name => @resource[:name], :ensure => :present}
+    else
+      return nil
+    end
+  end
+
+  def install
+    source = nil
+    unless source = @resource[:source]
+      raise Puppet::Error.new("Mac OS X PKG DMG's must specify a package source.")
+    end
+    unless name = @resource[:name]
+      raise Puppet::Error.new("Mac OS X PKG DMG's must specify a package name.")
+    end
+    self.class.installpkgdmg(source,name)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/pkgin.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/pkgin.rb
new file mode 100644
index 0000000..5cdb858
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/pkgin.rb
@@ -0,0 +1,87 @@
+require "puppet/provider/package"
+
+Puppet::Type.type(:package).provide :pkgin, :parent => Puppet::Provider::Package do
+  desc "Package management using pkgin, a binary package manager for pkgsrc."
+
+  commands :pkgin => "pkgin"
+
+  defaultfor :operatingsystem => [ :dragonfly , :smartos ]
+
+  has_feature :installable, :uninstallable, :upgradeable, :versionable
+
+  def self.parse_pkgin_line(package)
+
+    # e.g.
+    #   vim-7.2.446 =        Vim editor (vi clone) without GUI
+    match, name, version, status = *package.match(/(\S+)-(\S+)(?: (=|>|<))?\s+.+$/)
+    if match
+      {
+        :name     => name,
+        :status   => status,
+        :ensure   => version
+      }
+    end
+  end
+
+  def self.prefetch(packages)
+    super
+    # Withouth -f, no fresh pkg_summary files are downloaded
+    pkgin("-yf", :update)
+  end
+
+  def self.instances
+    pkgin(:list).split("\n").map do |package|
+      new(parse_pkgin_line(package))
+    end
+  end
+
+  def query
+    packages = parse_pkgsearch_line
+
+    if packages.empty?
+      if @resource[:ensure] == :absent
+        notice "declared as absent but unavailable #{@resource.file}:#{resource.line}"
+        return false
+      else
+        @resource.fail "No candidate to be installed"
+      end
+    end
+
+    packages.first.update( :ensure => :absent )
+  end
+
+  def parse_pkgsearch_line
+    packages = pkgin(:search, resource[:name]).split("\n")
+
+    return [] if packages.length == 1
+
+    # Remove the last three lines of help text.
+    packages.slice!(-4, 4)
+
+    pkglist = packages.map{ |line| self.class.parse_pkgin_line(line) }
+    pkglist.select{ |package| resource[:name] == package[:name] }
+  end
+
+  def install
+    if String === @resource[:ensure]
+      pkgin("-y", :install, "#{resource[:name]}-#{resource[:ensure]}")
+    else
+      pkgin("-y", :install, resource[:name])
+    end
+  end
+
+  def uninstall
+    pkgin("-y", :remove, resource[:name])
+  end
+
+  def latest
+    package = parse_pkgsearch_line.detect{ |package| package[:status] == '<' }
+    return properties[:ensure] if not package
+    return package[:ensure]
+  end
+
+  def update
+    pkgin("-y", :install, resource[:name])
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/pkgutil.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/pkgutil.rb
new file mode 100644
index 0000000..71aa291
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/pkgutil.rb
@@ -0,0 +1,186 @@
+# Packaging using Peter Bonivart's pkgutil program.
+Puppet::Type.type(:package).provide :pkgutil, :parent => :sun, :source => :sun do
+  desc "Package management using Peter Bonivart's ``pkgutil`` command on Solaris."
+
+  pkgutil_bin = "pkgutil"
+  if FileTest.executable?("/opt/csw/bin/pkgutil")
+    pkgutil_bin = "/opt/csw/bin/pkgutil"
+  end
+
+  confine :osfamily => :solaris
+
+  has_command(:pkguti, pkgutil_bin) do
+    environment :HOME => ENV['HOME']
+  end
+
+  def self.healthcheck()
+    unless Puppet::FileSystem.exist?("/var/opt/csw/pkgutil/admin")
+      Puppet.notice "It is highly recommended you create '/var/opt/csw/pkgutil/admin'."
+      Puppet.notice "See /var/opt/csw/pkgutil"
+    end
+
+    correct_wgetopts = false
+    [ "/opt/csw/etc/pkgutil.conf", "/etc/opt/csw/pkgutil.conf" ].each do |confpath|
+      File.open(confpath) do |conf|
+        conf.each_line {|line| correct_wgetopts = true if line =~ /^\s*wgetopts\s*=.*(-nv|-q|--no-verbose|--quiet)/ }
+      end
+    end
+    if ! correct_wgetopts
+      Puppet.notice "It is highly recommended that you set 'wgetopts=-nv' in your pkgutil.conf."
+    end
+  end
+
+  def self.instances(hash = {})
+    healthcheck
+
+    # Use the available pkg list (-a) to work out aliases
+    aliases = {}
+    availlist.each do |pkg|
+      aliases[pkg[:name]] = pkg[:alias]
+    end
+
+    # The -c pkglist lists installed packages
+    pkginsts = []
+    output = pkguti(["-c"])
+    parse_pkglist(output).each do |pkg|
+      pkg.delete(:avail)
+      pkginsts << new(pkg)
+
+      # Create a second instance with the alias if it's different
+      pkgalias = aliases[pkg[:name]]
+      if pkgalias and pkg[:name] != pkgalias
+        apkg = pkg.dup
+        apkg[:name] = pkgalias
+        pkginsts << new(apkg)
+      end
+    end
+
+    pkginsts
+  end
+
+  # Turns a pkgutil -a listing into hashes with the common alias, full
+  # package name and available version
+  def self.availlist
+    output = pkguti ["-a"]
+
+    output.split("\n").collect do |line|
+      next if line =~ /^common\s+package/  # header of package list
+      next if noise?(line)
+
+      if line =~ /\s*(\S+)\s+(\S+)\s+(.*)/
+        { :alias => $1, :name => $2, :avail => $3 }
+      else
+        Puppet.warning "Cannot match %s" % line
+      end
+    end.reject { |h| h.nil? }
+  end
+
+  # Turn our pkgutil -c listing into a hash for a single package.
+  def pkgsingle(resource)
+    # The --single option speeds up the execution, because it queries
+    # the package managament system for one package only.
+    command = ["-c", "--single", resource[:name]]
+    self.class.parse_pkglist(run_pkgutil(resource, command), { :justme => resource[:name] })
+  end
+
+  # Turn our pkgutil -c listing into a bunch of hashes.
+  def self.parse_pkglist(output, hash = {})
+    output = output.split("\n")
+
+    if output[-1] == "Not in catalog"
+      Puppet.warning "Package not in pkgutil catalog: %s" % hash[:justme]
+      return nil
+    end
+
+    list = output.collect do |line|
+      next if line =~ /installed\s+catalog/  # header of package list
+      next if noise?(line)
+
+      pkgsplit(line)
+    end.reject { |h| h.nil? }
+
+    if hash[:justme]
+      # Single queries may have been for an alias so return the name requested
+      if list.any?
+        list[-1][:name] = hash[:justme]
+        return list[-1]
+      end
+    else
+      list.reject! { |h| h[:ensure] == :absent }
+      return list
+    end
+  end
+
+  # Identify common types of pkgutil noise as it downloads catalogs etc
+  def self.noise?(line)
+    true if line =~ /^#/
+    true if line =~ /^Checking integrity / # use_gpg
+    true if line =~ /^gpg: /               # gpg verification
+    true if line =~ /^=+> /                # catalog fetch
+    true if line =~ /\d+:\d+:\d+ URL:/     # wget without -q
+    false
+  end
+
+  # Split the different lines into hashes.
+  def self.pkgsplit(line)
+    if line =~ /\s*(\S+)\s+(\S+)\s+(.*)/
+      hash = {}
+      hash[:name] = $1
+      hash[:ensure] = if $2 == "notinst"
+        :absent
+      else
+        $2
+      end
+      hash[:avail] = $3
+
+      if hash[:avail] =~ /^SAME\s*$/
+        hash[:avail] = hash[:ensure]
+      end
+
+      # Use the name method, so it works with subclasses.
+      hash[:provider] = self.name
+
+      return hash
+    else
+      Puppet.warning "Cannot match %s" % line
+      return nil
+    end
+  end
+
+  def run_pkgutil(resource, *args)
+    # Allow source to be one or more URLs pointing to a repository that all
+    # get passed to pkgutil via one or more -t options
+    if resource[:source]
+      sources = [resource[:source]].flatten
+      pkguti *[sources.map{|src| [ "-t", src ]}, *args].flatten
+    else
+      pkguti *args.flatten
+    end
+  end
+
+  def install
+    run_pkgutil @resource, "-y", "-i", @resource[:name]
+  end
+
+  # Retrieve the version from the current package file.
+  def latest
+    hash = pkgsingle(@resource)
+    hash[:avail] if hash
+  end
+
+  def query
+    if hash = pkgsingle(@resource)
+      hash
+    else
+      {:ensure => :absent}
+    end
+  end
+
+  def update
+    run_pkgutil @resource, "-y", "-u", @resource[:name]
+  end
+
+  def uninstall
+    run_pkgutil @resource, "-y", "-r", @resource[:name]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/portage.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/portage.rb
new file mode 100644
index 0000000..0daa68a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/portage.rb
@@ -0,0 +1,149 @@
+require 'puppet/provider/package'
+require 'fileutils'
+
+Puppet::Type.type(:package).provide :portage, :parent => Puppet::Provider::Package do
+  desc "Provides packaging support for Gentoo's portage system."
+
+  has_feature :versionable
+
+  {
+    :emerge => "/usr/bin/emerge",
+    :eix => "/usr/bin/eix",
+    :update_eix => "/usr/bin/eix-update",
+  }.each_pair do |name, path|
+    has_command(name, path) do
+      environment :HOME => '/'
+    end
+  end
+
+  confine :operatingsystem => :gentoo
+
+  defaultfor :operatingsystem => :gentoo
+
+  def self.instances
+    result_format = self.eix_result_format
+    result_fields = self.eix_result_fields
+
+    version_format = self.eix_version_format
+    begin
+      eix_file = File.directory?("/var/cache/eix") ? "/var/cache/eix/portage.eix" : "/var/cache/eix"
+      update_eix if !FileUtils.uptodate?(eix_file, %w{/usr/bin/eix /usr/portage/metadata/timestamp})
+
+      search_output = nil
+      Puppet::Util.withenv :LASTVERSION => version_format do
+        search_output = eix *(self.eix_search_arguments + ["--installed"])
+      end
+
+      packages = []
+      search_output.each_line do |search_result|
+        match = result_format.match(search_result)
+
+        if match
+          package = {}
+          result_fields.zip(match.captures) do |field, value|
+            package[field] = value unless !value or value.empty?
+          end
+          package[:provider] = :portage
+          packages << new(package)
+        end
+      end
+
+      return packages
+    rescue Puppet::ExecutionFailure => detail
+      raise Puppet::Error.new(detail)
+    end
+  end
+
+  def install
+    should = @resource.should(:ensure)
+    name = package_name
+    unless should == :present or should == :latest
+      # We must install a specific version
+      name = "=#{name}-#{should}"
+    end
+    emerge name
+  end
+
+  # The common package name format.
+  def package_name
+    @resource[:category] ? "#{@resource[:category]}/#{@resource[:name]}" : @resource[:name]
+  end
+
+  def uninstall
+    emerge "--unmerge", package_name
+  end
+
+  def update
+    self.install
+  end
+
+  def query
+    result_format = self.class.eix_result_format
+    result_fields = self.class.eix_result_fields
+
+    version_format = self.class.eix_version_format
+    search_field = package_name.count('/') > 0 ? "--category-name" : "--name"
+    search_value = package_name
+
+    begin
+      eix_file = File.directory?("/var/cache/eix") ? "/var/cache/eix/portage.eix" : "/var/cache/eix"
+      update_eix if !FileUtils.uptodate?(eix_file, %w{/usr/bin/eix /usr/portage/metadata/timestamp})
+
+      search_output = nil
+      Puppet::Util.withenv :LASTVERSION => version_format do
+        search_output = eix *(self.class.eix_search_arguments + ["--exact",search_field,search_value])
+      end
+
+      packages = []
+      search_output.each_line do |search_result|
+        match = result_format.match(search_result)
+
+        if match
+          package = {}
+          result_fields.zip(match.captures) do |field, value|
+            package[field] = value unless !value or value.empty?
+          end
+          package[:ensure] = package[:ensure] ? package[:ensure] : :absent
+          packages << package
+        end
+      end
+
+      case packages.size
+        when 0
+          not_found_value = "#{@resource[:category] ? @resource[:category] : "<unspecified category>"}/#{@resource[:name]}"
+          raise Puppet::Error.new("No package found with the specified name [#{not_found_value}]")
+        when 1
+          return packages[0]
+        else
+          raise Puppet::Error.new("More than one package with the specified name [#{search_value}], please use the category parameter to disambiguate")
+      end
+    rescue Puppet::ExecutionFailure => detail
+      raise Puppet::Error.new(detail)
+    end
+  end
+
+  def latest
+    self.query[:version_available]
+  end
+
+  private
+  def self.eix_search_format
+    "'<category> <name> [<installedversions:LASTVERSION>] [<bestversion:LASTVERSION>] <homepage> <description>'"
+  end
+
+  def self.eix_result_format
+    /^(\S+)\s+(\S+)\s+\[(\S*)\]\s+\[(\S*)\]\s+(\S+)\s+(.*)$/
+  end
+
+  def self.eix_result_fields
+    [:category, :name, :ensure, :version_available, :vendor, :description]
+  end
+
+  def self.eix_version_format
+    "{last}<version>{}"
+  end
+
+  def self.eix_search_arguments
+    ["--nocolor", "--pure-packages", "--format",self.eix_search_format]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/ports.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/ports.rb
new file mode 100644
index 0000000..ffc79d2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/ports.rb
@@ -0,0 +1,94 @@
+Puppet::Type.type(:package).provide :ports, :parent => :freebsd, :source => :freebsd do
+  desc "Support for FreeBSD's ports.  Note that this, too, mixes packages and ports."
+
+  commands :portupgrade => "/usr/local/sbin/portupgrade",
+    :portversion => "/usr/local/sbin/portversion",
+    :portuninstall => "/usr/local/sbin/pkg_deinstall",
+    :portinfo => "/usr/sbin/pkg_info"
+
+  defaultfor :operatingsystem => :freebsd
+
+  # I hate ports
+  %w{INTERACTIVE UNAME}.each do |var|
+    ENV.delete(var) if ENV.include?(var)
+  end
+
+  def install
+    # -N: install if the package is missing, otherwise upgrade
+    # -M: yes, we're a batch, so don't ask any questions
+    cmd = %w{-N -M BATCH=yes} << @resource[:name]
+
+    output = portupgrade(*cmd)
+    if output =~ /\*\* No such /
+      raise Puppet::ExecutionFailure, "Could not find package #{@resource[:name]}"
+    end
+  end
+
+  # If there are multiple packages, we only use the last one
+  def latest
+    cmd = ["-v", @resource[:name]]
+
+    begin
+      output = portversion(*cmd)
+    rescue Puppet::ExecutionFailure
+      raise Puppet::Error.new(output, $!)
+    end
+    line = output.split("\n").pop
+
+    unless line =~ /^(\S+)\s+(\S)\s+(.+)$/
+      # There's no "latest" version, so just return a placeholder
+      return :latest
+    end
+
+    pkgstuff = $1
+    match = $2
+    info = $3
+
+    unless pkgstuff =~ /^\S+-([^-\s]+)$/
+      raise Puppet::Error,
+        "Could not match package info '#{pkgstuff}'"
+    end
+
+    version = $1
+
+    if match == "=" or match == ">"
+      # we're up to date or more recent
+      return version
+    end
+
+    # Else, we need to be updated; we need to pull out the new version
+
+    unless info =~ /\((\w+) has (.+)\)/
+      raise Puppet::Error,
+        "Could not match version info '#{info}'"
+    end
+
+    source, newversion = $1, $2
+
+    debug "Newer version in #{source}"
+    newversion
+  end
+
+  def query
+    # support portorigin_glob such as "mail/postfix"
+    name = self.name
+    if name =~ /\//
+      name = self.name.split(/\//).slice(1)
+    end
+    self.class.instances.each do |instance|
+      if instance.name == name
+        return instance.properties
+      end
+    end
+
+    nil
+  end
+
+  def uninstall
+    portuninstall @resource[:name]
+  end
+
+  def update
+    install
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/portupgrade.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/portupgrade.rb
new file mode 100644
index 0000000..5347a79
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/portupgrade.rb
@@ -0,0 +1,241 @@
+# Whole new package, so include pack stuff
+require 'puppet/provider/package'
+
+Puppet::Type.type(:package).provide :portupgrade, :parent => Puppet::Provider::Package do
+  include Puppet::Util::Execution
+
+  desc "Support for FreeBSD's ports using the portupgrade ports management software.
+    Use the port's full origin as the resource name. eg (ports-mgmt/portupgrade)
+    for the portupgrade port."
+
+  ## has_features is usually autodetected based on defs below.
+  # has_features :installable, :uninstallable, :upgradeable
+
+  commands :portupgrade   => "/usr/local/sbin/portupgrade",
+  :portinstall   => "/usr/local/sbin/portinstall",
+  :portversion   => "/usr/local/sbin/portversion",
+  :portuninstall => "/usr/local/sbin/pkg_deinstall",
+  :portinfo      => "/usr/sbin/pkg_info"
+
+  ## Activate this only once approved by someone important.
+  # defaultfor :operatingsystem => :freebsd
+
+  # Remove unwanted environment variables.
+  %w{INTERACTIVE UNAME}.each do |var|
+    if ENV.include?(var)
+      ENV.delete(var)
+    end
+  end
+
+  ######## instances sub command (builds the installed packages list)
+
+  def self.instances
+    Puppet.debug "portupgrade.rb Building packages list from installed ports"
+
+    # regex to match output from pkg_info
+    regex = %r{^(\S+)-([^-\s]+):(\S+)$}
+    # Corresponding field names
+    fields = [:portname, :ensure, :portorigin]
+    # define Temporary hash used, packages array of hashes
+    hash = Hash.new
+    packages = []
+
+    # exec command
+    cmdline = ["-aoQ"]
+    begin
+      output = portinfo(*cmdline)
+    rescue Puppet::ExecutionFailure
+      raise Puppet::Error.new(output, $!)
+      return nil
+    end
+
+    # split output and match it and populate temp hash
+    output.split("\n").each { |data|
+      # reset hash to nil for each line
+      hash.clear
+      if match = regex.match(data)
+        # Output matched regex
+        fields.zip(match.captures) { |field, value|
+          hash[field] = value
+        }
+
+        # populate the actual :name field from the :portorigin
+        # Set :provider to this object name
+        hash[:name] = hash[:portorigin]
+        hash[:provider] = self.name
+
+        # Add to the full packages listing
+        packages << new(hash)
+      else
+        # unrecognised output from pkg_info
+        Puppet.debug "portupgrade.Instances() - unable to match output: #{data}"
+      end
+    }
+
+    # return the packages array of hashes
+    return packages
+  end
+
+  ######## Installation sub command
+
+  def install
+    Puppet.debug "portupgrade.install() - Installation call on #{@resource[:name]}"
+    # -M: yes, we're a batch, so don't ask any questions
+    cmdline = ["-M BATCH=yes", @resource[:name]]
+
+    # FIXME: it's possible that portinstall prompts for data so locks up.
+    begin
+      output = portinstall(*cmdline)
+    rescue Puppet::ExecutionFailure
+      raise Puppet::Error.new(output, $!)
+    end
+
+    if output =~ /\*\* No such /
+      raise Puppet::ExecutionFailure, "Could not find package #{@resource[:name]}"
+    end
+
+    # No return code required, so do nil to be clean
+    return nil
+  end
+
+  ######## Latest subcommand (returns the latest version available, or current version if installed is latest)
+
+  def latest
+    Puppet.debug "portupgrade.latest() - Latest check called on #{@resource[:name]}"
+    # search for latest version available, or return current version.
+    # cmdline = "portversion -v <portorigin>", returns "<portname> <code> <stuff>"
+    # or "** No matching package found: <portname>"
+    cmdline = ["-v", @resource[:name]]
+
+    begin
+      output = portversion(*cmdline)
+    rescue Puppet::ExecutionFailure
+      raise Puppet::Error.new(output, $!)
+    end
+
+    # Check: output format.
+    if output =~ /^\S+-([^-\s]+)\s+(\S)\s+(.*)/
+      installedversion = $1
+      comparison = $2
+      otherdata = $3
+
+      # Only return a new version number when it's clear that there is a new version
+      # all others return the current version so no unexpected 'upgrades' occur.
+      case comparison
+      when "=", ">"
+        Puppet.debug "portupgrade.latest() - Installed package is latest (#{installedversion})"
+        return installedversion
+      when "<"
+        # "portpkg-1.7_5 < needs updating (port has 1.14)"
+        # "portpkg-1.7_5 < needs updating (port has 1.14) (=> 'newport/pkg')
+        if otherdata =~ /\(port has (\S+)\)/
+          newversion = $1
+          Puppet.debug "portupgrade.latest() - Installed version needs updating to (#{newversion})"
+          return newversion
+        else
+          Puppet.debug "portupgrade.latest() - Unable to determine new version from (#{otherdata})"
+          return installedversion
+        end
+      when "?", "!", "#"
+        Puppet.debug "portupgrade.latest() - Comparison Error reported from portversion (#{output})"
+        return installedversion
+      else
+        Puppet.debug "portupgrade.latest() - Unknown code from portversion output (#{output})"
+        return installedversion
+      end
+
+    else
+      # error: output not parsed correctly, error out with nil.
+      # Seriously - this section should never be called in a perfect world.
+      # as verification that the port is installed has already happened in query.
+      if output =~ /^\*\* No matching package /
+        raise Puppet::ExecutionFailure, "Could not find package #{@resource[:name]}"
+      else
+        # Any other error (dump output to log)
+        raise Puppet::ExecutionFailure, "Unexpected output from portversion: #{output}"
+      end
+
+      # Just in case we still are running, return nil
+      return nil
+    end
+
+    # At this point normal operation has finished and we shouldn't have been called.
+    # Error out and let the admin deal with it.
+    raise Puppet::Error, "portversion.latest() - fatal error with portversion: #{output}"
+    return nil
+  end
+
+  ###### Query subcommand - return a hash of details if exists, or nil if it doesn't.
+  # Used to make sure the package is installed
+
+  def query
+    Puppet.debug "portupgrade.query() - Called on #{@resource[:name]}"
+
+    cmdline = ["-qO", @resource[:name]]
+    begin
+      output = portinfo(*cmdline)
+    rescue Puppet::ExecutionFailure
+      raise Puppet::Error.new(output, $!)
+    end
+
+    # Check: if output isn't in the right format, return nil
+    if output =~ /^(\S+)-([^-\s]+)/
+      # Fill in the details
+      hash = Hash.new
+      hash[:portorigin] = self.name
+      hash[:portname]   = $1
+      hash[:ensure]     = $2
+
+      # If more details are required, then we can do another pkg_info
+      # query here and parse out that output and add to the hash
+      # return the hash to the caller
+      return hash
+    else
+      Puppet.debug "portupgrade.query() - package (#{@resource[:name]}) not installed"
+      return nil
+    end
+  end
+
+  ####### Uninstall command
+
+  def uninstall
+    Puppet.debug "portupgrade.uninstall() - called on #{@resource[:name]}"
+    # Get full package name from port origin to uninstall with
+    cmdline = ["-qO", @resource[:name]]
+    begin
+      output = portinfo(*cmdline)
+    rescue Puppet::ExecutionFailure
+      raise Puppet::Error.new(output, $!)
+    end
+
+    if output =~ /^(\S+)/
+      # output matches, so uninstall it
+      portuninstall $1
+    end
+  end
+
+  ######## Update/upgrade command
+
+  def update
+    Puppet.debug "portupgrade.update() - called on (#{@resource[:name]})"
+
+    cmdline = ["-qO", @resource[:name]]
+    begin
+      output = portinfo(*cmdline)
+    rescue Puppet::ExecutionFailure
+      raise Puppet::Error.new(output, $!)
+    end
+
+    if output =~ /^(\S+)/
+      # output matches, so upgrade the software
+      cmdline = ["-M BATCH=yes", $1]
+      begin
+        output = portupgrade(*cmdline)
+      rescue Puppet::ExecutionFailure
+        raise Puppet::Error.new(output, $!)
+      end
+    end
+  end
+
+  ## EOF
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/rpm.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/rpm.rb
new file mode 100644
index 0000000..3b4b638
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/rpm.rb
@@ -0,0 +1,187 @@
+require 'puppet/provider/package'
+
+# RPM packaging.  Should work anywhere that has rpm installed.
+Puppet::Type.type(:package).provide :rpm, :source => :rpm, :parent => Puppet::Provider::Package do
+  desc "RPM packaging support; should work anywhere with a working `rpm`
+    binary.
+
+    This provider supports the `install_options` and `uninstall_options`
+    attributes, which allow command-line flags to be passed to rpm.
+    These options should be specified as a string (e.g. '--flag'), a hash (e.g. {'--flag' => 'value'}),
+    or an array where each element is either a string or a hash."
+
+  has_feature :versionable
+  has_feature :install_options
+  has_feature :uninstall_options
+  has_feature :virtual_packages
+
+  # Note: self:: is required here to keep these constants in the context of what will
+  # eventually become this Puppet::Type::Package::ProviderRpm class.
+  # The query format by which we identify installed packages
+  self::NEVRA_FORMAT = %Q{%{NAME} %|EPOCH?{%{EPOCH}}:{0}| %{VERSION} %{RELEASE} %{ARCH}\\n}
+  self::NEVRA_REGEX  = %r{^(\S+) (\S+) (\S+) (\S+) (\S+)$}
+  self::NEVRA_FIELDS = [:name, :epoch, :version, :release, :arch]
+
+  commands :rpm => "rpm"
+
+  if command('rpm')
+    confine :true => begin
+      rpm('--version')
+      rescue Puppet::ExecutionFailure
+        false
+      else
+        true
+      end
+  end
+
+  def self.current_version
+    return @current_version unless @current_version.nil?
+    output = rpm "--version"
+    @current_version = output.gsub('RPM version ', '').strip
+  end
+
+  # rpm < 4.1 does not support --nosignature
+  def self.nosignature
+    '--nosignature' unless Puppet::Util::Package.versioncmp(current_version, '4.1') < 0
+  end
+
+  # rpm < 4.0.2 does not support --nodigest
+  def self.nodigest
+    '--nodigest' unless Puppet::Util::Package.versioncmp(current_version, '4.0.2') < 0
+  end
+
+  def self.instances
+    packages = []
+
+    # list out all of the packages
+    begin
+      execpipe("#{command(:rpm)} -qa #{nosignature} #{nodigest} --qf '#{self::NEVRA_FORMAT}'") { |process|
+        # now turn each returned line into a package object
+        process.each_line { |line|
+          hash = nevra_to_hash(line)
+          packages << new(hash) unless hash.empty?
+        }
+      }
+    rescue Puppet::ExecutionFailure
+      raise Puppet::Error, "Failed to list packages", $!.backtrace
+    end
+
+    packages
+  end
+
+  # Find the fully versioned package name and the version alone. Returns
+  # a hash with entries :instance => fully versioned package name, and
+  # :ensure => version-release
+  def query
+    #NOTE: Prior to a fix for issue 1243, this method potentially returned a cached value
+    #IF YOU CALL THIS METHOD, IT WILL CALL RPM
+    #Use get(:property) to check if cached values are available
+    cmd = ["-q",  @resource[:name], "#{self.class.nosignature}", "#{self.class.nodigest}", "--qf", self.class::NEVRA_FORMAT]
+
+    begin
+      output = rpm(*cmd)
+    rescue Puppet::ExecutionFailure
+      return nil unless @resource.allow_virtual?
+
+      # rpm -q exits 1 if package not found
+      # retry the query for virtual packages
+      cmd << '--whatprovides'
+      begin
+        output = rpm(*cmd)
+      rescue Puppet::ExecutionFailure
+        # couldn't find a virtual package either
+        return nil
+      end
+    end
+    # FIXME: We could actually be getting back multiple packages
+    # for multilib and this will only return the first such package
+    @property_hash.update(self.class.nevra_to_hash(output))
+
+    @property_hash.dup
+  end
+
+  # Here we just retrieve the version from the file specified in the source.
+  def latest
+    unless source = @resource[:source]
+      @resource.fail "RPMs must specify a package source"
+    end
+
+    cmd = [command(:rpm), "-q", "--qf", self.class::NEVRA_FORMAT, "-p", source]
+    h = self.class.nevra_to_hash(execfail(cmd, Puppet::Error))
+    h[:ensure]
+  end
+
+  def install
+    unless source = @resource[:source]
+      @resource.fail "RPMs must specify a package source"
+    end
+    # RPM gets pissy if you try to install an already
+    # installed package
+    if @resource.should(:ensure) == @property_hash[:ensure] or
+      @resource.should(:ensure) == :latest && @property_hash[:ensure] == latest
+      return
+    end
+
+    flag = ["-i"]
+    flag = ["-U", "--oldpackage"] if @property_hash[:ensure] and @property_hash[:ensure] != :absent
+    flag += install_options if resource[:install_options]
+    rpm flag, source
+  end
+
+  def uninstall
+    query if get(:arch) == :absent
+    nvr = "#{get(:name)}-#{get(:version)}-#{get(:release)}"
+    arch = ".#{get(:arch)}"
+    # If they specified an arch in the manifest, erase that Otherwise,
+    # erase the arch we got back from the query. If multiple arches are
+    # installed and only the package name is specified (without the
+    # arch), this will uninstall all of them on successive runs of the
+    # client, one after the other
+
+    # version of RPM prior to 4.2.1 can't accept the architecture as
+    # part of the package name.
+    unless Puppet::Util::Package.versioncmp(self.class.current_version, '4.2.1') < 0
+      if @resource[:name][-arch.size, arch.size] == arch
+        nvr += arch
+      else
+        nvr += ".#{get(:arch)}"
+      end
+    end
+
+    flag = ['-e']
+    flag += uninstall_options if resource[:uninstall_options]
+    rpm flag, nvr
+  end
+
+  def update
+    self.install
+  end
+
+  def install_options
+    join_options(resource[:install_options])
+  end
+
+  def uninstall_options
+    join_options(resource[:uninstall_options])
+  end
+
+  private
+  # @param line [String] one line of rpm package query information
+  # @return [Hash] of NEVRA_FIELDS strings parsed from package info
+  # or an empty hash if we failed to parse
+  # @api private
+  def self.nevra_to_hash(line)
+    line.strip!
+    hash = {}
+
+    if match = self::NEVRA_REGEX.match(line)
+      self::NEVRA_FIELDS.zip(match.captures) { |f, v| hash[f] = v }
+      hash[:provider] = self.name
+      hash[:ensure] = "#{hash[:version]}-#{hash[:release]}"
+    else
+      Puppet.debug("Failed to match rpm line #{line}")
+    end
+
+    return hash
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/rug.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/rug.rb
new file mode 100644
index 0000000..f004b94
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/rug.rb
@@ -0,0 +1,52 @@
+Puppet::Type.type(:package).provide :rug, :parent => :rpm do
+  desc "Support for suse `rug` package manager."
+
+  has_feature :versionable
+
+  commands :rug => "/usr/bin/rug"
+  commands :rpm => "rpm"
+  defaultfor :operatingsystem => [:suse, :sles]
+  confine    :operatingsystem => [:suse, :sles]
+
+  # Install a package using 'rug'.
+  def install
+    should = @resource.should(:ensure)
+    self.debug "Ensuring => #{should}"
+    wanted = @resource[:name]
+
+    # XXX: We don't actually deal with epochs here.
+    case should
+    when true, false, Symbol
+      # pass
+    else
+      # Add the package version
+      wanted += "-#{should}"
+    end
+    rug "--quiet", :install, "-y", wanted
+
+    unless self.query
+      raise Puppet::ExecutionFailure.new(
+        "Could not find package #{self.name}"
+      )
+    end
+  end
+
+  # What's the latest package version available?
+  def latest
+    #rug can only get a list of *all* available packages?
+    output = rug "list-updates"
+
+    if output =~ /#{Regexp.escape @resource[:name]}\s*\|\s*([^\s\|]+)/
+      return $1
+    else
+      # rug didn't find updates, pretend the current
+      # version is the latest
+      return @property_hash[:ensure]
+    end
+  end
+
+  def update
+    # rug install can be used for update, too
+    self.install
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/sun.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/sun.rb
new file mode 100644
index 0000000..15b7839
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/sun.rb
@@ -0,0 +1,132 @@
+# Sun packaging.
+
+require 'puppet/provider/package'
+
+Puppet::Type.type(:package).provide :sun, :parent => Puppet::Provider::Package do
+  desc "Sun's packaging system.  Requires that you specify the source for
+    the packages you're managing.
+
+    This provider supports the `install_options` attribute, which allows command-line flags to be passed to pkgadd.
+    These options should be specified as a string (e.g. '--flag'), a hash (e.g. {'--flag' => 'value'}),
+    or an array where each element is either a string or a hash."
+
+  commands :pkginfo => "/usr/bin/pkginfo",
+    :pkgadd => "/usr/sbin/pkgadd",
+    :pkgrm => "/usr/sbin/pkgrm"
+
+  confine :osfamily => :solaris
+  defaultfor :osfamily => :solaris
+
+  has_feature :install_options
+
+  self::Namemap = {
+    "PKGINST"  => :name,
+    "CATEGORY" => :category,
+    "ARCH"     => :platform,
+    "VERSION"  => :ensure,
+    "BASEDIR"  => :root,
+    "VENDOR"   => :vendor,
+    "DESC"     => :description,
+  }
+
+  def self.namemap(hash)
+    self::Namemap.keys.inject({}) do |hsh,k|
+      hsh.merge(self::Namemap[k] => hash[k])
+    end
+  end
+
+  def self.parse_pkginfo(out)
+    # collect all the lines with : in them, and separate them out by ^$
+    pkgs = []
+    pkg = {}
+    out.each_line do |line|
+      case line.chomp
+      when /^\s*$/
+        pkgs << pkg unless pkg.empty?
+        pkg = {}
+      when /^\s*([^:]+):\s+(.+)$/
+        pkg[$1] = $2
+      end
+    end
+    pkgs << pkg unless pkg.empty?
+    pkgs
+  end
+
+  def self.instances
+    parse_pkginfo(pkginfo('-l')).collect do |p|
+      hash = namemap(p)
+      hash[:provider] = :sun
+      new(hash)
+    end
+  end
+
+  # Get info on a package, optionally specifying a device.
+  def info2hash(device = nil)
+    args = ['-l']
+    args << '-d' << device if device
+    args << @resource[:name]
+    begin
+      pkgs = self.class.parse_pkginfo(pkginfo(*args))
+      errmsg = case pkgs.size
+        when 0
+          'No message'
+        when 1
+           pkgs[0]['ERROR']
+      end
+      return self.class.namemap(pkgs[0]) if errmsg.nil?
+      # according to commit 41356a7 some errors do not raise an exception
+      # so eventhough pkginfo passed, we have to check the actual output
+      raise Puppet::Error, "Unable to get information about package #{@resource[:name]} because of: #{errmsg}"
+    rescue Puppet::ExecutionFailure
+      return {:ensure => :absent}
+    end
+  end
+
+  # Retrieve the version from the current package file.
+  def latest
+    info2hash(@resource[:source])[:ensure]
+  end
+
+  def query
+    info2hash
+  end
+
+  # only looking for -G now
+  def install
+    raise Puppet::Error, "Sun packages must specify a package source" unless @resource[:source]
+    options = {
+      :adminfile    => @resource[:adminfile],
+      :responsefile => @resource[:responsefile],
+      :source       => @resource[:source],
+      :cmd_options  => @resource[:install_options]
+    }
+    pkgadd prepare_cmd(options)
+  end
+
+  def uninstall
+    pkgrm prepare_cmd(:adminfile => @resource[:adminfile])
+  end
+
+  # Remove the old package, and install the new one.  This will probably
+  # often fail.
+  def update
+    self.uninstall if (@property_hash[:ensure] || info2hash[:ensure]) != :absent
+    self.install
+  end
+
+  def prepare_cmd(opt)
+    [if_have_value('-a', opt[:adminfile]),
+     if_have_value('-r', opt[:responsefile]),
+     if_have_value('-d', opt[:source]),
+     opt[:cmd_options] || [],
+     ['-n', @resource[:name]]].flatten
+  end
+
+  def if_have_value(prefix, value)
+    if value
+      [prefix, value]
+    else
+      []
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/sunfreeware.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/sunfreeware.rb
new file mode 100644
index 0000000..118d36b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/sunfreeware.rb
@@ -0,0 +1,9 @@
+# At this point, it's an exact copy of the Blastwave stuff.
+Puppet::Type.type(:package).provide :sunfreeware, :parent => :blastwave, :source => :sun do
+  desc "Package management using sunfreeware.com's `pkg-get` command on Solaris.
+    At this point, support is exactly the same as `blastwave` support and
+    has not actually been tested."
+  commands :pkgget => "pkg-get"
+
+  confine :osfamily => :solaris
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/up2date.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/up2date.rb
new file mode 100644
index 0000000..7c3ad5c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/up2date.rb
@@ -0,0 +1,40 @@
+Puppet::Type.type(:package).provide :up2date, :parent => :rpm, :source => :rpm do
+  desc "Support for Red Hat's proprietary `up2date` package update
+    mechanism."
+
+  commands :up2date => "/usr/sbin/up2date-nox"
+
+  defaultfor :osfamily => :redhat, :lsbdistrelease => ["2.1", "3", "4"]
+
+  confine    :osfamily => :redhat
+
+  # Install a package using 'up2date'.
+  def install
+    up2date "-u", @resource[:name]
+
+    unless self.query
+      raise Puppet::ExecutionFailure.new(
+        "Could not find package #{self.name}"
+      )
+    end
+  end
+
+  # What's the latest package version available?
+  def latest
+    #up2date can only get a list of *all* available packages?
+    output = up2date "--showall"
+
+    if output =~ /^#{Regexp.escape @resource[:name]}-(\d+.*)\.\w+/
+      return $1
+    else
+      # up2date didn't find updates, pretend the current
+      # version is the latest
+      return @property_hash[:ensure]
+    end
+  end
+
+  def update
+    # Install in up2date can be used for update, too
+    self.install
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/urpmi.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/urpmi.rb
new file mode 100644
index 0000000..4954d17
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/urpmi.rb
@@ -0,0 +1,55 @@
+Puppet::Type.type(:package).provide :urpmi, :parent => :rpm, :source => :rpm do
+  desc "Support via `urpmi`."
+  commands :urpmi => "urpmi", :urpmq => "urpmq", :rpm => "rpm", :urpme => "urpme"
+
+  defaultfor :operatingsystem => [:mandriva, :mandrake]
+
+  has_feature :versionable
+
+  def install
+    should = @resource.should(:ensure)
+    self.debug "Ensuring => #{should}"
+    wanted = @resource[:name]
+
+    # XXX: We don't actually deal with epochs here.
+    case should
+    when true, false, Symbol
+      # pass
+    else
+      # Add the package version
+      wanted += "-#{should}"
+    end
+
+    urpmi "--auto", wanted
+
+    unless self.query
+      raise Puppet::Error, "Package #{self.name} was not present after trying to install it"
+    end
+  end
+
+  # What's the latest package version available?
+  def latest
+    output = urpmq "-S", @resource[:name]
+
+    if output =~ /^#{Regexp.escape @resource[:name]}\s+:\s+.*\(\s+(\S+)\s+\)/
+      return $1
+    else
+      # urpmi didn't find updates, pretend the current
+      # version is the latest
+      return @resource[:ensure]
+    end
+  end
+
+  def update
+    # Install in urpmi can be used for update, too
+    self.install
+  end
+
+  # For normal package removal the urpmi provider will delegate to the RPM
+  # provider. If the package to remove has dependencies then uninstalling via
+  # rpm will fail, but `urpme` can be used to remove a package and its
+  # dependencies.
+  def purge
+    urpme '--auto', @resource[:name]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/windows.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/windows.rb
new file mode 100644
index 0000000..143d1c1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/windows.rb
@@ -0,0 +1,113 @@
+require 'puppet/provider/package'
+require 'puppet/util/windows'
+require 'puppet/provider/package/windows/package'
+
+Puppet::Type.type(:package).provide(:windows, :parent => Puppet::Provider::Package) do
+  desc "Windows package management.
+
+    This provider supports either MSI or self-extracting executable installers.
+
+    This provider requires a `source` attribute when installing the package.
+    It accepts paths to local files, mapped drives, or UNC paths.
+
+    This provider supports the `install_options` and `uninstall_options`
+    attributes, which allow command-line flags to be passed to the installer.
+    These options should be specified as a string (e.g. '--flag'), a hash (e.g. {'--flag' => 'value'}),
+    or an array where each element is either a string or a hash.
+
+    If the executable requires special arguments to perform a silent install or
+    uninstall, then the appropriate arguments should be specified using the
+    `install_options` or `uninstall_options` attributes, respectively.  Puppet
+    will automatically quote any option that contains spaces."
+
+  confine    :operatingsystem => :windows
+  defaultfor :operatingsystem => :windows
+
+  has_feature :installable
+  has_feature :uninstallable
+  has_feature :install_options
+  has_feature :uninstall_options
+  has_feature :versionable
+
+  attr_accessor :package
+
+  # Return an array of provider instances
+  def self.instances
+    Puppet::Provider::Package::Windows::Package.map do |pkg|
+      provider = new(to_hash(pkg))
+      provider.package = pkg
+      provider
+    end
+  end
+
+  def self.to_hash(pkg)
+    {
+      :name     => pkg.name,
+      :ensure   => pkg.version || :installed,
+      :provider => :windows
+    }
+  end
+
+  # Query for the provider hash for the current resource. The provider we
+  # are querying, may not have existed during prefetch
+  def query
+    Puppet::Provider::Package::Windows::Package.find do |pkg|
+      if pkg.match?(resource)
+        return self.class.to_hash(pkg)
+      end
+    end
+    nil
+  end
+
+  def install
+    installer = Puppet::Provider::Package::Windows::Package.installer_class(resource)
+
+    command = [installer.install_command(resource), install_options].flatten.compact.join(' ')
+    output = execute(command, :failonfail => false, :combine => true)
+
+    check_result(output.exitstatus)
+  end
+
+  def uninstall
+    command = [package.uninstall_command, uninstall_options].flatten.compact.join(' ')
+    output = execute(command, :failonfail => false, :combine => true)
+
+    check_result(output.exitstatus)
+  end
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa368542(v=vs.85).aspx
+  self::ERROR_SUCCESS                  = 0
+  self::ERROR_SUCCESS_REBOOT_INITIATED = 1641
+  self::ERROR_SUCCESS_REBOOT_REQUIRED  = 3010
+
+  # (Un)install may "fail" because the package requested a reboot, the system requested a
+  # reboot, or something else entirely. Reboot requests mean the package was installed
+  # successfully, but we warn since we don't have a good reboot strategy.
+  def check_result(hr)
+    operation = resource[:ensure] == :absent ? 'uninstall' : 'install'
+
+    case hr
+    when self.class::ERROR_SUCCESS
+      # yeah
+    when self.class::ERROR_SUCCESS_REBOOT_INITIATED
+      warning("The package #{operation}ed successfully and the system is rebooting now.")
+    when self.class::ERROR_SUCCESS_REBOOT_REQUIRED
+      warning("The package #{operation}ed successfully, but the system must be rebooted.")
+    else
+      raise Puppet::Util::Windows::Error.new("Failed to #{operation}", hr)
+    end
+  end
+
+  # This only gets called if there is a value to validate, but not if it's absent
+  def validate_source(value)
+    fail("The source parameter cannot be empty when using the Windows provider.") if value.empty?
+  end
+
+  def install_options
+    join_options(resource[:install_options])
+  end
+
+  def uninstall_options
+    join_options(resource[:uninstall_options])
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/windows/exe_package.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/windows/exe_package.rb
new file mode 100644
index 0000000..9c9e46f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/windows/exe_package.rb
@@ -0,0 +1,70 @@
+require 'puppet/provider/package/windows/package'
+
+class Puppet::Provider::Package::Windows
+  class ExePackage < Puppet::Provider::Package::Windows::Package
+    attr_reader :uninstall_string
+
+    # Return an instance of the package from the registry, or nil
+    def self.from_registry(name, values)
+      if valid?(name, values)
+        ExePackage.new(
+          values['DisplayName'],
+          values['DisplayVersion'],
+          values['UninstallString']
+        )
+      end
+    end
+
+    # Is this a valid executable package we should manage?
+    def self.valid?(name, values)
+      # See http://community.spiceworks.com/how_to/show/2238
+      !!(values['DisplayName'] and values['DisplayName'].length > 0 and
+         values['UninstallString'] and values['UninstallString'].length > 0 and
+         values['SystemComponent'] != 1 and # DWORD
+         values['WindowsInstaller'] != 1 and # DWORD
+         name !~ /^KB[0-9]{6}/ and
+         values['ParentKeyName'] == nil and
+         values['Security Update'] == nil and
+         values['Update Rollup'] == nil and
+         values['Hotfix'] == nil)
+    end
+
+    def initialize(name, version, uninstall_string)
+      super(name, version)
+
+      @uninstall_string = uninstall_string
+    end
+
+    # Does this package match the resource?
+    def match?(resource)
+      resource[:name] == name
+    end
+
+    def self.install_command(resource)
+      ['cmd.exe', '/c', 'start', '"puppet-install"', '/w', munge(resource[:source])]
+    end
+
+    def uninstall_command
+      # 1. Launch using cmd /c start because if the executable is a console
+      #    application Windows will automatically display its console window
+      # 2. Specify a quoted title, otherwise if uninstall_string is quoted,
+      #    start will interpret that to be the title, and get confused
+      # 3. Specify /w (wait) to wait for uninstall to finish
+      command = ['cmd.exe', '/c', 'start', '"puppet-uninstall"', '/w']
+
+      # Only quote bare uninstall strings, e.g.
+      #   C:\Program Files (x86)\Notepad++\uninstall.exe
+      # Don't quote uninstall strings that are already quoted, e.g.
+      #   "c:\ruby187\unins000.exe"
+      # Don't quote uninstall strings that contain arguments:
+      #   "C:\Program Files (x86)\Git\unins000.exe" /SILENT
+      if uninstall_string =~ /\A[^"]*.exe\Z/i
+        command << "\"#{uninstall_string}\""
+      else
+        command << uninstall_string
+      end
+
+      command
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/windows/msi_package.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/windows/msi_package.rb
new file mode 100644
index 0000000..1b8b04d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/windows/msi_package.rb
@@ -0,0 +1,62 @@
+require 'puppet/provider/package/windows/package'
+
+class Puppet::Provider::Package::Windows
+  class MsiPackage < Puppet::Provider::Package::Windows::Package
+    attr_reader :productcode, :packagecode
+
+    # From msi.h
+    INSTALLSTATE_DEFAULT = 5 # product is installed for the current user
+    INSTALLUILEVEL_NONE  = 2 # completely silent installation
+
+    # Get the COM installer object, it's in a separate method for testing
+    def self.installer
+      # REMIND: when does the COM release happen?
+      WIN32OLE.new("WindowsInstaller.Installer")
+    end
+
+    # Return an instance of the package from the registry, or nil
+    def self.from_registry(name, values)
+      if valid?(name, values)
+        inst = installer
+
+        if inst.ProductState(name) == INSTALLSTATE_DEFAULT
+          MsiPackage.new(values['DisplayName'],
+                         values['DisplayVersion'],
+                         name, # productcode
+                         inst.ProductInfo(name, 'PackageCode'))
+        end
+      end
+    end
+
+    # Is this a valid MSI package we should manage?
+    def self.valid?(name, values)
+      # See http://community.spiceworks.com/how_to/show/2238
+      !!(values['DisplayName'] and values['DisplayName'].length > 0 and
+         values['SystemComponent'] != 1 and # DWORD
+         values['WindowsInstaller'] == 1 and # DWORD
+         name =~ /\A\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\}\Z/i)
+    end
+
+    def initialize(name, version, productcode, packagecode)
+      super(name, version)
+
+      @productcode = productcode
+      @packagecode = packagecode
+    end
+
+    # Does this package match the resource?
+    def match?(resource)
+      resource[:name].casecmp(packagecode) == 0 ||
+        resource[:name].casecmp(productcode) == 0 ||
+        resource[:name] == name
+    end
+
+    def self.install_command(resource)
+      ['msiexec.exe', '/qn', '/norestart', '/i', munge(resource[:source])]
+    end
+
+    def uninstall_command
+      ['msiexec.exe', '/qn', '/norestart', '/x', productcode]
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/windows/package.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/windows/package.rb
new file mode 100644
index 0000000..a1526a8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/windows/package.rb
@@ -0,0 +1,92 @@
+require 'puppet/provider/package'
+require 'puppet/util/windows'
+
+class Puppet::Provider::Package::Windows
+  class Package
+    extend Enumerable
+    extend Puppet::Util::Errors
+
+    include Puppet::Util::Windows::Registry
+    extend Puppet::Util::Windows::Registry
+
+    attr_reader :name, :version
+
+    # Enumerate each package. The appropriate package subclass
+    # will be yielded.
+    def self.each(&block)
+      with_key do |key, values|
+        name = key.name.match(/^.+\\([^\\]+)$/).captures[0]
+
+        [MsiPackage, ExePackage].find do |klass|
+          if pkg = klass.from_registry(name, values)
+            yield pkg
+          end
+        end
+      end
+    end
+
+    # Yield each registry key and its values associated with an
+    # installed package. This searches both per-machine and current
+    # user contexts, as well as packages associated with 64 and
+    # 32-bit installers.
+    def self.with_key(&block)
+      %w[HKEY_LOCAL_MACHINE HKEY_CURRENT_USER].each do |hive|
+        [KEY64, KEY32].each do |mode|
+          mode |= KEY_READ
+          begin
+            open(hive, 'Software\Microsoft\Windows\CurrentVersion\Uninstall', mode) do |uninstall|
+              uninstall.each_key do |name, wtime|
+                open(hive, "#{uninstall.keyname}\\#{name}", mode) do |key|
+                  yield key, values(key)
+                end
+              end
+            end
+          rescue Puppet::Util::Windows::Error => e
+            raise e unless e.code == Puppet::Util::Windows::Error::ERROR_FILE_NOT_FOUND
+          end
+        end
+      end
+    end
+
+    # Get the class that knows how to install this resource
+    def self.installer_class(resource)
+      fail("The source parameter is required when using the Windows provider.") unless resource[:source]
+
+      case resource[:source]
+      when /\.msi"?\Z/i
+        # REMIND: can we install from URL?
+        # REMIND: what about msp, etc
+        MsiPackage
+      when /\.exe"?\Z/i
+        fail("The source does not exist: '#{resource[:source]}'") unless Puppet::FileSystem.exist?(resource[:source])
+        ExePackage
+      else
+        fail("Don't know how to install '#{resource[:source]}'")
+      end
+    end
+
+    def self.munge(value)
+      quote(replace_forward_slashes(value))
+    end
+
+    def self.replace_forward_slashes(value)
+      if value.include?('/')
+        value.gsub!('/', "\\") 
+        Puppet.debug('Package source parameter contained /s - replaced with \\s')
+      end
+      value
+    end
+
+    def self.quote(value)
+      value.include?(' ') ? %Q["#{value.gsub(/"/, '\"')}"] : value
+    end
+
+    def initialize(name, version)
+      @name = name
+      @version = version
+    end
+  end
+end
+
+require 'puppet/provider/package/windows/msi_package'
+require 'puppet/provider/package/windows/exe_package'
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/yum.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/yum.rb
new file mode 100644
index 0000000..bfbe9df
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/yum.rb
@@ -0,0 +1,199 @@
+require 'puppet/util/package'
+
+Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do
+  desc "Support via `yum`.
+
+  Using this provider's `uninstallable` feature will not remove dependent packages. To
+  remove dependent packages with this provider use the `purgeable` feature, but note this
+  feature is destructive and should be used with the utmost care.
+
+  This provider supports the `install_options` attribute, which allows command-line flags to be passed to yum.
+  These options should be specified as a string (e.g. '--flag'), a hash (e.g. {'--flag' => 'value'}),
+  or an array where each element is either a string or a hash."
+
+  has_feature :install_options, :versionable, :virtual_packages
+
+  commands :yum => "yum", :rpm => "rpm", :python => "python"
+
+  self::YUMHELPER = File::join(File::dirname(__FILE__), "yumhelper.py")
+
+  if command('rpm')
+    confine :true => begin
+      rpm('--version')
+      rescue Puppet::ExecutionFailure
+        false
+      else
+        true
+      end
+  end
+
+  defaultfor :osfamily => :redhat
+
+  def self.prefetch(packages)
+    raise Puppet::Error, "The yum provider can only be used as root" if Process.euid != 0
+    super
+  end
+
+  # Retrieve the latest package version information for a given package name
+  # and combination of repos to enable and disable.
+  #
+  # @note If multiple package versions are defined (such as in the case where a
+  #   package is built for multiple architectures), the first package found
+  #   will be used.
+  #
+  # @api private
+  # @param package [String] The name of the package to query
+  # @param enablerepo [Array<String>] A list of repositories to enable for this query
+  # @param disablerepo [Array<String>] A list of repositories to disable for this query
+  # @return [Hash<Symbol, String>]
+  def self.latest_package_version(package, enablerepo, disablerepo)
+
+    key = [enablerepo, disablerepo]
+
+    @latest_versions ||= {}
+    if @latest_versions[key].nil?
+      @latest_versions[key] = fetch_latest_versions(enablerepo, disablerepo)
+    end
+
+    if @latest_versions[key][package]
+      @latest_versions[key][package].first
+    end
+  end
+
+  # Search for all installed packages that have newer versions, given a
+  # combination of repositories to enable and disable.
+  #
+  # @api private
+  # @param enablerepo [Array<String>] A list of repositories to enable for this query
+  # @param disablerepo [Array<String>] A list of repositories to disable for this query
+  # @return [Hash<String, Array<Hash<String, String>>>] All packages that were
+  #   found with a list of found versions for each package.
+  def self.fetch_latest_versions(enablerepo, disablerepo)
+    latest_versions = Hash.new {|h, k| h[k] = []}
+
+    args = [self::YUMHELPER]
+    args.concat(enablerepo.map { |repo| ['-e', repo] }.flatten)
+    args.concat(disablerepo.map { |repo| ['-d', repo] }.flatten)
+
+    python(args).scan(/^_pkg (.*)$/) do |match|
+      hash = nevra_to_hash(match[0])
+
+      # Create entries for both the package name without a version and a
+      # version since yum considers those as mostly interchangeable.
+      short_name = hash[:name]
+      long_name  = "#{hash[:name]}.#{hash[:arch]}"
+
+      latest_versions[short_name] << hash
+      latest_versions[long_name]  << hash
+    end
+    latest_versions
+  end
+
+  def self.clear
+    @latest_versions = nil
+  end
+
+  def install
+    wanted = @resource[:name]
+    # If not allowing virtual packages, do a query to ensure a real package exists
+    unless @resource.allow_virtual?
+      yum *['-d', '0', '-e', '0', '-y', install_options, :list, wanted].compact
+    end
+
+    should = @resource.should(:ensure)
+    self.debug "Ensuring => #{should}"
+    operation = :install
+
+    case should
+    when true, false, Symbol
+      # pass
+      should = nil
+    else
+      # Add the package version
+      wanted += "-#{should}"
+      is = self.query
+      if is && Puppet::Util::Package.versioncmp(should, is[:ensure]) < 0
+        self.debug "Downgrading package #{@resource[:name]} from version #{is[:ensure]} to #{should}"
+        operation = :downgrade
+      end
+    end
+
+    args = ["-d", "0", "-e", "0", "-y", install_options, operation, wanted].compact
+    yum *args
+
+
+    # If a version was specified, query again to see if it is a matching version
+    if should
+      is = self.query
+      raise Puppet::Error, "Could not find package #{self.name}" unless is
+
+      # FIXME: Should we raise an exception even if should == :latest
+      # and yum updated us to a version other than @param_hash[:ensure] ?
+      raise Puppet::Error, "Failed to update to version #{should}, got version #{is[:ensure]} instead" if should != is[:ensure]
+    end
+  end
+
+  # What's the latest package version available?
+  def latest
+    upd = self.class.latest_package_version(@resource[:name], enablerepo, disablerepo)
+    unless upd.nil?
+      # FIXME: there could be more than one update for a package
+      # because of multiarch
+      return "#{upd[:epoch]}:#{upd[:version]}-#{upd[:release]}"
+    else
+      # Yum didn't find updates, pretend the current
+      # version is the latest
+      raise Puppet::DevError, "Tried to get latest on a missing package" if properties[:ensure] == :absent
+      return properties[:ensure]
+    end
+  end
+
+  def update
+    # Install in yum can be used for update, too
+    self.install
+  end
+
+  def purge
+    yum "-y", :erase, @resource[:name]
+  end
+
+  # @deprecated
+  def latest_info
+    Puppet.deprecation_warning("#{self.class}##{__method__} is deprecated and is no longer used.")
+    @latest_info
+  end
+
+  # @deprecated
+  def latest_info=(latest)
+    Puppet.deprecation_warning("#{self.class}##{__method__} is deprecated and is no longer used.")
+    @latest_info = latest
+  end
+
+  private
+
+  def enablerepo
+    scan_options(resource[:install_options], '--enablerepo')
+  end
+
+  def disablerepo
+    scan_options(resource[:install_options], '--disablerepo')
+  end
+
+  # Scan a structure that looks like the package type 'install_options'
+  # structure for all hashes that have a specific key.
+  #
+  # @api private
+  # @param options [Array<String | Hash>, nil] The options structure. If the
+  #   options are nil an empty array will be returned.
+  # @param key [String] The key to look for in all contained hashes
+  # @return [Array<String>] All hash values with the given key.
+  def scan_options(options, key)
+    return [] if options.nil?
+    options.inject([]) do |repos, opt|
+      if opt.is_a? Hash and opt[key]
+        repos << opt[key]
+      end
+      repos
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/yumhelper.py b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/yumhelper.py
new file mode 100644
index 0000000..a1f3f68
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/yumhelper.py
@@ -0,0 +1,159 @@
+# Python helper script to query for the packages that have
+# pending updates. Called by the yum package provider
+#
+# (C) 2007 Red Hat Inc.
+# David Lutterkort <dlutter @redhat.com>
+
+import sys
+import string
+import re
+
+# this maintains compatibility with really old platforms with python 1.x
+from os import popen, WEXITSTATUS
+
+# Try to use the yum libraries by default, but shell out to the yum executable
+# if they are not present (i.e. yum <= 2.0). This is only required for RHEL3
+# and earlier that do not support later versions of Yum. Once RHEL3 is EOL,
+# shell_out() and related code can be removed.
+try:
+    import yum
+except ImportError:
+    useyumlib = 0
+else:
+    useyumlib = 1
+
+OVERRIDE_OPTS = {
+    'debuglevel': 0,
+    'errorlevel': 0,
+    'logfile': '/dev/null'
+}
+
+enable = []
+disable = []
+args = list(sys.argv)
+
+while len(args) > 0:
+    a = args.pop(0)
+
+    if a == "-d":
+        if len(args) < 1:
+            raise ValueError, a
+        next = args.pop(0)
+        disable.extend( next.split(",") )
+    if a == "-e":
+        if len(args) < 1:
+            raise ValueError, a
+        next = args.pop(0)
+        enable.extend( next.split(",") )
+
+def pkg_lists(my):
+    my.doConfigSetup()
+
+    for k in OVERRIDE_OPTS.keys():
+        if hasattr(my.conf, k):
+            setattr(my.conf, k, OVERRIDE_OPTS[k])
+        else:
+            my.conf.setConfigOption(k, OVERRIDE_OPTS[k])
+
+    my.doTsSetup()
+    my.doRpmDBSetup()
+
+    # Yum 2.2/2.3 python libraries require a couple of extra function calls to setup package sacks.
+    # They also don't have a __version__ attribute
+    try:
+        yumver = yum.__version__
+    except AttributeError:
+        my.doRepoSetup()
+        my.doSackSetup()
+
+    return my.doPackageLists('updates')
+
+def shell_out():
+    try:
+        repostring = ""
+        if disable:
+            repostring += " '--disablerepo=%s'" % ",".join(disable)
+        if enable:
+            repostring += " '--disablerepo=%s'" % ",".join(enable)
+        p = popen("/usr/bin/env yum%s check-update 2>&1" % repostring)
+        output = p.readlines()
+        rc = p.close()
+
+        if rc is not None:
+            # None represents exit code of 0, otherwise the exit code is in the
+            # format returned by wait(). Exit code of 100 from yum represents
+            # updates available.
+            if WEXITSTATUS(rc) != 100:
+                return WEXITSTATUS(rc)
+        else:
+            # Exit code is None (0), no updates waiting so don't both parsing output
+            return 0
+
+        # Yum prints a line of hyphens (old versions) or a blank line between
+        # headers and package data, so skip everything before them
+        skipheaders = 0
+        for line in output:
+            if not skipheaders:
+                if re.compile("^((-){80}|)$").search(line):
+                    skipheaders = 1
+                continue
+
+            # Skip any blank lines
+            if re.compile("^[ \t]*$").search(line):
+                continue
+
+            # Format is:
+            # Yum 1.x: name arch (epoch:)?version
+            # Yum 2.0: name arch (epoch:)?version repo
+            # epoch is optional if 0
+
+            p = string.split(line)
+            pname = p[0]
+            parch = p[1]
+            pevr = p[2]
+
+            # Separate out epoch:version-release
+            evr_re = re.compile("^(\d:)?(\S+)-(\S+)$")
+            evr = evr_re.match(pevr)
+
+            pepoch = ""
+            if evr.group(1) is None:
+                pepoch = "0"
+            else:
+                pepoch = evr.group(1).replace(":", "")
+            pversion = evr.group(2)
+            prelease = evr.group(3)
+
+            print "_pkg", pname, pepoch, pversion, prelease, parch
+
+        return 0
+    except:
+        print sys.exc_info()[0]
+        return 1
+
+if useyumlib:
+    try:
+        try:
+            my = yum.YumBase()
+
+            for repo in disable:
+                my.repos.disableRepo(repo)
+
+            for repo in enable:
+                my.repos.enableRepo(repo)
+
+            ypl = pkg_lists(my)
+            for pkg in ypl.updates:
+                print "_pkg %s %s %s %s %s" % (pkg.name, pkg.epoch, pkg.version, pkg.release, pkg.arch)
+        finally:
+            my.closeRpmDB()
+    except IOError, e:
+        print "_err IOError %d %s" % (e.errno, e)
+        sys.exit(1)
+    except AttributeError, e:
+        # catch yumlib errors in buggy 2.x versions of yum
+        print "_err AttributeError %s" % e
+        sys.exit(1)
+else:
+    rc = shell_out()
+    sys.exit(rc)
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/zypper.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/zypper.rb
new file mode 100644
index 0000000..fc73b41
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/package/zypper.rb
@@ -0,0 +1,100 @@
+Puppet::Type.type(:package).provide :zypper, :parent => :rpm do
+  desc "Support for SuSE `zypper` package manager. Found in SLES10sp2+ and SLES11.
+
+    This provider supports the `install_options` attribute, which allows command-line flags to be passed to zypper.
+    These options should be specified as a string (e.g. '--flag'), a hash (e.g. {'--flag' => 'value'}),
+    or an array where each element is either a string or a hash."
+
+  has_feature :versionable, :install_options, :virtual_packages
+
+  commands :zypper => "/usr/bin/zypper"
+
+  confine    :operatingsystem => [:suse, :sles, :sled, :opensuse]
+
+  #on zypper versions <1.0, the version option returns 1
+  #some versions of zypper output on stderr
+  def zypper_version
+    cmd = [self.class.command(:zypper),"--version"]
+    execute(cmd, { :failonfail => false, :combine => true})
+  end
+
+  # Install a package using 'zypper'.
+  def install
+    should = @resource.should(:ensure)
+    self.debug "Ensuring => #{should}"
+    wanted = @resource[:name]
+
+    # XXX: We don't actually deal with epochs here.
+    case should
+    when true, false, Symbol
+      should = nil
+    else
+      # Add the package version
+      wanted = "#{wanted}-#{should}"
+    end
+
+    #This has been tested with following zypper versions
+    #SLE 10.4: 0.6.201
+    #SLE 11.3: 1.6.307
+    #SLE 12.0: 1.11.14
+    #Assume that this will work on newer zypper versions
+
+    #extract version numbers and convert to integers
+    major, minor, patch = zypper_version.scan(/\d+/).map{ |x| x.to_i }
+    self.debug "Detected zypper version #{major}.#{minor}.#{patch}"
+
+    #zypper version < 1.0 does not support --quiet flag
+    if major < 1
+      quiet = '--terse'
+    else
+      quiet = '--quiet'
+    end
+
+    inst_opts = []
+    inst_opts = install_options if resource[:install_options]
+
+
+    options = []
+    options << quiet
+    options << '--no-gpg-check' unless inst_opts.delete('--no-gpg-check').nil?
+    options << :install
+
+    #zypper 0.6.13 (OpenSuSE 10.2) does not support auto agree with licenses
+    options << '--auto-agree-with-licenses' unless major < 1 and minor <= 6 and patch <= 13
+    options << '--no-confirm'
+    options += inst_opts unless inst_opts.empty?
+
+    # Zypper 0.6.201 doesn't recognize '--name'
+    # It is unclear where this functionality was introduced, but it
+    # is present as early as 1.0.13
+    options << '--name' unless major < 1 || @resource.allow_virtual? || should
+    options << wanted
+
+    zypper *options
+
+    unless self.query
+      raise Puppet::ExecutionFailure.new(
+        "Could not find package #{self.name}"
+      )
+    end
+  end
+
+  # What's the latest package version available?
+  def latest
+    #zypper can only get a list of *all* available packages?
+    output = zypper "list-updates"
+
+    if output =~ /#{Regexp.escape @resource[:name]}\s*\|.*?\|\s*([^\s\|]+)/
+      return $1
+    else
+      # zypper didn't find updates, pretend the current
+      # version is the latest
+      return @property_hash[:ensure]
+    end
+  end
+
+  def update
+    # zypper install can be used for update, too
+    self.install
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/parsedfile.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/parsedfile.rb
new file mode 100644
index 0000000..37d0ec4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/parsedfile.rb
@@ -0,0 +1,459 @@
+require 'puppet'
+require 'puppet/util/filetype'
+require 'puppet/util/fileparsing'
+
+# This provider can be used as the parent class for a provider that
+# parses and generates files.  Its content must be loaded via the
+# 'prefetch' method, and the file will be written when 'flush' is called
+# on the provider instance.  At this point, the file is written once
+# for every provider instance.
+#
+# Once the provider prefetches the data, it's the resource's job to copy
+# that data over to the @is variables.
+class Puppet::Provider::ParsedFile < Puppet::Provider
+  extend Puppet::Util::FileParsing
+
+  class << self
+    attr_accessor :default_target, :target
+  end
+
+  attr_accessor :property_hash
+
+  def self.clean(hash)
+    newhash = hash.dup
+    [:record_type, :on_disk].each do |p|
+      newhash.delete(p) if newhash.include?(p)
+    end
+
+    newhash
+  end
+
+  def self.clear
+    @target_objects.clear
+    @records.clear
+  end
+
+  def self.filetype
+    @filetype ||= Puppet::Util::FileType.filetype(:flat)
+  end
+
+  def self.filetype=(type)
+    if type.is_a?(Class)
+      @filetype = type
+    elsif klass = Puppet::Util::FileType.filetype(type)
+      @filetype = klass
+    else
+      raise ArgumentError, "Invalid filetype #{type}"
+    end
+  end
+
+  # Flush all of the targets for which there are modified records.  The only
+  # reason we pass a record here is so that we can add it to the stack if
+  # necessary -- it's passed from the instance calling 'flush'.
+  def self.flush(record)
+    # Make sure this record is on the list to be flushed.
+    unless record[:on_disk]
+      record[:on_disk] = true
+      @records << record
+
+      # If we've just added the record, then make sure our
+      # target will get flushed.
+      modified(record[:target] || default_target)
+    end
+
+    return unless defined?(@modified) and ! @modified.empty?
+
+    flushed = []
+    begin
+      @modified.sort { |a,b| a.to_s <=> b.to_s }.uniq.each do |target|
+        Puppet.debug "Flushing #{@resource_type.name} provider target #{target}"
+        flushed << target
+        flush_target(target)
+      end
+    ensure
+      @modified.reject! { |t| flushed.include?(t) }
+    end
+  end
+
+  # Make sure our file is backed up, but only back it up once per transaction.
+  # We cheat and rely on the fact that @records is created on each prefetch.
+  def self.backup_target(target)
+    return nil unless target_object(target).respond_to?(:backup)
+
+    @backup_stats ||= {}
+    return nil if @backup_stats[target] == @records.object_id
+
+    target_object(target).backup
+    @backup_stats[target] = @records.object_id
+  end
+
+  # Flush all of the records relating to a specific target.
+  def self.flush_target(target)
+    backup_target(target)
+
+    records = target_records(target).reject { |r|
+      r[:ensure] == :absent
+    }
+
+    target_object(target).write(to_file(records))
+  end
+
+  # Return the header placed at the top of each generated file, warning
+  # users that modifying this file manually is probably a bad idea.
+  def self.header
+%{# HEADER: This file was autogenerated at #{Time.now}
+# HEADER: by puppet.  While it can still be managed manually, it
+# HEADER: is definitely not recommended.\n}
+  end
+
+  # An optional regular expression matched by third party headers.
+  #
+  # For example, this can be used to filter the vixie cron headers as
+  # erronously exported by older cron versions.
+  #
+  # @api private
+  # @abstract Providers based on ParsedFile may implement this to make it
+  #   possible to identify a header maintained by a third party tool.
+  #   The provider can then allow that header to remain near the top of the
+  #   written file, or remove it after composing the file content.
+  #   If implemented, the function must return a Regexp object.
+  #   The expression must be tailored to match exactly one third party header.
+  # @see drop_native_header
+  # @note When specifying regular expressions in multiline mode, avoid
+  #   greedy repititions such as '.*' (use .*? instead). Otherwise, the
+  #   provider may drop file content between sparse headers.
+  def self.native_header_regex
+    nil
+  end
+
+  # How to handle third party headers.
+  # @api private
+  # @abstract Providers based on ParsedFile that make use of the support for
+  #   third party headers may override this method to return +true+.
+  #   When this is done, headers that are matched by the native_header_regex
+  #   are not written back to disk.
+  # @see native_header_regex
+  def self.drop_native_header
+    false
+  end
+
+  # Add another type var.
+  def self.initvars
+    @records = []
+    @target_objects = {}
+
+    @target = nil
+
+    # Default to flat files
+    @filetype ||= Puppet::Util::FileType.filetype(:flat)
+    super
+  end
+
+  # Return a list of all of the records we can find.
+  def self.instances
+    targets.collect do |target|
+      prefetch_target(target)
+    end.flatten.reject { |r| skip_record?(r) }.collect do |record|
+      new(record)
+    end
+  end
+
+  # Override the default method with a lot more functionality.
+  def self.mk_resource_methods
+    [resource_type.validproperties, resource_type.parameters].flatten.each do |attr|
+      attr = attr.intern
+      define_method(attr) do
+        # If it's not a valid field for this record type (which can happen
+        # when different platforms support different fields), then just
+        # return the should value, so the resource shuts up.
+        if @property_hash[attr] or self.class.valid_attr?(self.class.name, attr)
+          @property_hash[attr] || :absent
+        else
+          if defined?(@resource)
+            @resource.should(attr)
+          else
+            nil
+          end
+        end
+      end
+
+      define_method(attr.to_s + "=") do |val|
+        mark_target_modified
+        @property_hash[attr] = val
+      end
+    end
+  end
+
+  # Always make the resource methods.
+  def self.resource_type=(resource)
+    super
+    mk_resource_methods
+  end
+
+  # Mark a target as modified so we know to flush it.  This only gets
+  # used within the attr= methods.
+  def self.modified(target)
+    @modified ||= []
+    @modified << target unless @modified.include?(target)
+  end
+
+  # Retrieve all of the data from disk.  There are three ways to know
+  # which files to retrieve:  We might have a list of file objects already
+  # set up, there might be instances of our associated resource and they
+  # will have a path parameter set, and we will have a default path
+  # set.  We need to turn those three locations into a list of files,
+  # prefetch each one, and make sure they're associated with each appropriate
+  # resource instance.
+  def self.prefetch(resources = nil)
+    # Reset the record list.
+    @records = prefetch_all_targets(resources)
+
+    match_providers_with_resources(resources)
+  end
+
+  # Match a list of catalog resources with provider instances
+  #
+  # @api private
+  #
+  # @param [Array<Puppet::Resource>] resources A list of resources using this class as a provider
+  def self.match_providers_with_resources(resources)
+    return unless resources
+    matchers = resources.dup
+    @records.each do |record|
+      # Skip things like comments and blank lines
+      next if skip_record?(record)
+
+      if (resource = resource_for_record(record, resources))
+        resource.provider = new(record)
+      elsif respond_to?(:match)
+        if resource = match(record, matchers)
+          matchers.delete(resource.title)
+          record[:name] = resource[:name]
+          resource.provider = new(record)
+        end
+      end
+    end
+  end
+
+  # Look up a resource based on a parsed file record
+  #
+  # @api private
+  #
+  # @param [Hash<Symbol, Object>] record
+  # @param [Array<Puppet::Resource>] resources
+  #
+  # @return [Puppet::Resource, nil] The resource if found, else nil
+  def self.resource_for_record(record, resources)
+    name = record[:name]
+    if name
+      resources[name]
+    end
+  end
+
+  def self.prefetch_all_targets(resources)
+    records = []
+    targets(resources).each do |target|
+      records += prefetch_target(target)
+    end
+    records
+  end
+
+  # Prefetch an individual target.
+  def self.prefetch_target(target)
+
+    begin
+      target_records = retrieve(target)
+    rescue Puppet::Util::FileType::FileReadError => detail
+      puts detail.backtrace if Puppet[:trace]
+      Puppet.err "Could not prefetch #{self.resource_type.name} provider '#{self.name}' target '#{target}': #{detail}. Treating as empty"
+      target_records = []
+    end
+
+    target_records.each do |r|
+      r[:on_disk] = true
+      r[:target] = target
+      r[:ensure] = :present
+    end
+
+    target_records = prefetch_hook(target_records) if respond_to?(:prefetch_hook)
+
+    raise Puppet::DevError, "Prefetching #{target} for provider #{self.name} returned nil" unless target_records
+
+    target_records
+  end
+
+  # Is there an existing record with this name?
+  def self.record?(name)
+    return nil unless @records
+    @records.find { |r| r[:name] == name }
+  end
+
+  # Retrieve the text for the file. Returns nil in the unlikely
+  # event that it doesn't exist.
+  def self.retrieve(path)
+    # XXX We need to be doing something special here in case of failure.
+    text = target_object(path).read
+    if text.nil? or text == ""
+      # there is no file
+      return []
+    else
+      # Set the target, for logging.
+      old = @target
+      begin
+        @target = path
+        return self.parse(text)
+      rescue Puppet::Error => detail
+        detail.file = @target if detail.respond_to?(:file=)
+        raise detail
+      ensure
+        @target = old
+      end
+    end
+  end
+
+  # Should we skip the record?  Basically, we skip text records.
+  # This is only here so subclasses can override it.
+  def self.skip_record?(record)
+    record_type(record[:record_type]).text?
+  end
+
+  # The mode for generated files if they are newly created.
+  # No mode will be set on existing files.
+  #
+  # @abstract Providers inheriting parsedfile can override this method
+  #   to provide a mode. The value should be suitable for File.chmod
+  def self.default_mode
+    nil
+  end
+
+  # Initialize the object if necessary.
+  def self.target_object(target)
+    # only send the default mode if the actual provider defined it,
+    # because certain filetypes (e.g. the crontab variants) do not
+    # expect it in their initialize method
+    if default_mode
+      @target_objects[target] ||= filetype.new(target, default_mode)
+    else
+      @target_objects[target] ||= filetype.new(target)
+    end
+
+    @target_objects[target]
+  end
+
+  # Find all of the records for a given target
+  def self.target_records(target)
+    @records.find_all { |r| r[:target] == target }
+  end
+
+  # Find a list of all of the targets that we should be reading.  This is
+  # used to figure out what targets we need to prefetch.
+  def self.targets(resources = nil)
+    targets = []
+    # First get the default target
+    raise Puppet::DevError, "Parsed Providers must define a default target" unless self.default_target
+    targets << self.default_target
+
+    # Then get each of the file objects
+    targets += @target_objects.keys
+
+    # Lastly, check the file from any resource instances
+    if resources
+      resources.each do |name, resource|
+        if value = resource.should(:target)
+          targets << value
+        end
+      end
+    end
+
+    targets.uniq.compact
+  end
+
+  # Compose file contents from the set of records.
+  #
+  # If self.native_header_regex is not nil, possible vendor headers are
+  # identified by matching the return value against the expression.
+  # If one (or several consecutive) such headers, are found, they are
+  # either moved in front of the self.header if self.drop_native_header
+  # is false (this is the default), or removed from the return value otherwise.
+  #
+  # @api private
+  def self.to_file(records)
+    text = super
+    if native_header_regex and (match = text.match(native_header_regex))
+      if drop_native_header
+        # concatenate the text in front of and after the native header
+        text = match.pre_match + match.post_match
+      else
+        native_header = match[0]
+        return native_header + header + match.pre_match + match.post_match
+      end
+    end
+    header + text
+  end
+
+  def create
+    @resource.class.validproperties.each do |property|
+      if value = @resource.should(property)
+        @property_hash[property] = value
+      end
+    end
+    mark_target_modified
+    (@resource.class.name.to_s + "_created").intern
+  end
+
+  def destroy
+    # We use the method here so it marks the target as modified.
+    self.ensure = :absent
+    (@resource.class.name.to_s + "_deleted").intern
+  end
+
+  def exists?
+    !(@property_hash[:ensure] == :absent or @property_hash[:ensure].nil?)
+  end
+
+  # Write our data to disk.
+  def flush
+    # Make sure we've got a target and name set.
+
+    # If the target isn't set, then this is our first modification, so
+    # mark it for flushing.
+    unless @property_hash[:target]
+      @property_hash[:target] = @resource.should(:target) || self.class.default_target
+      self.class.modified(@property_hash[:target])
+    end
+    @resource.class.key_attributes.each do |attr|
+      @property_hash[attr] ||= @resource[attr]
+    end
+
+    self.class.flush(@property_hash)
+  end
+
+  def initialize(record)
+    super
+
+    # The 'record' could be a resource or a record, depending on how the provider
+    # is initialized.  If we got an empty property hash (probably because the resource
+    # is just being initialized), then we want to set up some defaults.
+    @property_hash = self.class.record?(resource[:name]) || {:record_type => self.class.name, :ensure => :absent} if @property_hash.empty?
+  end
+
+  # Retrieve the current state from disk.
+  def prefetch
+    raise Puppet::DevError, "Somehow got told to prefetch with no resource set" unless @resource
+    self.class.prefetch(@resource[:name] => @resource)
+  end
+
+  def record_type
+    @property_hash[:record_type]
+  end
+
+  private
+
+  # Mark both the resource and provider target as modified.
+  def mark_target_modified
+    if defined?(@resource) and restarget = @resource.should(:target) and restarget != @property_hash[:target]
+      self.class.modified(restarget)
+    end
+    self.class.modified(@property_hash[:target]) if @property_hash[:target] != :absent and @property_hash[:target]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/scheduled_task/win32_taskscheduler.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/scheduled_task/win32_taskscheduler.rb
new file mode 100644
index 0000000..5721b18
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/scheduled_task/win32_taskscheduler.rb
@@ -0,0 +1,583 @@
+require 'puppet/parameter'
+
+if Puppet.features.microsoft_windows?
+  require 'puppet/util/windows/taskscheduler'
+end
+
+Puppet::Type.type(:scheduled_task).provide(:win32_taskscheduler) do
+  desc %q{This provider manages scheduled tasks on Windows.}
+
+  defaultfor :operatingsystem => :windows
+  confine    :operatingsystem => :windows
+
+  MINUTES_IN_DAY = 1440
+
+  def self.instances
+    Win32::TaskScheduler.new.tasks.collect do |job_file|
+      job_title = File.basename(job_file, '.job')
+
+      new(
+        :provider => :win32_taskscheduler,
+        :name     => job_title
+      )
+    end
+  end
+
+  def exists?
+    Win32::TaskScheduler.new.exists? resource[:name]
+  end
+
+  def task
+    return @task if @task
+
+    @task ||= Win32::TaskScheduler.new
+    @task.activate(resource[:name] + '.job') if exists?
+
+    @task
+  end
+
+  def clear_task
+    @task       = nil
+    @triggers   = nil
+  end
+
+  def enabled
+    task.flags & Win32::TaskScheduler::DISABLED == 0 ? :true : :false
+  end
+
+  def command
+    task.application_name
+  end
+
+  def arguments
+    task.parameters
+  end
+
+  def working_dir
+    task.working_directory
+  end
+
+  def user
+    account = task.account_information
+    return 'system' if account == ''
+    account
+  end
+
+  def trigger
+    return @triggers if @triggers
+
+    @triggers   = []
+    task.trigger_count.times do |i|
+      trigger = begin
+                  task.trigger(i)
+                rescue Win32::TaskScheduler::Error
+                  # Win32::TaskScheduler can't handle all of the
+                  # trigger types Windows uses, so we need to skip the
+                  # unhandled types to prevent "puppet resource" from
+                  # blowing up.
+                  nil
+                end
+      next unless trigger and scheduler_trigger_types.include?(trigger['trigger_type'])
+      puppet_trigger = {}
+      case trigger['trigger_type']
+      when Win32::TaskScheduler::TASK_TIME_TRIGGER_DAILY
+        puppet_trigger['schedule'] = 'daily'
+        puppet_trigger['every']    = trigger['type']['days_interval'].to_s
+      when Win32::TaskScheduler::TASK_TIME_TRIGGER_WEEKLY
+        puppet_trigger['schedule']    = 'weekly'
+        puppet_trigger['every']       = trigger['type']['weeks_interval'].to_s
+        puppet_trigger['day_of_week'] = days_of_week_from_bitfield(trigger['type']['days_of_week'])
+      when Win32::TaskScheduler::TASK_TIME_TRIGGER_MONTHLYDATE
+        puppet_trigger['schedule'] = 'monthly'
+        puppet_trigger['months']   = months_from_bitfield(trigger['type']['months'])
+        puppet_trigger['on']       = days_from_bitfield(trigger['type']['days'])
+      when Win32::TaskScheduler::TASK_TIME_TRIGGER_MONTHLYDOW
+        puppet_trigger['schedule']         = 'monthly'
+        puppet_trigger['months']           = months_from_bitfield(trigger['type']['months'])
+        puppet_trigger['which_occurrence'] = occurrence_constant_to_name(trigger['type']['weeks'])
+        puppet_trigger['day_of_week']      = days_of_week_from_bitfield(trigger['type']['days_of_week'])
+      when Win32::TaskScheduler::TASK_TIME_TRIGGER_ONCE
+        puppet_trigger['schedule'] = 'once'
+      end
+      puppet_trigger['start_date'] = self.class.normalized_date("#{trigger['start_year']}-#{trigger['start_month']}-#{trigger['start_day']}")
+      puppet_trigger['start_time'] = self.class.normalized_time("#{trigger['start_hour']}:#{trigger['start_minute']}")
+      puppet_trigger['enabled']    = trigger['flags'] & Win32::TaskScheduler::TASK_TRIGGER_FLAG_DISABLED == 0
+      puppet_trigger['minutes_interval'] = trigger['minutes_interval'] ||= 0
+      puppet_trigger['minutes_duration'] = trigger['minutes_duration'] ||= 0
+      puppet_trigger['index']      = i
+
+      @triggers << puppet_trigger
+    end
+
+    @triggers
+  end
+
+  def user_insync?(current, should)
+    return false unless current
+
+    # Win32::TaskScheduler can return the 'SYSTEM' account as the
+    # empty string.
+    current = 'system' if current == ''
+
+    # By comparing account SIDs we don't have to worry about case
+    # sensitivity, or canonicalization of the account name.
+    Puppet::Util::Windows::SID.name_to_sid(current) == Puppet::Util::Windows::SID.name_to_sid(should[0])
+  end
+
+  def trigger_insync?(current, should)
+    should  = [should] unless should.is_a?(Array)
+    current = [current] unless current.is_a?(Array)
+    return false unless current.length == should.length
+
+    current_in_sync = current.all? do |c|
+      should.any? {|s| triggers_same?(c, s)}
+    end
+
+    should_in_sync = should.all? do |s|
+      current.any? {|c| triggers_same?(c,s)}
+    end
+
+    current_in_sync && should_in_sync
+  end
+
+  def command=(value)
+    task.application_name = value
+  end
+
+  def arguments=(value)
+    task.parameters = value
+  end
+
+  def working_dir=(value)
+    task.working_directory = value
+  end
+
+  def enabled=(value)
+    if value == :true
+      task.flags = task.flags & ~Win32::TaskScheduler::DISABLED
+    else
+      task.flags = task.flags | Win32::TaskScheduler::DISABLED
+    end
+  end
+
+  def trigger=(value)
+    desired_triggers = value.is_a?(Array) ? value : [value]
+    current_triggers = trigger.is_a?(Array) ? trigger : [trigger]
+
+    extra_triggers = []
+    desired_to_search = desired_triggers.dup
+    current_triggers.each do |current|
+      if found = desired_to_search.find {|desired| triggers_same?(current, desired)}
+        desired_to_search.delete(found)
+      else
+        extra_triggers << current['index']
+      end
+    end
+
+    needed_triggers = []
+    current_to_search = current_triggers.dup
+    desired_triggers.each do |desired|
+      if found = current_to_search.find {|current| triggers_same?(current, desired)}
+        current_to_search.delete(found)
+      else
+        needed_triggers << desired
+      end
+    end
+
+    extra_triggers.reverse_each do |index|
+      task.delete_trigger(index)
+    end
+
+    needed_triggers.each do |trigger_hash|
+      # Even though this is an assignment, the API for
+      # Win32::TaskScheduler ends up appending this trigger to the
+      # list of triggers for the task, while #add_trigger is only able
+      # to replace existing triggers. *shrug*
+      task.trigger = translate_hash_to_trigger(trigger_hash)
+    end
+  end
+
+  def user=(value)
+    self.fail("Invalid user: #{value}") unless Puppet::Util::Windows::SID.name_to_sid(value)
+
+    if value.to_s.downcase != 'system'
+      task.set_account_information(value, resource[:password])
+    else
+      # Win32::TaskScheduler treats a nil/empty username & password as
+      # requesting the SYSTEM account.
+      task.set_account_information(nil, nil)
+    end
+  end
+
+  def create
+    clear_task
+    @task = Win32::TaskScheduler.new(resource[:name], dummy_time_trigger)
+    self.command = resource[:command]
+
+    [:arguments, :working_dir, :enabled, :trigger, :user].each do |prop|
+      send("#{prop}=", resource[prop]) if resource[prop]
+    end
+  end
+
+  def destroy
+    Win32::TaskScheduler.new.delete(resource[:name] + '.job')
+  end
+
+  def flush
+    unless resource[:ensure] == :absent
+      self.fail('Parameter command is required.') unless resource[:command]
+      task.save
+      @task = nil
+    end
+  end
+
+  def triggers_same?(current_trigger, desired_trigger)
+    return false unless current_trigger['schedule'] == desired_trigger['schedule']
+    return false if current_trigger.has_key?('enabled') && !current_trigger['enabled']
+
+    desired = desired_trigger.dup
+    desired['start_date']  ||= current_trigger['start_date']  if current_trigger.has_key?('start_date')
+    desired['every']       ||= current_trigger['every']       if current_trigger.has_key?('every')
+    desired['months']      ||= current_trigger['months']      if current_trigger.has_key?('months')
+    desired['on']          ||= current_trigger['on']          if current_trigger.has_key?('on')
+    desired['day_of_week'] ||= current_trigger['day_of_week'] if current_trigger.has_key?('day_of_week')
+
+    translate_hash_to_trigger(current_trigger) == translate_hash_to_trigger(desired)
+  end
+
+  def self.normalized_date(date_string)
+    date = Date.parse("#{date_string}")
+    "#{date.year}-#{date.month}-#{date.day}"
+  end
+
+  def self.normalized_time(time_string)
+    Time.parse("#{time_string}").strftime('%H:%M')
+  end
+
+  def dummy_time_trigger
+    now = Time.now
+    {
+      'flags'                   => 0,
+      'random_minutes_interval' => 0,
+      'end_day'                 => 0,
+      'end_year'                => 0,
+      'minutes_interval'        => 0,
+      'end_month'               => 0,
+      'minutes_duration'        => 0,
+      'start_year'              => now.year,
+      'start_month'             => now.month,
+      'start_day'               => now.day,
+      'start_hour'              => now.hour,
+      'start_minute'            => now.min,
+      'trigger_type'            => Win32::TaskScheduler::ONCE,
+    }
+  end
+
+  def translate_hash_to_trigger(puppet_trigger)
+    trigger = dummy_time_trigger
+
+    if puppet_trigger['enabled'] == false
+      trigger['flags'] |= Win32::TaskScheduler::TASK_TRIGGER_FLAG_DISABLED
+    else
+      trigger['flags'] &= ~Win32::TaskScheduler::TASK_TRIGGER_FLAG_DISABLED
+    end
+
+    extra_keys = puppet_trigger.keys.sort - ['index', 'enabled', 'schedule', 'start_date', 'start_time', 'every', 'months', 'on', 'which_occurrence', 'day_of_week', 'minutes_interval', 'minutes_duration']
+    self.fail "Unknown trigger option(s): #{Puppet::Parameter.format_value_for_display(extra_keys)}" unless extra_keys.empty?
+    self.fail "Must specify 'start_time' when defining a trigger" unless puppet_trigger['start_time']
+
+    case puppet_trigger['schedule']
+    when 'daily'
+      trigger['trigger_type'] = Win32::TaskScheduler::DAILY
+      trigger['type'] = {
+        'days_interval' => Integer(puppet_trigger['every'] || 1)
+      }
+    when 'weekly'
+      trigger['trigger_type'] = Win32::TaskScheduler::WEEKLY
+      trigger['type'] = {
+        'weeks_interval' => Integer(puppet_trigger['every'] || 1)
+      }
+
+      trigger['type']['days_of_week'] = if puppet_trigger['day_of_week']
+                                          bitfield_from_days_of_week(puppet_trigger['day_of_week'])
+                                        else
+                                          scheduler_days_of_week.inject(0) {|day_flags,day| day_flags |= day}
+                                        end
+    when 'monthly'
+      trigger['type'] = {
+        'months' => bitfield_from_months(puppet_trigger['months'] || (1..12).to_a),
+      }
+
+      if puppet_trigger.keys.include?('on')
+        if puppet_trigger.has_key?('day_of_week') or puppet_trigger.has_key?('which_occurrence')
+          self.fail "Neither 'day_of_week' nor 'which_occurrence' can be specified when creating a monthly date-based trigger"
+        end
+
+        trigger['trigger_type'] = Win32::TaskScheduler::MONTHLYDATE
+        trigger['type']['days'] = bitfield_from_days(puppet_trigger['on'])
+      elsif puppet_trigger.keys.include?('which_occurrence') or puppet_trigger.keys.include?('day_of_week')
+        self.fail 'which_occurrence cannot be specified as an array' if puppet_trigger['which_occurrence'].is_a?(Array)
+        %w{day_of_week which_occurrence}.each do |field|
+          self.fail "#{field} must be specified when creating a monthly day-of-week based trigger" unless puppet_trigger.has_key?(field)
+        end
+
+        trigger['trigger_type']         = Win32::TaskScheduler::MONTHLYDOW
+        trigger['type']['weeks']        = occurrence_name_to_constant(puppet_trigger['which_occurrence'])
+        trigger['type']['days_of_week'] = bitfield_from_days_of_week(puppet_trigger['day_of_week'])
+      else
+        self.fail "Don't know how to create a 'monthly' schedule with the options: #{puppet_trigger.keys.sort.join(', ')}"
+      end
+    when 'once'
+      self.fail "Must specify 'start_date' when defining a one-time trigger" unless puppet_trigger['start_date']
+
+      trigger['trigger_type'] = Win32::TaskScheduler::ONCE
+    else
+      self.fail "Unknown schedule type: #{puppet_trigger["schedule"].inspect}"
+    end
+
+    integer_interval = -1
+    if puppet_trigger['minutes_interval']
+      integer_interval = Integer(puppet_trigger['minutes_interval'])
+      self.fail 'minutes_interval must be an integer greater or equal to 0' if integer_interval < 0
+      trigger['minutes_interval'] = integer_interval
+    end
+
+    integer_duration = -1
+    if puppet_trigger['minutes_duration']
+      integer_duration = Integer(puppet_trigger['minutes_duration'])
+      self.fail 'minutes_duration must be an integer greater than minutes_interval and equal to or greater than 0' if integer_duration <= integer_interval && integer_duration != 0
+      trigger['minutes_duration'] = integer_duration
+    end
+
+    if integer_interval > 0 && integer_duration == -1
+      integer_duration = MINUTES_IN_DAY
+      trigger['minutes_duration'] = MINUTES_IN_DAY
+    end
+
+    if integer_interval >= integer_duration && integer_interval > 0
+      self.fail 'minutes_interval cannot be set without minutes_duration also being set to a number greater than 0'
+    end
+
+    if start_date = puppet_trigger['start_date']
+      start_date = Date.parse(start_date)
+      self.fail "start_date must be on or after 1753-01-01" unless start_date >= Date.new(1753, 1, 1)
+
+      trigger['start_year']  = start_date.year
+      trigger['start_month'] = start_date.month
+      trigger['start_day']   = start_date.day
+    end
+
+    start_time = Time.parse(puppet_trigger['start_time'])
+    trigger['start_hour']   = start_time.hour
+    trigger['start_minute'] = start_time.min
+
+    trigger
+  end
+
+  def validate_trigger(value)
+    value = [value] unless value.is_a?(Array)
+
+    value.each do |t|
+      if t.has_key?('index')
+        self.fail "'index' is read-only on scheduled_task triggers and should be removed ('index' is usually provided in puppet resource scheduled_task)."
+      end
+
+      if t.has_key?('enabled')
+        self.fail "'enabled' is read-only on scheduled_task triggers and should be removed ('enabled' is usually provided in puppet resource scheduled_task)."
+      end
+
+      translate_hash_to_trigger(t)
+    end
+
+    true
+  end
+
+  private
+
+  def bitfield_from_months(months)
+    bitfield = 0
+
+    months = [months] unless months.is_a?(Array)
+    months.each do |month|
+      integer_month = Integer(month) rescue nil
+      self.fail 'Month must be specified as an integer in the range 1-12' unless integer_month == month.to_f and integer_month.between?(1,12)
+
+      bitfield |= scheduler_months[integer_month - 1]
+    end
+
+    bitfield
+  end
+
+  def bitfield_from_days(days)
+    bitfield = 0
+
+    days = [days] unless days.is_a?(Array)
+    days.each do |day|
+      # The special "day" of 'last' is represented by day "number"
+      # 32. 'last' has the special meaning of "the last day of the
+      # month", no matter how many days there are in the month.
+      day = 32 if day == 'last'
+
+      integer_day = Integer(day)
+      self.fail "Day must be specified as an integer in the range 1-31, or as 'last'" unless integer_day = day.to_f and integer_day.between?(1,32)
+
+      bitfield |= 1 << integer_day - 1
+    end
+
+    bitfield
+  end
+
+  def bitfield_from_days_of_week(days_of_week)
+    bitfield = 0
+
+    days_of_week = [days_of_week] unless days_of_week.is_a?(Array)
+    days_of_week.each do |day_of_week|
+      bitfield |= day_of_week_name_to_constant(day_of_week)
+    end
+
+    bitfield
+  end
+
+  def months_from_bitfield(bitfield)
+    months = []
+
+    scheduler_months.each do |month|
+      if bitfield & month != 0
+        months << month_constant_to_number(month)
+      end
+    end
+
+    months
+  end
+
+  def days_from_bitfield(bitfield)
+    days = []
+
+    i = 0
+    while bitfield > 0
+      if bitfield & 1 > 0
+        # Day 32 has the special meaning of "the last day of the
+        # month", no matter how many days there are in the month.
+        days << (i == 31 ? 'last' : i + 1)
+      end
+
+      bitfield = bitfield >> 1
+      i += 1
+    end
+
+    days
+  end
+
+  def days_of_week_from_bitfield(bitfield)
+    days_of_week = []
+
+    scheduler_days_of_week.each do |day_of_week|
+      if bitfield & day_of_week != 0
+        days_of_week << day_of_week_constant_to_name(day_of_week)
+      end
+    end
+
+    days_of_week
+  end
+
+  def scheduler_trigger_types
+    [
+      Win32::TaskScheduler::TASK_TIME_TRIGGER_DAILY,
+      Win32::TaskScheduler::TASK_TIME_TRIGGER_WEEKLY,
+      Win32::TaskScheduler::TASK_TIME_TRIGGER_MONTHLYDATE,
+      Win32::TaskScheduler::TASK_TIME_TRIGGER_MONTHLYDOW,
+      Win32::TaskScheduler::TASK_TIME_TRIGGER_ONCE
+    ]
+  end
+
+  def scheduler_days_of_week
+    [
+      Win32::TaskScheduler::SUNDAY,
+      Win32::TaskScheduler::MONDAY,
+      Win32::TaskScheduler::TUESDAY,
+      Win32::TaskScheduler::WEDNESDAY,
+      Win32::TaskScheduler::THURSDAY,
+      Win32::TaskScheduler::FRIDAY,
+      Win32::TaskScheduler::SATURDAY
+    ]
+  end
+
+  def scheduler_months
+    [
+      Win32::TaskScheduler::JANUARY,
+      Win32::TaskScheduler::FEBRUARY,
+      Win32::TaskScheduler::MARCH,
+      Win32::TaskScheduler::APRIL,
+      Win32::TaskScheduler::MAY,
+      Win32::TaskScheduler::JUNE,
+      Win32::TaskScheduler::JULY,
+      Win32::TaskScheduler::AUGUST,
+      Win32::TaskScheduler::SEPTEMBER,
+      Win32::TaskScheduler::OCTOBER,
+      Win32::TaskScheduler::NOVEMBER,
+      Win32::TaskScheduler::DECEMBER
+    ]
+  end
+
+  def scheduler_occurrences
+    [
+      Win32::TaskScheduler::FIRST_WEEK,
+      Win32::TaskScheduler::SECOND_WEEK,
+      Win32::TaskScheduler::THIRD_WEEK,
+      Win32::TaskScheduler::FOURTH_WEEK,
+      Win32::TaskScheduler::LAST_WEEK
+    ]
+  end
+
+  def day_of_week_constant_to_name(constant)
+    case constant
+    when Win32::TaskScheduler::SUNDAY;    'sun'
+    when Win32::TaskScheduler::MONDAY;    'mon'
+    when Win32::TaskScheduler::TUESDAY;   'tues'
+    when Win32::TaskScheduler::WEDNESDAY; 'wed'
+    when Win32::TaskScheduler::THURSDAY;  'thurs'
+    when Win32::TaskScheduler::FRIDAY;    'fri'
+    when Win32::TaskScheduler::SATURDAY;  'sat'
+    end
+  end
+
+  def day_of_week_name_to_constant(name)
+    case name
+    when 'sun';   Win32::TaskScheduler::SUNDAY
+    when 'mon';   Win32::TaskScheduler::MONDAY
+    when 'tues';  Win32::TaskScheduler::TUESDAY
+    when 'wed';   Win32::TaskScheduler::WEDNESDAY
+    when 'thurs'; Win32::TaskScheduler::THURSDAY
+    when 'fri';   Win32::TaskScheduler::FRIDAY
+    when 'sat';   Win32::TaskScheduler::SATURDAY
+    end
+  end
+
+  def month_constant_to_number(constant)
+    month_num = 1
+    while constant >> month_num - 1 > 1
+      month_num += 1
+    end
+    month_num
+  end
+
+  def occurrence_constant_to_name(constant)
+    case constant
+    when Win32::TaskScheduler::FIRST_WEEK;  'first'
+    when Win32::TaskScheduler::SECOND_WEEK; 'second'
+    when Win32::TaskScheduler::THIRD_WEEK;  'third'
+    when Win32::TaskScheduler::FOURTH_WEEK; 'fourth'
+    when Win32::TaskScheduler::LAST_WEEK;   'last'
+    end
+  end
+
+  def occurrence_name_to_constant(name)
+    case name
+    when 'first';  Win32::TaskScheduler::FIRST_WEEK
+    when 'second'; Win32::TaskScheduler::SECOND_WEEK
+    when 'third';  Win32::TaskScheduler::THIRD_WEEK
+    when 'fourth'; Win32::TaskScheduler::FOURTH_WEEK
+    when 'last';   Win32::TaskScheduler::LAST_WEEK
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/selboolean/getsetsebool.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/selboolean/getsetsebool.rb
new file mode 100644
index 0000000..d8823fe
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/selboolean/getsetsebool.rb
@@ -0,0 +1,47 @@
+Puppet::Type.type(:selboolean).provide(:getsetsebool) do
+  desc "Manage SELinux booleans using the getsebool and setsebool binaries."
+
+  commands :getsebool => "/usr/sbin/getsebool"
+  commands :setsebool => "/usr/sbin/setsebool"
+
+  def value
+    self.debug "Retrieving value of selboolean #{@resource[:name]}"
+
+    status = getsebool(@resource[:name])
+
+    if status =~ / off$/
+      return :off
+    elsif status =~ / on$/ then
+      return :on
+    else
+      status.chomp!
+      raise Puppet::Error, "Invalid response '#{status}' returned from getsebool"
+    end
+  end
+
+  def value=(new)
+    persist = ""
+    if @resource[:persistent] == :true
+      self.debug "Enabling persistence"
+      persist = "-P"
+    end
+    execoutput("#{command(:setsebool)} #{persist} #{@resource[:name]} #{new}")
+    :file_changed
+  end
+
+  # Required workaround, since SELinux policy prevents setsebool
+  # from writing to any files, even tmp, preventing the standard
+  # 'setsebool("...")' construct from working.
+
+  def execoutput (cmd)
+    output = ''
+    begin
+      execpipe(cmd) do |out|
+        output = out.readlines.join('').chomp!
+      end
+    rescue Puppet::ExecutionFailure
+      raise Puppet::ExecutionFailure, output.split("\n")[0], $!.backtrace
+    end
+    output
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/selmodule/semodule.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/selmodule/semodule.rb
new file mode 100644
index 0000000..dc9a77d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/selmodule/semodule.rb
@@ -0,0 +1,134 @@
+Puppet::Type.type(:selmodule).provide(:semodule) do
+  desc "Manage SELinux policy modules using the semodule binary."
+
+  commands :semodule => "/usr/sbin/semodule"
+
+  def create
+    begin
+      execoutput("#{command(:semodule)} --install #{selmod_name_to_filename}")
+    rescue Puppet::ExecutionFailure => detail
+      raise Puppet::Error, "Could not load policy module: #{detail}", detail.backtrace
+    end
+    :true
+  end
+
+  def destroy
+      execoutput("#{command(:semodule)} --remove #{@resource[:name]}")
+  rescue Puppet::ExecutionFailure => detail
+      raise Puppet::Error, "Could not remove policy module: #{detail}", detail.backtrace
+  end
+
+  def exists?
+    self.debug "Checking for module #{@resource[:name]}"
+    execpipe("#{command(:semodule)} --list") do |out|
+      out.each_line do |line|
+        if line =~ /#{@resource[:name]}\b/
+          return :true
+        end
+      end
+    end
+    nil
+  end
+
+  def syncversion
+    self.debug "Checking syncversion on #{@resource[:name]}"
+
+    loadver = selmodversion_loaded
+
+    if(loadver) then
+      filever = selmodversion_file
+      if (filever == loadver)
+        return :true
+      end
+    end
+    :false
+  end
+
+  def syncversion= (dosync)
+      execoutput("#{command(:semodule)} --upgrade #{selmod_name_to_filename}")
+  rescue Puppet::ExecutionFailure => detail
+      raise Puppet::Error, "Could not upgrade policy module: #{detail}", detail.backtrace
+  end
+
+  # Helper functions
+
+  def execoutput (cmd)
+    output = ''
+    begin
+      execpipe(cmd) do |out|
+        output = out.readlines.join('').chomp!
+      end
+    rescue Puppet::ExecutionFailure
+      raise Puppet::ExecutionFailure, output.split("\n")[0], $!.backtrace
+    end
+    output
+  end
+
+  def selmod_name_to_filename
+    if @resource[:selmodulepath]
+      return @resource[:selmodulepath]
+    else
+      return "#{@resource[:selmoduledir]}/#{@resource[:name]}.pp"
+    end
+  end
+
+  def selmod_readnext (handle)
+    len = handle.read(4).unpack('V')[0]
+    handle.read(len)
+  end
+
+  def selmodversion_file
+    magic = 0xF97CFF8F
+
+    filename = selmod_name_to_filename
+    mod = File.new(filename, "r")
+
+    (hdr, ver, numsec) = mod.read(12).unpack('VVV')
+
+    raise Puppet::Error, "Found #{hdr} instead of magic #{magic} in #{filename}" if hdr != magic
+
+    raise Puppet::Error, "Unknown policy file version #{ver} in #{filename}" if ver != 1
+
+    # Read through (and throw away) the file section offsets, and also
+    # the magic header for the first section.
+
+    mod.read((numsec + 1) * 4)
+
+    ## Section 1 should be "SE Linux Module"
+
+    selmod_readnext(mod)
+    selmod_readnext(mod)
+
+    # Skip past the section headers
+    mod.read(14)
+
+    # Module name
+    selmod_readnext(mod)
+
+    # At last!  the version
+
+    v = selmod_readnext(mod)
+
+    self.debug "file version #{v}"
+    v
+  end
+
+  def selmodversion_loaded
+    lines = ()
+    begin
+      execpipe("#{command(:semodule)} --list") do |output|
+        output.each_line do |line|
+          line.chomp!
+          bits = line.split
+          if bits[0] == @resource[:name]
+            self.debug "load version #{bits[1]}"
+            return bits[1]
+          end
+        end
+      end
+    rescue Puppet::ExecutionFailure
+      raise Puppet::ExecutionFailure, "Could not list policy modules: #{lines.join(' ').chomp!}", $!.backtrace
+    end
+    nil
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/base.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/base.rb
new file mode 100644
index 0000000..9e37d1f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/base.rb
@@ -0,0 +1,106 @@
+Puppet::Type.type(:service).provide :base, :parent => :service do
+  desc "The simplest form of Unix service support.
+
+  You have to specify enough about your service for this to work; the
+  minimum you can specify is a binary for starting the process, and this
+  same binary will be searched for in the process table to stop the
+  service.  As with `init`-style services, it is preferable to specify start,
+  stop, and status commands.
+
+  "
+
+  commands :kill => "kill"
+
+  # Get the process ID for a running process. Requires the 'pattern'
+  # parameter.
+  def getpid
+    @resource.fail "Either stop/status commands or a pattern must be specified" unless @resource[:pattern]
+    ps = Facter["ps"].value
+    @resource.fail "You must upgrade Facter to a version that includes 'ps'" unless ps and ps != ""
+    regex = Regexp.new(@resource[:pattern])
+    self.debug "Executing '#{ps}'"
+    IO.popen(ps) { |table|
+      table.each_line { |line|
+        if regex.match(line)
+          self.debug "Process matched: #{line}"
+          ary = line.sub(/^\s+/, '').split(/\s+/)
+          return ary[1]
+        end
+      }
+    }
+
+    nil
+  end
+
+  # Check if the process is running.  Prefer the 'status' parameter,
+  # then 'statuscmd' method, then look in the process table.  We give
+  # the object the option to not return a status command, which might
+  # happen if, for instance, it has an init script (and thus responds to
+  # 'statuscmd') but does not have 'hasstatus' enabled.
+  def status
+    if @resource[:status] or statuscmd
+      # Don't fail when the exit status is not 0.
+      ucommand(:status, false)
+
+      # Expicitly calling exitstatus to facilitate testing
+      if $CHILD_STATUS.exitstatus == 0
+        return :running
+      else
+        return :stopped
+      end
+    elsif pid = self.getpid
+      self.debug "PID is #{pid}"
+      return :running
+    else
+      return :stopped
+    end
+  end
+
+  # There is no default command, which causes other methods to be used
+  def statuscmd
+  end
+
+  # Run the 'start' parameter command, or the specified 'startcmd'.
+  def start
+    ucommand(:start)
+  end
+
+  # The command used to start.  Generated if the 'binary' argument
+  # is passed.
+  def startcmd
+    if @resource[:binary]
+      return @resource[:binary]
+    else
+      raise Puppet::Error,
+        "Services must specify a start command or a binary"
+    end
+  end
+
+  # Stop the service.  If a 'stop' parameter is specified, it
+  # takes precedence; otherwise checks if the object responds to
+  # a 'stopcmd' method, and if so runs that; otherwise, looks
+  # for the process in the process table.
+  # This method will generally not be overridden by submodules.
+  def stop
+    if @resource[:stop] or stopcmd
+      ucommand(:stop)
+    else
+      pid = getpid
+      unless pid
+        self.info "#{self.name} is not running"
+        return false
+      end
+      begin
+        output = kill pid
+      rescue Puppet::ExecutionFailure
+        @resource.fail Puppet::Error, "Could not kill #{self.name}, PID #{pid}: #{output}", $!
+      end
+      return true
+    end
+  end
+
+  # There is no default command, which causes other methods to be used
+  def stopcmd
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/bsd.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/bsd.rb
new file mode 100644
index 0000000..d779aad
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/bsd.rb
@@ -0,0 +1,51 @@
+# Manage FreeBSD services.
+Puppet::Type.type(:service).provide :bsd, :parent => :init do
+  desc <<-EOT
+    FreeBSD's (and probably NetBSD's?) form of `init`-style service management.
+
+    Uses `rc.conf.d` for service enabling and disabling.
+
+  EOT
+
+  confine :operatingsystem => [:freebsd, :netbsd, :openbsd, :dragonfly]
+
+  def rcconf_dir
+    '/etc/rc.conf.d'
+  end
+
+  def self.defpath
+    superclass.defpath
+  end
+
+  # remove service file from rc.conf.d to disable it
+  def disable
+    rcfile = File.join(rcconf_dir, @model[:name])
+    File.delete(rcfile) if Puppet::FileSystem.exist?(rcfile)
+  end
+
+  # if the service file exists in rc.conf.d then it's already enabled
+  def enabled?
+    rcfile = File.join(rcconf_dir, @model[:name])
+    return :true if Puppet::FileSystem.exist?(rcfile)
+
+    :false
+  end
+
+  # enable service by creating a service file under rc.conf.d with the
+  # proper contents
+  def enable
+    Dir.mkdir(rcconf_dir) if not Puppet::FileSystem.exist?(rcconf_dir)
+    rcfile = File.join(rcconf_dir, @model[:name])
+    open(rcfile, 'w') { |f| f << "%s_enable=\"YES\"\n" % @model[:name] }
+  end
+
+  # Override stop/start commands to use one<cmd>'s and the avoid race condition
+  # where provider trys to stop/start the service before it is enabled
+  def startcmd
+    [self.initscript, :onestart]
+  end
+
+  def stopcmd
+    [self.initscript, :onestop]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/daemontools.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/daemontools.rb
new file mode 100644
index 0000000..b510f25
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/daemontools.rb
@@ -0,0 +1,194 @@
+# Daemontools service management
+#
+# author Brice Figureau <brice-puppet@daysofwonder.com>
+Puppet::Type.type(:service).provide :daemontools, :parent => :base do
+  desc <<-'EOT'
+    Daemontools service management.
+
+    This provider manages daemons supervised by D.J. Bernstein daemontools.
+    When detecting the service directory it will check, in order of preference:
+
+    * `/service`
+    * `/etc/service`
+    * `/var/lib/svscan`
+
+    The daemon directory should be in one of the following locations:
+
+    * `/var/lib/service`
+    * `/etc`
+
+    ...or this can be overriden in the resource's attributes:
+
+        service { "myservice":
+          provider => "daemontools",
+          path     => "/path/to/daemons",
+        }
+
+    This provider supports out of the box:
+
+    * start/stop (mapped to enable/disable)
+    * enable/disable
+    * restart
+    * status
+
+    If a service has `ensure => "running"`, it will link /path/to/daemon to
+    /path/to/service, which will automatically enable the service.
+
+    If a service has `ensure => "stopped"`, it will only shut down the service, not
+    remove the `/path/to/service` link.
+
+  EOT
+
+  commands :svc  => "/usr/bin/svc", :svstat => "/usr/bin/svstat"
+
+  class << self
+    attr_writer :defpath
+
+    # Determine the daemon path.
+    def defpath(dummy_argument=:work_arround_for_ruby_GC_bug)
+      unless @defpath
+        ["/var/lib/service", "/etc"].each do |path|
+          if Puppet::FileSystem.exist?(path)
+            @defpath = path
+            break
+          end
+        end
+        raise "Could not find the daemon directory (tested [/var/lib/service,/etc])" unless @defpath
+      end
+      @defpath
+    end
+  end
+
+  attr_writer :servicedir
+
+  # returns all providers for all existing services in @defpath
+  # ie enabled or not
+  def self.instances
+    path = self.defpath
+    unless FileTest.directory?(path)
+      Puppet.notice "Service path #{path} does not exist"
+      return
+    end
+
+    # reject entries that aren't either a directory
+    # or don't contain a run file
+    Dir.entries(path).reject { |e|
+      fullpath = File.join(path, e)
+      e =~ /^\./ or ! FileTest.directory?(fullpath) or ! Puppet::FileSystem.exist?(File.join(fullpath,"run"))
+    }.collect do |name|
+      new(:name => name, :path => path)
+    end
+  end
+
+  # returns the daemon dir on this node
+  def self.daemondir
+    self.defpath
+  end
+
+  # find the service dir on this node
+  def servicedir
+    unless @servicedir
+      ["/service", "/etc/service","/var/lib/svscan"].each do |path|
+        if Puppet::FileSystem.exist?(path)
+          @servicedir = path
+          break
+        end
+      end
+      raise "Could not find service directory" unless @servicedir
+    end
+    @servicedir
+  end
+
+  # returns the full path of this service when enabled
+  # (ie in the service directory)
+  def service
+    File.join(self.servicedir, resource[:name])
+  end
+
+  # returns the full path to the current daemon directory
+  # note that this path can be overriden in the resource
+  # definition
+  def daemon
+    File.join(resource[:path], resource[:name])
+  end
+
+  def status
+    begin
+      output = svstat self.service
+      if output =~ /:\s+up \(/
+        return :running
+      end
+    rescue Puppet::ExecutionFailure => detail
+      raise Puppet::Error.new( "Could not get status for service #{resource.ref}: #{detail}", detail)
+    end
+    :stopped
+  end
+
+  def setupservice
+      if resource[:manifest]
+        Puppet.notice "Configuring #{resource[:name]}"
+        command = [ resource[:manifest], resource[:name] ]
+        #texecute("setupservice", command)
+        system("#{command}")
+      end
+  rescue Puppet::ExecutionFailure => detail
+      raise Puppet::Error.new( "Cannot config #{self.service} to enable it: #{detail}", detail)
+  end
+
+  def enabled?
+    case self.status
+    when :running
+      # obviously if the daemon is running then it is enabled
+      return :true
+    else
+      # the service is enabled if it is linked
+      return Puppet::FileSystem.symlink?(self.service) ? :true : :false
+    end
+  end
+
+  def enable
+    if ! FileTest.directory?(self.daemon)
+      Puppet.notice "No daemon dir, calling setupservice for #{resource[:name]}"
+      self.setupservice
+    end
+    if self.daemon
+      if ! Puppet::FileSystem.symlink?(self.service)
+        Puppet.notice "Enabling #{self.service}: linking #{self.daemon} -> #{self.service}"
+        Puppet::FileSystem.symlink(self.daemon, self.service)
+      end
+    end
+rescue Puppet::ExecutionFailure
+    raise Puppet::Error.new( "No daemon directory found for #{self.service}", $!)
+  end
+
+  def disable
+    begin
+      if ! FileTest.directory?(self.daemon)
+        Puppet.notice "No daemon dir, calling setupservice for #{resource[:name]}"
+        self.setupservice
+      end
+      if self.daemon
+        if Puppet::FileSystem.symlink?(self.service)
+          Puppet.notice "Disabling #{self.service}: removing link #{self.daemon} -> #{self.service}"
+          Puppet::FileSystem.unlink(self.service)
+        end
+      end
+    rescue Puppet::ExecutionFailure
+      raise Puppet::Error.new( "No daemon directory found for #{self.service}", $!)
+    end
+    self.stop
+  end
+
+  def restart
+    svc "-t", self.service
+  end
+
+  def start
+    enable unless enabled? == :true
+    svc "-u", self.service
+  end
+
+  def stop
+    svc "-d", self.service
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/debian.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/debian.rb
new file mode 100644
index 0000000..5a0a4a3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/debian.rb
@@ -0,0 +1,143 @@
+# Manage debian services.  Start/stop is the same as InitSvc, but enable/disable
+# is special.
+Puppet::Type.type(:service).provide :debian, :parent => :init do
+  desc <<-EOT
+    Debian's form of `init`-style management.
+
+    The only differences from `init` are support for enabling and disabling
+    services via `update-rc.d` and the ability to determine enabled status via
+    `invoke-rc.d`.
+
+  EOT
+
+  commands :update_rc => "/usr/sbin/update-rc.d"
+  # note this isn't being used as a command until
+  # http://projects.reductivelabs.com/issues/2538
+  # is resolved.
+  commands :invoke_rc => "/usr/sbin/invoke-rc.d"
+  optional_commands :systemctl => "/bin/systemctl"
+
+  # This isn't being used directly, it's just here to ensure
+  # that the /usr/sbin/service binary is available.
+  SERVICE = "/usr/sbin/service"
+  commands :service_cmd => SERVICE
+
+  defaultfor :operatingsystem => :debian
+
+  def self.runs_on_systemd?
+    Dir.exists? "/run/systemd/system"
+  end
+
+  def is_sysv_unit?
+    # The sysv generator sets the SourcePath attribute to the name of the
+    # initscript. Use this to detect whether a unit is backed by an initscript
+    # or not.
+    source = systemctl(:show, "-pSourcePath", @resource[:name])
+    source.start_with? "SourcePath=/etc/init.d/"
+  end
+
+  def self.instances
+    # We need to merge services with systemd unit files with those only having
+    # an initscript. Note that we could use `systemctl --all` to get sysv
+    # services as well, however it would only output *enabled* services.
+    i = {}
+    if self.runs_on_systemd?
+      begin
+        output = systemctl('list-unit-files', '--type', 'service', '--full', '--all',  '--no-pager')
+        output.scan(/^(\S+)\.service\s+(disabled|enabled)\s*$/i).each do |m|
+          i[m[0]] = new(:name => m[0])
+        end
+      rescue Puppet::ExecutionFailure
+      end
+    end
+    get_services(defpath).each do |sysv|
+      unless i.has_key?(sysv.name)
+        i[sysv.name] = sysv
+      end
+    end
+    return i.values
+  end
+
+  # Remove the symlinks
+  def disable
+    if self.class.runs_on_systemd?
+      systemctl(:disable, @resource[:name])
+    else
+      update_rc @resource[:name], "disable"
+    end
+  end
+
+  def enabled?
+    # Initscript-backed services have no enabled status in systemd, so we
+    # need to query them using invoke-rc.d.
+    if self.class.runs_on_systemd? and not is_sysv_unit?
+      begin
+        systemctl("is-enabled", @resource[:name])
+        return :true
+      rescue Puppet::ExecutionFailure
+        return :false
+      end
+    else
+      # TODO: Replace system call when Puppet::Util::Execution.execute gives us a way
+      # to determine exit status.  http://projects.reductivelabs.com/issues/2538
+      system("/usr/sbin/invoke-rc.d", "--quiet", "--query", @resource[:name], "start")
+
+      # 104 is the exit status when you query start an enabled service.
+      # 106 is the exit status when the policy layer supplies a fallback action
+      # See x-man-page://invoke-rc.d
+      if [104, 106].include?($CHILD_STATUS.exitstatus)
+        return :true
+      elsif [101, 105].include?($CHILD_STATUS.exitstatus)
+        # 101 is action not allowed, which means we have to do the check manually.
+        # 105 is unknown, which generally means the iniscript does not support query
+        # The debian policy states that the initscript should support methods of query
+        # For those that do not, peform the checks manually
+        # http://www.debian.org/doc/debian-policy/ch-opersys.html
+        if get_start_link_count >= 4
+          return :true
+        else
+          return :false
+        end
+      else
+        return :false
+      end
+    end
+  end
+
+  def get_start_link_count
+    Dir.glob("/etc/rc*.d/S??#{@resource[:name]}").length
+  end
+
+  def enable
+    if self.class.runs_on_systemd?
+      systemctl(:enable, @resource[:name])
+    else
+      update_rc @resource[:name], "defaults"
+      update_rc @resource[:name], "enable"
+    end
+  end
+
+  # The start, stop, restart and status command use service
+  # this makes sure that these commands work with whatever init
+  # system is installed
+  def startcmd
+    [SERVICE, @resource[:name], :start]
+  end
+
+  # The stop command is just the init script with 'stop'.
+  def stopcmd
+    [SERVICE, @resource[:name], :stop]
+  end
+
+  def restartcmd
+    (@resource[:hasrestart] == :true) && [SERVICE, @resource[:name], :restart]
+  end
+
+  # If it was specified that the init script has a 'status' command, then
+  # we just return that; otherwise, we return false, which causes it to
+  # fallback to other mechanisms.
+  def statuscmd
+    (@resource[:hasstatus] == :true) && [SERVICE, @resource[:name], :status]
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/freebsd.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/freebsd.rb
new file mode 100644
index 0000000..91a3e02
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/freebsd.rb
@@ -0,0 +1,143 @@
+Puppet::Type.type(:service).provide :freebsd, :parent => :init do
+
+  desc "Provider for FreeBSD and DragonFly BSD. Uses the `rcvar` argument of init scripts and parses/edits rc files."
+
+  confine :operatingsystem => [:freebsd, :dragonfly]
+  defaultfor :operatingsystem => [:freebsd, :dragonfly]
+
+  def rcconf()        '/etc/rc.conf' end
+  def rcconf_local()  '/etc/rc.conf.local' end
+  def rcconf_dir()    '/etc/rc.conf.d' end
+
+  def self.defpath
+    superclass.defpath
+  end
+
+  def error(msg)
+    raise Puppet::Error, msg
+  end
+
+  # Executing an init script with the 'rcvar' argument returns
+  # the service name, rcvar name and whether it's enabled/disabled
+  def rcvar
+    rcvar = execute([self.initscript, :rcvar], :failonfail => true, :combine => false, :squelch => false)
+    rcvar = rcvar.split("\n")
+    rcvar.delete_if {|str| str =~ /^#\s*$/}
+    rcvar[1] = rcvar[1].gsub(/^\$/, '')
+    rcvar
+  end
+
+  # Extract value name from service or rcvar
+  def extract_value_name(name, rc_index, regex, regex_index)
+    value_name = self.rcvar[rc_index]
+    self.error("No #{name} name found in rcvar") if value_name.nil?
+    value_name = value_name.gsub!(regex, regex_index)
+    self.error("#{name} name is empty") if value_name.nil?
+    self.debug("#{name} name is #{value_name}")
+    value_name
+  end
+
+  # Extract service name
+  def service_name
+    extract_value_name('service', 0, /# (.*)/, '\1')
+  end
+
+  # Extract rcvar name
+  def rcvar_name
+    extract_value_name('rcvar', 1, /(.*?)(_enable)?=(.*)/, '\1')
+  end
+
+  # Extract rcvar value
+  def rcvar_value
+    value = self.rcvar[1]
+    self.error("No rcvar value found in rcvar") if value.nil?
+    value = value.gsub!(/(.*)(_enable)?="?(\w+)"?/, '\3')
+    self.error("rcvar value is empty") if value.nil?
+    self.debug("rcvar value is #{value}")
+    value
+  end
+
+  # Edit rc files and set the service to yes/no
+  def rc_edit(yesno)
+    service = self.service_name
+    rcvar = self.rcvar_name
+    self.debug("Editing rc files: setting #{rcvar} to #{yesno} for #{service}")
+    self.rc_add(service, rcvar, yesno) if not self.rc_replace(service, rcvar, yesno)
+  end
+
+  # Try to find an existing setting in the rc files
+  # and replace the value
+  def rc_replace(service, rcvar, yesno)
+    success = false
+    # Replace in all files, not just in the first found with a match
+    [rcconf, rcconf_local, rcconf_dir + "/#{service}"].each do |filename|
+      if Puppet::FileSystem.exist?(filename)
+        s = File.read(filename)
+        if s.gsub!(/^(#{rcvar}(_enable)?)=\"?(YES|NO)\"?/, "\\1=\"#{yesno}\"")
+          File.open(filename, File::WRONLY) { |f| f << s }
+          self.debug("Replaced in #{filename}")
+          success = true
+        end
+      end
+    end
+    success
+  end
+
+  # Add a new setting to the rc files
+  def rc_add(service, rcvar, yesno)
+    append = "\# Added by Puppet\n#{rcvar}_enable=\"#{yesno}\"\n"
+    # First, try the one-file-per-service style
+    if Puppet::FileSystem.exist?(rcconf_dir)
+      File.open(rcconf_dir + "/#{service}", File::WRONLY | File::APPEND | File::CREAT, 0644) {
+        |f| f << append
+        self.debug("Appended to #{f.path}")
+      }
+    else
+      # Else, check the local rc file first, but don't create it
+      if Puppet::FileSystem.exist?(rcconf_local)
+        File.open(rcconf_local, File::WRONLY | File::APPEND) {
+          |f| f << append
+          self.debug("Appended to #{f.path}")
+        }
+      else
+        # At last use the standard rc.conf file
+        File.open(rcconf, File::WRONLY | File::APPEND | File::CREAT, 0644) {
+          |f| f << append
+          self.debug("Appended to #{f.path}")
+        }
+      end
+    end
+  end
+
+  def enabled?
+    if /YES$/ =~ self.rcvar_value
+      self.debug("Is enabled")
+      return :true
+    end
+    self.debug("Is disabled")
+    :false
+  end
+
+  def enable
+    self.debug("Enabling")
+    self.rc_edit("YES")
+  end
+
+  def disable
+    self.debug("Disabling")
+    self.rc_edit("NO")
+  end
+
+  def startcmd
+    [self.initscript, :onestart]
+  end
+
+  def stopcmd
+    [self.initscript, :onestop]
+  end
+
+  def statuscmd
+    [self.initscript, :onestatus]
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/gentoo.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/gentoo.rb
new file mode 100644
index 0000000..4fecbde
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/gentoo.rb
@@ -0,0 +1,45 @@
+# Manage gentoo services.  Start/stop is the same as InitSvc, but enable/disable
+# is special.
+Puppet::Type.type(:service).provide :gentoo, :parent => :init do
+  desc <<-EOT
+    Gentoo's form of `init`-style service management.
+
+    Uses `rc-update` for service enabling and disabling.
+
+  EOT
+
+  commands :update => "/sbin/rc-update"
+
+  confine :operatingsystem => :gentoo
+
+  def disable
+      output = update :del, @resource[:name], :default
+  rescue Puppet::ExecutionFailure
+      raise Puppet::Error, "Could not disable #{self.name}: #{output}", $!.backtrace
+  end
+
+  def enabled?
+    begin
+      output = update :show
+    rescue Puppet::ExecutionFailure
+      return :false
+    end
+
+    line = output.split(/\n/).find { |l| l.include?(@resource[:name]) }
+
+    return :false unless line
+
+    # If it's enabled then it will print output showing service | runlevel
+    if output =~ /^\s*#{@resource[:name]}\s*\|\s*(boot|default)/
+      return :true
+    else
+      return :false
+    end
+  end
+
+  def enable
+      output = update :add, @resource[:name], :default
+  rescue Puppet::ExecutionFailure
+      raise Puppet::Error, "Could not enable #{self.name}: #{output}", $!.backtrace
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/init.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/init.rb
new file mode 100644
index 0000000..9f2d030
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/init.rb
@@ -0,0 +1,176 @@
+# The standard init-based service type.  Many other service types are
+# customizations of this module.
+Puppet::Type.type(:service).provide :init, :parent => :base do
+  desc "Standard `init`-style service management."
+
+  def self.defpath
+    case Facter.value(:operatingsystem)
+    when "FreeBSD", "DragonFly"
+      ["/etc/rc.d", "/usr/local/etc/rc.d"]
+    when "HP-UX"
+      "/sbin/init.d"
+    when "Archlinux"
+      "/etc/rc.d"
+    else
+      "/etc/init.d"
+    end
+  end
+
+  # We can't confine this here, because the init path can be overridden.
+  #confine :exists => defpath
+
+  # some init scripts are not safe to execute, e.g. we do not want
+  # to suddently run /etc/init.d/reboot.sh status and reboot our system. The
+  # exclude list could be platform agnostic but I assume an invalid init script
+  # on system A will never be a valid init script on system B
+  def self.excludes
+    excludes = []
+    # these exclude list was found with grep -L '\/sbin\/runscript' /etc/init.d/* on gentoo
+    excludes += %w{functions.sh reboot.sh shutdown.sh}
+    # this exclude list is all from /sbin/service (5.x), but I did not exclude kudzu
+    excludes += %w{functions halt killall single linuxconf reboot boot}
+    # 'wait-for-state' and 'portmap-wait' are excluded from instances here
+    # because they take parameters that have unclear meaning. It looks like
+    # 'wait-for-state' is a generic waiter mainly used internally for other
+    # upstart services as a 'sleep until something happens'
+    # (http://lists.debian.org/debian-devel/2012/02/msg01139.html), while
+    # 'portmap-wait' is a specific instance of a waiter. There is an open
+    # launchpad bug
+    # (https://bugs.launchpad.net/ubuntu/+source/upstart/+bug/962047) that may
+    # eventually explain how to use the wait-for-state service or perhaps why
+    # it should remain excluded. When that bug is adddressed this should be
+    # reexamined.
+    excludes += %w{wait-for-state portmap-wait}
+    # these excludes were found with grep -r -L start /etc/init.d
+    excludes += %w{rcS module-init-tools}
+    # Prevent puppet failing to get status of the new service introduced
+    # by the fix for this (bug https://bugs.launchpad.net/ubuntu/+source/lightdm/+bug/982889)
+    # due to puppet's inability to deal with upstart services with instances.
+    excludes += %w{plymouth-ready}
+    # Prevent puppet failing to get status of these services, which need parameters
+    # passed in (see https://bugs.launchpad.net/ubuntu/+source/puppet/+bug/1276766).
+    excludes += %w{idmapd-mounting startpar-bridge}
+    # Prevent puppet failing to get status of these services, additional upstart
+    # service with instances
+    excludes += %w{cryptdisks-udev}
+    excludes += %w{statd-mounting}
+    excludes += %w{gssd-mounting}
+  end
+
+  # List all services of this type.
+  def self.instances
+    get_services(self.defpath)
+  end
+
+  def self.get_services(defpath, exclude = self.excludes)
+    defpath = [defpath] unless defpath.is_a? Array
+    instances = []
+    defpath.each do |path|
+      unless FileTest.directory?(path)
+        Puppet.debug "Service path #{path} does not exist"
+        next
+      end
+
+      check = [:ensure]
+
+      check << :enable if public_method_defined? :enabled?
+
+      Dir.entries(path).each do |name|
+        fullpath = File.join(path, name)
+        next if name =~ /^\./
+        next if exclude.include? name
+        next if not FileTest.executable?(fullpath)
+        next if not is_init?(fullpath)
+        instances << new(:name => name, :path => path, :hasstatus => true)
+      end
+    end
+    instances
+  end
+
+  # Mark that our init script supports 'status' commands.
+  def hasstatus=(value)
+    case value
+    when true, "true"; @parameters[:hasstatus] = true
+    when false, "false"; @parameters[:hasstatus] = false
+    else
+      raise Puppet::Error, "Invalid 'hasstatus' value #{value.inspect}"
+    end
+  end
+
+  # Where is our init script?
+  def initscript
+    @initscript ||= self.search(@resource[:name])
+  end
+
+  def paths
+    @paths ||= @resource[:path].find_all do |path|
+      if File.directory?(path)
+        true
+      else
+        if Puppet::FileSystem.exist?(path)
+          self.debug "Search path #{path} is not a directory"
+        else
+          self.debug "Search path #{path} does not exist"
+        end
+        false
+      end
+    end
+  end
+
+  def search(name)
+    paths.each do |path|
+      fqname = File.join(path,name)
+      if Puppet::FileSystem.exist? fqname
+        return fqname
+      else
+        self.debug("Could not find #{name} in #{path}")
+      end
+    end
+
+    paths.each do |path|
+      fqname_sh = File.join(path,"#{name}.sh")
+      if Puppet::FileSystem.exist? fqname_sh
+        return fqname_sh
+      else
+        self.debug("Could not find #{name}.sh in #{path}")
+      end
+    end
+    raise Puppet::Error, "Could not find init script for '#{name}'"
+  end
+
+  # The start command is just the init scriptwith 'start'.
+  def startcmd
+    [initscript, :start]
+  end
+
+  # The stop command is just the init script with 'stop'.
+  def stopcmd
+    [initscript, :stop]
+  end
+
+  def restartcmd
+    (@resource[:hasrestart] == :true) && [initscript, :restart]
+  end
+
+  def texecute(type, command, fof = true, squelch = false, combine = true)
+    if type == :start && Facter.value(:osfamily) == "Solaris"
+        command =  ["/usr/bin/ctrun -l none", command].flatten.join(" ")
+    end
+    super(type, command, fof, squelch, combine)
+  end
+
+  # If it was specified that the init script has a 'status' command, then
+  # we just return that; otherwise, we return false, which causes it to
+  # fallback to other mechanisms.
+  def statuscmd
+    (@resource[:hasstatus] == :true) && [initscript, :status]
+  end
+
+private
+
+  def self.is_init?(script = initscript)
+    file = Puppet::FileSystem.pathname(script)
+    !Puppet::FileSystem.symlink?(file) || Puppet::FileSystem.readlink(file) != "/lib/init/upstart-job"
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/launchd.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/launchd.rb
new file mode 100644
index 0000000..a7eb3a3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/launchd.rb
@@ -0,0 +1,386 @@
+require 'facter/util/plist'
+Puppet::Type.type(:service).provide :launchd, :parent => :base do
+  desc <<-'EOT'
+    This provider manages jobs with `launchd`, which is the default service
+    framework for Mac OS X (and may be available for use on other platforms).
+
+    For `launchd` documentation, see:
+
+    * <http://developer.apple.com/macosx/launchd.html>
+    * <http://launchd.macosforge.org/>
+
+    This provider reads plists out of the following directories:
+
+    * `/System/Library/LaunchDaemons`
+    * `/System/Library/LaunchAgents`
+    * `/Library/LaunchDaemons`
+    * `/Library/LaunchAgents`
+
+    ...and builds up a list of services based upon each plist's "Label" entry.
+
+    This provider supports:
+
+    * ensure => running/stopped,
+    * enable => true/false
+    * status
+    * restart
+
+    Here is how the Puppet states correspond to `launchd` states:
+
+    * stopped --- job unloaded
+    * started --- job loaded
+    * enabled --- 'Disable' removed from job plist file
+    * disabled --- 'Disable' added to job plist file
+
+    Note that this allows you to do something `launchctl` can't do, which is to
+    be in a state of "stopped/enabled" or "running/disabled".
+
+    Note that this provider does not support overriding 'restart' or 'status'.
+
+  EOT
+
+  include Puppet::Util::Warnings
+
+  commands :launchctl => "/bin/launchctl"
+  commands :sw_vers   => "/usr/bin/sw_vers"
+  commands :plutil    => "/usr/bin/plutil"
+
+  defaultfor :operatingsystem => :darwin
+  confine :operatingsystem    => :darwin
+
+  has_feature :enableable
+  has_feature :refreshable
+  mk_resource_methods
+
+  # These are the paths in OS X where a launchd service plist could
+  # exist. This is a helper method, versus a constant, for easy testing
+  # and mocking
+  #
+  # @api private
+  def self.launchd_paths
+    [
+      "/Library/LaunchAgents",
+      "/Library/LaunchDaemons",
+      "/System/Library/LaunchAgents",
+      "/System/Library/LaunchDaemons"
+    ]
+  end
+
+  # Gets the current Darwin version, example 10.6 returns 9 and 10.10 returns 14
+  # See https://en.wikipedia.org/wiki/Darwin_(operating_system)#Release_history
+  # for more information.
+  #
+  # @api private
+  def self.get_os_version
+    @os_version ||= Facter.value(:operatingsystemmajrelease).to_i
+  end
+
+  # Defines the path to the overrides plist file where service enabling
+  # behavior is defined in 10.6 and greater.
+  #
+  # With the rewrite of launchd in 10.10+, this moves and slightly changes format.
+  #
+  # @api private
+  def self.launchd_overrides
+    if self.get_os_version < 14
+      "/var/db/launchd.db/com.apple.launchd/overrides.plist"
+    else
+      "/var/db/com.apple.xpc.launchd/disabled.plist"
+    end
+  end
+
+  # Caching is enabled through the following three methods. Self.prefetch will
+  # call self.instances to create an instance for each service. Self.flush will
+  # clear out our cache when we're done.
+  def self.prefetch(resources)
+    instances.each do |prov|
+      if resource = resources[prov.name]
+        resource.provider = prov
+      end
+    end
+  end
+
+  # Self.instances will return an array with each element being a hash
+  # containing the name, provider, path, and status of each service on the
+  # system.
+  def self.instances
+    jobs = self.jobsearch
+    @job_list ||= self.job_list
+    jobs.keys.collect do |job|
+      job_status = @job_list.has_key?(job) ? :running : :stopped
+      new(:name => job, :provider => :launchd, :path => jobs[job], :status => job_status)
+    end
+  end
+
+  # This method will return a list of files in the passed directory. This method
+  # does not go recursively down the tree and does not return directories
+  #
+  # @param path [String] The directory to glob
+  #
+  # @api private
+  #
+  # @return [Array] of String instances modeling file paths
+  def self.return_globbed_list_of_file_paths(path)
+    array_of_files = Dir.glob(File.join(path, '*')).collect do |filepath|
+      File.file?(filepath) ? filepath : nil
+    end
+    array_of_files.compact
+  end
+
+  # Get a hash of all launchd plists, keyed by label.  This value is cached, but
+  # the cache will be refreshed if refresh is true.
+  #
+  # @api private
+  def self.make_label_to_path_map(refresh=false)
+    return @label_to_path_map if @label_to_path_map and not refresh
+    @label_to_path_map = {}
+    launchd_paths.each do |path|
+      return_globbed_list_of_file_paths(path).each do |filepath|
+        job = read_plist(filepath)
+        next if job.nil?
+        if job.has_key?("Label")
+          @label_to_path_map[job["Label"]] = filepath
+        else
+          Puppet.warning("The #{filepath} plist does not contain a 'label' key; " +
+                       "Puppet is skipping it")
+          next
+        end
+      end
+    end
+    @label_to_path_map
+  end
+
+  # Sets a class instance variable with a hash of all launchd plist files that
+  # are found on the system. The key of the hash is the job id and the value
+  # is the path to the file. If a label is passed, we return the job id and
+  # path for that specific job.
+  def self.jobsearch(label=nil)
+    by_label = make_label_to_path_map
+
+    if label
+      if by_label.has_key? label
+        return { label => by_label[label] }
+      else
+        # try refreshing the map, in case a plist has been added in the interim
+        by_label = make_label_to_path_map(true)
+        if by_label.has_key? label
+          return { label => by_label[label] }
+        else
+          raise Puppet::Error, "Unable to find launchd plist for job: #{label}"
+        end
+      end
+    else
+      # caller wants the whole map
+      by_label
+    end
+  end
+
+  # This status method lists out all currently running services.
+  # This hash is returned at the end of the method.
+  def self.job_list
+    @job_list = Hash.new
+    begin
+      output = launchctl :list
+      raise Puppet::Error.new("launchctl list failed to return any data.") if output.nil?
+      output.split("\n").each do |line|
+        @job_list[line.split(/\s/).last] = :running
+      end
+    rescue Puppet::ExecutionFailure
+      raise Puppet::Error.new("Unable to determine status of #{resource[:name]}", $!)
+    end
+    @job_list
+  end
+
+  # Launchd implemented plist overrides in version 10.6.
+  # This method checks the major_version of OS X and returns true if
+  # it is 10.6 or greater. This allows us to implement different plist
+  # behavior for versions >= 10.6
+  def has_macosx_plist_overrides?
+    # (#11593) Remove support for OS X 10.4 & earlier
+    # leaving this as is because 10.5 still didn't have plist support
+    return self.class.get_os_version > 9
+  end
+
+  # Read a plist, whether its format is XML or in Apple's "binary1"
+  # format.
+  def self.read_plist(path)
+    begin
+      return Plist::parse_xml(path)
+    rescue ArgumentError => detail
+      Puppet.debug("Error reading #{path}: #{detail}. Retrying with plutil.")
+    end
+
+    begin
+      Plist::parse_xml(plutil('-convert', 'xml1', '-o', '/dev/stdout', path))
+    rescue Puppet::ExecutionFailure => detail
+      Puppet.warning("Cannot read file #{path}; Puppet is skipping it. \n" +
+                     "Details: #{detail}")
+      return nil
+    end
+  end
+
+  # Clean out the @property_hash variable containing the cached list of services
+  def flush
+    @property_hash.clear
+  end
+
+  def exists?
+    Puppet.debug("Puppet::Provider::Launchd:Ensure for #{@property_hash[:name]}: #{@property_hash[:ensure]}")
+    @property_hash[:ensure] != :absent
+  end
+
+  def self.get_macosx_version_major
+    return @macosx_version_major if @macosx_version_major
+    begin
+      product_version_major = Facter.value(:macosx_productversion_major)
+
+      fail("#{product_version_major} is not supported by the launchd provider") if %w{10.0 10.1 10.2 10.3 10.4}.include?(product_version_major)
+      @macosx_version_major = product_version_major
+      return @macosx_version_major
+    rescue Puppet::ExecutionFailure => detail
+      self.fail Puppet::Error, "Could not determine OS X version: #{detail}", detail
+    end
+  end
+
+
+  # finds the path for a given label and returns the path and parsed plist
+  # as an array of [path, plist]. Note plist is really a Hash here.
+  def plist_from_label(label)
+    job = self.class.jobsearch(label)
+    job_path = job[label]
+    if FileTest.file?(job_path)
+      job_plist = self.class.read_plist(job_path)
+    else
+      raise Puppet::Error.new("Unable to parse launchd plist at path: #{job_path}")
+    end
+    [job_path, job_plist]
+  end
+
+  # start the service. To get to a state of running/enabled, we need to
+  # conditionally enable at load, then disable by modifying the plist file
+  # directly.
+  def start
+    return ucommand(:start) if resource[:start]
+    job_path, job_plist = plist_from_label(resource[:name])
+    did_enable_job = false
+    cmds = []
+    cmds << :launchctl << :load
+    # always add -w so it always starts the job, it is a noop if it is not needed, this means we do
+    # not have to rescan all launchd plists.
+    cmds << "-w"
+    if self.enabled? == :false  || self.status == :stopped # launchctl won't load disabled jobs
+      did_enable_job = true
+    end
+    cmds << job_path
+    begin
+      execute(cmds)
+    rescue Puppet::ExecutionFailure
+      raise Puppet::Error.new("Unable to start service: #{resource[:name]} at path: #{job_path}", $!)
+    end
+    # As load -w clears the Disabled flag, we need to add it in after
+    self.disable if did_enable_job and resource[:enable] == :false
+  end
+
+
+  def stop
+    return ucommand(:stop) if resource[:stop]
+    job_path, job_plist = plist_from_label(resource[:name])
+    did_disable_job = false
+    cmds = []
+    cmds << :launchctl << :unload
+    if self.enabled? == :true # keepalive jobs can't be stopped without disabling
+      cmds << "-w"
+      did_disable_job = true
+    end
+    cmds << job_path
+    begin
+      execute(cmds)
+    rescue Puppet::ExecutionFailure
+      raise Puppet::Error.new("Unable to stop service: #{resource[:name]} at path: #{job_path}", $!)
+    end
+    # As unload -w sets the Disabled flag, we need to add it in after
+    self.enable if did_disable_job and resource[:enable] == :true
+  end
+
+  def restart
+    Puppet.debug("A restart has been triggered for the #{resource[:name]} service")
+    Puppet.debug("Stopping the #{resource[:name]} service")
+    self.stop
+    Puppet.debug("Starting the #{resource[:name]} service")
+    self.start
+  end
+
+  # launchd jobs are enabled by default. They are only disabled if the key
+  # "Disabled" is set to true, but it can also be set to false to enable it.
+  # Starting in 10.6, the Disabled key in the job plist is consulted, but only
+  # if there is no entry in the global overrides plist.  We need to draw a
+  # distinction between undefined, true and false for both locations where the
+  # Disabled flag can be defined.
+  def enabled?
+    job_plist_disabled = nil
+    overrides_disabled = nil
+
+    job_path, job_plist = plist_from_label(resource[:name])
+    job_plist_disabled = job_plist["Disabled"] if job_plist.has_key?("Disabled")
+
+    if has_macosx_plist_overrides?
+      if FileTest.file?(self.class.launchd_overrides) and overrides = self.class.read_plist(self.class.launchd_overrides)
+        if overrides.has_key?(resource[:name])
+          if self.class.get_os_version < 14
+            overrides_disabled = overrides[resource[:name]]["Disabled"] if overrides[resource[:name]].has_key?("Disabled")
+          else
+            overrides_disabled = overrides[resource[:name]]
+          end
+        end
+      end
+    end
+
+    if overrides_disabled.nil?
+      if job_plist_disabled.nil? or job_plist_disabled == false
+        return :true
+      end
+    elsif overrides_disabled == false
+      return :true
+    end
+    :false
+  end
+
+  # enable and disable are a bit hacky. We write out the plist with the appropriate value
+  # rather than dealing with launchctl as it is unable to change the Disabled flag
+  # without actually loading/unloading the job.
+  # Starting in 10.6 we need to write out a disabled key to the global
+  # overrides plist, in earlier versions this is stored in the job plist itself.
+  def enable
+    if has_macosx_plist_overrides?
+      overrides = self.class.read_plist(self.class.launchd_overrides)
+      if self.class.get_os_version < 14
+        overrides[resource[:name]] = { "Disabled" => false }
+      else
+        overrides[resource[:name]] = false
+      end
+      Plist::Emit.save_plist(overrides, self.class.launchd_overrides)
+    else
+      job_path, job_plist = plist_from_label(resource[:name])
+      if self.enabled? == :false
+        job_plist.delete("Disabled")
+        Plist::Emit.save_plist(job_plist, job_path)
+      end
+    end
+  end
+
+  def disable
+    if has_macosx_plist_overrides?
+      overrides = self.class.read_plist(self.class.launchd_overrides)
+      if self.class.get_os_version < 14
+        overrides[resource[:name]] = { "Disabled" => true }
+      else
+        overrides[resource[:name]] = true
+      end
+      Plist::Emit.save_plist(overrides, self.class.launchd_overrides)
+    else
+      job_path, job_plist = plist_from_label(resource[:name])
+      job_plist["Disabled"] = true
+      Plist::Emit.save_plist(job_plist, job_path)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/openbsd.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/openbsd.rb
new file mode 100644
index 0000000..521462b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/openbsd.rb
@@ -0,0 +1,342 @@
+Puppet::Type.type(:service).provide :openbsd, :parent => :init do
+
+  desc "Provider for OpenBSD's rc.d daemon control scripts"
+
+  confine :operatingsystem => :openbsd
+  defaultfor :operatingsystem => :openbsd
+  has_feature :flaggable
+
+  def self.rcconf()        '/etc/rc.conf' end
+  def self.rcconf_local()  '/etc/rc.conf.local' end
+
+  def self.defpath
+    ["/etc/rc.d"]
+  end
+
+  def startcmd
+    [self.initscript, "-f", :start]
+  end
+
+  def restartcmd
+    (@resource[:hasrestart] == :true) && [self.initscript, "-f", :restart]
+  end
+
+  def statuscmd
+    [self.initscript, :check]
+  end
+
+  # Fetch the state of all service resources
+  def self.prefetch(resources)
+    services = instances
+    resources.keys.each do |name|
+      if provider = services.find { |svc| svc.name == name }
+        resources[name].provider = provider
+      end
+    end
+  end
+
+  # Return the list of rc scripts
+  # @api private
+  def self.rclist
+    unless @rclist
+      Puppet.debug "Building list of rc scripts"
+      @rclist = []
+      defpath.each do |p|
+        Dir.glob(p + '/*').each do |item|
+          @rclist << item if File.executable?(item)
+        end
+      end
+    end
+    @rclist
+  end
+
+  # Return a hash where the keys are the rc script names as symbols with flags
+  # as values
+  # @api private
+  def self.rcflags
+    unless @flag_hash
+      Puppet.debug "Retrieving flags for all discovered services"
+
+      Puppet.debug "Reading the contents of the rc conf files"
+
+      if File.exists?(rcconf_local())
+        rcconf_local_contents = File.readlines(rcconf_local())
+      else
+        rcconf_local_contents = []
+      end
+
+      if File.exists?(rcconf())
+        rcconf_contents = File.readlines(rcconf())
+      else
+        rcconf_contents = []
+      end
+
+      @flag_hash = {}
+      rclist().each do |rcitem|
+
+        rcname = rcitem.split('/').last
+
+        if flagline = rcconf_local_contents.find {|l| l =~ /^#{rcname}_flags/ }
+          flag = parse_rc_line(flagline)
+          @flag_hash[rcname.to_sym] ||= flag
+        end
+
+        # For the defaults, if the flags are set to 'NO', we skip setting the
+        # flag here, since it will already be disabled, and this makes the
+        # output of `puppet resource service` a bit more correct.
+        if flagline = rcconf_contents.find {|l| l =~ /^#{rcname}_flags/ }
+          flag = parse_rc_line(flagline)
+          unless flag == "NO"
+            @flag_hash[rcname.to_sym] ||= flag
+          end
+        end
+        @flag_hash[rcname.to_sym] ||= nil
+      end
+    end
+    @flag_hash
+  end
+
+  # @api private
+  def self.parse_rc_line(rc_line)
+    rc_line.sub!(/\s*#(.*)$/,'')
+    regex = /\w+_flags=(.*)/
+    rc_line.match(regex)[1].gsub(/^"/,'').gsub(/"$/,'')
+  end
+
+  # Read the rc.conf* files and determine the value of the flags
+  # @api private
+  def self.get_flags(rcname)
+    rcflags()
+    @flag_hash[rcname.to_sym]
+  end
+
+  def self.instances
+    instances = []
+    defpath.each do |path|
+      unless File.directory?(path)
+        Puppet.debug "Service path #{path} does not exist"
+        next
+      end
+
+      rclist().each do |d|
+        instances << new(
+          :name      => File.basename(d),
+          :path      => path,
+          :flags     => get_flags(File.basename(d)),
+          :hasstatus => true
+        )
+      end
+    end
+    instances
+  end
+
+  # @api private
+  def rcvar_name
+    self.name + '_flags'
+  end
+
+  # @api private
+  def read_rcconf_local_text()
+    if File.exists?(self.class.rcconf_local())
+      File.read(self.class.rcconf_local())
+    else
+      []
+    end
+  end
+
+  # @api private
+  def load_rcconf_local_array
+    if File.exists?(self.class.rcconf_local())
+      File.readlines(self.class.rcconf_local()).map {|l|
+        l.chomp!
+      }
+    else
+      []
+    end
+  end
+
+  # @api private
+  def write_rc_contents(file, text)
+    Puppet::Util.replace_file(file, 0644) do |f|
+      f.write(text)
+    end
+  end
+
+  # @api private
+  def set_content_flags(content,flags)
+    unless content.is_a? Array
+      debug "content must be an array at flags"
+      return ""
+    else
+      content.reject! {|l| l.nil? }
+    end
+
+    if flags.nil? or flags.size == 0
+      if in_base?
+        append = resource[:name] + '_flags=""'
+      end
+    else
+      append = resource[:name] + '_flags="' + flags + '"'
+    end
+
+    if content.find {|l| l =~ /#{resource[:name]}_flags/ }.nil?
+      content << append
+    else
+      content.map {|l| l.gsub!(/^#{resource[:name]}_flags="(.*)?"(.*)?$/, append) }
+    end
+    content
+  end
+
+  # @api private
+  def remove_content_flags(content)
+    content.reject {|l| l =~ /#{resource[:name]}_flags/ }
+  end
+
+  # return an array of the currently enabled pkg_scripts
+  # @api private
+  def pkg_scripts
+    current = load_rcconf_local_array()
+    if scripts = current.find{|l| l =~ /^pkg_scripts/ }
+      if match = scripts.match(/^pkg_scripts="(.*)?"(.*)?$/)
+        match[1].split(' ')
+      else
+        []
+      end
+    else
+      []
+    end
+  end
+
+  # return the array with the current resource added
+  # @api private
+  def pkg_scripts_append
+    [pkg_scripts(), resource[:name]].flatten.uniq
+  end
+
+  # return the array without the current resource
+  # @api private
+  def pkg_scripts_remove
+    pkg_scripts().reject {|s| s == resource[:name] }
+  end
+
+  # Modify the content array to contain the requsted pkg_scripts line and retun
+  # the resulting array
+  # @api private
+  def set_content_scripts(content,scripts)
+    unless content.is_a? Array
+      debug "content must be an array at scripts"
+      return ""
+    else
+      content.reject! {|l| l.nil? }
+    end
+
+    scripts_line = 'pkg_scripts="' + scripts.join(' ') + '"'
+
+    if content.find {|l| l =~ /^pkg_scripts/ }.nil?
+      content << scripts_line
+    else
+      # Replace the found pkg_scripts line with our own
+      content.each_with_index {|l,i|
+        if l =~ /^pkg_scripts/
+          content[i] = scripts_line
+        end
+      }
+    end
+    content
+  end
+
+  # Determine if the rc script is included in base
+  # @api private
+  def in_base?
+    script = File.readlines(self.class.rcconf).find {|s| s =~ /^#{rcvar_name}/ }
+    !script.nil?
+  end
+
+  # @api private
+  def default_disabled?
+    line = File.readlines(self.class.rcconf).find {|l| l =~ /#{rcvar_name}/ }
+    self.class.parse_rc_line(line) == 'NO'
+  end
+
+  def enabled?
+    if in_base?
+      if (@property_hash[:flags].nil? or @property_hash[:flags] == 'NO')
+        :false
+      else
+        :true
+      end
+    else
+      if (pkg_scripts().include?(@property_hash[:name]))
+        :true
+      else
+        :false
+      end
+    end
+  end
+
+  def enable
+    self.debug("Enabling #{self.name}")
+  end
+
+  # We should also check for default state
+  def disable
+    self.debug("Disabling #{self.name}")
+  end
+
+  def flags
+    @property_hash[:flags]
+  end
+
+  def flags=(value)
+    @property_hash[:flags] = value
+  end
+
+  def flush
+    debug "Flusing resource for #{self.name}"
+
+    # Here we load the contents of the rc.conf.local file into the contents
+    # variable, modify it if needed, and then compare that to the original.  If
+    # they are different, we write it out.
+
+    original = load_rcconf_local_array()
+    content = original
+
+    debug @property_hash.inspect
+
+    if resource[:enable] == :true
+      #set_flags(resource[:flags])
+      content = set_content_flags(content, resource[:flags])
+
+      # We need only add append the resource name to the pkg_scripts if the
+      # package is not found in the base system.
+
+      if not in_base?
+        content = set_content_scripts(content,pkg_scripts_append())
+      end
+    elsif resource[:enable] == :false
+
+      # By virtue of being excluded from the base system, all packages are
+      # disabled by default and need not be set in the rc.conf.local at all.
+
+      if not in_base?
+        content = remove_content_flags(content)
+        content = set_content_scripts(content,pkg_scripts_remove())
+      else
+        if default_disabled?
+          content = remove_content_flags(content)
+        else
+          content = set_content_flags(content, "NO")
+        end
+      end
+    end
+
+    # Make sure to append a newline to the end of the file
+    unless content[-1] == ""
+      content << ""
+    end
+    output = content.join("\n")
+
+    # Write the contents only if necessary, and only once
+    write_rc_contents(self.class.rcconf_local(), output)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/openrc.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/openrc.rb
new file mode 100644
index 0000000..8243f65
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/openrc.rb
@@ -0,0 +1,71 @@
+# Gentoo OpenRC
+Puppet::Type.type(:service).provide :openrc, :parent => :base do
+  desc <<-EOT
+    Support for Gentoo's OpenRC initskripts
+
+    Uses rc-update, rc-status and rc-service to manage services.
+
+  EOT
+
+  defaultfor :operatingsystem => :gentoo
+  defaultfor :operatingsystem => :funtoo
+
+  has_command(:rcstatus, '/bin/rc-status') do
+    environment :RC_SVCNAME => nil
+  end
+  commands :rcservice => '/sbin/rc-service'
+  commands :rcupdate  => '/sbin/rc-update'
+
+  self::STATUSLINE = /^\s+(.*?)\s*\[\s*(.*)\s*\]$/
+
+  def enable
+    rcupdate('-C', :add, @resource[:name])
+  end
+
+  def disable
+    rcupdate('-C', :del, @resource[:name])
+  end
+
+  # rc-status -a shows all runlevels and dynamic runlevels which
+  # are not considered as enabled. We have to find out under which
+  # runlevel our service is listed
+  def enabled?
+    enabled = :false
+    rcstatus('-C', '-a').each_line do |line|
+      case line.chomp
+      when /^Runlevel: /
+        enabled = :true
+      when /^\S+/ # caption of a dynamic runlevel
+        enabled = :false
+      when self.class::STATUSLINE
+        return enabled if @resource[:name] == $1
+      end
+    end
+    :false
+  end
+
+  def self.instances
+    instances = []
+    rcservice('-C', '--list').each_line do |line|
+      instances << new(:name => line.chomp)
+    end
+    instances
+  end
+
+  def restartcmd
+    (@resource[:hasrestart] == :true) && [command(:rcservice), @resource[:name], :restart]
+  end
+
+  def startcmd
+    [command(:rcservice), @resource[:name], :start ]
+  end
+
+  def stopcmd
+    [command(:rcservice), @resource[:name], :stop]
+  end
+
+  def statuscmd
+    ((@resource.provider.get(:hasstatus) == true) || (@resource[:hasstatus] == :true)) && [command(:rcservice), @resource[:name], :status]
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/openwrt.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/openwrt.rb
new file mode 100644
index 0000000..f117127
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/openwrt.rb
@@ -0,0 +1,36 @@
+Puppet::Type.type(:service).provide :openwrt, :parent => :init, :source => :init do
+  desc <<-EOT
+    Support for OpenWrt flavored init scripts.
+
+    Uses /etc/init.d/service_name enable, disable, and enabled.
+
+  EOT
+
+  defaultfor :operatingsystem => :openwrt
+  confine :operatingsystem => :openwrt
+
+  has_feature :enableable
+
+  def self.defpath
+    ["/etc/init.d"]
+  end
+
+  def enable
+    system(self.initscript, 'enable')
+  end
+
+  def disable
+    system(self.initscript, 'disable')
+  end
+
+  def enabled?
+    # We can't define the "command" for the init script, so we call system?
+    if system(self.initscript, 'enabled') then return :true else return :false end
+  end
+
+  # Purposely leave blank so we fail back to ps based status detection
+  # As OpenWrt init script do not have status commands
+  def statuscmd
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/redhat.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/redhat.rb
new file mode 100644
index 0000000..6e49a8f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/redhat.rb
@@ -0,0 +1,70 @@
+# Manage Red Hat services.  Start/stop uses /sbin/service and enable/disable uses chkconfig
+
+Puppet::Type.type(:service).provide :redhat, :parent => :init, :source => :init do
+  desc "Red Hat's (and probably many others') form of `init`-style service
+    management. Uses `chkconfig` for service enabling and disabling.
+
+  "
+
+  commands :chkconfig => "/sbin/chkconfig", :service => "/sbin/service"
+
+  defaultfor :osfamily => [:redhat, :suse]
+
+  # Remove the symlinks
+  def disable
+    # The off method operates on run levels 2,3,4 and 5 by default We ensure
+    # all run levels are turned off because the reset method may turn on the
+    # service in run levels 0, 1 and/or 6
+    # We're not using --del here because we want to disable the service only,
+    # and --del removes the service from chkconfig management
+    chkconfig("--level", "0123456", @resource[:name], :off)
+  rescue Puppet::ExecutionFailure => detail
+    raise Puppet::Error, "Could not disable #{self.name}: #{detail}", detail.backtrace
+  end
+
+  def enabled?
+    name = @resource[:name]
+
+    begin
+      output = chkconfig name
+    rescue Puppet::ExecutionFailure
+      return :false
+    end
+
+    # For Suse OS family, chkconfig returns 0 even if the service is disabled or non-existent
+    # Therefore, check the output for '<name>  on' to see if it is enabled
+    return :false unless Facter.value(:osfamily) != 'Suse' || output =~ /^#{name}\s+on$/
+
+    :true
+  end
+
+  # Don't support them specifying runlevels; always use the runlevels
+  # in the init scripts.
+  def enable
+      chkconfig("--add", @resource[:name])
+      chkconfig(@resource[:name], :on)
+  rescue Puppet::ExecutionFailure => detail
+    raise Puppet::Error, "Could not enable #{self.name}: #{detail}", detail.backtrace
+  end
+
+  def initscript
+    raise Puppet::Error, "Do not directly call the init script for '#{@resource[:name]}'; use 'service' instead"
+  end
+
+  # use hasstatus=>true when its set for the provider.
+  def statuscmd
+    ((@resource.provider.get(:hasstatus) == true) || (@resource[:hasstatus] == :true)) && [command(:service), @resource[:name], "status"]
+  end
+
+  def restartcmd
+    (@resource[:hasrestart] == :true) && [command(:service), @resource[:name], "restart"]
+  end
+
+  def startcmd
+    [command(:service), @resource[:name], "start"]
+  end
+
+  def stopcmd
+    [command(:service), @resource[:name], "stop"]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/runit.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/runit.rb
new file mode 100644
index 0000000..f73c709
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/runit.rb
@@ -0,0 +1,111 @@
+# Daemontools service management
+#
+# author Brice Figureau <brice-puppet@daysofwonder.com>
+Puppet::Type.type(:service).provide :runit, :parent => :daemontools do
+  desc <<-'EOT'
+    Runit service management.
+
+    This provider manages daemons running supervised by Runit.
+    When detecting the service directory it will check, in order of preference:
+
+    * `/service`
+    * `/etc/service`
+    * `/var/service`
+
+    The daemon directory should be in one of the following locations:
+
+    * `/etc/sv`
+    * `/var/lib/service`
+
+    or this can be overriden in the service resource parameters::
+
+        service { "myservice":
+          provider => "runit",
+          path => "/path/to/daemons",
+        }
+
+    This provider supports out of the box:
+
+    * start/stop
+    * enable/disable
+    * restart
+    * status
+
+
+  EOT
+
+  commands :sv => "/usr/bin/sv"
+
+  class << self
+    # this is necessary to autodetect a valid resource
+    # default path, since there is no standard for such directory.
+    def defpath(dummy_argument=:work_arround_for_ruby_GC_bug)
+      unless @defpath
+        ["/etc/sv", "/var/lib/service"].each do |path|
+          if Puppet::FileSystem.exist?(path)
+            @defpath = path
+            break
+          end
+        end
+        raise "Could not find the daemon directory (tested [/etc/sv,/var/lib/service])" unless @defpath
+      end
+      @defpath
+    end
+  end
+
+  # find the service dir on this node
+  def servicedir
+    unless @servicedir
+      ["/service", "/etc/service","/var/service"].each do |path|
+        if Puppet::FileSystem.exist?(path)
+          @servicedir = path
+          break
+        end
+      end
+      raise "Could not find service directory" unless @servicedir
+    end
+    @servicedir
+  end
+
+  def status
+    begin
+      output = sv "status", self.daemon
+      return :running if output =~ /^run: /
+    rescue Puppet::ExecutionFailure => detail
+      unless detail.message =~ /(warning: |runsv not running$)/
+        raise Puppet::Error.new( "Could not get status for service #{resource.ref}: #{detail}", detail )
+      end
+    end
+    :stopped
+  end
+
+  def stop
+    sv "stop", self.service
+  end
+
+  def start
+    if enabled? != :true
+        enable
+        # Work around issue #4480
+        # runsvdir takes up to 5 seconds to recognize
+        # the symlink created by this call to enable
+        Puppet.info "Waiting 5 seconds for runsvdir to discover service #{self.service}"
+        sleep 5
+    end
+    sv "start", self.service
+  end
+
+  def restart
+    sv "restart", self.service
+  end
+
+  # disable by removing the symlink so that runit
+  # doesn't restart our service behind our back
+  # note that runit doesn't need to perform a stop
+  # before a disable
+  def disable
+    # unlink the daemon symlink to disable it
+    Puppet::FileSystem.unlink(self.service) if Puppet::FileSystem.symlink?(self.service)
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/service.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/service.rb
new file mode 100644
index 0000000..1b95542
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/service.rb
@@ -0,0 +1,42 @@
+Puppet::Type.type(:service).provide :service do
+  desc "The simplest form of service support."
+
+  def self.instances
+    []
+  end
+
+  # How to restart the process.
+  def restart
+    if @resource[:restart] or restartcmd
+      ucommand(:restart)
+    else
+      self.stop
+      self.start
+    end
+  end
+
+  # There is no default command, which causes other methods to be used
+  def restartcmd
+  end
+
+  # A simple wrapper so execution failures are a bit more informative.
+  def texecute(type, command, fof = true, squelch = false, combine = true)
+    begin
+      execute(command, :failonfail => fof, :override_locale => false, :squelch => squelch, :combine => combine)
+    rescue Puppet::ExecutionFailure => detail
+      @resource.fail Puppet::Error, "Could not #{type} #{@resource.ref}: #{detail}", detail
+    end
+    nil
+  end
+
+  # Use either a specified command or the default for our provider.
+  def ucommand(type, fof = true)
+    if c = @resource[type]
+      cmd = [c]
+    else
+      cmd = [send("#{type}cmd")].flatten
+    end
+    texecute(type, cmd, fof)
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/smf.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/smf.rb
new file mode 100644
index 0000000..fd7793f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/smf.rb
@@ -0,0 +1,116 @@
+# Solaris 10 SMF-style services.
+Puppet::Type.type(:service).provide :smf, :parent => :base do
+  desc <<-EOT
+    Support for Sun's new Service Management Framework.
+
+    Starting a service is effectively equivalent to enabling it, so there is
+    only support for starting and stopping services, which also enables and
+    disables them, respectively.
+
+    By specifying `manifest => "/path/to/service.xml"`, the SMF manifest will
+    be imported if it does not exist.
+
+  EOT
+
+  defaultfor :osfamily => :solaris
+
+  confine :osfamily => :solaris
+
+  commands :adm => "/usr/sbin/svcadm", :svcs => "/usr/bin/svcs"
+  commands :svccfg => "/usr/sbin/svccfg"
+
+  def setupservice
+      if resource[:manifest]
+        [command(:svcs), "-l", @resource[:name]]
+        if $CHILD_STATUS.exitstatus == 1
+          Puppet.notice "Importing #{@resource[:manifest]} for #{@resource[:name]}"
+          svccfg :import, resource[:manifest]
+        end
+      end
+  rescue Puppet::ExecutionFailure => detail
+      raise Puppet::Error.new( "Cannot config #{self.name} to enable it: #{detail}", detail )
+  end
+
+  def self.instances
+   svcs.split("\n").select{|l| l !~ /^legacy_run/ }.collect do |line|
+     state,stime,fmri = line.split(/\s+/)
+     status =  case state
+               when /online/; :running
+               when /maintenance/; :maintenance
+               else :stopped
+               end
+     new({:name => fmri, :ensure => status})
+   end
+  end
+
+  def enable
+    self.start
+  end
+
+  def enabled?
+    case self.status
+    when :running
+      return :true
+    else
+      return :false
+    end
+  end
+
+  def disable
+    self.stop
+  end
+
+  def restartcmd
+    [command(:adm), :restart, @resource[:name]]
+  end
+
+  def startcmd
+    self.setupservice
+    case self.status
+    when :maintenance
+      [command(:adm), :clear, @resource[:name]]
+    else
+      [command(:adm), :enable, "-s", @resource[:name]]
+    end
+  end
+
+  def status
+    if @resource[:status]
+      super
+      return
+    end
+
+    begin
+      # get the current state and the next state, and if the next
+      # state is set (i.e. not "-") use it for state comparison
+      states = svcs("-H", "-o", "state,nstate", @resource[:name]).chomp.split
+      state = states[1] == "-" ? states[0] : states[1]
+    rescue Puppet::ExecutionFailure
+      info "Could not get status on service #{self.name}"
+      return :stopped
+    end
+
+    case state
+    when "online"
+      #self.warning "matched running #{line.inspect}"
+      return :running
+    when "offline", "disabled", "uninitialized"
+      #self.warning "matched stopped #{line.inspect}"
+      return :stopped
+    when "maintenance"
+      return :maintenance
+    when "legacy_run"
+      raise Puppet::Error,
+        "Cannot manage legacy services through SMF"
+    else
+      raise Puppet::Error,
+        "Unmanageable state '#{state}' on service #{self.name}"
+    end
+
+  end
+
+  def stopcmd
+    [command(:adm), :disable, "-s", @resource[:name]]
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/src.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/src.rb
new file mode 100644
index 0000000..e4bcbd9
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/src.rb
@@ -0,0 +1,120 @@
+# AIX System Resource controller (SRC)
+Puppet::Type.type(:service).provide :src, :parent => :base do
+
+  desc "Support for AIX's System Resource controller.
+
+  Services are started/stopped based on the `stopsrc` and `startsrc`
+  commands, and some services can be refreshed with `refresh` command.
+
+  Enabling and disabling services is not supported, as it requires
+  modifications to `/etc/inittab`. Starting and stopping groups of subsystems
+  is not yet supported.
+  "
+
+  defaultfor :operatingsystem => :aix
+  confine :operatingsystem => :aix
+
+  optional_commands :stopsrc  => "/usr/bin/stopsrc",
+                    :startsrc => "/usr/bin/startsrc",
+                    :refresh  => "/usr/bin/refresh",
+                    :lssrc    => "/usr/bin/lssrc",
+                    :lsitab   => "/usr/sbin/lsitab",
+                    :mkitab   => "/usr/sbin/mkitab",
+                    :rmitab   => "/usr/sbin/rmitab",
+                    :chitab   => "/usr/sbin/chitab"
+
+  has_feature :refreshable
+
+  def self.instances
+    services = lssrc('-S')
+    services.split("\n").reject { |x| x.strip.start_with? '#' }.collect do |line|
+      data = line.split(':')
+      service_name = data[0]
+      new(:name => service_name)
+    end
+  end
+
+  def startcmd
+    [command(:startsrc), "-s", @resource[:name]]
+  end
+
+  def stopcmd
+    [command(:stopsrc), "-s", @resource[:name]]
+  end
+
+  def default_runlevel
+    "2"
+  end
+
+  def default_action
+    "once"
+  end
+
+  def enabled?
+    execute([command(:lsitab), @resource[:name]], {:failonfail => false, :combine => true})
+    $CHILD_STATUS.exitstatus == 0 ? :true : :false
+  end
+
+  def enable
+    mkitab("%s:%s:%s:%s" % [@resource[:name], default_runlevel, default_action, startcmd.join(" ")])
+  end
+
+  def disable
+    rmitab(@resource[:name])
+  end
+
+  def restart
+      execute([command(:lssrc), "-Ss", @resource[:name]]).each_line do |line|
+        args = line.split(":")
+
+        next unless args[0] == @resource[:name]
+
+        # Subsystems with the -K flag can get refreshed (HUPed)
+        # While subsystems with -S (signals) must be stopped/started
+        method = args[11]
+        do_refresh = case method
+          when "-K" then :true
+          when "-S" then :false
+          else self.fail("Unknown service communication method #{method}")
+        end
+
+        begin
+          if do_refresh == :true
+            execute([command(:refresh), "-s", @resource[:name]])
+          else
+            self.stop
+            self.start
+          end
+          return :true
+        rescue Puppet::ExecutionFailure => detail
+          raise Puppet::Error.new("Unable to restart service #{@resource[:name]}, error was: #{detail}", detail )
+        end
+      end
+      self.fail("No such service found")
+  rescue Puppet::ExecutionFailure => detail
+      raise Puppet::Error.new("Cannot get status of #{@resource[:name]}, error was: #{detail}", detail )
+  end
+
+  def status
+      execute([command(:lssrc), "-s", @resource[:name]]).each_line do |line|
+        args = line.split
+
+        # This is the header line
+        next unless args[0] == @resource[:name]
+
+        # PID is the 3rd field, but inoperative subsystems
+        # skip this so split doesn't work right
+        state = case args[-1]
+          when "active" then :running
+          when "inoperative" then :stopped
+        end
+        Puppet.debug("Service #{@resource[:name]} is #{args[-1]}")
+        return state
+      end
+      self.fail("No such service found")
+  rescue Puppet::ExecutionFailure => detail
+      raise Puppet::Error.new("Cannot get status of #{@resource[:name]}, error was: #{detail}", detail )
+  end
+
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/systemd.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/systemd.rb
new file mode 100644
index 0000000..94443e4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/systemd.rb
@@ -0,0 +1,66 @@
+# Manage systemd services using /bin/systemctl
+
+Puppet::Type.type(:service).provide :systemd, :parent => :base do
+  desc "Manages `systemd` services using `systemctl`."
+
+  commands :systemctl => "systemctl"
+
+  defaultfor :osfamily => [:archlinux]
+  defaultfor :osfamily => :redhat, :operatingsystemmajrelease => "7"
+  defaultfor :osfamily => :redhat, :operatingsystem => :fedora, :operatingsystemmajrelease => ["17", "18", "19", "20", "21"]
+
+  def self.instances
+    i = []
+    output = systemctl('list-unit-files', '--type', 'service', '--full', '--all',  '--no-pager')
+    output.scan(/^(\S+)\s+(disabled|enabled)\s*$/i).each do |m|
+      i << new(:name => m[0])
+    end
+    return i
+  rescue Puppet::ExecutionFailure
+    return []
+  end
+
+  def disable
+    output = systemctl(:disable, @resource[:name])
+  rescue Puppet::ExecutionFailure
+    raise Puppet::Error, "Could not disable #{self.name}: #{output}", $!.backtrace
+  end
+
+  def enabled?
+    begin
+      systemctl("is-enabled", @resource[:name])
+    rescue Puppet::ExecutionFailure
+      return :false
+    end
+
+    :true
+  end
+
+  def status
+    begin
+      systemctl("is-active", @resource[:name])
+    rescue Puppet::ExecutionFailure
+      return :stopped
+    end
+    return :running
+  end
+
+  def enable
+    output = systemctl("enable", @resource[:name])
+  rescue Puppet::ExecutionFailure
+    raise Puppet::Error, "Could not enable #{self.name}: #{output}", $!.backtrace
+  end
+
+  def restartcmd
+    [command(:systemctl), "restart", @resource[:name]]
+  end
+
+  def startcmd
+    [command(:systemctl), "start", @resource[:name]]
+  end
+
+  def stopcmd
+    [command(:systemctl), "stop", @resource[:name]]
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/upstart.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/upstart.rb
new file mode 100644
index 0000000..a963dde
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/upstart.rb
@@ -0,0 +1,359 @@
+require 'semver'
+
+Puppet::Type.type(:service).provide :upstart, :parent => :debian do
+  START_ON = /^\s*start\s+on/
+  COMMENTED_START_ON = /^\s*#+\s*start\s+on/
+  MANUAL   = /^\s*manual\s*$/
+
+  desc "Ubuntu service management with `upstart`.
+
+  This provider manages `upstart` jobs on Ubuntu. For `upstart` documentation,
+  see <http://upstart.ubuntu.com/>.
+  "
+
+  confine :any => [
+    Facter.value(:operatingsystem) == 'Ubuntu',
+    (Facter.value(:osfamily) == 'RedHat' and Facter.value(:operatingsystemrelease) =~ /^6\./),
+  ]
+
+  defaultfor :operatingsystem => :ubuntu
+
+  commands :start   => "/sbin/start",
+           :stop    => "/sbin/stop",
+           :restart => "/sbin/restart",
+           :status_exec  => "/sbin/status",
+           :initctl => "/sbin/initctl"
+
+  # upstart developer haven't implemented initctl enable/disable yet:
+  # http://www.linuxplanet.com/linuxplanet/tutorials/7033/2/
+  has_feature :enableable
+
+  def self.instances
+    self.get_services(self.excludes) # Take exclude list from init provider
+  end
+
+  def self.excludes
+    excludes = super
+    if Facter.value(:osfamily) == 'RedHat'
+      # Puppet cannot deal with services that have instances, so we have to
+      # ignore these services using instances on redhat based systems.
+      excludes += %w[serial tty]
+    end
+
+    excludes
+  end
+
+
+  def self.get_services(exclude=[])
+    instances = []
+    execpipe("#{command(:initctl)} list") { |process|
+      process.each_line { |line|
+        # needs special handling of services such as network-interface:
+        # initctl list:
+        # network-interface (lo) start/running
+        # network-interface (eth0) start/running
+        # network-interface-security start/running
+        name = \
+          if matcher = line.match(/^(network-interface)\s\(([^\)]+)\)/)
+            "#{matcher[1]} INTERFACE=#{matcher[2]}"
+          elsif matcher = line.match(/^(network-interface-security)\s\(([^\)]+)\)/)
+            "#{matcher[1]} JOB=#{matcher[2]}"
+          else
+            line.split.first
+          end
+        instances << new(:name => name)
+      }
+    }
+    instances.reject { |instance| exclude.include?(instance.name) }
+  end
+
+  def self.defpath
+    ["/etc/init", "/etc/init.d"]
+  end
+
+  def upstart_version
+    @upstart_version ||= initctl("--version").match(/initctl \(upstart ([^\)]*)\)/)[1]
+  end
+
+  # Where is our override script?
+  def overscript
+    @overscript ||= initscript.gsub(/\.conf$/,".override")
+  end
+
+  def search(name)
+    # Search prefers .conf as that is what upstart uses
+    [".conf", "", ".sh"].each do |suffix|
+      paths.each do |path|
+        service_name = name.match(/^(\S+)/)[1]
+        fqname = File.join(path, service_name + suffix)
+        if Puppet::FileSystem.exist?(fqname)
+          return fqname
+        end
+
+        self.debug("Could not find #{name}#{suffix} in #{path}")
+      end
+    end
+
+    raise Puppet::Error, "Could not find init script or upstart conf file for '#{name}'"
+  end
+
+  def enabled?
+    return super if not is_upstart?
+
+    script_contents = read_script_from(initscript)
+    if version_is_pre_0_6_7
+      enabled_pre_0_6_7?(script_contents)
+    elsif version_is_pre_0_9_0
+      enabled_pre_0_9_0?(script_contents)
+    elsif version_is_post_0_9_0
+      enabled_post_0_9_0?(script_contents, read_override_file)
+    end
+  end
+
+  def enable
+    return super if not is_upstart?
+
+    script_text = read_script_from(initscript)
+    if version_is_pre_0_9_0
+      enable_pre_0_9_0(script_text)
+    else
+      enable_post_0_9_0(script_text, read_override_file)
+    end
+  end
+
+  def disable
+    return super if not is_upstart?
+
+    script_text = read_script_from(initscript)
+    if version_is_pre_0_6_7
+      disable_pre_0_6_7(script_text)
+    elsif version_is_pre_0_9_0
+      disable_pre_0_9_0(script_text)
+    elsif version_is_post_0_9_0
+      disable_post_0_9_0(read_override_file)
+    end
+  end
+
+  def startcmd
+    is_upstart? ? [command(:start), @resource[:name]] : super
+  end
+
+  def stopcmd
+    is_upstart? ? [command(:stop),  @resource[:name]] : super
+  end
+
+  def restartcmd
+    is_upstart? ? (@resource[:hasrestart] == :true) && [command(:restart), @resource[:name]] : super
+  end
+
+  def statuscmd
+    is_upstart? ? nil : super #this is because upstart is broken with its return codes
+  end
+
+  def status
+    if (@resource[:hasstatus] == :false) ||
+        @resource[:status] ||
+        ! is_upstart?
+      return super
+    end
+
+    output = status_exec(@resource[:name].split)
+    if output =~ /start\//
+      return :running
+    else
+      return :stopped
+    end
+  end
+
+private
+  def is_upstart?(script = initscript)
+    Puppet::FileSystem.exist?(script) && script.match(/\/etc\/init\/\S+\.conf/)
+  end
+
+  def version_is_pre_0_6_7
+    Puppet::Util::Package.versioncmp(upstart_version, "0.6.7") == -1
+  end
+
+  def version_is_pre_0_9_0
+    Puppet::Util::Package.versioncmp(upstart_version, "0.9.0") == -1
+  end
+
+  def version_is_post_0_9_0
+    Puppet::Util::Package.versioncmp(upstart_version, "0.9.0") >= 0
+  end
+
+  def enabled_pre_0_6_7?(script_text)
+    # Upstart version < 0.6.7 means no manual stanza.
+    if script_text.match(START_ON)
+      return :true
+    else
+      return :false
+    end
+  end
+
+  def enabled_pre_0_9_0?(script_text)
+    # Upstart version < 0.9.0 means no override files
+    # So we check to see if an uncommented start on or manual stanza is the last one in the file
+    # The last one in the file wins.
+    enabled = :false
+    script_text.each_line do |line|
+      if line.match(START_ON)
+        enabled = :true
+      elsif line.match(MANUAL)
+        enabled = :false
+      end
+    end
+    enabled
+  end
+
+  def enabled_post_0_9_0?(script_text, over_text)
+    # This version has manual stanzas and override files
+    # So we check to see if an uncommented start on or manual stanza is the last one in the
+    # conf file and any override files. The last one in the file wins.
+    enabled = :false
+
+    script_text.each_line do |line|
+      if line.match(START_ON)
+        enabled = :true
+      elsif line.match(MANUAL)
+        enabled = :false
+      end
+    end
+    over_text.each_line do |line|
+      if line.match(START_ON)
+        enabled = :true
+      elsif line.match(MANUAL)
+        enabled = :false
+      end
+    end if over_text
+    enabled
+  end
+
+  def enable_pre_0_9_0(text)
+    # We also need to remove any manual stanzas to ensure that it is enabled
+    text = remove_manual_from(text)
+
+    if enabled_pre_0_9_0?(text) == :false
+      enabled_script =
+        if text.match(COMMENTED_START_ON)
+          uncomment_start_block_in(text)
+        else
+          add_default_start_to(text)
+        end
+    else
+      enabled_script = text
+    end
+
+    write_script_to(initscript, enabled_script)
+  end
+
+  def enable_post_0_9_0(script_text, over_text)
+    over_text = remove_manual_from(over_text)
+
+    if enabled_post_0_9_0?(script_text, over_text) == :false
+      if script_text.match(START_ON)
+        over_text << extract_start_on_block_from(script_text)
+      else
+        over_text << "\nstart on runlevel [2,3,4,5]"
+      end
+    end
+
+    write_script_to(overscript, over_text)
+  end
+
+  def disable_pre_0_6_7(script_text)
+    disabled_script = comment_start_block_in(script_text)
+    write_script_to(initscript, disabled_script)
+  end
+
+  def disable_pre_0_9_0(script_text)
+    write_script_to(initscript, ensure_disabled_with_manual(script_text))
+  end
+
+  def disable_post_0_9_0(over_text)
+    write_script_to(overscript, ensure_disabled_with_manual(over_text))
+  end
+
+  def read_override_file
+    if Puppet::FileSystem.exist?(overscript)
+      read_script_from(overscript)
+    else
+      ""
+    end
+  end
+
+  def uncomment(line)
+    line.gsub(/^(\s*)#+/, '\1')
+  end
+
+  def remove_trailing_comments_from_commented_line_of(line)
+    line.gsub(/^(\s*#+\s*[^#]*).*/, '\1')
+  end
+
+  def remove_trailing_comments_from(line)
+    line.gsub(/^(\s*[^#]*).*/, '\1')
+  end
+
+  def unbalanced_parens_on(line)
+    line.count('(') - line.count(')')
+  end
+
+  def remove_manual_from(text)
+    text.gsub(MANUAL, "")
+  end
+
+  def comment_start_block_in(text)
+    parens = 0
+    text.lines.map do |line|
+      if line.match(START_ON) || parens > 0
+        # If there are more opening parens than closing parens, we need to comment out a multiline 'start on' stanza
+        parens += unbalanced_parens_on(remove_trailing_comments_from(line))
+        "#" + line
+      else
+        line
+      end
+    end.join('')
+  end
+
+  def uncomment_start_block_in(text)
+    parens = 0
+    text.lines.map do |line|
+      if line.match(COMMENTED_START_ON) || parens > 0
+        parens += unbalanced_parens_on(remove_trailing_comments_from_commented_line_of(line))
+        uncomment(line)
+      else
+        line
+      end
+    end.join('')
+  end
+
+  def extract_start_on_block_from(text)
+    parens = 0
+    text.lines.map do |line|
+      if line.match(START_ON) || parens > 0
+        parens += unbalanced_parens_on(remove_trailing_comments_from(line))
+        line
+      end
+    end.join('')
+  end
+
+  def add_default_start_to(text)
+    text + "\nstart on runlevel [2,3,4,5]"
+  end
+
+  def ensure_disabled_with_manual(text)
+    remove_manual_from(text) + "\nmanual"
+  end
+
+  def read_script_from(filename)
+    File.open(filename) do |file|
+      file.read
+    end
+  end
+
+  def write_script_to(file, text)
+    Puppet::Util.replace_file(file, 0644) do |file|
+      file.write(text)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/windows.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/windows.rb
new file mode 100644
index 0000000..2eb55f3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/service/windows.rb
@@ -0,0 +1,106 @@
+# Windows Service Control Manager (SCM) provider
+
+Puppet::Type.type(:service).provide :windows, :parent => :service do
+
+  desc <<-EOT
+    Support for Windows Service Control Manager (SCM). This provider can
+    start, stop, enable, and disable services, and the SCM provides working
+    status methods for all services.
+
+    Control of service groups (dependencies) is not yet supported, nor is running
+    services as a specific user.
+  EOT
+
+  defaultfor :operatingsystem => :windows
+  confine    :operatingsystem => :windows
+
+  has_feature :refreshable
+
+  commands :net => 'net.exe'
+
+  def enable
+    w32ss = Win32::Service.configure( 'service_name' => @resource[:name], 'start_type' => Win32::Service::SERVICE_AUTO_START )
+    raise Puppet::Error.new("Win32 service enable of #{@resource[:name]} failed" ) if( w32ss.nil? )
+  rescue => detail
+    raise Puppet::Error.new("Cannot enable #{@resource[:name]}, error was: #{detail}", detail )
+  end
+
+  def disable
+    w32ss = Win32::Service.configure( 'service_name' => @resource[:name], 'start_type' => Win32::Service::SERVICE_DISABLED )
+    raise Puppet::Error.new("Win32 service disable of #{@resource[:name]} failed" ) if( w32ss.nil? )
+  rescue => detail
+    raise Puppet::Error.new("Cannot disable #{@resource[:name]}, error was: #{detail}", detail )
+  end
+
+  def manual_start
+    w32ss = Win32::Service.configure( 'service_name' => @resource[:name], 'start_type' => Win32::Service::SERVICE_DEMAND_START )
+    raise Puppet::Error.new("Win32 service manual enable of #{@resource[:name]} failed" ) if( w32ss.nil? )
+  rescue => detail
+    raise Puppet::Error.new("Cannot enable #{@resource[:name]} for manual start, error was: #{detail}", detail )
+  end
+
+  def enabled?
+    w32ss = Win32::Service.config_info( @resource[:name] )
+    raise Puppet::Error.new("Win32 service query of #{@resource[:name]} failed" ) unless( !w32ss.nil? && w32ss.instance_of?( Struct::ServiceConfigInfo ) )
+    debug("Service #{@resource[:name]} start type is #{w32ss.start_type}")
+    case w32ss.start_type
+      when Win32::Service.get_start_type(Win32::Service::SERVICE_AUTO_START),
+           Win32::Service.get_start_type(Win32::Service::SERVICE_BOOT_START),
+           Win32::Service.get_start_type(Win32::Service::SERVICE_SYSTEM_START)
+        :true
+      when Win32::Service.get_start_type(Win32::Service::SERVICE_DEMAND_START)
+        :manual
+      when Win32::Service.get_start_type(Win32::Service::SERVICE_DISABLED)
+        :false
+      else
+        raise Puppet::Error.new("Unknown start type: #{w32ss.start_type}")
+    end
+  rescue => detail
+    raise Puppet::Error.new("Cannot get start type for #{@resource[:name]}, error was: #{detail}", detail )
+  end
+
+  def start
+    if enabled? == :false
+      # If disabled and not managing enable, respect disabled and fail.
+      if @resource[:enable].nil?
+        raise Puppet::Error, "Will not start disabled service #{@resource[:name]} without managing enable. Specify 'enable => false' to override."
+      # Otherwise start. If enable => false, we will later sync enable and
+      # disable the service again.
+      elsif @resource[:enable] == :true
+        enable
+      else
+        manual_start
+      end
+    end
+
+    net(:start, @resource[:name])
+  rescue Puppet::ExecutionFailure => detail
+    raise Puppet::Error.new("Cannot start #{@resource[:name]}, error was: #{detail}", detail )
+  end
+
+  def stop
+    net(:stop, @resource[:name])
+  rescue Puppet::ExecutionFailure => detail
+    raise Puppet::Error.new("Cannot stop #{@resource[:name]}, error was: #{detail}", detail )
+  end
+
+  def status
+    w32ss = Win32::Service.status( @resource[:name] )
+    raise Puppet::Error.new("Win32 service query of #{@resource[:name]} failed" ) unless( !w32ss.nil? && w32ss.instance_of?( Struct::ServiceStatus ) )
+    state = case w32ss.current_state
+      when "stopped", "pause pending", "stop pending", "paused" then :stopped
+      when "running", "continue pending", "start pending"       then :running
+      else
+        raise Puppet::Error.new("Unknown service state '#{w32ss.current_state}' for service '#{@resource[:name]}'")
+    end
+    debug("Service #{@resource[:name]} is #{w32ss.current_state}")
+    return state
+  rescue => detail
+    raise Puppet::Error.new("Cannot get status of #{@resource[:name]}, error was: #{detail}", detail )
+  end
+
+  # returns all providers for all existing services and startup state
+  def self.instances
+    Win32::Service.services.collect { |s| new(:name => s.service_name) }
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/ssh_authorized_key/parsed.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/ssh_authorized_key/parsed.rb
new file mode 100644
index 0000000..a1c9ad4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/ssh_authorized_key/parsed.rb
@@ -0,0 +1,105 @@
+require 'puppet/provider/parsedfile'
+
+Puppet::Type.type(:ssh_authorized_key).provide(
+  :parsed,
+  :parent         => Puppet::Provider::ParsedFile,
+  :filetype       => :flat,
+  :default_target => ''
+) do
+  desc "Parse and generate authorized_keys files for SSH."
+
+  text_line :comment, :match => /^\s*#/
+  text_line :blank, :match => /^\s*$/
+
+  record_line :parsed,
+    :fields   => %w{options type key name},
+    :optional => %w{options},
+    :rts => /^\s+/,
+    :match    => Puppet::Type.type(:ssh_authorized_key).keyline_regex,
+    :post_parse => proc { |h|
+      h[:name] = "" if h[:name] == :absent
+      h[:options] ||= [:absent]
+      h[:options] = Puppet::Type::Ssh_authorized_key::ProviderParsed.parse_options(h[:options]) if h[:options].is_a? String
+    },
+    :pre_gen => proc { |h|
+      # if this name was generated, don't write it back to disk
+      h[:name] = "" if h[:unnamed]
+      h[:options] = [] if h[:options].include?(:absent)
+      h[:options] = h[:options].join(',')
+    }
+
+  record_line :key_v1,
+    :fields   => %w{options bits exponent modulus name},
+    :optional => %w{options},
+    :rts      => /^\s+/,
+    :match    => /^(?:(.+) )?(\d+) (\d+) (\d+)(?: (.+))?$/
+
+  def dir_perm
+    0700
+  end
+
+  def file_perm
+    0600
+  end
+
+  def user
+    uid = Puppet::FileSystem.stat(target).uid
+    Etc.getpwuid(uid).name
+  end
+
+  def flush
+    raise Puppet::Error, "Cannot write SSH authorized keys without user"    unless @resource.should(:user)
+    raise Puppet::Error, "User '#{@resource.should(:user)}' does not exist" unless Puppet::Util.uid(@resource.should(:user))
+    # ParsedFile usually calls backup_target much later in the flush process,
+    # but our SUID makes that fail to open filebucket files for writing.
+    # Fortunately, there's already logic to make sure it only ever happens once,
+    # so calling it here supresses the later attempt by our superclass's flush method.
+    self.class.backup_target(target)
+
+    Puppet::Util::SUIDManager.asuser(@resource.should(:user)) do
+        unless Puppet::FileSystem.exist?(dir = File.dirname(target))
+          Puppet.debug "Creating #{dir}"
+          Dir.mkdir(dir, dir_perm)
+        end
+
+        super
+
+        File.chmod(file_perm, target)
+    end
+  end
+
+  # parse sshv2 option strings, wich is a comma separated list of
+  # either key="values" elements or bare-word elements
+  def self.parse_options(options)
+    result = []
+    scanner = StringScanner.new(options)
+    while !scanner.eos?
+      scanner.skip(/[ \t]*/)
+      # scan a long option
+      if out = scanner.scan(/[-a-z0-9A-Z_]+=\".*?[^\\]\"/) or out = scanner.scan(/[-a-z0-9A-Z_]+/)
+        result << out
+      else
+        # found an unscannable token, let's abort
+        break
+      end
+      # eat a comma
+      scanner.skip(/[ \t]*,[ \t]*/)
+    end
+    result
+  end
+
+  def self.prefetch_hook(records)
+    name_index = 0
+    records.each do |record|
+      if record[:record_type] == :parsed && record[:name].empty?
+        record[:unnamed] = true
+        # Generate a unique ID for unnamed keys, in case they need purging.
+        # If you change this, you have to keep
+        # Puppet::Type::User#unknown_keys_in_file in sync! (PUP-3357)
+        record[:name] = "#{record[:target]}:unnamed-#{ name_index += 1 }"
+        Puppet.debug("generating name for on-disk ssh_authorized_key #{record[:key]}: #{record[:name]}")
+      end
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/sshkey/parsed.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/sshkey/parsed.rb
new file mode 100644
index 0000000..29f3459
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/sshkey/parsed.rb
@@ -0,0 +1,40 @@
+require 'puppet/provider/parsedfile'
+
+known = nil
+case Facter.value(:operatingsystem)
+when "Darwin"; known = "/etc/ssh_known_hosts"
+else
+  known = "/etc/ssh/ssh_known_hosts"
+end
+
+
+Puppet::Type.type(:sshkey).provide(
+  :parsed,
+  :parent => Puppet::Provider::ParsedFile,
+  :default_target => known,
+  :filetype => :flat
+) do
+  desc "Parse and generate host-wide known hosts files for SSH."
+
+  text_line :comment, :match => /^#/
+  text_line :blank, :match => /^\s+/
+
+  record_line :parsed, :fields => %w{name type key},
+    :post_parse => proc { |hash|
+      names = hash[:name].split(",", -1)
+      hash[:name]  = names.shift
+      hash[:host_aliases] = names
+    },
+    :pre_gen => proc { |hash|
+      if hash[:host_aliases]
+        hash[:name] = [hash[:name], hash[:host_aliases]].flatten.join(",")
+        hash.delete(:host_aliases)
+      end
+    }
+
+  # Make sure to use mode 644 if ssh_known_hosts is newly created
+  def self.default_mode
+    0644
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/aix.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/aix.rb
new file mode 100644
index 0000000..e75763a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/aix.rb
@@ -0,0 +1,369 @@
+#
+# User Puppet provider for AIX. It uses standard commands to manage users:
+#  mkuser, rmuser, lsuser, chuser
+#
+# Notes:
+# - AIX users can have expiry date defined with minute granularity,
+#   but puppet does not allow it. There is a ticket open for that (#5431)
+# - AIX maximum password age is in WEEKs, not days
+#
+# See  http://docs.puppetlabs.com/guides/provider_development.html
+# for more information
+#
+# Author::    Hector Rivas Gandara <keymon@gmail.com>
+#
+require 'puppet/provider/aixobject'
+require 'tempfile'
+require 'date'
+
+Puppet::Type.type(:user).provide :aix, :parent => Puppet::Provider::AixObject do
+  desc "User management for AIX."
+
+  # This will the default provider for this platform
+  defaultfor :operatingsystem => :aix
+  confine :operatingsystem => :aix
+
+  # Commands that manage the element
+  commands :list      => "/usr/sbin/lsuser"
+  commands :add       => "/usr/bin/mkuser"
+  commands :delete    => "/usr/sbin/rmuser"
+  commands :modify    => "/usr/bin/chuser"
+
+  commands :lsgroup   => "/usr/sbin/lsgroup"
+  commands :chpasswd  => "/bin/chpasswd"
+
+  # Provider features
+  has_features :manages_aix_lam
+  has_features :manages_homedir, :manages_passwords, :manages_shell
+  has_features :manages_expiry,  :manages_password_age
+
+  # Attribute verification (TODO)
+  #verify :gid, "GID must be a string or int of a valid group" do |value|
+  #  value.is_a? String || value.is_a? Integer
+  #end
+  #
+  #verify :groups, "Groups must be comma-separated" do |value|
+  #  value !~ /\s/
+  #end
+
+  # User attributes to ignore from AIX output.
+  def self.attribute_ignore
+    ["name"]
+  end
+
+  # AIX attributes to properties mapping.
+  #
+  # Valid attributes to be managed by this provider.
+  # It is a list with of hash
+  #  :aix_attr      AIX command attribute name
+  #  :puppet_prop   Puppet propertie name
+  #  :to            Method to adapt puppet property to aix command value. Optional.
+  #  :from          Method to adapt aix command value to puppet property. Optional
+  self.attribute_mapping = [
+    {:aix_attr => :pgrp,       :puppet_prop => :gid,
+                                :to => :gid_to_attr,
+                                :from => :gid_from_attr },
+    {:aix_attr => :id,         :puppet_prop => :uid},
+    {:aix_attr => :groups,     :puppet_prop => :groups},
+    {:aix_attr => :home,       :puppet_prop => :home},
+    {:aix_attr => :shell,      :puppet_prop => :shell},
+    {:aix_attr => :expires,    :puppet_prop => :expiry,
+                                :to => :expiry_to_attr,
+                                :from => :expiry_from_attr },
+    {:aix_attr => :maxage,     :puppet_prop => :password_max_age},
+    {:aix_attr => :minage,     :puppet_prop => :password_min_age},
+    {:aix_attr => :attributes, :puppet_prop => :attributes},
+    { :aix_attr => :gecos,      :puppet_prop => :comment },
+  ]
+
+  #--------------
+  # Command definition
+
+  # Return the IA module arguments based on the resource param ia_load_module
+  def get_ia_module_args
+    if @resource[:ia_load_module]
+      ["-R", @resource[:ia_load_module].to_s]
+    else
+      []
+    end
+  end
+
+  # List groups and Ids
+  def lsgroupscmd(value=@resource[:name])
+    [command(:lsgroup)] +
+      self.get_ia_module_args +
+      ["-a", "id", value]
+  end
+
+  def lscmd(value=@resource[:name])
+    [self.class.command(:list), "-c"] + self.get_ia_module_args + [ value]
+  end
+
+  def lsallcmd()
+    lscmd("ALL")
+  end
+
+  def addcmd(extra_attrs = [])
+    # Here we use the @resource.to_hash to get the list of provided parameters
+    # Puppet does not call to self.<parameter>= method if it does not exists.
+    #
+    # It gets an extra list of arguments to add to the user.
+    [self.class.command(:add)] + self.get_ia_module_args +
+      self.hash2args(@resource.to_hash) +
+      extra_attrs + [@resource[:name]]
+  end
+
+  # Get modify command. Set translate=false if no mapping must be used.
+  # Needed for special properties like "attributes"
+  def modifycmd(hash = property_hash)
+    args = self.hash2args(hash)
+    return nil if args.empty?
+
+    [self.class.command(:modify)] + self.get_ia_module_args +
+      args + [@resource[:name]]
+  end
+
+  def deletecmd
+    [self.class.command(:delete)] + self.get_ia_module_args + [@resource[:name]]
+  end
+
+  #--------------
+  # We overwrite the create function to change the password after creation.
+  def create
+    super
+    # Reset the password if needed
+    self.password = @resource[:password] if @resource[:password]
+  end
+
+
+  def get_arguments(key, value, mapping, objectinfo)
+    # In the case of attributes, return a list of key=vlaue
+    if key == :attributes
+      raise Puppet::Error, "Attributes must be a list of pairs key=value on #{@resource.class.name}[#{@resource.name}]" \
+        unless value and value.is_a? Hash
+      return value.map { |k,v| k.to_s.strip + "=" + v.to_s.strip}
+    end
+
+    super(key, value, mapping, objectinfo)
+  end
+
+  # Get the groupname from its id
+  def groupname_by_id(gid)
+    groupname=nil
+    execute(lsgroupscmd("ALL")).each_line { |entry|
+      attrs = self.parse_attr_list(entry, nil)
+      if attrs and attrs.include? :id and gid == attrs[:id].to_i
+        groupname = entry.split(" ")[0]
+      end
+    }
+    groupname
+  end
+
+  # Get the groupname from its id
+  def groupid_by_name(groupname)
+    attrs = self.parse_attr_list(execute(lsgroupscmd(groupname)).split("\n")[0], nil)
+    attrs ? attrs[:id].to_i : nil
+  end
+
+  # Check that a group exists and is valid
+  def verify_group(value)
+    if value.is_a? Integer or value.is_a? Fixnum
+      groupname = groupname_by_id(value)
+      raise ArgumentError, "AIX group must be a valid existing group" unless groupname
+    else
+      raise ArgumentError, "AIX group must be a valid existing group" unless groupid_by_name(value)
+      groupname = value
+    end
+    groupname
+  end
+
+  # The user's primary group.  Can be specified numerically or by name.
+  def gid_to_attr(value)
+    verify_group(value)
+  end
+
+  # Get the group gid from its name
+  def gid_from_attr(value)
+    groupid_by_name(value)
+  end
+
+  # The expiry date for this user. Must be provided in
+  # a zero padded YYYY-MM-DD HH:MM format
+  def expiry_to_attr(value)
+    # For chuser the expires parameter is a 10-character string in the MMDDhhmmyy format
+    # that is,"%m%d%H%M%y"
+    newdate = '0'
+    if value.is_a? String and value!="0000-00-00"
+      d = DateTime.parse(value, "%Y-%m-%d %H:%M")
+      newdate = d.strftime("%m%d%H%M%y")
+    end
+    newdate
+  end
+
+  def expiry_from_attr(value)
+    if value =~ /(..)(..)(..)(..)(..)/
+      #d= DateTime.parse("20#{$5}-#{$1}-#{$2} #{$3}:#{$4}")
+      #expiry_date = d.strftime("%Y-%m-%d %H:%M")
+      #expiry_date = d.strftime("%Y-%m-%d")
+      expiry_date = "20#{$5}-#{$1}-#{$2}"
+    else
+      Puppet.warn("Could not convert AIX expires date '#{value}' on #{@resource.class.name}[#{@resource.name}]") \
+        unless value == '0'
+      expiry_date = :absent
+    end
+    expiry_date
+  end
+
+  def open_security_passwd
+    # helper method for tests
+    File.open("/etc/security/passwd", 'r')
+  end
+
+  #--------------------------------
+  # Getter and Setter
+  # When the provider is initialized, create getter/setter methods for each
+  # property our resource type supports.
+  # If setter or getter already defined it will not be overwritten
+
+  #- **password**
+  #    The user's password, in whatever encrypted format the local machine
+  #    requires. Be sure to enclose any value that includes a dollar sign ($)
+  #    in single quotes (').  Requires features manages_passwords.
+  #
+  # Retrieve the password parsing directly the /etc/security/passwd
+  def password
+    password = :absent
+    user = @resource[:name]
+    f = open_security_passwd
+    # Skip to the user
+    f.each_line { |l| break if l  =~ /^#{user}:\s*$/ }
+    if ! f.eof?
+      f.each_line { |l|
+        # If there is a new user stanza, stop
+        break if l  =~ /^\S*:\s*$/
+        # If the password= entry is found, return it, stripping trailing space
+        if l  =~ /^\s*password\s*=\s*(\S*)\s*$/
+          password = $1; break;
+        end
+      }
+    end
+    f.close()
+    return password
+  end
+
+  def password=(value)
+    user = @resource[:name]
+
+    # Puppet execute does not support strings as input, only files.
+    tmpfile = Tempfile.new('puppet_#{user}_pw')
+    tmpfile << "#{user}:#{value}\n"
+    tmpfile.close()
+
+    # Options '-e', '-c', use encrypted password and clear flags
+    # Must receive "user:enc_password" as input
+    # command, arguments = {:failonfail => true, :combine => true}
+    # Fix for bugs #11200 and #10915
+    cmd = [self.class.command(:chpasswd), get_ia_module_args, '-e', '-c', user].flatten
+    begin
+      output = execute(cmd, {:failonfail => false, :combine => true, :stdinfile => tmpfile.path })
+      # chpasswd can return 1, even on success (at least on AIX 6.1); empty output indicates success
+      if output != ""
+        raise Puppet::ExecutionFailure, "chpasswd said #{output}"
+      end
+    rescue Puppet::ExecutionFailure  => detail
+      raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}", detail.backtrace
+    ensure
+      tmpfile.delete()
+    end
+  end
+
+  def managed_attribute_keys(hash)
+    managed_attributes ||= @resource.original_parameters[:attributes] || hash.keys.map{|k| k.to_s}
+    managed_attributes.map {|attr| key, value = attr.split("="); key.strip.to_sym}
+  end
+
+  def should_include?(key, managed_keys)
+    !self.class.attribute_mapping_from.include?(key) and
+            !self.class.attribute_ignore.include?(key) and
+            managed_keys.include?(key)
+  end
+
+  def filter_attributes(hash)
+    # Return only managed attributtes.
+    managed_keys = managed_attribute_keys(hash)
+    results = hash.select {
+        |k,v| should_include?(k, managed_keys)
+      }.inject({}) {
+        |hash, array| hash[array[0]] = array[1]; hash
+      }
+    results
+  end
+
+  def attributes
+    filter_attributes(getosinfo(false))
+  end
+
+  def attributes=(attr_hash)
+    #self.class.validate(param, value)
+    param = :attributes
+    cmd = modifycmd({param => filter_attributes(attr_hash)})
+    if cmd
+      begin
+        execute(cmd)
+      rescue Puppet::ExecutionFailure  => detail
+        raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}", detail.backtrace
+      end
+    end
+  end
+
+  # UNSUPPORTED
+  #- **profile_membership**
+  #    Whether specified roles should be treated as the only roles
+  #    of which the user is a member or whether they should merely
+  #    be treated as the minimum membership list.  Valid values are
+  #    `inclusive`, `minimum`.
+  # UNSUPPORTED
+  #- **profiles**
+  #    The profiles the user has.  Multiple profiles should be
+  #    specified as an array.  Requires features manages_solaris_rbac.
+  # UNSUPPORTED
+  #- **project**
+  #    The name of the project associated with a user  Requires features
+  #    manages_solaris_rbac.
+  # UNSUPPORTED
+  #- **role_membership**
+  #    Whether specified roles should be treated as the only roles
+  #    of which the user is a member or whether they should merely
+  #    be treated as the minimum membership list.  Valid values are
+  #    `inclusive`, `minimum`.
+  # UNSUPPORTED
+  #- **roles**
+  #    The roles the user has.  Multiple roles should be
+  #    specified as an array.  Requires features manages_solaris_rbac.
+  # UNSUPPORTED
+  #- **key_membership**
+  #    Whether specified key value pairs should be treated as the only
+  #    attributes
+  #    of the user or whether they should merely
+  #    be treated as the minimum list.  Valid values are `inclusive`,
+  #    `minimum`.
+  # UNSUPPORTED
+  #- **keys**
+  #    Specify user attributes in an array of keyvalue pairs  Requires features
+  #    manages_solaris_rbac.
+  # UNSUPPORTED
+  #- **allowdupe**
+  #  Whether to allow duplicate UIDs.  Valid values are `true`, `false`.
+  # UNSUPPORTED
+  #- **auths**
+  #    The auths the user has.  Multiple auths should be
+  #    specified as an array.  Requires features manages_solaris_rbac.
+  # UNSUPPORTED
+  #- **auth_membership**
+  #    Whether specified auths should be treated as the only auths
+  #    of which the user is a member or whether they should merely
+  #    be treated as the minimum membership list.  Valid values are
+  #    `inclusive`, `minimum`.
+  # UNSUPPORTED
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/directoryservice.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/directoryservice.rb
new file mode 100644
index 0000000..b2f2ac8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/directoryservice.rb
@@ -0,0 +1,685 @@
+require 'puppet'
+require 'facter/util/plist'
+require 'base64'
+
+Puppet::Type.type(:user).provide :directoryservice do
+  desc "User management on OS X."
+
+##                   ##
+## Provider Settings ##
+##                   ##
+
+  # Provider command declarations
+  commands :uuidgen      => '/usr/bin/uuidgen'
+  commands :dsimport     => '/usr/bin/dsimport'
+  commands :dscl         => '/usr/bin/dscl'
+  commands :plutil       => '/usr/bin/plutil'
+  commands :dscacheutil  => '/usr/bin/dscacheutil'
+
+  # Provider confines and defaults
+  confine    :operatingsystem => :darwin
+  defaultfor :operatingsystem => :darwin
+
+  # Need this to create getter/setter methods automagically
+  # This command creates methods that return @property_hash[:value]
+  mk_resource_methods
+
+  # JJM: OS X can manage passwords.
+  has_feature :manages_passwords
+
+  # 10.8 Passwords use a PBKDF2 salt value
+  has_features :manages_password_salt
+
+  #provider can set the user's shell
+  has_feature :manages_shell
+
+##               ##
+## Class Methods ##
+##               ##
+
+  # This method exists to map the dscl values to the correct Puppet
+  # properties. This stays relatively consistent, but who knows what
+  # Apple will do next year...
+  def self.ds_to_ns_attribute_map
+    {
+      'RecordName'       => :name,
+      'PrimaryGroupID'   => :gid,
+      'NFSHomeDirectory' => :home,
+      'UserShell'        => :shell,
+      'UniqueID'         => :uid,
+      'RealName'         => :comment,
+      'Password'         => :password,
+      'GeneratedUID'     => :guid,
+      'IPAddress'        => :ip_address,
+      'ENetAddress'      => :en_address,
+      'GroupMembership'  => :members,
+    }
+  end
+
+  def self.ns_to_ds_attribute_map
+    @ns_to_ds_attribute_map ||= ds_to_ns_attribute_map.invert
+  end
+
+  # Prefetching is necessary to use @property_hash inside any setter methods.
+  # self.prefetch uses self.instances to gather an array of user instances
+  # on the system, and then populates the @property_hash instance variable
+  # with attribute data for the specific instance in question (i.e. it
+  # gathers the 'is' values of the resource into the @property_hash instance
+  # variable so you don't have to read from the system every time you need
+  # to gather the 'is' values for a resource. The downside here is that
+  # populating this instance variable for every resource on the system
+  # takes time and front-loads your Puppet run.
+  def self.prefetch(resources)
+    instances.each do |prov|
+      if resource = resources[prov.name]
+        resource.provider = prov
+      end
+    end
+  end
+
+  # This method assembles an array of provider instances containing
+  # information about every instance of the user type on the system (i.e.
+  # every user and its attributes). The `puppet resource` command relies
+  # on self.instances to gather an array of user instances in order to
+  # display its output.
+  def self.instances
+    get_all_users.collect do |user|
+      self.new(generate_attribute_hash(user))
+    end
+  end
+
+  # Return an array of hashes containing information about every user on
+  # the system.
+  def self.get_all_users
+    Plist.parse_xml(dscl '-plist', '.', 'readall', '/Users')
+  end
+
+  # This method accepts an individual user plist, passed as a hash, and
+  # strips the dsAttrTypeStandard: prefix that dscl adds for each key.
+  # An attribute hash is assembled and returned from the properties
+  # supported by the user type.
+  def self.generate_attribute_hash(input_hash)
+    attribute_hash = {}
+    input_hash.keys.each do |key|
+      ds_attribute = key.sub("dsAttrTypeStandard:", "")
+      next unless ds_to_ns_attribute_map.keys.include?(ds_attribute)
+      ds_value = input_hash[key]
+      case ds_to_ns_attribute_map[ds_attribute]
+        when :gid, :uid
+          # OS X stores objects like uid/gid as strings.
+          # Try casting to an integer for these cases to be
+          # consistent with the other providers and the group type
+          # validation
+          begin
+            ds_value = Integer(ds_value[0])
+          rescue ArgumentError
+            ds_value = ds_value[0]
+          end
+        else ds_value = ds_value[0]
+      end
+      attribute_hash[ds_to_ns_attribute_map[ds_attribute]] = ds_value
+    end
+    attribute_hash[:ensure]         = :present
+    attribute_hash[:provider]       = :directoryservice
+    attribute_hash[:shadowhashdata] = get_attribute_from_dscl('Users', attribute_hash[:name], 'ShadowHashData')
+
+    ##############
+    # Get Groups #
+    ##############
+    groups_array = []
+    get_list_of_groups.each do |group|
+      if group["dsAttrTypeStandard:GroupMembership"] and group["dsAttrTypeStandard:GroupMembership"].include?(attribute_hash[:name])
+        groups_array << group["dsAttrTypeStandard:RecordName"][0]
+      end
+
+      if group["dsAttrTypeStandard:GroupMembers"] and group["dsAttrTypeStandard:GroupMembers"].include?(attribute_hash[:guid])
+        groups_array << group["dsAttrTypeStandard:RecordName"][0]
+      end
+    end
+    attribute_hash[:groups] = groups_array.uniq.sort.join(',')
+
+    ################################
+    # Get Password/Salt/Iterations #
+    ################################
+    if (Puppet::Util::Package.versioncmp(get_os_version, '10.7') == -1)
+      attribute_hash[:password] = get_sha1(attribute_hash[:guid])
+    else
+      if attribute_hash[:shadowhashdata].empty?
+        attribute_hash[:password] = '*'
+      else
+        embedded_binary_plist = get_embedded_binary_plist(attribute_hash[:shadowhashdata])
+        if embedded_binary_plist['SALTED-SHA512']
+          attribute_hash[:password] = get_salted_sha512(embedded_binary_plist)
+        else
+          attribute_hash[:password]   = get_salted_sha512_pbkdf2('entropy', embedded_binary_plist)
+          attribute_hash[:salt]       = get_salted_sha512_pbkdf2('salt', embedded_binary_plist)
+          attribute_hash[:iterations] = get_salted_sha512_pbkdf2('iterations', embedded_binary_plist)
+        end
+      end
+    end
+
+    attribute_hash
+  end
+
+  def self.get_os_version
+    @os_version ||= Facter.value(:macosx_productversion_major)
+  end
+
+  # Use dscl to retrieve an array of hashes containing attributes about all
+  # of the local groups on the machine.
+  def self.get_list_of_groups
+    @groups ||= Plist.parse_xml(dscl '-plist', '.', 'readall', '/Groups')
+  end
+
+  # Perform a dscl lookup at the path specified for the specific keyname
+  # value. The value returned is the first item within the array returned
+  # from dscl
+  def self.get_attribute_from_dscl(path, username, keyname)
+    Plist.parse_xml(dscl '-plist', '.', 'read', "/#{path}/#{username}", keyname)
+  end
+
+  # The plist embedded in the ShadowHashData key is a binary plist. The
+  # facter/util/plist library doesn't read binary plists, so we need to
+  # extract the binary plist, convert it to XML, and return it.
+  def self.get_embedded_binary_plist(shadow_hash_data)
+    embedded_binary_plist = Array(shadow_hash_data['dsAttrTypeNative:ShadowHashData'][0].delete(' ')).pack('H*')
+    convert_binary_to_xml(embedded_binary_plist)
+  end
+
+  # This method will accept a hash that has been returned from Plist::parse_xml
+  # and convert it to a binary plist (string value).
+  def self.convert_xml_to_binary(plist_data)
+    Puppet.debug('Converting XML plist to binary')
+    Puppet.debug('Executing: \'plutil -convert binary1 -o - -\'')
+    IO.popen('plutil -convert binary1 -o - -', 'r+') do |io|
+      io.write Plist::Emit.dump(plist_data)
+      io.close_write
+      @converted_plist = io.read
+    end
+    @converted_plist
+  end
+
+  # This method will accept a binary plist (as a string) and convert it to a
+  # hash via Plist::parse_xml.
+  def self.convert_binary_to_xml(plist_data)
+    Puppet.debug('Converting binary plist to XML')
+    Puppet.debug('Executing: \'plutil -convert xml1 -o - -\'')
+    IO.popen('plutil -convert xml1 -o - -', 'r+') do |io|
+      io.write plist_data
+      io.close_write
+      @converted_plist = io.read
+    end
+    Puppet.debug('Converting XML values to a hash.')
+    Plist::parse_xml(@converted_plist)
+  end
+
+  # The salted-SHA512 password hash in 10.7 is stored in the 'SALTED-SHA512'
+  # key as binary data. That data is extracted and converted to a hex string.
+  def self.get_salted_sha512(embedded_binary_plist)
+    embedded_binary_plist['SALTED-SHA512'].string.unpack("H*")[0]
+  end
+
+  # This method reads the passed embedded_binary_plist hash and returns values
+  # according to which field is passed.  Arguments passed are the hash
+  # containing the value read from the 'ShadowHashData' key in the User's
+  # plist, and the field to be read (one of 'entropy', 'salt', or 'iterations')
+  def self.get_salted_sha512_pbkdf2(field, embedded_binary_plist)
+    case field
+    when 'salt', 'entropy'
+      embedded_binary_plist['SALTED-SHA512-PBKDF2'][field].string.unpack('H*').first
+    when 'iterations'
+      Integer(embedded_binary_plist['SALTED-SHA512-PBKDF2'][field])
+    else
+      raise Puppet::Error, 'Puppet has tried to read an incorrect value from the ' +
+           "SALTED-SHA512-PBKDF2 hash. Acceptable fields are 'salt', " +
+           "'entropy', or 'iterations'."
+    end
+  end
+
+  # In versions 10.5 and 10.6 of OS X, the password hash is stored in a file
+  # in the /var/db/shadow/hash directory that matches the GUID of the user.
+  def self.get_sha1(guid)
+    password_hash = nil
+    password_hash_file = "#{password_hash_dir}/#{guid}"
+    if Puppet::FileSystem.exist?(password_hash_file) and File.file?(password_hash_file)
+      raise Puppet::Error, "Could not read password hash file at #{password_hash_file}" if not File.readable?(password_hash_file)
+      f = File.new(password_hash_file)
+      password_hash = f.read
+      f.close
+    end
+    password_hash
+  end
+
+
+##                   ##
+## Ensurable Methods ##
+##                   ##
+
+  def exists?
+    begin
+      dscl '.', 'read', "/Users/#{@resource.name}"
+    rescue Puppet::ExecutionFailure => e
+      Puppet.debug("User was not found, dscl returned: #{e.inspect}")
+      return false
+    end
+    true
+  end
+
+  # This method is called if ensure => present is passed and the exists?
+  # method returns false. Dscl will directly set most values, but the
+  # setter methods will be used for any exceptions.
+  def create
+    create_new_user(@resource.name)
+
+    # Retrieve the user's GUID
+    @guid = self.class.get_attribute_from_dscl('Users', @resource.name, 'GeneratedUID')['dsAttrTypeStandard:GeneratedUID'][0]
+
+    # Get an array of valid User type properties
+    valid_properties = Puppet::Type.type('User').validproperties
+
+    # Iterate through valid User type properties
+    valid_properties.each do |attribute|
+      next if attribute == :ensure
+      value = @resource.should(attribute)
+
+      # Value defaults
+      if value.nil?
+        value = case attribute
+                when :gid
+                  '20'
+                when :uid
+                  next_system_id
+                when :comment
+                  @resource.name
+                when :shell
+                  '/bin/bash'
+                when :home
+                  "/Users/#{@resource.name}"
+                else
+                  nil
+                end
+      end
+
+      # Ensure group names are converted to integers.
+      value = Puppet::Util.gid(value) if attribute == :gid
+
+      ## Set values ##
+      # For the :password and :groups properties, call the setter methods
+      # to enforce those values. For everything else, use dscl with the
+      # ns_to_ds_attribute_map to set the appropriate values.
+      if value != "" and not value.nil?
+        case attribute
+        when :password
+          self.password = value
+        when :iterations
+          self.iterations = value
+        when :salt
+          self.salt = value
+        when :groups
+          value.split(',').each do |group|
+            merge_attribute_with_dscl('Groups', group, 'GroupMembership', @resource.name)
+            merge_attribute_with_dscl('Groups', group, 'GroupMembers', @guid)
+          end
+        else
+          merge_attribute_with_dscl('Users', @resource.name, self.class.ns_to_ds_attribute_map[attribute], value)
+        end
+      end
+    end
+  end
+
+  # This method is called when ensure => absent has been set.
+  # Deleting a user is handled by dscl
+  def delete
+    dscl '.', '-delete', "/Users/#{@resource.name}"
+  end
+
+##                       ##
+## Getter/Setter Methods ##
+##                       ##
+
+  # In the setter method we're only going to take action on groups for which
+  # the user is not currently a member.
+  def groups=(value)
+    guid = self.class.get_attribute_from_dscl('Users', @resource.name, 'GeneratedUID')['dsAttrTypeStandard:GeneratedUID'][0]
+    groups_to_add = value.split(',') - groups.split(',')
+    groups_to_add.each do |group|
+      merge_attribute_with_dscl('Groups', group, 'GroupMembership', @resource.name)
+      merge_attribute_with_dscl('Groups', group, 'GroupMembers', guid)
+    end
+  end
+
+  # If you thought GETTING a password was bad, try SETTING it. This method
+  # makes me want to cry. A thousand tears...
+  #
+  # I've been unsuccessful in tracking down a way to set the password for
+  # a user using dscl that DOESN'T require passing it as plaintext. We were
+  # also unable to get dsimport to work like this. Due to these downfalls,
+  # the sanest method requires opening the user's plist, dropping in the
+  # password hash, and serializing it back to disk. The problems with THIS
+  # method revolve around dscl. Any time you directly modify a user's plist,
+  # you need to flush the cache that dscl maintains.
+  def password=(value)
+    if (Puppet::Util::Package.versioncmp(self.class.get_os_version, '10.7') == -1)
+      write_sha1_hash(value)
+    else
+      if self.class.get_os_version == '10.7'
+        if value.length != 136
+          raise Puppet::Error, "OS X 10.7 requires a Salted SHA512 hash password of 136 characters.  Please check your password and try again."
+        end
+      else
+        if value.length != 256
+           raise Puppet::Error, "OS X versions > 10.7 require a Salted SHA512 PBKDF2 password hash of 256 characters. Please check your password and try again."
+        end
+
+        assert_full_pbkdf2_password
+      end
+
+      # Methods around setting the password on OS X are the ONLY methods that
+      # cannot use dscl (because the only way to set it via dscl is by passing
+      # a plaintext password - which is bad). Because of this, we have to change
+      # the user's plist directly. DSCL has its own caching mechanism, which
+      # means that every time we call dscl in this provider we're not directly
+      # changing values on disk (instead, those calls are cached and written
+      # to disk according to Apple's prioritization algorithms). When Puppet
+      # needs to set the password property on OS X > 10.6, the provider has to
+      # tell dscl to write its cache to disk before modifying the user's
+      # plist. The 'dscacheutil -flushcache' command does this. Another issue
+      # is how fast Puppet makes calls to dscl and how long it takes dscl to
+      # enter those calls into its cache. We have to sleep for 2 seconds before
+      # flushing the dscl cache to allow all dscl calls to get INTO the cache
+      # first. This could be made faster (and avoid a sleep call) by finding
+      # a way to enter calls into the dscl cache faster. A sleep time of 1
+      # second would intermittantly require a second Puppet run to set
+      # properties, so 2 seconds seems to be the minimum working value.
+      sleep 2
+      flush_dscl_cache
+      write_password_to_users_plist(value)
+
+      # Since we just modified the user's plist, we need to flush the ds cache
+      # again so dscl can pick up on the changes we made.
+      flush_dscl_cache
+    end
+  end
+
+  # The iterations and salt properties, like the password property, can only
+  # be modified by directly changing the user's plist. Because of this fact,
+  # we have to treat the ds cache just like you would in the password=
+  # method.
+  def iterations=(value)
+    if (Puppet::Util::Package.versioncmp(self.class.get_os_version, '10.7') > 0)
+      assert_full_pbkdf2_password
+
+      sleep 2
+      flush_dscl_cache
+      users_plist = get_users_plist(@resource.name)
+      shadow_hash_data = get_shadow_hash_data(users_plist)
+      set_salted_pbkdf2(users_plist, shadow_hash_data, 'iterations', value)
+      flush_dscl_cache
+    end
+  end
+
+  # The iterations and salt properties, like the password property, can only
+  # be modified by directly changing the user's plist. Because of this fact,
+  # we have to treat the ds cache just like you would in the password=
+  # method.
+  def salt=(value)
+    if (Puppet::Util::Package.versioncmp(self.class.get_os_version, '10.7') > 0)
+      assert_full_pbkdf2_password
+
+      sleep 2
+      flush_dscl_cache
+      users_plist = get_users_plist(@resource.name)
+      shadow_hash_data = get_shadow_hash_data(users_plist)
+      set_salted_pbkdf2(users_plist, shadow_hash_data, 'salt', value)
+      flush_dscl_cache
+    end
+  end
+
+  #####
+  # Dynamically create setter methods for dscl properties
+  #####
+  #
+  # Setter methods are only called when a resource currently has a value for
+  # that property and it needs changed (true here since all of these values
+  # have a default that is set in the create method). We don't want to merge
+  # in additional values if an incorrect value is set, we want to CHANGE it.
+  # When using the -change argument in dscl, the old value needs to be passed
+  # first (followed by the new value). Because of this, we get the current
+  # value from the @property_hash variable and then use the value passed as
+  # the new value. Because we're prefetching instances of the provider, it's
+  # possible that the value determined at the start of the run may be stale
+  # (i.e. someone changed the value by hand during a Puppet run) - if that's
+  # the case we rescue the error from dscl and alert the user.
+  #
+  # In the event that the user doesn't HAVE a value for the attribute, the
+  # provider should use the -merge option with dscl to add the attribute value
+  # for the user record
+  ['home', 'uid', 'gid', 'comment', 'shell'].each do |setter_method|
+    define_method("#{setter_method}=") do |value|
+      if @property_hash[setter_method.intern]
+        begin
+          dscl '.', '-change', "/Users/#{resource.name}", self.class.ns_to_ds_attribute_map[setter_method.intern], @property_hash[setter_method.intern], value
+        rescue Puppet::ExecutionFailure => e
+          raise Puppet::Error, "Cannot set the #{setter_method} value of '#{value}' for user " +
+               "#{@resource.name} due to the following error: #{e.inspect}", e.backtrace
+        end
+      else
+        begin
+          dscl '.', '-merge', "/Users/#{resource.name}", self.class.ns_to_ds_attribute_map[setter_method.intern], value
+        rescue Puppet::ExecutionFailure => e
+          raise Puppet::Error, "Cannot set the #{setter_method} value of '#{value}' for user " +
+               "#{@resource.name} due to the following error: #{e.inspect}", e.backtrace
+        end
+      end
+    end
+  end
+
+
+  ##                ##
+  ## Helper Methods ##
+  ##                ##
+
+  def assert_full_pbkdf2_password
+    missing = [:password, :salt, :iterations].select { |parameter| @resource[parameter].nil? }
+
+    if !missing.empty?
+       raise Puppet::Error, "OS X versions > 10\.7 use PBKDF2 password hashes, which requires all three of salt, iterations, and password hash. This resource is missing: #{missing.join(', ')}."
+    end
+  end
+
+  def users_plist_dir
+    '/var/db/dslocal/nodes/Default/users'
+  end
+
+  def self.password_hash_dir
+    '/var/db/shadow/hash'
+  end
+
+  # This method will merge in a given value using dscl
+  def merge_attribute_with_dscl(path, username, keyname, value)
+    begin
+      dscl '.', '-merge', "/#{path}/#{username}", keyname, value
+    rescue Puppet::ExecutionFailure => detail
+      raise Puppet::Error, "Could not set the dscl #{keyname} key with value: #{value} - #{detail.inspect}", detail.backtrace
+    end
+  end
+
+  # Create the new user with dscl
+  def create_new_user(username)
+    dscl '.', '-create',  "/Users/#{username}"
+  end
+
+  # Get the next available uid on the system by getting a list of user ids,
+  # sorting them, grabbing the last one, and adding a 1. Scientific stuff here.
+  def next_system_id(min_id=20)
+    dscl_output = dscl '.', '-list', '/Users', 'uid'
+    # We're ok with throwing away negative uids here. Also, remove nil values.
+    user_ids = dscl_output.split.compact.collect { |l| l.to_i if l.match(/^\d+$/) }
+    ids = user_ids.compact!.sort! { |a,b| a.to_f <=> b.to_f }
+    # We're just looking for an unused id in our sorted array.
+    ids.each_index do |i|
+      next_id = ids[i] + 1
+      return next_id if ids[i+1] != next_id and next_id >= min_id
+    end
+  end
+
+  # This method is only called on version 10.7 or greater. On 10.7 machines,
+  # passwords are set using a salted-SHA512 hash, and on 10.8 machines,
+  # passwords are set using PBKDF2. It's possible to have users on 10.8
+  # who have upgraded from 10.7 and thus have a salted-SHA512 password hash.
+  # If we encounter this, do what 10.8 does - remove that key and give them
+  # a 10.8-style PBKDF2 password.
+  def write_password_to_users_plist(value)
+    users_plist = get_users_plist(@resource.name)
+    shadow_hash_data = get_shadow_hash_data(users_plist)
+    if self.class.get_os_version == '10.7'
+      set_salted_sha512(users_plist, shadow_hash_data, value)
+    else
+      # It's possible that a user could exist on the system and NOT have
+      # a ShadowHashData key (especially if the system was upgraded from 10.6).
+      # In this case, a conditional check is needed to determine if the
+      # shadow_hash_data variable is a Hash (it would be false if the key
+      # didn't exist for this user on the system). If the shadow_hash_data
+      # variable IS a Hash and contains the 'SALTED-SHA512' key (indicating an
+      # older 10.7-style password hash), it will be deleted and a newer
+      # 10.8-style (PBKDF2) password hash will be generated.
+      if (shadow_hash_data.class == Hash) && (shadow_hash_data.has_key?('SALTED-SHA512'))
+        shadow_hash_data.delete('SALTED-SHA512')
+      end
+      set_salted_pbkdf2(users_plist, shadow_hash_data, 'entropy', value)
+    end
+  end
+
+  def flush_dscl_cache
+    dscacheutil '-flushcache'
+  end
+
+  def get_users_plist(username)
+    # This method will retrieve the data stored in a user's plist and
+    # return it as a native Ruby hash.
+    Plist::parse_xml(plutil('-convert', 'xml1', '-o', '/dev/stdout', "#{users_plist_dir}/#{username}.plist"))
+  end
+
+  # This method will return the binary plist that's embedded in the
+  # ShadowHashData key of a user's plist, or false if it doesn't exist.
+  def get_shadow_hash_data(users_plist)
+    if users_plist['ShadowHashData']
+      password_hash_plist  = users_plist['ShadowHashData'][0].string
+      self.class.convert_binary_to_xml(password_hash_plist)
+    else
+      false
+    end
+  end
+
+  # This method will embed the binary plist data comprising the user's
+  # password hash (and Salt/Iterations value if the OS is 10.8 or greater)
+  # into the ShadowHashData key of the user's plist.
+  def set_shadow_hash_data(users_plist, binary_plist)
+    if users_plist.has_key?('ShadowHashData')
+      users_plist['ShadowHashData'][0].string = binary_plist
+    else
+      users_plist['ShadowHashData'] = [new_stringio_object(binary_plist)]
+    end
+    write_users_plist_to_disk(users_plist)
+  end
+
+  # This method returns a new StringIO object. Why does it exist?
+  # Well, StringIO objects have their own 'serial number', so when
+  # writing rspec tests it's difficult to compare StringIO objects
+  # due to this serial number. If this action is wrapped in its own
+  # method, it can be mocked for easier testing.
+  def new_stringio_object(value = '')
+    StringIO.new(value)
+  end
+
+  # This method accepts an argument of a hex password hash, and base64
+  # decodes it into a format that OS X 10.7 and 10.8 will store
+  # in the user's plist.
+  def base64_decode_string(value)
+    Base64.decode64([[value].pack("H*")].pack("m").strip)
+  end
+
+  # Puppet requires a salted-sha512 password hash for 10.7 users to be passed
+  # in Hex, but the embedded plist stores that value as a Base64 encoded
+  # string. This method converts the string and calls the
+  # set_shadow_hash_data method to serialize and write the plist to disk.
+  def set_salted_sha512(users_plist, shadow_hash_data, value)
+    unless shadow_hash_data
+      shadow_hash_data = Hash.new
+      shadow_hash_data['SALTED-SHA512'] = new_stringio_object
+    end
+    shadow_hash_data['SALTED-SHA512'].string = base64_decode_string(value)
+    binary_plist = self.class.convert_xml_to_binary(shadow_hash_data)
+    set_shadow_hash_data(users_plist, binary_plist)
+  end
+
+  # This method accepts a passed value and one of three fields: 'salt',
+  # 'entropy', or 'iterations'.  These fields correspond with the fields
+  # utilized in a PBKDF2 password hashing system
+  # (see http://en.wikipedia.org/wiki/PBKDF2 ) where 'entropy' is the
+  # password hash, 'salt' is the password hash salt value, and 'iterations'
+  # is an integer recommended to be > 10,000. The remaining arguments are
+  # the user's plist itself, and the shadow_hash_data hash containing the
+  # existing PBKDF2 values.
+  def set_salted_pbkdf2(users_plist, shadow_hash_data, field, value)
+    shadow_hash_data = Hash.new unless shadow_hash_data
+    shadow_hash_data['SALTED-SHA512-PBKDF2'] = Hash.new unless shadow_hash_data['SALTED-SHA512-PBKDF2']
+    case field
+    when 'salt', 'entropy'
+      shadow_hash_data['SALTED-SHA512-PBKDF2'][field] =  new_stringio_object unless shadow_hash_data['SALTED-SHA512-PBKDF2'][field]
+      shadow_hash_data['SALTED-SHA512-PBKDF2'][field].string = base64_decode_string(value)
+    when 'iterations'
+      shadow_hash_data['SALTED-SHA512-PBKDF2'][field] = Integer(value)
+    else
+      raise Puppet::Error "Puppet has tried to set an incorrect field for the 'SALTED-SHA512-PBKDF2' hash. Acceptable fields are 'salt', 'entropy', or 'iterations'."
+    end
+
+    # on 10.8, this field *must* contain 8 stars, or authentication will
+    # fail.
+    users_plist['passwd'] = ('*' * 8)
+
+    # Convert shadow_hash_data to a binary plist, and call the
+    # set_shadow_hash_data method to serialize and write the data
+    # back to the user's plist.
+    binary_plist = self.class.convert_xml_to_binary(shadow_hash_data)
+    set_shadow_hash_data(users_plist, binary_plist)
+  end
+
+  # This method will accept a plist in XML format, save it to disk, convert
+  # the plist to a binary format, and flush the dscl cache.
+  def write_users_plist_to_disk(users_plist)
+    Plist::Emit.save_plist(users_plist, "#{users_plist_dir}/#{@resource.name}.plist")
+    plutil'-convert', 'binary1', "#{users_plist_dir}/#{@resource.name}.plist"
+  end
+
+  # This is a simple wrapper method for writing values to a file.
+  def write_to_file(filename, value)
+    begin
+      File.open(filename, 'w') { |f| f.write(value)}
+    rescue Errno::EACCES => detail
+      raise Puppet::Error, "Could not write to file #{filename}: #{detail}", detail.backtrace
+    end
+  end
+
+  def write_sha1_hash(value)
+    users_guid = self.class.get_attribute_from_dscl('Users', @resource.name, 'GeneratedUID')['dsAttrTypeStandard:GeneratedUID'][0]
+    password_hash_file = "#{self.class.password_hash_dir}/#{users_guid}"
+    write_to_file(password_hash_file, value)
+
+    # NBK: For shadow hashes, the user AuthenticationAuthority must contain a value of
+    # ";ShadowHash;". The LKDC in 10.5 makes this more interesting though as it
+    # will dynamically generate ;Kerberosv5;;username@LKDC:SHA1 attributes if
+    # missing. Thus we make sure we only set ;ShadowHash; if it is missing, and
+    # we can do this with the merge command. This allows people to continue to
+    # use other custom AuthenticationAuthority attributes without stomping on them.
+    #
+    # There is a potential problem here in that we're only doing this when setting
+    # the password, and the attribute could get modified at other times while the
+    # hash doesn't change and so this doesn't get called at all... but
+    # without switching all the other attributes to merge instead of create I can't
+    # see a simple enough solution for this that doesn't modify the user record
+    # every single time. This should be a rather rare edge case. (famous last words)
+
+    merge_attribute_with_dscl('Users', @resource.name, 'AuthenticationAuthority', ';ShadowHash;')
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/hpux.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/hpux.rb
new file mode 100644
index 0000000..c38879a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/hpux.rb
@@ -0,0 +1,66 @@
+Puppet::Type.type(:user).provide :hpuxuseradd, :parent => :useradd do
+  desc "User management for HP-UX. This provider uses the undocumented `-F`
+    switch to HP-UX's special `usermod` binary to work around the fact that
+    its standard `usermod` cannot make changes while the user is logged in."
+
+  defaultfor :operatingsystem => "hp-ux"
+  confine :operatingsystem => "hp-ux"
+
+  commands :modify => "/usr/sam/lbin/usermod.sam", :delete => "/usr/sam/lbin/userdel.sam", :add => "/usr/sam/lbin/useradd.sam"
+  options :comment, :method => :gecos
+  options :groups, :flag => "-G"
+  options :home, :flag => "-d", :method => :dir
+
+  verify :gid, "GID must be an integer" do |value|
+    value.is_a? Integer
+  end
+
+  verify :groups, "Groups must be comma-separated" do |value|
+    value !~ /\s/
+  end
+
+  has_features :manages_homedir, :allows_duplicates, :manages_passwords
+
+  def deletecmd
+    super.insert(1,"-F")
+  end
+
+  def modifycmd(param,value)
+    super.insert(1,"-F")
+  end
+
+  def password
+    # Password management routine for trusted and non-trusted systems
+    #temp=""
+    while ent = Etc.getpwent() do
+      if ent.name == resource.name
+        temp=ent.name
+        break
+      end
+    end
+    Etc.endpwent()
+    if !temp
+      return nil
+    end
+
+    ent = Etc.getpwnam(resource.name)
+    if ent.passwd == "*"
+      # Either no password or trusted password, check trusted
+      file_name="/tcb/files/auth/#{resource.name.chars.first}/#{resource.name}"
+      if File.file?(file_name)
+        # Found the tcb user for the specific user, now get passwd
+        File.open(file_name).each do |line|
+          if ( line =~ /u_pwd/ )
+            temp_passwd=line.split(":")[1].split("=")[1]
+            ent.passwd = temp_passwd
+            return ent.passwd
+          end
+        end
+      else
+        debug "No trusted computing user file #{file_name} found."
+      end
+    else
+      return ent.passwd
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/ldap.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/ldap.rb
new file mode 100644
index 0000000..6dbda5f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/ldap.rb
@@ -0,0 +1,128 @@
+require 'puppet/provider/ldap'
+
+Puppet::Type.type(:user).provide :ldap, :parent => Puppet::Provider::Ldap do
+  desc "User management via LDAP.
+
+    This provider requires that you have valid values for all of the
+    LDAP-related settings in `puppet.conf`, including `ldapbase`.  You will
+    almost definitely need settings for `ldapuser` and `ldappassword` in order
+    for your clients to write to LDAP.
+
+    Note that this provider will automatically generate a UID for you if
+    you do not specify one, but it is a potentially expensive operation,
+    as it iterates across all existing users to pick the appropriate next one."
+
+  confine :feature => :ldap, :false => (Puppet[:ldapuser] == "")
+
+  has_feature :manages_passwords, :manages_shell
+
+  manages(:posixAccount, :person).at("ou=People").named_by(:uid).and.maps :name => :uid,
+    :password => :userPassword,
+    :comment => :cn,
+    :uid => :uidNumber,
+    :gid => :gidNumber,
+    :home => :homeDirectory,
+    :shell => :loginShell
+
+  # Use the last field of a space-separated array as
+  # the sn.  LDAP requires a surname, for some stupid reason.
+  manager.generates(:sn).from(:cn).with do |cn|
+    cn[0].split(/\s+/)[-1]
+  end
+
+  # Find the next uid after the current largest uid.
+  provider = self
+  manager.generates(:uidNumber).with do
+    largest = 500
+    if existing = provider.manager.search
+      existing.each do |hash|
+        next unless value = hash[:uid]
+        num = value[0].to_i
+        largest = num if num > largest
+      end
+    end
+    largest + 1
+  end
+
+  # Convert our gid to a group name, if necessary.
+  def gid=(value)
+    value = group2id(value) unless [Fixnum, Bignum].include?(value.class)
+
+    @property_hash[:gid] = value
+  end
+
+  # Find all groups this user is a member of in ldap.
+  def groups
+    # We want to cache the current result, so we know if we
+    # have to remove old values.
+    unless @property_hash[:groups]
+      unless result = group_manager.search("memberUid=#{name}")
+        return @property_hash[:groups] = :absent
+      end
+
+      return @property_hash[:groups] = result.collect { |r| r[:name] }.sort.join(",")
+    end
+    @property_hash[:groups]
+  end
+
+  # Manage the list of groups this user is a member of.
+  def groups=(values)
+    should = values.split(",")
+
+    if groups == :absent
+      is = []
+    else
+      is = groups.split(",")
+    end
+
+    modes = {}
+    [is, should].flatten.uniq.each do |group|
+      # Skip it when they're in both
+      next if is.include?(group) and should.include?(group)
+
+      # We're adding a group.
+      modes[group] = :add and next unless is.include?(group)
+
+      # We're removing a group.
+      modes[group] = :remove and next unless should.include?(group)
+    end
+
+    modes.each do |group, form|
+      self.fail "Could not find ldap group #{group}" unless ldap_group = group_manager.find(group)
+
+      current = ldap_group[:members]
+
+      if form == :add
+        if current.is_a?(Array) and ! current.empty?
+          new = current + [name]
+        else
+          new = [name]
+        end
+      else
+        new = current - [name]
+        new = :absent if new.empty?
+      end
+
+      group_manager.update(group, {:ensure => :present, :members => current}, {:ensure => :present, :members => new})
+    end
+  end
+
+  # Convert a gropu name to an id.
+  def group2id(group)
+    Puppet::Type.type(:group).provider(:ldap).name2id(group)
+  end
+
+  private
+
+  def group_manager
+    Puppet::Type.type(:group).provider(:ldap).manager
+  end
+
+  def group_properties(values)
+    if values.empty? or values == :absent
+      {:ensure => :present}
+    else
+      {:ensure => :present, :members => values}
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/pw.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/pw.rb
new file mode 100644
index 0000000..1e3034a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/pw.rb
@@ -0,0 +1,98 @@
+require 'puppet/provider/nameservice/pw'
+require 'open3'
+
+Puppet::Type.type(:user).provide :pw, :parent => Puppet::Provider::NameService::PW do
+  desc "User management via `pw` on FreeBSD and DragonFly BSD."
+
+  commands :pw => "pw"
+  has_features :manages_homedir, :allows_duplicates, :manages_passwords, :manages_expiry, :manages_shell
+
+  defaultfor :operatingsystem => [:freebsd, :dragonfly]
+  confine    :operatingsystem => [:freebsd, :dragonfly]
+
+  options :home, :flag => "-d", :method => :dir
+  options :comment, :method => :gecos
+  options :groups, :flag => "-G"
+  options :expiry, :method => :expire, :munge => proc { |value|
+    value = '0000-00-00' if value == :absent
+    value.split("-").reverse.join("-")
+  }
+
+
+  verify :gid, "GID must be an integer" do |value|
+    value.is_a? Integer
+  end
+
+  verify :groups, "Groups must be comma-separated" do |value|
+    value !~ /\s/
+  end
+
+  def addcmd
+    cmd = [command(:pw), "useradd", @resource[:name]]
+    @resource.class.validproperties.each do |property|
+      next if property == :ensure or property == :password
+      if value = @resource.should(property) and value != ""
+        cmd << flag(property) << munge(property,value)
+      end
+    end
+
+    cmd << "-o" if @resource.allowdupe?
+    cmd << "-m" if @resource.managehome?
+    cmd
+  end
+
+  def modifycmd(param, value)
+    if param == :expiry
+      # FreeBSD uses DD-MM-YYYY rather than YYYY-MM-DD
+      value = value.split("-").reverse.join("-")
+    end
+    cmd = super(param, value)
+    cmd << "-m" if @resource.managehome?
+    cmd
+  end
+
+  def deletecmd
+    cmd = super
+    cmd << "-r" if @resource.managehome?
+    cmd
+  end
+
+  def create
+    super
+
+    # Set the password after create if given
+    self.password = @resource[:password] if @resource[:password]
+  end
+
+  # use pw to update password hash
+  def password=(cryptopw)
+    Puppet.debug "change password for user '#{@resource[:name]}' method called with hash '#{cryptopw}'"
+    stdin, stdout, stderr = Open3.popen3("pw user mod #{@resource[:name]} -H 0")
+    stdin.puts(cryptopw)
+    stdin.close
+    Puppet.debug "finished password for user '#{@resource[:name]}' method called with hash '#{cryptopw}'"
+  end
+
+  # get password from /etc/master.passwd
+  def password
+    Puppet.debug "checking password for user '#{@resource[:name]}' method called"
+    current_passline = `getent passwd #{@resource[:name]}`
+    current_password = current_passline.chomp.split(':')[1] if current_passline
+    Puppet.debug "finished password for user '#{@resource[:name]}' method called : '#{current_password}'"
+    current_password
+  end
+
+  # Get expiry from system and convert to Puppet-style date
+  def expiry
+    expiry = self.get(:expiry)
+    expiry = :absent if expiry == 0
+
+    if expiry != :absent
+      t = Time.at(expiry)
+      expiry = "%4d-%02d-%02d" % [t.year, t.month, t.mday]
+    end
+
+    expiry
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/user_role_add.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/user_role_add.rb
new file mode 100644
index 0000000..f3100e0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/user_role_add.rb
@@ -0,0 +1,210 @@
+require 'puppet/util'
+require 'puppet/util/user_attr'
+require 'date'
+
+Puppet::Type.type(:user).provide :user_role_add, :parent => :useradd, :source => :useradd do
+
+  desc "User and role management on Solaris, via `useradd` and `roleadd`."
+
+  defaultfor :osfamily => :solaris
+
+  commands :add => "useradd", :delete => "userdel", :modify => "usermod", :password => "passwd", :role_add => "roleadd", :role_delete => "roledel", :role_modify => "rolemod"
+  options :home, :flag => "-d", :method => :dir
+  options :comment, :method => :gecos
+  options :groups, :flag => "-G"
+  options :roles, :flag => "-R"
+  options :auths, :flag => "-A"
+  options :profiles, :flag => "-P"
+  options :password_min_age, :flag => "-n"
+  options :password_max_age, :flag => "-x"
+
+  verify :gid, "GID must be an integer" do |value|
+    value.is_a? Integer
+  end
+
+  verify :groups, "Groups must be comma-separated" do |value|
+    value !~ /\s/
+  end
+
+  has_features :manages_homedir, :allows_duplicates, :manages_solaris_rbac, :manages_passwords, :manages_password_age, :manages_shell
+
+  #must override this to hand the keyvalue pairs
+  def add_properties
+    cmd = []
+    Puppet::Type.type(:user).validproperties.each do |property|
+      #skip the password because we can't create it with the solaris useradd
+      next if [:ensure, :password, :password_min_age, :password_max_age].include?(property)
+      # 1680 Now you can set the hashed passwords on solaris:lib/puppet/provider/user/user_role_add.rb
+      # the value needs to be quoted, mostly because -c might
+      # have spaces in it
+      if value = @resource.should(property) and value != ""
+        if property == :keys
+          cmd += build_keys_cmd(value)
+        else
+          cmd << flag(property) << value
+        end
+      end
+    end
+    cmd
+  end
+
+  def user_attributes
+    @user_attributes ||= UserAttr.get_attributes_by_name(@resource[:name])
+  end
+
+  def flush
+    @user_attributes = nil
+  end
+
+  def command(cmd)
+    cmd = ("role_#{cmd}").intern if is_role? or (!exists? and @resource[:ensure] == :role)
+    super(cmd)
+  end
+
+  def is_role?
+    user_attributes and user_attributes[:type] == "role"
+  end
+
+  def run(cmd, msg)
+      execute(cmd)
+  rescue Puppet::ExecutionFailure => detail
+      raise Puppet::Error, "Could not #{msg} #{@resource.class.name} #{@resource.name}: #{detail}", detail.backtrace
+  end
+
+  def transition(type)
+    cmd = [command(:modify)]
+    cmd << "-K" << "type=#{type}"
+    cmd += add_properties
+    cmd << @resource[:name]
+  end
+
+  def create
+    if is_role?
+      run(transition("normal"), "transition role to")
+    else
+      run(addcmd, "create")
+      if cmd = passcmd
+        run(cmd, "change password policy for")
+      end
+    end
+    # added to handle case when password is specified
+    self.password = @resource[:password] if @resource[:password]
+  end
+
+  def destroy
+    run(deletecmd, "delete "+ (is_role? ? "role" : "user"))
+  end
+
+  def create_role
+    if exists? and !is_role?
+      run(transition("role"), "transition user to")
+    else
+      run(addcmd, "create role")
+    end
+  end
+
+  def roles
+    user_attributes[:roles] if user_attributes
+  end
+
+  def auths
+    user_attributes[:auths] if user_attributes
+  end
+
+  def profiles
+    user_attributes[:profiles] if user_attributes
+  end
+
+  def project
+    user_attributes[:project] if user_attributes
+  end
+
+  def managed_attributes
+    [:name, :type, :roles, :auths, :profiles, :project]
+  end
+
+  def remove_managed_attributes
+    managed = managed_attributes
+    user_attributes.select { |k,v| !managed.include?(k) }.inject({}) { |hash, array| hash[array[0]] = array[1]; hash }
+  end
+
+  def keys
+    if user_attributes
+      #we have to get rid of all the keys we are managing another way
+      remove_managed_attributes
+    end
+  end
+
+  def build_keys_cmd(keys_hash)
+    cmd = []
+    keys_hash.each do |k,v|
+      cmd << "-K" << "#{k}=#{v}"
+    end
+    cmd
+  end
+
+  def keys=(keys_hash)
+    run([command(:modify)] + build_keys_cmd(keys_hash) << @resource[:name], "modify attribute key pairs")
+  end
+
+
+  # This helper makes it possible to test this on stub data without having to
+  # do too many crazy things!
+  def target_file_path
+    "/etc/shadow"
+  end
+  private :target_file_path
+
+  #Read in /etc/shadow, find the line for this user (skipping comments, because who knows) and return it
+  #No abstraction, all esoteric knowledge of file formats, yay
+  def shadow_entry
+    return @shadow_entry if defined? @shadow_entry
+    @shadow_entry = File.readlines(target_file_path).
+      reject { |r| r =~ /^[^\w]/ }.
+      # PUP-229 dont suppress the empty fields
+      collect { |l| l.chomp.split(':', -1) }.
+      find { |user, _| user == @resource[:name] }
+  end
+
+  def password
+    shadow_entry[1] if shadow_entry
+  end
+
+  def password_min_age
+    shadow_entry[3].empty? ? -1 : shadow_entry[3]
+  end
+
+  def password_max_age
+    return :absent unless shadow_entry
+    shadow_entry[4].empty? ? -1 : shadow_entry[4]
+  end
+
+  # Read in /etc/shadow, find the line for our used and rewrite it with the
+  # new pw.  Smooth like 80 grit sandpaper.
+  #
+  # Now uses the `replace_file` mechanism to minimize the chance that we lose
+  # data, but it is still terrible.  We still skip platform locking, so a
+  # concurrent `vipw -s` session will have no idea we risk data loss.
+  def password=(cryptopw)
+    begin
+      shadow = File.read(target_file_path)
+
+      # Go Mifune loves the race here where we can lose data because
+      # /etc/shadow changed between reading it and writing it.
+      # --daniel 2012-02-05
+      Puppet::Util.replace_file(target_file_path, 0640) do |fh|
+        shadow.each_line do |line|
+          line_arr = line.split(':')
+          if line_arr[0] == @resource[:name]
+            line_arr[1] = cryptopw
+            line_arr[2] = (Date.today - Date.new(1970,1,1)).to_i.to_s
+            line = line_arr.join(':')
+          end
+          fh.print line
+        end
+      end
+    rescue => detail
+      self.fail Puppet::Error, "Could not write replace #{target_file_path}: #{detail}", detail
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/useradd.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/useradd.rb
new file mode 100644
index 0000000..dd2d24b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/useradd.rb
@@ -0,0 +1,231 @@
+require 'puppet/provider/nameservice/objectadd'
+require 'date'
+require 'puppet/util/libuser'
+require 'time'
+require 'puppet/error'
+
+Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameService::ObjectAdd do
+  desc "User management via `useradd` and its ilk.  Note that you will need to
+    install Ruby's shadow password library (often known as `ruby-libshadow`)
+    if you wish to manage user passwords."
+
+  commands :add => "useradd", :delete => "userdel", :modify => "usermod", :password => "chage"
+
+  options :home, :flag => "-d", :method => :dir
+  options :comment, :method => :gecos
+  options :groups, :flag => "-G"
+  options :password_min_age, :flag => "-m", :method => :sp_min
+  options :password_max_age, :flag => "-M", :method => :sp_max
+  options :password, :method => :sp_pwdp
+  options :expiry, :method => :sp_expire,
+    :munge => proc { |value|
+      if value == :absent
+        ''
+      else
+        case Facter.value(:operatingsystem)
+        when 'Solaris'
+          # Solaris uses %m/%d/%Y for useradd/usermod
+          expiry_year, expiry_month, expiry_day = value.split('-')
+          [expiry_month, expiry_day, expiry_year].join('/')
+        else
+          value
+        end
+      end
+    },
+    :unmunge => proc { |value|
+      if value == -1
+        :absent
+      else
+        # Expiry is days after 1970-01-01
+        (Date.new(1970,1,1) + value).strftime('%Y-%m-%d')
+      end
+    }
+
+  optional_commands :localadd => "luseradd"
+  has_feature :libuser if Puppet.features.libuser?
+
+  def exists?
+    return !!localuid if @resource.forcelocal?
+    super
+  end
+
+  def uid
+     return localuid if @resource.forcelocal?
+     get(:uid)
+  end
+
+  def finduser(key, value)
+    passwd_file = "/etc/passwd"
+    passwd_keys = ['account', 'password', 'uid', 'gid', 'gecos', 'directory', 'shell']
+    index = passwd_keys.index(key)
+    File.open(passwd_file) do |f|
+      f.each_line do |line|
+         user = line.split(":")
+         if user[index] == value
+             f.close
+             return user
+         end
+      end
+    end
+    false
+  end
+
+  def local_username
+    finduser('uid', @resource.uid)
+  end
+
+  def localuid
+    user = finduser('account', resource[:name])
+    return user[2] if user
+    false
+  end
+
+  def shell=(value)
+    check_valid_shell
+    set("shell", value)
+  end
+
+  verify :gid, "GID must be an integer" do |value|
+    value.is_a? Integer
+  end
+
+  verify :groups, "Groups must be comma-separated" do |value|
+    value !~ /\s/
+  end
+
+  has_features :manages_homedir, :allows_duplicates, :manages_expiry
+  has_features :system_users unless %w{HP-UX Solaris}.include? Facter.value(:operatingsystem)
+
+  has_features :manages_passwords, :manages_password_age if Puppet.features.libshadow?
+  has_features :manages_shell
+
+  def check_allow_dup
+    # We have to manually check for duplicates when using libuser
+    # because by default duplicates are allowed.  This check is
+    # to ensure consistent behaviour of the useradd provider when
+    # using both useradd and luseradd
+    if not @resource.allowdupe? and @resource.forcelocal?
+       if @resource.should(:uid) and finduser('uid', @resource.should(:uid).to_s)
+           raise(Puppet::Error, "UID #{@resource.should(:uid).to_s} already exists, use allowdupe to force user creation")
+       end
+    elsif @resource.allowdupe? and not @resource.forcelocal?
+       return ["-o"]
+    end
+    []
+  end
+
+  def check_valid_shell
+    unless File.exists?(@resource.should(:shell))
+      raise(Puppet::Error, "Shell #{@resource.should(:shell)} must exist")
+    end
+    unless File.executable?(@resource.should(:shell).to_s)
+      raise(Puppet::Error, "Shell #{@resource.should(:shell)} must be executable")
+    end
+  end
+
+  def check_manage_home
+    cmd = []
+    if @resource.managehome? and not @resource.forcelocal?
+      cmd << "-m"
+    elsif not @resource.managehome? and Facter.value(:osfamily) == 'RedHat'
+      cmd << "-M"
+    end
+    cmd
+  end
+
+  def check_manage_expiry
+    cmd = []
+    if @resource[:expiry] and not @resource.forcelocal?
+      cmd << "-e #{@resource[:expiry]}"
+    end
+
+    cmd
+  end
+
+  def check_system_users
+    if self.class.system_users? and resource.system?
+      ["-r"]
+    else
+      []
+    end
+  end
+
+  def add_properties
+    cmd = []
+    # validproperties is a list of properties in undefined order
+    # sort them to have a predictable command line in tests
+    Puppet::Type.type(:user).validproperties.sort.each do |property|
+      next if property == :ensure
+      next if property.to_s =~ /password_.+_age/
+      next if property == :groups and @resource.forcelocal?
+      next if property == :expiry and @resource.forcelocal?
+      # the value needs to be quoted, mostly because -c might
+      # have spaces in it
+      if value = @resource.should(property) and value != ""
+        cmd << flag(property) << munge(property, value)
+      end
+    end
+    cmd
+  end
+
+  def addcmd
+    if @resource.forcelocal?
+      cmd = [command(:localadd)]
+      @custom_environment = Puppet::Util::Libuser.getenv
+    else
+      cmd = [command(:add)]
+    end
+    if not @resource.should(:gid) and Puppet::Util.gid(@resource[:name])
+      cmd += ["-g", @resource[:name]]
+    end
+    cmd += add_properties
+    cmd += check_allow_dup
+    cmd += check_manage_home
+    cmd += check_system_users
+    cmd << @resource[:name]
+  end
+
+  def deletecmd
+    cmd = [command(:delete)]
+    cmd += @resource.managehome? ? ['-r'] : []
+    cmd << @resource[:name]
+  end
+
+  def passcmd
+    age_limits = [:password_min_age, :password_max_age].select { |property| @resource.should(property) }
+    if age_limits.empty?
+      nil
+    else
+      [command(:password),age_limits.collect { |property| [flag(property), @resource.should(property)]}, @resource[:name]].flatten
+    end
+  end
+
+  [:expiry, :password_min_age, :password_max_age, :password].each do |shadow_property|
+    define_method(shadow_property) do
+      if Puppet.features.libshadow?
+        if ent = Shadow::Passwd.getspnam(@resource.name)
+          method = self.class.option(shadow_property, :method)
+          return unmunge(shadow_property, ent.send(method))
+        end
+      end
+      :absent
+    end
+  end
+
+  def create
+    if @resource[:shell]
+      check_valid_shell
+    end
+     super
+     if @resource.forcelocal? and self.groups?
+       set(:groups, @resource[:groups])
+     end
+     if @resource.forcelocal? and @resource[:expiry]
+       set(:expiry, @resource[:expiry])
+     end
+  end
+
+  def groups?
+    !!@resource[:groups]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/windows_adsi.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/windows_adsi.rb
new file mode 100644
index 0000000..20570b2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/user/windows_adsi.rb
@@ -0,0 +1,106 @@
+require 'puppet/util/windows'
+
+Puppet::Type.type(:user).provide :windows_adsi do
+  desc "Local user management for Windows."
+
+  defaultfor :operatingsystem => :windows
+  confine    :operatingsystem => :windows
+
+  has_features :manages_homedir, :manages_passwords
+
+  def initialize(value={})
+    super(value)
+    @deleted = false
+  end
+
+  def user
+    @user ||= Puppet::Util::Windows::ADSI::User.new(@resource[:name])
+  end
+
+  def groups
+    user.groups.join(',')
+  end
+
+  def groups=(groups)
+    user.set_groups(groups, @resource[:membership] == :minimum)
+  end
+
+  def create
+    @user = Puppet::Util::Windows::ADSI::User.create(@resource[:name])
+    @user.password = @resource[:password]
+    @user.commit
+
+    [:comment, :home, :groups].each do |prop|
+      send("#{prop}=", @resource[prop]) if @resource[prop]
+    end
+
+    if @resource.managehome?
+      Puppet::Util::Windows::User.load_profile(@resource[:name], @resource[:password])
+    end
+  end
+
+  def exists?
+    Puppet::Util::Windows::ADSI::User.exists?(@resource[:name])
+  end
+
+  def delete
+    # lookup sid before we delete account
+    sid = uid if @resource.managehome?
+
+    Puppet::Util::Windows::ADSI::User.delete(@resource[:name])
+
+    if sid
+      Puppet::Util::Windows::ADSI::UserProfile.delete(sid)
+    end
+
+    @deleted = true
+  end
+
+  # Only flush if we created or modified a user, not deleted
+  def flush
+    @user.commit if @user && !@deleted
+  end
+
+  def comment
+    user['Description']
+  end
+
+  def comment=(value)
+    user['Description'] = value
+  end
+
+  def home
+    user['HomeDirectory']
+  end
+
+  def home=(value)
+    user['HomeDirectory'] = value
+  end
+
+  def password
+    user.password_is?( @resource[:password] ) ? @resource[:password] : :absent
+  end
+
+  def password=(value)
+    user.password = value
+  end
+
+  def uid
+    Puppet::Util::Windows::SID.name_to_sid(@resource[:name])
+  end
+
+  def uid=(value)
+    fail "uid is read-only"
+  end
+
+  [:gid, :shell].each do |prop|
+    define_method(prop) { nil }
+    define_method("#{prop}=") do |v|
+      fail "No support for managing property #{prop} of user #{@resource[:name]} on Windows"
+    end
+  end
+
+  def self.instances
+    Puppet::Util::Windows::ADSI::User.map { |u| new(:ensure => :present, :name => u.name) }
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/vlan/cisco.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/vlan/cisco.rb
new file mode 100644
index 0000000..6d03764
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/vlan/cisco.rb
@@ -0,0 +1,28 @@
+require 'puppet/provider/cisco'
+
+Puppet::Type.type(:vlan).provide :cisco, :parent => Puppet::Provider::Cisco do
+
+  desc "Cisco switch/router provider for vlans."
+
+  mk_resource_methods
+
+  def self.lookup(device, id)
+    vlans = {}
+    device.command do |dev|
+      vlans = dev.parse_vlans || {}
+    end
+    vlans[id]
+  end
+
+  def initialize(device, *args)
+    super
+  end
+
+  # Clear out the cached values.
+  def flush
+    device.command do |dev|
+      dev.update_vlan(resource[:name], former_properties, properties)
+    end
+    super
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/yumrepo/inifile.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/yumrepo/inifile.rb
new file mode 100644
index 0000000..6592ab2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/yumrepo/inifile.rb
@@ -0,0 +1,303 @@
+require 'puppet/util/inifile'
+
+Puppet::Type.type(:yumrepo).provide(:inifile) do
+  desc <<-EOD
+    Manage yum repo configurations by parsing yum INI configuration files.
+
+    ## Fetching instances
+
+    When fetching repo instances, directory entries in '/etc/yum/repos.d',
+    '/etc/yum.repos.d', and the directory optionally specified by the reposdir
+    key in '/etc/yum.conf' will be checked. If a given directory does not exist it
+    will be ignored. In addition, all sections in '/etc/yum.conf' aside from
+    'main' will be created as sections.
+
+    ## Storing instances
+
+    When creating a new repository, a new section will be added in the first
+    yum repo directory that exists. The custom directory specified by the
+    '/etc/yum.conf' reposdir property is checked first, followed by
+    '/etc/yum/repos.d', and then '/etc/yum.repos.d'. If none of these exist, the
+    section will be created in '/etc/yum.conf'.
+  EOD
+
+  PROPERTIES = Puppet::Type.type(:yumrepo).validproperties
+
+  # Retrieve all providers based on existing yum repositories
+  #
+  # @api public
+  # @return [Array<Puppet::Provider>] providers generated from existing yum
+  #   repository definitions.
+  def self.instances
+    instances = []
+
+    virtual_inifile.each_section do |section|
+      # Ignore the 'main' section in yum.conf since it's not a repository.
+      next if section.name == "main"
+
+      attributes_hash = {:name => section.name, :ensure => :present, :provider => :yumrepo}
+
+      section.entries.each do |key, value|
+        key = key.to_sym
+        if valid_property?(key)
+          attributes_hash[key] = value
+        elsif key == :name
+          attributes_hash[:descr] = value
+        end
+      end
+      instances << new(attributes_hash)
+    end
+
+    instances
+  end
+
+  # Match catalog type instances to provider instances.
+  #
+  # @api public
+  # @param resources [Array<Puppet::Type::Yumrepo>] Resources to prefetch.
+  # @return [void]
+  def self.prefetch(resources)
+    repos = instances
+    resources.keys.each do |name|
+      if provider = repos.find { |repo| repo.name == name }
+        resources[name].provider = provider
+      end
+    end
+  end
+
+  # Return a list of existing directories that could contain repo files.
+  #
+  # @api private
+  # @param conf [String] Configuration file to look for directories in.
+  # @param dirs [Array<String>] Default locations for yum repos.
+  # @return [Array<String>] All present directories that may contain yum repo configs.
+  def self.reposdir(conf='/etc/yum.conf', dirs=['/etc/yum.repos.d', '/etc/yum/repos.d'])
+    reposdir = find_conf_value('reposdir', conf)
+    # Use directories in reposdir if they are set instead of default
+    dirs = reposdir.split(",").map(&:strip) if reposdir
+    
+
+    # We can't use the below due to Ruby 1.8.7
+    # dirs.select! { |dir| Puppet::FileSystem.exist?(dir) }
+    dirs.delete_if { |dir| ! Puppet::FileSystem.exist?(dir)  }
+    if dirs.empty?
+      Puppet.debug('No yum directories were found on the local filesystem')
+    end
+
+    dirs
+  end
+
+  # Used for testing only
+  # @api private
+  def self.clear
+    @virtual = nil
+  end
+
+  # Helper method to look up specific values in ini style files.
+  #
+  # @api private
+  # @param value [String] Value to look for in the configuration file.
+  # @param conf [String] Configuration file to check for value.
+  # @return [String] The value of a looked up key from the configuration file.
+  def self.find_conf_value(value, conf='/etc/yum.conf')
+    if Puppet::FileSystem.exist?(conf)
+      file = Puppet::Util::IniConfig::PhysicalFile.new(conf)
+      file.read
+      if (main = file.get_section('main'))
+        main[value]
+      end
+    end
+  end
+
+  # Enumerate all files that may contain yum repository configs.
+  # '/etc/yum.conf' is always included.
+  #
+  # @api private
+  # @return [Array<String>
+  def self.repofiles
+    files = ["/etc/yum.conf"]
+    reposdir.each do |dir|
+      Dir.glob("#{dir}/*.repo").each do |file|
+        files << file
+      end
+    end
+
+    files
+  end
+
+  # Build a virtual inifile by reading in numerous .repo files into a single
+  # virtual file to ease manipulation.
+  # @api private
+  # @return [Puppet::Util::IniConfig::File] The virtual inifile representing
+  #   multiple real files.
+  def self.virtual_inifile
+    unless @virtual
+      @virtual = Puppet::Util::IniConfig::File.new
+      self.repofiles.each do |file|
+        @virtual.read(file) if Puppet::FileSystem.file?(file)
+      end
+    end
+    return @virtual
+  end
+
+  # Is the given key a valid type property?
+  #
+  # @api private
+  # @param key [String] The property to look up.
+  # @return [Boolean] Returns true if the property is defined in the type.
+  def self.valid_property?(key)
+    PROPERTIES.include?(key)
+  end
+
+  # Return an existing INI section or create a new section in the default location
+  #
+  # The default location is determined based on what yum repo directories
+  # and files are present. If /etc/yum.conf has a value for 'reposdir' then that
+  # is preferred. If no such INI property is found then the first default yum
+  # repo directory that is present is used. If no default directories exist then
+  # /etc/yum.conf is used.
+  #
+  # @param name [String] Section name to lookup in the virtual inifile.
+  # @return [Puppet::Util::IniConfig] The IniConfig section
+  def self.section(name)
+    result = self.virtual_inifile[name]
+    # Create a new section if not found.
+    unless result
+      dirs = reposdir()
+      if dirs.empty?
+        # If no repo directories are present, default to using yum.conf.
+        path = '/etc/yum.conf'
+      else
+        # The ordering of reposdir is [defaults, custom], and we want to use
+        # the custom directory if present.
+        path = File.join(dirs.last, "#{name}.repo")
+      end
+      result = self.virtual_inifile.add_section(name, path)
+    end
+    result
+  end
+
+  # Save all yum repository files and force the mode to 0644
+  # @api private
+  # @return [void]
+  def self.store
+    inifile = self.virtual_inifile
+    inifile.store
+
+    target_mode = 0644
+    inifile.each_file do |file|
+      current_mode = Puppet::FileSystem.stat(file).mode & 0777
+      unless current_mode == target_mode
+        Puppet.info "changing mode of #{file} from %03o to %03o" % [current_mode, target_mode]
+        Puppet::FileSystem.chmod(target_mode, file)
+      end
+    end
+  end
+
+  # Create a new section for the given repository and set all the specified
+  # properties in the section.
+  #
+  # @api public
+  # @return [void]
+  def create
+    @property_hash[:ensure] = :present
+
+    new_section = current_section
+
+    # We fetch a list of properties from the type, then iterate
+    # over them, avoiding ensure.  We're relying on .should to
+    # check if the property has been set and should be modified,
+    # and if so we set it in the virtual inifile.
+    PROPERTIES.each do |property|
+      next if property == :ensure
+
+      if value = @resource.should(property)
+        self.send("#{property}=", value)
+      end
+    end
+  end
+
+  # Does the given repository already exist?
+  #
+  # @api public
+  # @return [Boolean]
+  def exists?
+    @property_hash[:ensure] == :present
+  end
+
+  # Mark the given repository section for destruction.
+  #
+  # The actual removal of the section will be handled by {#flush} after the
+  # resource has been fully evaluated.
+  #
+  # @api public
+  # @return [void]
+  def destroy
+    # Flag file for deletion on flush.
+    current_section.destroy=(true)
+
+    @property_hash.clear
+  end
+
+  # Finalize the application of the given resource.
+  #
+  # @api public
+  # @return [void]
+  def flush
+    self.class.store
+  end
+
+  # Generate setters and getters for our INI properties.
+  PROPERTIES.each do |property|
+    # The ensure property uses #create, #exists, and #destroy we can't generate
+    # meaningful setters and getters for this
+    next if property == :ensure
+
+    define_method(property) do
+      get_property(property)
+    end
+
+    define_method("#{property}=") do |value|
+      set_property(property, value)
+    end
+  end
+
+  # Map the yumrepo 'descr' type property to the 'name' INI property.
+  def descr
+    if ! @property_hash.has_key?(:descr)
+      @property_hash[:descr] = current_section['name']
+    end
+    value = @property_hash[:descr]
+    value.nil? ? :absent : value
+  end
+
+  def descr=(value)
+    value = (value == :absent ? nil : value)
+    current_section['name'] = value
+    @property_hash[:descr] = value
+  end
+
+  private
+
+  def get_property(property)
+    if ! @property_hash.has_key?(property)
+      @property_hash[property] = current_section[property.to_s]
+    end
+    value = @property_hash[property]
+    value.nil? ? :absent : value
+  end
+
+  def set_property(property, value)
+    value = (value == :absent ? nil : value)
+    current_section[property.to_s] = value
+    @property_hash[property] = value
+  end
+
+  def section(name)
+    self.class.section(name)
+  end
+
+  def current_section
+    self.class.section(self.name)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/zfs/zfs.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/zfs/zfs.rb
new file mode 100644
index 0000000..a88fb7a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/zfs/zfs.rb
@@ -0,0 +1,83 @@
+Puppet::Type.type(:zfs).provide(:zfs) do
+  desc "Provider for zfs."
+
+  commands :zfs => 'zfs'
+
+  def self.instances
+    zfs(:list, '-H').split("\n").collect do |line|
+      name,used,avail,refer,mountpoint = line.split(/\s+/)
+      new({:name => name, :ensure => :present})
+    end
+  end
+
+  def add_properties
+    properties = []
+    Puppet::Type.type(:zfs).validproperties.each do |property|
+      next if property == :ensure
+      if value = @resource[property] and value != ""
+        properties << "-o" << "#{property}=#{value}"
+      end
+    end
+    properties
+  end
+
+  def create
+    zfs *([:create] + add_properties + [@resource[:name]])
+  end
+
+  def destroy
+    zfs(:destroy, @resource[:name])
+  end
+
+  def exists?
+    if zfs(:list).split("\n").detect { |line| line.split("\s")[0] == @resource[:name] }
+      true
+    else
+      false
+    end
+  end
+
+  PARAMETER_UNSET_OR_NOT_AVAILABLE = '-'
+
+  # http://docs.oracle.com/cd/E19963-01/html/821-1448/gbscy.html
+  # shareiscsi (added in build 120) was removed from S11 build 136
+  # aclmode was removed from S11 in build 139 but it may have been added back
+  # http://webcache.googleusercontent.com/search?q=cache:-p74K0DVsdwJ:developers.slashdot.org/story/11/11/09/2343258/solaris-11-released+&cd=13
+  [:aclmode, :shareiscsi].each do |field|
+    # The zfs commands use the property value '-' to indicate that the
+    # property is not set. We make use of this value to indicate that the
+    # property is not set since it is not avaliable. Conversely, if these
+    # properties are attempted to be unset, and resulted in an error, our
+    # best bet is to catch the exception and continue.
+    define_method(field) do
+      begin
+        zfs(:get, "-H", "-o", "value", field, @resource[:name]).strip
+      rescue
+        PARAMETER_UNSET_OR_NOT_AVAILABLE
+      end
+    end
+    define_method(field.to_s + "=") do |should|
+      begin
+        zfs(:set, "#{field}=#{should}", @resource[:name])
+      rescue
+      end
+    end
+  end
+
+  [:aclinherit, :atime, :canmount, :checksum,
+   :compression, :copies, :dedup, :devices, :exec, :logbias,
+   :mountpoint, :nbmand,  :primarycache, :quota, :readonly,
+   :recordsize, :refquota, :refreservation, :reservation,
+   :secondarycache, :setuid, :sharenfs, :sharesmb,
+   :snapdir, :version, :volsize, :vscan, :xattr, :zoned].each do |field|
+    define_method(field) do
+      zfs(:get, "-H", "-o", "value", field, @resource[:name]).strip
+    end
+
+    define_method(field.to_s + "=") do |should|
+      zfs(:set, "#{field}=#{should}", @resource[:name])
+    end
+  end
+
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/zone/solaris.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/zone/solaris.rb
new file mode 100644
index 0000000..cbf07ee
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/zone/solaris.rb
@@ -0,0 +1,361 @@
+Puppet::Type.type(:zone).provide(:solaris) do
+  desc "Provider for Solaris Zones."
+
+  commands :adm => "/usr/sbin/zoneadm", :cfg => "/usr/sbin/zonecfg"
+  defaultfor :osfamily => :solaris
+
+  mk_resource_methods
+
+  # Convert the output of a list into a hash
+  def self.line2hash(line)
+    fields = [:id, :name, :ensure, :path, :uuid, :brand, :iptype]
+    properties = Hash[fields.zip(line.split(':'))]
+
+    del_id = [:brand, :uuid]
+    # Configured but not installed zones do not have IDs
+    del_id << :id if properties[:id] == "-"
+    del_id.each { |p| properties.delete(p) }
+
+    properties[:ensure] = properties[:ensure].intern
+    properties[:iptype] = 'exclusive' if properties[:iptype] == 'excl'
+
+    properties
+  end
+
+  def self.instances
+    adm(:list, "-cp").split("\n").collect do |line|
+      new(line2hash(line))
+    end
+  end
+
+  def multi_conf(name, should, &action)
+    has = properties[name]
+    has = [] if !has || has == :absent
+    rms = has - should
+    adds = should - has
+    (rms.map{|o| action.call(:rm,o)} + adds.map{|o| action.call(:add,o)}).join("\n")
+  end
+
+  def self.def_prop(var, str)
+    define_method('%s_conf' % var.to_s) do |v|
+      str % v
+    end
+    define_method('%s=' % var.to_s) do |v|
+      setconfig self.send( ('%s_conf'% var).intern, v)
+    end
+  end
+
+  def self.def_multiprop(var, &conf)
+    define_method(var.to_s) do |v|
+      o = properties[var]
+      return '' if o.nil? or o == :absent
+      o.join(' ')
+    end
+    define_method('%s=' % var.to_s) do |v|
+      setconfig self.send( ('%s_conf'% var).intern, v)
+    end
+    define_method('%s_conf' % var.to_s) do |v|
+      multi_conf(var, v, &conf)
+    end
+  end
+
+  def_prop :iptype, "set ip-type=%s"
+  def_prop :autoboot, "set autoboot=%s"
+  def_prop :path, "set zonepath=%s"
+  def_prop :pool, "set pool=%s"
+  def_prop :shares, "add rctl\nset name=zone.cpu-shares\nadd value (priv=privileged,limit=%s,action=none)\nend"
+
+  def_multiprop :ip do |action, str|
+    interface, ip, defrouter = str.split(':')
+    case action
+    when :add
+      cmd = ["add net"]
+      cmd << "set physical=#{interface}" if interface
+      cmd << "set address=#{ip}" if ip
+      cmd << "set defrouter=#{defrouter}" if defrouter
+      cmd << "end"
+      cmd.join("\n")
+    when :rm
+      if ip
+        "remove net address=#{ip}"
+      elsif interface
+        "remove net physical=#{interface}"
+      else
+        raise ArgumentError, "can not remove network based on default router"
+      end
+    else self.fail action
+    end
+  end
+
+  def_multiprop :dataset do |action, str|
+    case action
+    when :add; ['add dataset',"set name=#{str}",'end'].join("\n")
+    when :rm; "remove dataset name=#{str}"
+    else self.fail action
+    end
+  end
+
+  def_multiprop :inherit do |action, str|
+    case action
+    when :add; ['add inherit-pkg-dir', "set dir=#{str}",'end'].join("\n")
+    when :rm; "remove inherit-pkg-dir dir=#{str}"
+    else self.fail action
+    end
+  end
+
+  def my_properties
+    [:path, :iptype, :autoboot, :pool, :shares, :ip, :dataset, :inherit]
+  end
+
+  # Perform all of our configuration steps.
+  def configure
+    self.fail "Path is required" unless @resource[:path]
+    arr = ["create -b #{@resource[:create_args]}"]
+
+    # Then perform all of our configuration steps.  It's annoying
+    # that we need this much internal info on the resource.
+    self.resource.properties.each do |property|
+      next unless my_properties.include? property.name
+      method = (property.name.to_s + '_conf').intern
+      arr << self.send(method ,@resource[property.name]) unless property.safe_insync?(properties[property.name])
+    end
+    setconfig(arr.join("\n"))
+  end
+
+  def destroy
+    zonecfg :delete, "-F"
+  end
+
+  def add_cmd(cmd)
+    @cmds = [] if @cmds.nil?
+    @cmds << cmd
+  end
+
+  def exists?
+    properties[:ensure] != :absent
+  end
+
+  # We cannot use the execpipe in util because the pipe is not opened in
+  # read/write mode.
+  def exec_cmd(var)
+    # In bash, the exit value of the last command is the exit value of the
+    # entire pipeline
+    out = execute("echo \"#{var[:input]}\" | #{var[:cmd]}", :failonfail => false, :combine => true)
+    st = $?.exitstatus
+    {:out => out, :exit => st}
+  end
+
+  # Clear out the cached values.
+  def flush
+    return if @cmds.nil? || @cmds.empty?
+    str = (@cmds << "commit" << "exit").join("\n")
+    @cmds = []
+    @property_hash.clear
+
+    command = "#{command(:cfg)} -z #{@resource[:name]} -f -"
+    r = exec_cmd(:cmd => command, :input => str)
+    if r[:exit] != 0 or r[:out] =~ /not allowed/
+      raise ArgumentError, "Failed to apply configuration"
+    end
+  end
+
+  def install(dummy_argument=:work_arround_for_ruby_GC_bug)
+    if @resource[:clone] # TODO: add support for "-s snapshot"
+      zoneadm :clone, @resource[:clone]
+    elsif @resource[:install_args]
+      zoneadm :install, @resource[:install_args].split(" ")
+    else
+      zoneadm :install
+    end
+  end
+
+  # Look up the current status.
+  def properties
+    if @property_hash.empty?
+      @property_hash = status || {}
+      if @property_hash.empty?
+        @property_hash[:ensure] = :absent
+      else
+        @resource.class.validproperties.each do |name|
+          @property_hash[name] ||= :absent
+        end
+      end
+    end
+    @property_hash.dup
+  end
+
+  # We need a way to test whether a zone is in process.  Our 'ensure'
+  # property models the static states, but we need to handle the temporary ones.
+  def processing?
+    hash = status
+    return false unless hash
+    ["incomplete", "ready", "shutting_down"].include? hash[:ensure]
+  end
+
+  # Collect the configuration of the zone. The output looks like:
+  # zonename: z1
+  # zonepath: /export/z1
+  # brand: native
+  # autoboot: true
+  # bootargs:
+  # pool:
+  # limitpriv:
+  # scheduling-class:
+  # ip-type: shared
+  # hostid:
+  # net:
+  #         address: 192.168.1.1
+  #         physical: eg0001
+  #         defrouter not specified
+  # net:
+  #         address: 192.168.1.3
+  #         physical: eg0002
+  #         defrouter not specified
+  #
+  def getconfig
+    output = zonecfg :info
+
+    name = nil
+    current = nil
+    hash = {}
+    output.split("\n").each do |line|
+      case line
+      when /^(\S+):\s*$/
+        name = $1
+        current = nil # reset it
+      when /^(\S+):\s*(\S+)$/
+        hash[$1.intern] = $2
+      when /^\s+(\S+):\s*(.+)$/
+        if name
+          hash[name] ||= []
+          unless current
+            current = {}
+            hash[name] << current
+          end
+          current[$1.intern] = $2
+        else
+          err "Ignoring '#{line}'"
+        end
+      else
+        debug "Ignoring zone output '#{line}'"
+      end
+    end
+
+    hash
+  end
+
+  # Execute a configuration string.  Can't be private because it's called
+  # by the properties.
+  def setconfig(str)
+    add_cmd str
+  end
+
+  def start
+    # Check the sysidcfg stuff
+    if cfg = @resource[:sysidcfg]
+      self.fail "Path is required" unless @resource[:path]
+      zoneetc = File.join(@resource[:path], "root", "etc")
+      sysidcfg = File.join(zoneetc, "sysidcfg")
+
+      # if the zone root isn't present "ready" the zone
+      # which makes zoneadmd mount the zone root
+      zoneadm :ready unless File.directory?(zoneetc)
+
+      unless Puppet::FileSystem.exist?(sysidcfg)
+        begin
+          File.open(sysidcfg, "w", 0600) do |f|
+            f.puts cfg
+          end
+        rescue => detail
+          puts detail.stacktrace if Puppet[:debug]
+          raise Puppet::Error, "Could not create sysidcfg: #{detail}", detail.backtrace
+        end
+      end
+    end
+
+    zoneadm :boot
+  end
+
+  # Return a hash of the current status of this zone.
+  def status
+    begin
+      output = adm "-z", @resource[:name], :list, "-p"
+    rescue Puppet::ExecutionFailure
+      return nil
+    end
+
+    main = self.class.line2hash(output.chomp)
+
+    # Now add in the configuration information
+    config_status.each do |name, value|
+      main[name] = value
+    end
+
+    main
+  end
+
+  def ready
+    zoneadm :ready
+  end
+
+  def stop
+    zoneadm :halt
+  end
+
+  def unconfigure
+    zonecfg :delete, "-F"
+  end
+
+  def uninstall
+    zoneadm :uninstall, "-F"
+  end
+
+  private
+
+  # Turn the results of getconfig into status information.
+  def config_status
+    config = getconfig
+    result = {}
+
+    result[:autoboot] = config[:autoboot] ? config[:autoboot].intern : :true
+    result[:pool] = config[:pool]
+    result[:shares] = config[:shares]
+    if dir = config["inherit-pkg-dir"]
+      result[:inherit] = dir.collect { |dirs| dirs[:dir] }
+    end
+    if datasets = config["dataset"]
+      result[:dataset] = datasets.collect { |dataset| dataset[:name] }
+    end
+    result[:iptype] = config[:'ip-type'] if config[:'ip-type']
+    if net = config["net"]
+      result[:ip] = net.collect do |params|
+        if params[:defrouter]
+          "#{params[:physical]}:#{params[:address]}:#{params[:defrouter]}"
+        elsif params[:address]
+          "#{params[:physical]}:#{params[:address]}"
+        else
+          params[:physical]
+        end
+      end
+    end
+
+    result
+  end
+
+  def zoneadm(*cmd)
+    adm("-z", @resource[:name], *cmd)
+  rescue Puppet::ExecutionFailure => detail
+    self.fail Puppet::Error, "Could not #{cmd[0]} zone: #{detail}", detail
+  end
+
+  def zonecfg(*cmd)
+    # You apparently can't get the configuration of the global zone (strictly in solaris11)
+    return "" if self.name == "global"
+    begin
+      cfg("-z", self.name, *cmd)
+    rescue Puppet::ExecutionFailure => detail
+      self.fail Puppet::Error, "Could not #{cmd[0]} zone: #{detail}", detail
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/zpool/zpool.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/zpool/zpool.rb
new file mode 100644
index 0000000..d6f7b3f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/provider/zpool/zpool.rb
@@ -0,0 +1,125 @@
+Puppet::Type.type(:zpool).provide(:zpool) do
+  desc "Provider for zpool."
+
+  commands :zpool => 'zpool'
+
+  #NAME    SIZE  ALLOC   FREE    CAP  HEALTH  ALTROOT
+  def self.instances
+    zpool(:list, '-H').split("\n").collect do |line|
+      name, size, alloc, free, cap, health, altroot = line.split(/\s+/)
+      new({:name => name, :ensure => :present})
+    end
+  end
+
+  def process_zpool_data(pool_array)
+    if pool_array == []
+      return Hash.new(:absent)
+    end
+    #get the name and get rid of it
+    pool = Hash.new
+    pool[:pool] = pool_array[0]
+    pool_array.shift
+
+    tmp = []
+
+    #order matters here :(
+    pool_array.reverse.each do |value|
+      sym = nil
+      case value
+      when "spares";
+        sym = :spare
+      when "logs";
+        sym = :log
+      when /^mirror|^raidz1|^raidz2/;
+        sym = value =~ /^mirror/ ? :mirror : :raidz
+        pool[:raid_parity] = "raidz2" if value =~ /^raidz2/
+      else
+        tmp << value
+        sym = :disk if value == pool_array.first
+      end
+
+      if sym
+        pool[sym] = pool[sym] ? pool[sym].unshift(tmp.reverse.join(' ')) : [tmp.reverse.join(' ')]
+        tmp.clear
+      end
+    end
+
+    pool
+  end
+
+  def get_pool_data
+    # http://docs.oracle.com/cd/E19082-01/817-2271/gbcve/index.html
+    # we could also use zpool iostat -v mypool for a (little bit) cleaner output
+    out = execute("zpool status #{@resource[:pool]}", :failonfail => false, :combine => false)
+    zpool_data = out.lines.select { |line| line.index("\t") == 0 }.collect { |l| l.strip.split("\s")[0] }
+    zpool_data.shift
+    zpool_data
+  end
+
+  def current_pool
+    @current_pool = process_zpool_data(get_pool_data) unless (defined?(@current_pool) and @current_pool)
+    @current_pool
+  end
+
+  def flush
+    @current_pool= nil
+  end
+
+  #Adds log and spare
+  def build_named(name)
+    if prop = @resource[name.intern]
+      [name] + prop.collect { |p| p.split(' ') }.flatten
+    else
+      []
+    end
+  end
+
+  #query for parity and set the right string
+  def raidzarity
+    @resource[:raid_parity] ? @resource[:raid_parity] : "raidz1"
+  end
+
+  #handle mirror or raid
+  def handle_multi_arrays(prefix, array)
+    array.collect{ |a| [prefix] +  a.split(' ') }.flatten
+  end
+
+  #builds up the vdevs for create command
+  def build_vdevs
+    if disk = @resource[:disk]
+      disk.collect { |d| d.split(' ') }.flatten
+    elsif mirror = @resource[:mirror]
+      handle_multi_arrays("mirror", mirror)
+    elsif raidz = @resource[:raidz]
+      handle_multi_arrays(raidzarity, raidz)
+    end
+  end
+
+  def create
+    zpool(*([:create, @resource[:pool]] + build_vdevs + build_named("spare") + build_named("log")))
+  end
+
+  def destroy
+    zpool :destroy, @resource[:pool]
+  end
+
+  def exists?
+    if current_pool[:pool] == :absent
+      false
+    else
+      true
+    end
+  end
+
+  [:disk, :mirror, :raidz, :log, :spare].each do |field|
+    define_method(field) do
+      current_pool[field]
+    end
+
+    define_method(field.to_s + "=") do |should|
+      self.fail "zpool #{field} can't be changed. should be #{should}, currently is #{current_pool[field]}"
+    end
+  end
+
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails.rb
new file mode 100644
index 0000000..adb20fb
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails.rb
@@ -0,0 +1,142 @@
+# Load the appropriate libraries, or set a class indicating they aren't available
+
+require 'facter'
+require 'puppet'
+require 'logger'
+
+module Puppet::Rails
+  TIME_DEBUG = true
+
+  def self.connect
+    # Silence activerecord deprecation warnings
+    ActiveSupport::Deprecation.silenced = true
+
+    # This global init does not work for testing, because we remove
+    # the state dir on every test.
+    return if ActiveRecord::Base.connected?
+
+    Puppet.settings.use(:main, :rails, :master)
+
+    ActiveRecord::Base.logger = Logger.new(Puppet[:railslog])
+    begin
+      loglevel = Logger.const_get(Puppet[:rails_loglevel].upcase)
+      ActiveRecord::Base.logger.level = loglevel
+    rescue => detail
+      Puppet.warning "'#{Puppet[:rails_loglevel]}' is not a valid Rails log level; using debug"
+      ActiveRecord::Base.logger.level = Logger::DEBUG
+    end
+
+    # As of ActiveRecord 2.2 allow_concurrency has been deprecated and no longer has any effect.
+    ActiveRecord::Base.allow_concurrency = true if Puppet::Util.activerecord_version < 2.2
+
+    ActiveRecord::Base.clear_active_connections!
+
+    begin
+      args = database_arguments
+      Puppet.info "Connecting to #{args[:adapter]} database: #{args[:database]}"
+      ActiveRecord::Base.establish_connection(args)
+    rescue => detail
+      message = "Could not connect to database: #{detail}"
+      Puppet.log_exception(detail, message)
+      raise Puppet::Error, message, detail.backtrace
+    end
+  end
+
+  # The arguments for initializing the database connection.
+  def self.database_arguments
+    adapter = Puppet[:dbadapter]
+
+    args = {:adapter => adapter, :log_level => Puppet[:rails_loglevel]}
+
+    case adapter
+    when "sqlite3"
+      args[:database] = Puppet[:dblocation]
+    when "mysql", "mysql2", "postgresql"
+      args[:host]     = Puppet[:dbserver] unless Puppet[:dbserver].to_s.empty?
+      args[:port]     = Puppet[:dbport] unless Puppet[:dbport].to_s.empty?
+      args[:username] = Puppet[:dbuser] unless Puppet[:dbuser].to_s.empty?
+      args[:password] = Puppet[:dbpassword] unless Puppet[:dbpassword].to_s.empty?
+      args[:pool]     = Puppet[:dbconnections].to_i unless Puppet[:dbconnections].to_i <= 0
+      args[:database] = Puppet[:dbname]
+      args[:reconnect]= true
+
+      socket          = Puppet[:dbsocket]
+      args[:socket]   = socket unless socket.to_s.empty?
+    when "oracle_enhanced"
+      args[:database] = Puppet[:dbname] unless Puppet[:dbname].to_s.empty?
+      args[:username] = Puppet[:dbuser] unless Puppet[:dbuser].to_s.empty?
+      args[:password] = Puppet[:dbpassword] unless Puppet[:dbpassword].to_s.empty?
+      args[:pool]     = Puppet[:dbconnections].to_i unless Puppet[:dbconnections].to_i <= 0
+    else
+      raise ArgumentError, "Invalid db adapter #{adapter}"
+    end
+    args
+  end
+
+  # Set up our database connection.  It'd be nice to have a "use" system
+  # that could make callbacks.
+  def self.init
+    raise Puppet::DevError, "No activerecord, cannot init Puppet::Rails" unless Puppet.features.rails?
+
+    connect
+
+    unless ActiveRecord::Base.connection.tables.include?("resources")
+      require 'puppet/rails/database/schema'
+      Puppet::Rails::Schema.init
+    end
+
+    migrate if Puppet[:dbmigrate]
+  end
+
+  # Migrate to the latest db schema.
+  def self.migrate
+    dbdir = nil
+    $LOAD_PATH.each { |d|
+      tmp = File.join(d, "puppet/rails/database")
+      if FileTest.directory?(tmp)
+        dbdir = tmp
+        break
+      end
+    }
+
+    raise Puppet::Error, "Could not find Puppet::Rails database dir" unless dbdir
+
+    raise Puppet::Error, "Database has problems, can't migrate." unless ActiveRecord::Base.connection.tables.include?("resources")
+
+    Puppet.notice "Migrating"
+
+    begin
+      ActiveRecord::Migrator.migrate(dbdir)
+    rescue => detail
+      message = "Could not migrate database: #{detail}"
+      Puppet.log_exception(detail, message)
+      raise Puppet::Error, "Could not migrate database: #{detail}", detail.backtrace
+    end
+  end
+
+  # Tear down the database.  Mostly only used during testing.
+  def self.teardown
+    raise Puppet::DevError, "No activerecord, cannot init Puppet::Rails" unless Puppet.features.rails?
+
+    begin
+      Puppet.settings.use(:master, :rails)
+
+      begin
+        ActiveRecord::Base.establish_connection(database_arguments)
+      rescue => detail
+        Puppet.log_exception(detail)
+        raise Puppet::Error, "Could not connect to database: #{detail}", detail.backtrace
+      end
+
+      ActiveRecord::Base.connection.tables.each do |t|
+        ActiveRecord::Base.connection.drop_table t
+      end
+    ensure
+      # allow temp files to get cleaned up
+      ActiveRecord::Base.logger.close if ActiveRecord::Base.logger
+    end
+  end
+end
+
+require 'puppet/rails/host' if Puppet.features.rails?
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/benchmark.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/benchmark.rb
new file mode 100644
index 0000000..cf1afd8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/benchmark.rb
@@ -0,0 +1,63 @@
+require 'benchmark'
+require 'yaml'
+
+module Puppet::Rails::Benchmark
+  $benchmarks = {:accumulated => {}}
+
+  def time_debug?
+    Puppet::Rails::TIME_DEBUG
+  end
+
+  def railsmark(message)
+    result = nil
+    seconds = Benchmark.realtime { result = yield }
+    Puppet.debug(message + " in %0.2f seconds" % seconds)
+
+    $benchmarks[message] = seconds if time_debug?
+    result
+  end
+
+  def debug_benchmark(message)
+    return yield unless Puppet::Rails::TIME_DEBUG
+
+    railsmark(message) { yield }
+  end
+
+  # Collect partial benchmarks to be logged when they're
+  # all done.
+  #   These are always low-level debugging so we only
+  # print them if time_debug is enabled.
+  def accumulate_benchmark(message, label)
+    return yield unless time_debug?
+
+    $benchmarks[:accumulated][message] ||= Hash.new(0)
+    $benchmarks[:accumulated][message][label] += Benchmark.realtime { yield }
+  end
+
+  # Log the accumulated marks.
+  def log_accumulated_marks(message)
+    return unless time_debug?
+
+    return if $benchmarks[:accumulated].empty? or $benchmarks[:accumulated][message].nil? or $benchmarks[:accumulated][message].empty?
+
+    $benchmarks[:accumulated][message].each do |label, value|
+      Puppet.debug(message + ("(#{label})") + (" in %0.2f seconds" % value))
+    end
+  end
+
+  def write_benchmarks
+    return unless time_debug?
+
+    branch = %x{git branch}.split("\n").find { |l| l =~ /^\*/ }.sub("* ", '')
+
+    file = "/tmp/time_debugging.yaml"
+
+    if Puppet::FileSystem.exist?(file)
+      data = YAML.load_file(file)
+    else
+      data = {}
+    end
+    data[branch] = $benchmarks
+    Puppet::Util.replace_file(file, 0644) { |f| f.print YAML.dump(data) }
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/database/001_add_created_at_to_all_tables.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/database/001_add_created_at_to_all_tables.rb
new file mode 100644
index 0000000..22dffb8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/database/001_add_created_at_to_all_tables.rb
@@ -0,0 +1,13 @@
+class AddCreatedAtToAllTables < ActiveRecord::Migration
+  def self.up
+    ActiveRecord::Base.connection.tables.each do |t|
+      add_column t.to_s, :created_at, :datetime unless ActiveRecord::Base.connection.columns(t).collect {|c| c.name}.include?("created_at")
+    end
+  end
+
+  def self.down
+    ActiveRecord::Base.connection.tables.each do |t|
+      remove_column t.to_s, :created_at unless ActiveRecord::Base.connection.columns(t).collect {|c| c.name}.include?("created_at")
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/database/002_remove_duplicated_index_on_all_tables.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/database/002_remove_duplicated_index_on_all_tables.rb
new file mode 100644
index 0000000..021889d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/database/002_remove_duplicated_index_on_all_tables.rb
@@ -0,0 +1,13 @@
+class RemoveDuplicatedIndexOnAllTables < ActiveRecord::Migration
+  def self.up
+    ActiveRecord::Base.connection.tables.each do |t|
+      remove_index t.to_s, :id if ActiveRecord::Base.connection.indexes(t).collect {|c| c.columns}.include?("id")
+    end
+  end
+
+  def self.down
+    ActiveRecord::Base.connection.tables.each do |t|
+      add_index t.to_s, :id, :integer => true unless ActiveRecord::Base.connection.indexes(t).collect {|c| c.columns}.include?("id")
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/database/003_add_environment_to_host.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/database/003_add_environment_to_host.rb
new file mode 100644
index 0000000..5c06bb8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/database/003_add_environment_to_host.rb
@@ -0,0 +1,9 @@
+class AddEnvironmentToHost < ActiveRecord::Migration
+  def self.up
+    add_column :hosts, :environment, :string unless ActiveRecord::Base.connection.columns(:hosts).collect {|c| c.name}.include?("environment")
+  end
+
+  def self.down
+    remove_column :hosts, :environment if ActiveRecord::Base.connection.columns(:hosts).collect {|c| c.name}.include?("environment")
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/database/004_add_inventory_service_tables.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/database/004_add_inventory_service_tables.rb
new file mode 100644
index 0000000..6e6b28c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/database/004_add_inventory_service_tables.rb
@@ -0,0 +1,36 @@
+class AddInventoryServiceTables < ActiveRecord::Migration
+  def self.up
+    unless ActiveRecord::Base.connection.tables.include?("inventory_nodes")
+      create_table :inventory_nodes do |t|
+        t.column :name, :string, :null => false
+        t.column :timestamp, :datetime, :null => false
+        t.column :updated_at, :datetime
+        t.column :created_at, :datetime
+      end
+
+      add_index :inventory_nodes, :name, :unique => true
+    end
+
+    unless ActiveRecord::Base.connection.tables.include?("inventory_facts")
+      create_table :inventory_facts, :id => false do |t|
+        t.column :node_id, :integer, :null => false
+        t.column :name, :string, :null => false
+        t.column :value, :text, :null => false
+      end
+
+      add_index :inventory_facts, [:node_id, :name], :unique => true
+    end
+  end
+
+  def self.down
+    unless ActiveRecord::Base.connection.tables.include?("inventory_nodes")
+      remove_index :inventory_nodes, :name
+      drop_table :inventory_nodes
+    end
+
+    if ActiveRecord::Base.connection.tables.include?("inventory_facts")
+      remove_index :inventory_facts, [:node_id, :name]
+      drop_table :inventory_facts
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/database/schema.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/database/schema.rb
new file mode 100644
index 0000000..1216719
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/database/schema.rb
@@ -0,0 +1,136 @@
+require 'stringio'
+
+class Puppet::Rails::Schema
+  def self.init
+    oldout = nil
+    text = ''
+    Puppet::Util.benchmark(Puppet, :notice, "Initialized database") do
+      # We want to rewrite stdout, so we don't get migration messages.
+      oldout = $stdout
+      $stdout = StringIO.new(text, 'w')
+      ActiveRecord::Schema.define do
+        create_table :resources do |t|
+          t.column :title, :text, :null => false
+          t.column :restype,  :string, :null => false
+          t.column :host_id, :integer
+          t.column :source_file_id, :integer
+          t.column :exported, :boolean
+          t.column :line, :integer
+          t.column :updated_at, :datetime
+          t.column :created_at, :datetime
+        end
+        add_index :resources, :host_id
+        add_index :resources, :source_file_id
+
+        # Thanks, mysql!  MySQL requires a length on indexes in text fields.
+        # So, we provide them for mysql and handle everything else specially.
+        # Oracle doesn't index on CLOB fields, so we skip it
+        if ['mysql','mysql2'].include? Puppet[:dbadapter]
+          execute "CREATE INDEX typentitle ON resources (restype,title(50));"
+        elsif Puppet[:dbadapter] != "oracle_enhanced"
+          add_index :resources, [:title, :restype]
+        end
+
+        create_table :source_files do |t|
+          t.column :filename, :string
+          t.column :path, :string
+          t.column :updated_at, :datetime
+          t.column :created_at, :datetime
+        end
+        add_index :source_files, :filename
+
+        create_table :resource_tags do |t|
+          t.column :resource_id, :integer
+          t.column :puppet_tag_id, :integer
+          t.column :updated_at, :datetime
+          t.column :created_at, :datetime
+        end
+        add_index :resource_tags, :resource_id
+        add_index :resource_tags, :puppet_tag_id
+
+        create_table :puppet_tags do |t|
+          t.column :name, :string
+          t.column :updated_at, :datetime
+          t.column :created_at, :datetime
+        end
+
+        # Oracle automatically creates a primary key index
+        add_index :puppet_tags, :id if Puppet[:dbadapter] != "oracle_enhanced"
+
+        create_table :hosts do |t|
+          t.column :name, :string, :null => false
+          t.column :ip, :string
+          t.column :environment, :text
+          t.column :last_compile, :datetime
+          t.column :last_freshcheck, :datetime
+          t.column :last_report, :datetime
+          #Use updated_at to automatically add timestamp on save.
+          t.column :updated_at, :datetime
+          t.column :source_file_id, :integer
+          t.column :created_at, :datetime
+        end
+        add_index :hosts, :source_file_id
+        add_index :hosts, :name
+
+        create_table :fact_names do |t|
+          t.column :name, :string, :null => false
+          t.column :updated_at, :datetime
+          t.column :created_at, :datetime
+        end
+        add_index :fact_names, :name
+
+        create_table :fact_values do |t|
+          t.column :value, :text, :null => false
+          t.column :fact_name_id, :integer, :null => false
+          t.column :host_id, :integer, :null => false
+          t.column :updated_at, :datetime
+          t.column :created_at, :datetime
+        end
+        add_index :fact_values, :fact_name_id
+        add_index :fact_values, :host_id
+
+        create_table :param_values do |t|
+          t.column :value,  :text, :null => false
+          t.column :param_name_id, :integer, :null => false
+          t.column :line, :integer
+          t.column :resource_id, :integer
+          t.column :updated_at, :datetime
+          t.column :created_at, :datetime
+        end
+        add_index :param_values, :param_name_id
+        add_index :param_values, :resource_id
+
+        create_table :param_names do |t|
+          t.column :name, :string, :null => false
+          t.column :updated_at, :datetime
+          t.column :created_at, :datetime
+        end
+        add_index :param_names, :name
+
+        create_table :inventory_nodes do |t|
+          t.column :name, :string, :null => false
+          t.column :timestamp, :datetime, :null => false
+          t.column :updated_at, :datetime
+          t.column :created_at, :datetime
+        end
+
+        add_index :inventory_nodes, :name, :unique => true
+
+        create_table :inventory_facts do |t|
+          t.column :node_id, :integer, :null => false
+          t.column :name, :string, :null => false
+          t.column :value, :text, :null => false
+        end
+
+        add_index :inventory_facts, [:node_id, :name], :unique => true
+      end
+    end
+  rescue Exception => e
+    $stderr.puts e
+    $stderr.puts "The output from running the code was:", text
+    raise e
+  ensure
+    $stdout = oldout if oldout
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/fact_name.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/fact_name.rb
new file mode 100644
index 0000000..5fe5264
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/fact_name.rb
@@ -0,0 +1,10 @@
+require 'active_record'
+if Gem::Version.new(ActiveRecord::VERSION::STRING) >= Gem::Version.new('4.1')
+  require 'active_record/deprecated_finders'
+end
+require 'puppet/rails'
+require 'puppet/rails/fact_value'
+
+class Puppet::Rails::FactName < ActiveRecord::Base
+  has_many :fact_values, :dependent => :destroy
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/fact_value.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/fact_value.rb
new file mode 100644
index 0000000..d1657b9
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/fact_value.rb
@@ -0,0 +1,13 @@
+require 'active_record'
+if Gem::Version.new(ActiveRecord::VERSION::STRING) >= Gem::Version.new('4.1')
+  require 'active_record/deprecated_finders'
+end
+
+class Puppet::Rails::FactValue < ActiveRecord::Base
+  belongs_to :fact_name
+  belongs_to :host
+
+  def to_label
+    "#{self.fact_name.name}"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/host.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/host.rb
new file mode 100644
index 0000000..e536021
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/host.rb
@@ -0,0 +1,258 @@
+require 'puppet/node/environment'
+require 'puppet/rails'
+require 'puppet/rails/resource'
+require 'puppet/rails/fact_name'
+require 'puppet/rails/source_file'
+require 'puppet/rails/benchmark'
+require 'puppet/util/rails/collection_merger'
+
+class Puppet::Rails::Host < ActiveRecord::Base
+  include Puppet::Rails::Benchmark
+  extend Puppet::Rails::Benchmark
+  include Puppet::Util
+  include Puppet::Util::CollectionMerger
+
+  has_many :fact_values, :dependent => :destroy, :class_name => "Puppet::Rails::FactValue"
+  has_many :fact_names, :through => :fact_values, :class_name => "Puppet::Rails::FactName"
+  belongs_to :source_file
+  has_many :resources, :dependent => :destroy, :class_name => "Puppet::Rails::Resource"
+
+  def self.from_puppet(node)
+    host = find_by_name(node.name) || new(:name => node.name)
+
+    {"ipaddress" => "ip", "environment" => "environment"}.each do |myparam, itsparam|
+      if value = node.send(myparam)
+        host.send(itsparam + "=", value)
+      end
+    end
+
+    host
+  end
+
+  # Override the setter for environment to force it to be a string, lest it
+  # be YAML encoded.  See #4487.
+  def environment=(value)
+    super value.to_s
+  end
+
+  # returns a hash of fact_names.name => [ fact_values ] for this host.
+  # Note that 'fact_values' is actually a list of the value instances, not
+  # just actual values.
+  def get_facts_hash
+    fact_values = self.fact_values.find(:all, :include => :fact_name)
+    return fact_values.inject({}) do | hash, value |
+      hash[value.fact_name.name] ||= []
+      hash[value.fact_name.name] << value
+      hash
+    end
+  end
+
+
+  # This is *very* similar to the merge_parameters method
+  # of Puppet::Rails::Resource.
+  def merge_facts(facts)
+    db_facts = {}
+
+    deletions = []
+    self.fact_values.find(:all, :include => :fact_name).each do |value|
+      deletions << value['id'] and next unless facts.include?(value['name'])
+      # Now store them for later testing.
+      db_facts[value['name']] ||= []
+      db_facts[value['name']] << value
+    end
+
+    # Now get rid of any parameters whose value list is different.
+    # This might be extra work in cases where an array has added or lost
+    # a single value, but in the most common case (a single value has changed)
+    # this makes sense.
+    db_facts.each do |name, value_hashes|
+      values = value_hashes.collect { |v| v['value'] }
+
+      unless values == facts[name]
+        value_hashes.each { |v| deletions << v['id'] }
+      end
+    end
+
+    # Perform our deletions.
+    Puppet::Rails::FactValue.delete(deletions) unless deletions.empty?
+
+    # Lastly, add any new parameters.
+    facts.each do |name, value|
+      next if db_facts.include?(name)
+      values = value.is_a?(Array) ? value : [value]
+
+      values.each do |v|
+        fact_values.build(:value => v, :fact_name => Puppet::Rails::FactName.find_or_create_by_name(name))
+      end
+    end
+  end
+
+  # Set our resources.
+  def merge_resources(list)
+    # keep only exported resources in thin_storeconfig mode
+    list = list.select { |r| r.exported? } if Puppet.settings[:thin_storeconfigs]
+
+    resources_by_id = nil
+    debug_benchmark("Searched for resources") {
+      resources_by_id = find_resources
+    }
+
+    debug_benchmark("Searched for resource params and tags") {
+      find_resources_parameters_tags(resources_by_id)
+    } if id
+
+    debug_benchmark("Performed resource comparison") {
+      compare_to_catalog(resources_by_id, list)
+    }
+  end
+
+  def find_resources
+    condition = { :exported => true } if Puppet.settings[:thin_storeconfigs]
+
+    resources.find(:all, :include => :source_file, :conditions => condition || {}).inject({}) do | hash, resource |
+      hash[resource.id] = resource
+      hash
+    end
+  end
+
+  def find_resources_parameters_tags(resources)
+    find_resources_parameters(resources)
+    find_resources_tags(resources)
+  end
+
+  def compare_to_catalog(existing, list)
+    compiled = list.inject({}) do |hash, resource|
+      hash[resource.ref] = resource
+      hash
+    end
+
+    resources = nil
+    debug_benchmark("Resource removal") {
+      resources = remove_unneeded_resources(compiled, existing)
+    }
+
+    # Now for all resources in the catalog but not in the db, we're pretty easy.
+    additions = nil
+    debug_benchmark("Resource merger") {
+      additions = perform_resource_merger(compiled, resources)
+    }
+
+    debug_benchmark("Resource addition") {
+      additions.each do |resource|
+        build_rails_resource_from_parser_resource(resource)
+      end
+
+      log_accumulated_marks "Added resources"
+    }
+  end
+
+  def add_new_resources(additions)
+    additions.each do |resource|
+      Puppet::Rails::Resource.from_parser_resource(self, resource)
+    end
+  end
+
+  # Turn a parser resource into a Rails resource.
+  def build_rails_resource_from_parser_resource(resource)
+    db_resource = nil
+    accumulate_benchmark("Added resources", :initialization) {
+      args = Puppet::Rails::Resource.rails_resource_initial_args(resource)
+
+      db_resource = self.resources.build(args)
+
+      # Our file= method does the name to id conversion.
+      db_resource.file = resource.file
+    }
+
+
+    accumulate_benchmark("Added resources", :parameters) {
+      resource.each do |param, value|
+        Puppet::Rails::ParamValue.from_parser_param(param, value).each do |value_hash|
+          db_resource.param_values.build(value_hash)
+        end
+      end
+    }
+
+    accumulate_benchmark("Added resources", :tags) {
+      resource.tags.each { |tag| db_resource.add_resource_tag(tag) }
+    }
+
+    db_resource.save
+
+    db_resource
+  end
+
+
+  def perform_resource_merger(compiled, resources)
+    return compiled.values if resources.empty?
+
+    # Now for all resources in the catalog but not in the db, we're pretty easy.
+    additions = []
+    compiled.each do |ref, resource|
+      if db_resource = resources[ref]
+        db_resource.merge_parser_resource(resource)
+      else
+        additions << resource
+      end
+    end
+    log_accumulated_marks "Resource merger"
+
+    additions
+  end
+
+  def remove_unneeded_resources(compiled, existing)
+    deletions = []
+    resources = {}
+    existing.each do |id, resource|
+      # it seems that it can happen (see bug #2010) some resources are duplicated in the
+      # database (ie logically corrupted database), in which case we remove the extraneous
+      # entries.
+      if resources.include?(resource.ref)
+        deletions << id
+        next
+      end
+
+      # If the resource is in the db but not in the catalog, mark it
+      # for removal.
+      unless compiled.include?(resource.ref)
+        deletions << id
+        next
+      end
+
+      resources[resource.ref] = resource
+    end
+    # We need to use 'destroy' here, not 'delete', so that all
+    # dependent objects get removed, too.
+    Puppet::Rails::Resource.destroy(deletions) unless deletions.empty?
+
+    resources
+  end
+
+  def find_resources_parameters(resources)
+    params = Puppet::Rails::ParamValue.find_all_params_from_host(self)
+
+    # assign each loaded parameters/tags to the resource it belongs to
+    params.each do |param|
+      resources[param['resource_id']].add_param_to_list(param) if resources.include?(param['resource_id'])
+    end
+  end
+
+  def find_resources_tags(resources)
+    tags = Puppet::Rails::ResourceTag.find_all_tags_from_host(self)
+
+    tags.each do |tag|
+      resources[tag['resource_id']].add_tag_to_list(tag) if resources.include?(tag['resource_id'])
+    end
+  end
+
+  def to_puppet
+    node = Puppet::Node.new(self.name)
+    {"ip" => "ipaddress", "environment" => "environment"}.each do |myparam, itsparam|
+      if value = send(myparam)
+        node.send(itsparam + "=", value)
+      end
+    end
+
+    node
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/inventory_fact.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/inventory_fact.rb
new file mode 100644
index 0000000..aa6334e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/inventory_fact.rb
@@ -0,0 +1,5 @@
+require 'puppet/rails/inventory_node'
+
+class Puppet::Rails::InventoryFact < ::ActiveRecord::Base
+  belongs_to :node, :class_name => "Puppet::Rails::InventoryNode"
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/inventory_node.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/inventory_node.rb
new file mode 100644
index 0000000..52d25f0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/inventory_node.rb
@@ -0,0 +1,43 @@
+require 'puppet/rails/inventory_fact'
+
+class Puppet::Rails::InventoryNode < ::ActiveRecord::Base
+  has_many :facts, :class_name => "Puppet::Rails::InventoryFact", :foreign_key => :node_id, :dependent => :delete_all
+
+  if Puppet::Util.activerecord_version < 3.0
+    # For backward compatibility, use the old named_scope with pre 3.0 activerecord
+    named_scope :has_fact_with_value, lambda { |name,value|
+      {
+        :conditions => ["inventory_facts.name = ? AND inventory_facts.value = ?", name, value.to_s],
+        :joins => :facts
+      }
+    }
+
+    named_scope :has_fact_without_value, lambda { |name,value|
+      {
+        :conditions => ["inventory_facts.name = ? AND inventory_facts.value != ?", name, value.to_s],
+        :joins => :facts
+      }
+    }
+  else
+    # Use scope for activerecord >= 3.0
+    scope :has_fact_with_value, lambda { |name,value|
+      {
+        :conditions => ["inventory_facts.name = ? AND inventory_facts.value = ?", name, value.to_s],
+        :joins => :facts
+      }
+    }
+
+    scope :has_fact_without_value, lambda { |name,value|
+      {
+        :conditions => ["inventory_facts.name = ? AND inventory_facts.value != ?", name, value.to_s],
+        :joins => :facts
+      }
+    }
+  end
+
+  def facts_to_hash
+    facts.inject({}) do |fact_hash,fact|
+      fact_hash.merge(fact.name => fact.value)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/param_name.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/param_name.rb
new file mode 100644
index 0000000..91cf456
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/param_name.rb
@@ -0,0 +1,25 @@
+require 'puppet/util/rails/collection_merger'
+require 'puppet/rails/param_value'
+require 'puppet/util/rails/cache_accumulator'
+
+class Puppet::Rails::ParamName < ActiveRecord::Base
+  include Puppet::Util::CollectionMerger
+  has_many :param_values, :dependent => :destroy
+
+  include Puppet::Util::CacheAccumulator
+  accumulates :name
+
+  def to_resourceparam(resource, source)
+    hash = {}
+    hash[:name] = self.name.to_sym
+    hash[:source] = source
+    hash[:value] = resource.param_values.find(:all, :conditions => [ "param_name_id = ?", self.id]).collect { |v| v.value }
+    if hash[:value].length == 1
+      hash[:value] = hash[:value].shift
+    elsif hash[:value].empty?
+      hash[:value] = nil
+    end
+    Puppet::Parser::Resource::Param.new hash
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/param_value.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/param_value.rb
new file mode 100644
index 0000000..e082ed8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/param_value.rb
@@ -0,0 +1,74 @@
+require 'puppet/util/rails/reference_serializer'
+
+class Puppet::Rails::ParamValue < ActiveRecord::Base
+  include Puppet::Util::ReferenceSerializer
+  extend Puppet::Util::ReferenceSerializer
+
+  belongs_to :param_name
+  belongs_to :resource
+
+  # Store a new parameter in a Rails db.
+  def self.from_parser_param(param, values)
+    values = munge_parser_values(values)
+
+    param_name = Puppet::Rails::ParamName.find_or_create_by_name(param.to_s)
+    return values.collect do |v|
+      {:value => v, :param_name => param_name}
+    end
+  end
+
+  # Make sure an array (or possibly not an array) of values is correctly
+  # set up for Rails.  The main thing is that Resource::Reference objects
+  # should stay objects, so they just get serialized.
+  def self.munge_parser_values(value)
+    values = value.is_a?(Array) ? value : [value]
+    values.map do |v|
+      if v.is_a?(Puppet::Resource)
+        v
+      else
+        v.to_s
+      end
+    end
+  end
+
+
+  def value
+    unserialize_value(self[:value])
+  end
+
+  # I could not find a cleaner way to handle making sure that resource references
+  # were consistently serialized and deserialized.
+  def value=(val)
+    self[:value] = serialize_value(val)
+  end
+
+  def to_label
+    "#{self.param_name.name}"
+  end
+
+  # returns an array of hash containing all the parameters of a given resource
+  def self.find_all_params_from_resource(db_resource)
+    params = ActiveRecord::Base.connection.select_all("SELECT v.id, v.value, v.line, v.resource_id, v.param_name_id, n.name FROM param_values v INNER JOIN param_names n ON v.param_name_id=n.id WHERE v.resource_id=#{db_resource.id}")
+    params.each do |val|
+      val['value'] = unserialize_value(val['value'])
+      val['line'] = val['line'] ? Integer(val['line']) : nil
+      val['resource_id'] = Integer(val['resource_id'])
+    end
+    params
+  end
+
+  # returns an array of hash containing all the parameters of a given host
+  def self.find_all_params_from_host(db_host)
+    params = ActiveRecord::Base.connection.select_all("SELECT v.id, v.value,  v.line, v.resource_id, v.param_name_id, n.name FROM param_values v INNER JOIN resources r ON v.resource_id=r.id INNER JOIN param_names n ON v.param_name_id=n.id WHERE r.host_id=#{db_host.id}")
+    params.each do |val|
+      val['value'] = unserialize_value(val['value'])
+      val['line'] = val['line'] ? Integer(val['line']) : nil
+      val['resource_id'] = Integer(val['resource_id'])
+    end
+    params
+  end
+
+  def to_s
+    "#{self.name} => #{self.value}"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/puppet_tag.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/puppet_tag.rb
new file mode 100644
index 0000000..fadbfa6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/puppet_tag.rb
@@ -0,0 +1,10 @@
+require 'puppet/rails/resource_tag'
+require 'puppet/util/rails/cache_accumulator'
+
+class Puppet::Rails::PuppetTag < ActiveRecord::Base
+  has_many :resource_tags, :dependent => :destroy
+  has_many :resources, :through => :resource_tags
+
+  include Puppet::Util::CacheAccumulator
+  accumulates :name
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/resource.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/resource.rb
new file mode 100644
index 0000000..a2f7326
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/resource.rb
@@ -0,0 +1,235 @@
+require 'puppet'
+require 'puppet/rails/param_name'
+require 'puppet/rails/param_value'
+require 'puppet/rails/puppet_tag'
+require 'puppet/rails/benchmark'
+require 'puppet/util/rails/collection_merger'
+
+class Puppet::Rails::Resource < ActiveRecord::Base
+  include Puppet::Util::CollectionMerger
+  include Puppet::Util::ReferenceSerializer
+  include Puppet::Rails::Benchmark
+
+  has_many :param_values, :dependent => :destroy, :class_name => "Puppet::Rails::ParamValue"
+  has_many :param_names, :through => :param_values, :class_name => "Puppet::Rails::ParamName"
+
+  has_many :resource_tags, :dependent => :destroy, :class_name => "Puppet::Rails::ResourceTag"
+  has_many :puppet_tags, :through => :resource_tags, :class_name => "Puppet::Rails::PuppetTag"
+
+  belongs_to :source_file
+  belongs_to :host
+
+  @tags = {}
+  def self.tags
+    @tags
+  end
+
+  # Determine the basic details on the resource.
+  def self.rails_resource_initial_args(resource)
+    result = [:type, :title, :line].inject({}) do |hash, param|
+      # 'type' isn't a valid column name, so we have to use another name.
+      to = (param == :type) ? :restype : param
+      if value = resource.send(param)
+        hash[to] = value
+      end
+      hash
+    end
+
+    # We always want a value here, regardless of what the resource has,
+    # so we break it out separately.
+    result[:exported] = resource.exported || false
+
+    result
+  end
+
+  def add_resource_tag(tag)
+    pt = Puppet::Rails::PuppetTag.accumulate_by_name(tag)
+    resource_tags.build(:puppet_tag => pt)
+  end
+
+  def file
+    (f = self.source_file) ? f.filename : nil
+  end
+
+  def file=(file)
+    self.source_file = Puppet::Rails::SourceFile.find_or_create_by_filename(file)
+  end
+
+  def title
+    unserialize_value(self[:title])
+  end
+
+  def params_list
+    @params_list ||= []
+  end
+
+  def params_list=(params)
+    @params_list = params
+  end
+
+  def add_param_to_list(param)
+    params_list << param
+  end
+
+  def tags_list
+    @tags_list ||= []
+  end
+
+  def tags_list=(tags)
+    @tags_list = tags
+  end
+
+  def add_tag_to_list(tag)
+    tags_list << tag
+  end
+
+  def [](param)
+    if param == 'id'
+      super
+    else
+      super || parameter(param)
+    end
+  end
+
+  # Make sure this resource is equivalent to the provided Parser resource.
+  def merge_parser_resource(resource)
+    accumulate_benchmark("Individual resource merger", :attributes) { merge_attributes(resource) }
+    accumulate_benchmark("Individual resource merger", :parameters) { merge_parameters(resource) }
+    accumulate_benchmark("Individual resource merger", :tags) { merge_tags(resource) }
+    save
+  end
+
+  def merge_attributes(resource)
+    args = self.class.rails_resource_initial_args(resource)
+    args.each do |param, value|
+      self[param] = value unless resource[param] == value
+    end
+
+    # Handle file specially
+    self.file = resource.file if (resource.file and  (!resource.file or self.file != resource.file))
+  end
+
+  def merge_parameters(resource)
+    catalog_params = {}
+    resource.each do |param, value|
+      catalog_params[param.to_s] = value
+    end
+
+    db_params = {}
+
+    deletions = []
+    params_list.each do |value|
+      # First remove any parameters our catalog resource doesn't have at all.
+      deletions << value['id'] and next unless catalog_params.include?(value['name'])
+
+      # Now store them for later testing.
+      db_params[value['name']] ||= []
+      db_params[value['name']] << value
+    end
+
+    # Now get rid of any parameters whose value list is different.
+    # This might be extra work in cases where an array has added or lost
+    # a single value, but in the most common case (a single value has changed)
+    # this makes sense.
+    db_params.each do |name, value_hashes|
+      values = value_hashes.collect { |v| v['value'] }
+
+      value_hashes.each { |v| deletions << v['id'] } unless value_compare(catalog_params[name], values)
+    end
+
+    # Perform our deletions.
+    Puppet::Rails::ParamValue.delete(deletions) unless deletions.empty?
+
+    # Lastly, add any new parameters.
+    catalog_params.each do |name, value|
+      next if db_params.include?(name) && ! db_params[name].find{ |val| deletions.include?( val["id"] ) }
+      values = value.is_a?(Array) ? value : [value]
+
+      values.each do |v|
+        param_values.build(:value => serialize_value(v), :line => resource.line, :param_name => Puppet::Rails::ParamName.accumulate_by_name(name))
+      end
+    end
+  end
+
+  # Make sure the tag list is correct.
+  def merge_tags(resource)
+    in_db = []
+    deletions = []
+    resource_tags = resource.tags
+    tags_list.each do |tag|
+      deletions << tag['id'] and next unless resource_tags.include?(tag['name'])
+      in_db << tag['name']
+    end
+    Puppet::Rails::ResourceTag.delete(deletions) unless deletions.empty?
+
+    (resource_tags - in_db).each do |tag|
+      add_resource_tag(tag)
+    end
+  end
+
+  def value_compare(v,db_value)
+    v = [v] unless v.is_a?(Array)
+
+    v == db_value
+  end
+
+  def name
+    ref
+  end
+
+  def parameter(param)
+    if pn = param_names.find_by_name(param)
+      return (pv = param_values.find(:first, :conditions => [ 'param_name_id = ?', pn])) ? pv.value : nil
+    end
+  end
+
+  def ref(dummy_argument=:work_arround_for_ruby_GC_bug)
+    "#{self[:restype].split("::").collect { |s| s.capitalize }.join("::")}[#{self.title}]"
+  end
+
+  # Returns a hash of parameter names and values, no ActiveRecord instances.
+  def to_hash
+    Puppet::Rails::ParamValue.find_all_params_from_resource(self).inject({}) do |hash, value|
+      hash[value['name']] ||= []
+      hash[value['name']] << value.value
+      hash
+    end
+  end
+
+  # Convert our object to a resource.  Do not retain whether the object
+  # is exported, though, since that would cause it to get stripped
+  # from the configuration.
+  def to_resource(scope)
+    hash = self.attributes
+    hash["type"] = hash["restype"]
+    hash.delete("restype")
+
+    # FIXME At some point, we're going to want to retain this information
+    # for logging and auditing.
+    hash.delete("host_id")
+    hash.delete("updated_at")
+    hash.delete("source_file_id")
+    hash.delete("created_at")
+    hash.delete("id")
+    hash.each do |p, v|
+      hash.delete(p) if v.nil?
+    end
+    hash[:scope] = scope
+    hash[:source] = scope.source
+    hash[:parameters] = []
+    names = []
+    self.param_names.each do |pname|
+      # We can get the same name multiple times because of how the
+      # db layout works.
+      next if names.include?(pname.name)
+      names << pname.name
+      hash[:parameters] << pname.to_resourceparam(self, scope.source)
+    end
+    obj = Puppet::Parser::Resource.new(hash.delete("type"), hash.delete("title"), hash)
+
+    # Store the ID, so we can check if we're re-collecting the same resource.
+    obj.collector_id = self.id
+
+    obj
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/resource_tag.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/resource_tag.rb
new file mode 100644
index 0000000..1493d3e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/resource_tag.rb
@@ -0,0 +1,26 @@
+class Puppet::Rails::ResourceTag < ActiveRecord::Base
+  belongs_to :puppet_tag
+  belongs_to :resource
+
+  def to_label
+    "#{self.puppet_tag.name}"
+  end
+
+  # returns an array of hash containing tags of resource
+  def self.find_all_tags_from_resource(db_resource)
+    tags = ActiveRecord::Base.connection.select_all("SELECT t.id, t.resource_id, p.name FROM resource_tags t INNER JOIN puppet_tags p ON t.puppet_tag_id=p.id WHERE t.resource_id=#{db_resource.id}")
+    tags.each do |val|
+      val['resource_id'] = Integer(val['resource_id'])
+    end
+    tags
+  end
+
+  # returns an array of hash containing tags of a host
+  def self.find_all_tags_from_host(db_host)
+    tags = ActiveRecord::Base.connection.select_all("SELECT t.id, t.resource_id, p.name FROM resource_tags t INNER JOIN resources r ON t.resource_id=r.id INNER JOIN puppet_tags p ON t.puppet_tag_id=p.id WHERE r.host_id=#{db_host.id}")
+    tags.each do |val|
+      val['resource_id'] = Integer(val['resource_id'])
+    end
+    tags
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/source_file.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/source_file.rb
new file mode 100644
index 0000000..02557ff
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/rails/source_file.rb
@@ -0,0 +1,8 @@
+class Puppet::Rails::SourceFile < ActiveRecord::Base
+  has_one :host
+  has_one :resource
+
+  def to_label
+    "#{self.filename}"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reference/configuration.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reference/configuration.rb
new file mode 100644
index 0000000..0475067
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reference/configuration.rb
@@ -0,0 +1,73 @@
+config = Puppet::Util::Reference.newreference(:configuration, :depth => 1, :doc => "A reference for all settings") do
+  docs = {}
+  Puppet.settings.each do |name, object|
+    docs[name] = object
+  end
+
+  str = ""
+  docs.sort { |a, b|
+    a[0].to_s <=> b[0].to_s
+  }.each do |name, object|
+    # Make each name an anchor
+    header = name.to_s
+    str << markdown_header(header, 3)
+
+    # Print the doc string itself
+    begin
+      str << Puppet::Util::Docs.scrub(object.desc)
+    rescue => detail
+      Puppet.log_exception(detail)
+    end
+    str << "\n\n"
+
+    # Now print the data about the item.
+    val = object.default
+    if name.to_s == "vardir"
+      val = "/var/lib/puppet"
+    elsif name.to_s == "confdir"
+      val = "/etc/puppet"
+    end
+
+    # Leave out the section information; it was apparently confusing people.
+    #str << "- **Section**: #{object.section}\n"
+    unless val == ""
+      str << "- *Default*: #{val}\n"
+    end
+    str << "\n"
+  end
+
+  return str
+end
+
+config.header = <<EOT
+## Configuration Settings
+
+* Each of these settings can be specified in `puppet.conf` or on the
+  command line.
+* When using boolean settings on the command line, use `--setting` and
+  `--no-setting` instead of `--setting (true|false)`.
+* Settings can be interpolated as `$variables` in other settings; `$environment`
+  is special, in that puppet master will interpolate each agent node's
+  environment instead of its own.
+* Multiple values should be specified as comma-separated lists; multiple
+  directories should be separated with the system path separator (usually
+  a colon).
+* Settings that represent time intervals should be specified in duration format:
+  an integer immediately followed by one of the units 'y' (years of 365 days),
+  'd' (days), 'h' (hours), 'm' (minutes), or 's' (seconds). The unit cannot be
+  combined with other units, and defaults to seconds when omitted. Examples are
+  '3600' which is equivalent to '1h' (one hour), and '1825d' which is equivalent
+  to '5y' (5 years).
+* Settings that take a single file or directory can optionally set the owner,
+  group, and mode for their value: `rundir = $vardir/run { owner = puppet,
+  group = puppet, mode = 644 }`
+* The Puppet executables will ignore any setting that isn't relevant to
+  their function.
+
+See the [configuration guide][confguide] for more details.
+
+[confguide]: http://docs.puppetlabs.com/guides/configuring.html
+
+* * *
+
+EOT
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reference/function.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reference/function.rb
new file mode 100644
index 0000000..78f6aa9
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reference/function.rb
@@ -0,0 +1,17 @@
+function = Puppet::Util::Reference.newreference :function, :doc => "All functions available in the parser" do
+  Puppet::Parser::Functions.functiondocs
+end
+function.header = "
+There are two types of functions in Puppet: Statements and rvalues.
+Statements stand on their own and do not return arguments; they are used for
+performing stand-alone work like importing.  Rvalues return values and can
+only be used in a statement requiring a value, such as an assignment or a case
+statement.
+
+Functions execute on the Puppet master.  They do not execute on the Puppet agent.
+Hence they only have access to the commands and data available on the Puppet master
+host.
+
+Here are the functions available in Puppet:
+
+"
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reference/indirection.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reference/indirection.rb
new file mode 100644
index 0000000..b1685ec
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reference/indirection.rb
@@ -0,0 +1,71 @@
+require 'puppet/indirector/indirection'
+require 'puppet/util/checksums'
+require 'puppet/file_serving/content'
+require 'puppet/file_serving/metadata'
+
+reference = Puppet::Util::Reference.newreference :indirection, :doc => "Indirection types and their terminus classes" do
+  text = ""
+  Puppet::Indirector::Indirection.instances.sort { |a,b| a.to_s <=> b.to_s }.each do |indirection|
+    ind = Puppet::Indirector::Indirection.instance(indirection)
+    name = indirection.to_s.capitalize
+    text << "## " + indirection.to_s + "\n\n"
+
+    text << Puppet::Util::Docs.scrub(ind.doc) + "\n\n"
+
+    Puppet::Indirector::Terminus.terminus_classes(ind.name).sort { |a,b| a.to_s <=> b.to_s }.each do |terminus|
+      terminus_name = terminus.to_s
+      term_class = Puppet::Indirector::Terminus.terminus_class(ind.name, terminus)
+      if term_class
+        terminus_doc = Puppet::Util::Docs.scrub(term_class.doc)
+        text << markdown_header("`#{terminus_name}` terminus", 3) << terminus_doc << "\n\n"
+      else
+        Puppet.warning "Could not build docs for indirector #{name.inspect}, terminus #{terminus_name.inspect}: could not locate terminus."
+      end
+    end
+  end
+
+  text
+end
+
+reference.header = <<HEADER
+
+## About Indirection
+
+Puppet's indirector support pluggable backends (termini) for a variety of key-value stores (indirections).
+Each indirection type corresponds to a particular Ruby class (the "Indirected Class" below) and values are instances of that class.
+Each instance's key is available from its `name` method.
+The termini can be local (e.g., on-disk files) or remote (e.g., using a REST interface to talk to a puppet master).
+
+An indirector has five methods, which are mapped into HTTP verbs for the REST interface:
+
+* `find(key)` - get a single value (mapped to GET or POST with a singular endpoint)
+* `search(key)` - get a list of matching values (mapped to GET with a plural endpoint)
+* `head(key)` - return true if the key exists (mapped to HEAD)
+* `destroy(key)` - remove the key van value (mapped to DELETE)
+* `save(instance)` - write the instance to the store, using the instance's name as the key (mapped to PUT)
+
+These methods are available via the `indirection` class method on the indirected classes.  For example:
+
+    foo_cert = Puppet::SSL::Certificate.indirection.find('foo.example.com')
+
+At startup, each indirection is configured with a terminus.
+In most cases, this is the default terminus defined by the indirected class, but it can be overridden by the application or face, or overridden with the `route_file` configuration.
+The available termini differ for each indirection, and are listed below.
+
+Indirections can also have a cache, represented by a second terminus.
+This is a write-through cache: modifications are written both to the cache and to the primary terminus.
+Values fetched from the terminus are written to the cache.
+
+### Interaction with REST
+
+REST endpoints have the form `/{environment}/{indirection}/{key}`, where the indirection can be singular or plural, following normal English spelling rules.
+On the server side, REST responses are generated from the locally-configured endpoints.
+
+### Indirections and Termini
+
+Below is the list of all indirections, their associated terminus classes, and how you select between them.
+
+In general, the appropriate terminus class is selected by the application for you (e.g., `puppet agent` would always use the `rest`
+terminus for most of its indirected classes), but some classes are tunable via normal settings.  These will have `terminus setting` documentation listed with them.
+
+HEADER
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reference/metaparameter.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reference/metaparameter.rb
new file mode 100644
index 0000000..cd8d6d4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reference/metaparameter.rb
@@ -0,0 +1,44 @@
+Puppet::Util::Reference.newreference :metaparameter, :doc => "All Puppet metaparameters and all their details" do
+  types = {}
+  Puppet::Type.loadall
+
+  Puppet::Type.eachtype { |type|
+    next if type.name == :puppet
+    next if type.name == :component
+    types[type.name] = type
+  }
+
+  str = %{
+
+Metaparameters are attributes that work with any resource type, including custom
+types and defined types.
+
+In general, they affect _Puppet's_ behavior rather than the desired state of the
+resource. Metaparameters do things like add metadata to a resource (`alias`,
+`tag`), set limits on when the resource should be synced (`require`, `schedule`,
+etc.), prevent Puppet from making changes (`noop`), and change logging verbosity
+(`loglevel`).
+
+## Available Metaparameters
+
+}
+  begin
+    params = []
+    Puppet::Type.eachmetaparam { |param|
+      params << param
+    }
+
+    params.sort { |a,b|
+      a.to_s <=> b.to_s
+    }.each { |param|
+      str << markdown_header(param.to_s, 3)
+      str << scrub(Puppet::Type.metaparamdoc(param))
+      str << "\n\n"
+    }
+  rescue => detail
+    Puppet.log_exception(detail, "incorrect metaparams: #{detail}")
+    exit(1)
+  end
+
+  str
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reference/providers.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reference/providers.rb
new file mode 100644
index 0000000..afd31c0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reference/providers.rb
@@ -0,0 +1,119 @@
+# This doesn't get stored in trac, since it changes every time.
+providers = Puppet::Util::Reference.newreference :providers, :title => "Provider Suitability Report", :depth => 1, :dynamic => true, :doc => "Which providers are valid for this machine" do
+  types = []
+  Puppet::Type.loadall
+  Puppet::Type.eachtype do |klass|
+    next unless klass.providers.length > 0
+    types << klass
+  end
+  types.sort! { |a,b| a.name.to_s <=> b.name.to_s }
+
+  command_line = Puppet::Util::CommandLine.new
+  types.reject! { |type| ! command_line.args.include?(type.name.to_s) } unless command_line.args.empty?
+
+  ret = "Details about this host:\n\n"
+
+  # Throw some facts in there, so we know where the report is from.
+  ["Ruby Version", "Puppet Version", "Operating System", "Operating System Release"].each do |label|
+    name = label.gsub(/\s+/, '')
+    value = Facter.value(name)
+    ret << option(label, value)
+  end
+  ret << "\n"
+
+  count = 1
+
+  # Produce output for each type.
+  types.each do |type|
+    features = type.features
+    ret << "\n" # add a trailing newline
+
+    # Now build up a table of provider suitability.
+    headers = %w{Provider Suitable?} + features.collect { |f| f.to_s }.sort
+
+    table_data = {}
+
+    functional = false
+    notes = []
+    default = type.defaultprovider ? type.defaultprovider.name : 'none'
+    type.providers.sort { |a,b| a.to_s <=> b.to_s }.each do |pname|
+      data = []
+      table_data[pname] = data
+      provider = type.provider(pname)
+
+      # Add the suitability note
+      if missing = provider.suitable?(false) and missing.empty?
+        data << "*X*"
+        suit = true
+        functional = true
+      else
+        data << "[#{count}]_" # A pointer to the appropriate footnote
+        suit = false
+      end
+
+      # Add a footnote with the details about why this provider is unsuitable, if that's the case
+      unless suit
+        details = ".. [#{count}]\n"
+        missing.each do |test, values|
+          case test
+          when :exists
+            details << "  - Missing files #{values.join(", ")}\n"
+          when :variable
+            values.each do |name, facts|
+              if Puppet.settings.valid?(name)
+                details << "  - Setting #{name} (currently #{Puppet.settings.value(name).inspect}) not in list #{facts.join(", ")}\n"
+              else
+                details << "  - Fact #{name} (currently #{Facter.value(name).inspect}) not in list #{facts.join(", ")}\n"
+              end
+            end
+          when :true
+            details << "  - Got #{values} true tests that should have been false\n"
+          when :false
+            details << "  - Got #{values} false tests that should have been true\n"
+          when :feature
+            details << "  - Missing features #{values.collect { |f| f.to_s }.join(",")}\n"
+          end
+        end
+        notes << details
+
+        count += 1
+      end
+
+      # Add a note for every feature
+      features.each do |feature|
+        if provider.features.include?(feature)
+          data << "*X*"
+        else
+          data << ""
+        end
+      end
+    end
+
+    ret << markdown_header(type.name.to_s + "_", 2)
+
+    ret << "[#{type.name}](#{"http://docs.puppetlabs.com/references/stable/type.html##{type.name}"})\n\n"
+    ret << option("Default provider", default)
+    ret << doctable(headers, table_data)
+
+    notes.each do |note|
+      ret << note + "\n"
+    end
+
+    ret << "\n"
+  end
+
+  ret << "\n"
+
+  ret
+end
+providers.header = "
+Puppet resource types are usually backed by multiple implementations called `providers`,
+which handle variance between platforms and tools.
+
+Different providers are suitable or unsuitable on different platforms based on things
+like the presence of a given tool.
+
+Here are all of the provider-backed types and their different providers.  Any unmentioned
+types do not use providers yet.
+
+"
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reference/report.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reference/report.rb
new file mode 100644
index 0000000..b161a4a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reference/report.rb
@@ -0,0 +1,23 @@
+require 'puppet/reports'
+
+report = Puppet::Util::Reference.newreference :report, :doc => "All available transaction reports" do
+  Puppet::Reports.reportdocs
+end
+
+report.header = "
+Puppet clients can report back to the server after each transaction.  This
+transaction report is sent as a YAML dump of the
+`Puppet::Transaction::Report` class and includes every log message that was
+generated during the transaction along with as many metrics as Puppet knows how
+to collect.  See [Reports and Reporting](http://docs.puppetlabs.com/guides/reporting.html) for more information on how to use reports.
+
+Currently, clients default to not sending in reports; you can enable reporting
+by setting the `report` parameter to true.
+
+To use a report, set the `reports` parameter on the server; multiple
+reports must be comma-separated.  You can also specify `none` to disable
+reports entirely.
+
+Puppet provides multiple report handlers that will process client reports:
+
+"
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reference/type.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reference/type.rb
new file mode 100644
index 0000000..56487ab
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reference/type.rb
@@ -0,0 +1,116 @@
+Puppet::Util::Reference.newreference :type, :doc => "All Puppet resource types and all their details" do
+  types = {}
+  Puppet::Type.loadall
+
+  Puppet::Type.eachtype { |type|
+    next if type.name == :puppet
+    next if type.name == :component
+    next if type.name == :whit
+    types[type.name] = type
+  }
+
+  str = %{
+
+## Resource Types
+
+- The *namevar* is the parameter used to uniquely identify a type instance.
+  This is the parameter that gets assigned when a string is provided before
+  the colon in a type declaration.  In general, only developers will need to
+  worry about which parameter is the `namevar`.
+
+  In the following code:
+
+      file { "/etc/passwd":
+        owner => root,
+        group => root,
+        mode  => 644
+      }
+
+  `/etc/passwd` is considered the title of the file object (used for things like
+  dependency handling), and because `path` is the namevar for `file`, that
+  string is assigned to the `path` parameter.
+
+- *Parameters* determine the specific configuration of the instance.  They either
+  directly modify the system (internally, these are called properties) or they affect
+  how the instance behaves (e.g., adding a search path for `exec` instances or determining recursion on `file` instances).
+
+- *Providers* provide low-level functionality for a given resource type.  This is
+  usually in the form of calling out to external commands.
+
+  When required binaries are specified for providers, fully qualifed paths
+  indicate that the binary must exist at that specific path and unqualified
+  binaries indicate that Puppet will search for the binary using the shell
+  path.
+
+- *Features* are abilities that some providers might not support.  You can use the list
+  of supported features to determine how a given provider can be used.
+
+  Resource types define features they can use, and providers can be tested to see
+  which features they provide.
+
+    }
+
+    types.sort { |a,b|
+      a.to_s <=> b.to_s
+    }.each { |name,type|
+
+      str << "
+
+----------------
+
+"
+
+  str << markdown_header(name, 3)
+  str << scrub(type.doc) + "\n\n"
+
+  # Handle the feature docs.
+  if featuredocs = type.featuredocs
+    str << markdown_header("Features", 4)
+    str << featuredocs
+    end
+
+    docs = {}
+    type.validproperties.sort { |a,b|
+      a.to_s <=> b.to_s
+    }.reject { |sname|
+      property = type.propertybyname(sname)
+      property.nodoc
+    }.each { |sname|
+      property = type.propertybyname(sname)
+
+      raise "Could not retrieve property #{sname} on type #{type.name}" unless property
+
+      doc = nil
+      unless doc = property.doc
+        $stderr.puts "No docs for #{type}[#{sname}]"
+        next
+      end
+      doc = doc.dup
+      tmp = doc
+      tmp = scrub(tmp)
+
+      docs[sname]  = tmp
+    }
+
+    str << markdown_header("Parameters", 4) + "\n"
+    type.parameters.sort { |a,b|
+      a.to_s <=> b.to_s
+    }.each { |name,param|
+      #docs[name] = indent(scrub(type.paramdoc(name)), $tab)
+      docs[name] = scrub(type.paramdoc(name))
+    }
+
+    additional_key_attributes = type.key_attributes - [:name]
+    docs.sort { |a, b|
+      a[0].to_s <=> b[0].to_s
+    }.each { |name, doc|
+      if additional_key_attributes.include?(name)
+        doc = "(**Namevar:** If omitted, this parameter's value defaults to the resource's title.)\n\n" + doc
+      end
+      str << markdown_definitionlist(name, doc)
+    }
+    str << "\n"
+  }
+
+  str
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/relationship.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/relationship.rb
new file mode 100644
index 0000000..d0a3e24
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/relationship.rb
@@ -0,0 +1,103 @@
+# subscriptions are permanent associations determining how different
+# objects react to an event
+
+require 'puppet/util/pson'
+
+# This is Puppet's class for modeling edges in its configuration graph.
+# It used to be a subclass of GRATR::Edge, but that class has weird hash
+# overrides that dramatically slow down the graphing.
+class Puppet::Relationship
+  extend Puppet::Util::Pson
+  attr_accessor :source, :target, :callback
+
+  attr_reader :event
+
+  def self.from_data_hash(data)
+    source = data["source"]
+    target = data["target"]
+
+    args = {}
+    if event = data["event"]
+      args[:event] = event
+    end
+    if callback = data["callback"]
+      args[:callback] = callback
+    end
+
+    new(source, target, args)
+  end
+
+  def self.from_pson(pson)
+    Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
+    self.from_data_hash(pson)
+  end
+
+  def event=(event)
+    raise ArgumentError, "You must pass a callback for non-NONE events" if event != :NONE and ! callback
+    @event = event
+  end
+
+  def initialize(source, target, options = {})
+    @source, @target = source, target
+
+    options = (options || {}).inject({}) { |h,a| h[a[0].to_sym] = a[1]; h }
+    [:callback, :event].each do |option|
+      if value = options[option]
+        send(option.to_s + "=", value)
+      end
+    end
+  end
+
+  # Does the passed event match our event?  This is where the meaning
+  # of :NONE comes from.
+  def match?(event)
+    if self.event.nil? or event == :NONE or self.event == :NONE
+      return false
+    elsif self.event == :ALL_EVENTS or event == self.event
+      return true
+    else
+      return false
+    end
+  end
+
+  def label
+    result = {}
+    result[:callback] = callback if callback
+    result[:event] = event if event
+    result
+  end
+
+  def ref
+    "#{source} => #{target}"
+  end
+
+  def inspect
+    "{ #{source} => #{target} }"
+  end
+
+  def to_data_hash
+    data = {
+      'source' => source.to_s,
+      'target' => target.to_s
+    }
+
+    ["event", "callback"].each do |attr|
+      next unless value = send(attr)
+      data[attr] = value
+    end
+    data
+  end
+
+  # This doesn't include document type as it is part of a catalog
+  def to_pson_data_hash
+    to_data_hash
+  end
+
+  def to_pson(*args)
+    to_data_hash.to_pson(*args)
+  end
+
+  def to_s
+    ref
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reports.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reports.rb
new file mode 100644
index 0000000..e219971
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reports.rb
@@ -0,0 +1,89 @@
+require 'puppet/util/instance_loader'
+
+# This class is an implementation of a simple mechanism for loading and returning reports.
+# The intent is that a user registers a report by calling {register_report} and providing a code
+# block that performs setup, and defines a method called `process`. The setup, and the `process` method
+# are called in the context where `self` is an instance of {Puppet::Transaction::Report} which provides the actual
+# data for the report via its methods.
+#
+# @example Minimal scaffolding for a report...
+#   Puppet::Reports::.register_report(:myreport) do
+#     # do setup here
+#     def process
+#       if self.status == 'failed'
+#         msg = "failed puppet run for #{self.host} #{self.status}"
+#         . . .
+#       else
+#         . . .
+#       end
+#     end
+#   end
+#
+# Required configuration:
+# --
+# * A .rb file that defines a new report should be placed in the master's directory `lib/puppet/reports`
+# * The `puppet.conf` file must have `report = true` in the `[agent]` section
+#
+# @see Puppet::Transaction::Report
+# @api public
+#
+class Puppet::Reports
+  extend Puppet::Util::ClassGen
+  extend Puppet::Util::InstanceLoader
+
+  # Set up autoloading and retrieving of reports.
+  instance_load :report, 'puppet/reports'
+
+  class << self
+    # @api private
+    attr_reader :hooks
+  end
+
+  # Adds a new report type.
+  # The block should contain setup, and define a method with the name `process`. The `process` method is
+  # called when the report is executed; the `process` method has access to report data via methods available
+  # in its context where `self` is an instance of {Puppet::Transaction::Report}.
+  #
+  # For an example, see the overview of this class.
+  #
+  # @param name [Symbol] the name of the report (do not use whitespace in the name).
+  # @param options [Hash] a hash of options
+  # @option options [Boolean] :useyaml whether yaml should be used or not
+  # @todo Uncertain what the options :useyaml really does; "whether yaml should be used or not", used where/how?
+  #
+  def self.register_report(name, options = {}, &block)
+    name = name.intern
+
+    mod = genmodule(name, :extend => Puppet::Util::Docs, :hash => instance_hash(:report), :block => block)
+
+    mod.useyaml = true if options[:useyaml]
+
+    mod.send(:define_method, :report_name) do
+      name
+    end
+  end
+
+  # Collects the docs for all reports.
+  # @api private
+  def self.reportdocs
+    docs = ""
+
+    # Use this method so they all get loaded
+    instance_loader(:report).loadall
+    loaded_instances(:report).sort { |a,b| a.to_s <=> b.to_s }.each do |name|
+      mod = self.report(name)
+      docs << "#{name}\n#{"-" * name.to_s.length}\n"
+
+      docs << Puppet::Util::Docs.scrub(mod.doc) << "\n\n"
+    end
+
+    docs
+  end
+
+  # Lists each of the reports.
+  # @api private
+  def self.reports
+    instance_loader(:report).loadall
+    loaded_instances(:report)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reports/http.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reports/http.rb
new file mode 100644
index 0000000..403e81a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reports/http.rb
@@ -0,0 +1,31 @@
+require 'puppet'
+require 'puppet/network/http_pool'
+require 'uri'
+
+Puppet::Reports.register_report(:http) do
+
+  desc <<-DESC
+    Send reports via HTTP or HTTPS. This report processor submits reports as
+    POST requests to the address in the `reporturl` setting. The body of each POST
+    request is the YAML dump of a Puppet::Transaction::Report object, and the
+    Content-Type is set as `application/x-yaml`.
+  DESC
+
+  def process
+    url = URI.parse(Puppet[:reporturl])
+    headers = { "Content-Type" => "application/x-yaml" }
+    options = {}
+    if url.user && url.password
+      options[:basic_auth] = {
+        :user => url.user,
+        :password => url.password
+      }
+    end
+    use_ssl = url.scheme == 'https'
+    conn = Puppet::Network::HttpPool.http_instance(url.host, url.port, use_ssl)
+    response = conn.post(url.path, self.to_yaml, headers, options)
+    unless response.kind_of?(Net::HTTPSuccess)
+      Puppet.err "Unable to submit report to #{Puppet[:reporturl].to_s} [#{response.code}] #{response.msg}"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reports/log.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reports/log.rb
new file mode 100644
index 0000000..1fc6876
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reports/log.rb
@@ -0,0 +1,14 @@
+require 'puppet/reports'
+
+Puppet::Reports.register_report(:log) do
+  desc "Send all received logs to the local log destinations.  Usually
+    the log destination is syslog."
+
+  def process
+    self.logs.each do |log|
+      log.source = "//#{self.host}/#{log.source}"
+      Puppet::Util::Log.newmessage(log)
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reports/rrdgraph.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reports/rrdgraph.rb
new file mode 100644
index 0000000..6238ddd
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reports/rrdgraph.rb
@@ -0,0 +1,128 @@
+Puppet::Reports.register_report(:rrdgraph) do
+  desc "Graph all available data about hosts using the RRD library.  You
+    must have the Ruby RRDtool library installed to use this report, which
+    you can get from
+    [the RubyRRDTool RubyForge page](http://rubyforge.org/projects/rubyrrdtool/).
+    This package may also be available as `librrd-ruby`, `ruby-rrd`, or `rrdtool-ruby` in your
+    distribution's package management system.  The library and/or package will both
+    require the binary `rrdtool` package from your distribution to be installed.
+
+    This report will create, manage, and graph RRD database files for each
+    of the metrics generated during transactions, and it will create a
+    few simple html files to display the reporting host's graphs.  At this
+    point, it will not create a common index file to display links to
+    all hosts.
+
+    All RRD files and graphs get created in the `rrddir` directory.  If
+    you want to serve these publicly, you should be able to just alias that
+    directory in a web server.
+
+    If you really know what you're doing, you can tune the `rrdinterval`,
+    which defaults to the `runinterval`."
+
+  def hostdir
+    @hostdir ||= File.join(Puppet[:rrddir], self.host)
+  end
+
+  def htmlfile(type, graphs, field)
+    file = File.join(hostdir, "#{type}.html")
+    File.open(file, "w") do |of|
+      of.puts "<html><head><title>#{type.capitalize} graphs for #{host}</title></head><body>"
+
+      graphs.each do |graph|
+        if field == :first
+          name = graph.sub(/-\w+.png/, '').capitalize
+        else
+          name = graph.sub(/\w+-/, '').sub(".png", '').capitalize
+        end
+        of.puts "<img src=#{graph}><br>"
+      end
+      of.puts "</body></html>"
+    end
+
+    file
+  end
+
+  def mkhtml
+    images = Dir.entries(hostdir).find_all { |d| d =~ /\.png/ }
+
+    periodorder = %w{daily weekly monthly yearly}
+
+    periods = {}
+    types = {}
+    images.each do |n|
+      type, period = n.sub(".png", '').split("-")
+      periods[period] ||= []
+      types[type] ||= []
+      periods[period] << n
+      types[type] << n
+    end
+
+    files = []
+    # Make the period html files
+    periodorder.each do |period|
+      unless ary = periods[period]
+        raise Puppet::Error, "Could not find graphs for #{period}"
+      end
+      files << htmlfile(period, ary, :first)
+    end
+
+    # make the type html files
+    types.sort { |a,b| a[0] <=> b[0] }.each do |type, ary|
+      newary = []
+      periodorder.each do |period|
+        if graph = ary.find { |g| g.include?("-#{period}.png") }
+          newary << graph
+        else
+          raise "Could not find #{type}-#{period} graph"
+        end
+      end
+
+      files << htmlfile(type, newary, :second)
+    end
+
+    File.open(File.join(hostdir, "index.html"), "w") do |of|
+      of.puts "<html><head><title>Report graphs for #{host}</title></head><body>"
+      files.each do |file|
+        of.puts "<a href='#{File.basename(file)}'>#{File.basename(file).sub(".html",'').capitalize}</a><br/>"
+      end
+      of.puts "</body></html>"
+    end
+  end
+
+  def process(time = nil)
+    time ||= Time.now.to_i
+
+    unless File.directory?(hostdir) and FileTest.writable?(hostdir)
+      # Some hackishness to create the dir with all of the right modes and ownership
+      config = Puppet::Settings.new
+      config.define_settings(:reports, :hostdir => {:type => :directory, :default => hostdir, :owner => 'service', :mode => 0755, :group => 'service', :desc => "eh"})
+
+      # This creates the dir.
+      config.use(:reports)
+    end
+
+    self.metrics.each do |name, metric|
+      metric.basedir = hostdir
+
+      if name == "time"
+        timeclean(metric)
+      end
+
+      metric.store(time)
+
+      metric.graph
+    end
+
+    mkhtml unless Puppet::FileSystem.exist?(File.join(hostdir, "index.html"))
+  end
+
+  # Unfortunately, RRD does not deal well with changing lists of values,
+  # so we have to pick a list of values and stick with it.  In this case,
+  # that means we record the total time, the config time, and that's about
+  # it.  We should probably send each type's time as a separate metric.
+  def timeclean(metric)
+    metric.values = metric.values.find_all { |name, label, value| ['total', 'config_retrieval'].include?(name.to_s) }
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reports/store.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reports/store.rb
new file mode 100644
index 0000000..528f9db
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reports/store.rb
@@ -0,0 +1,68 @@
+require 'puppet'
+require 'fileutils'
+require 'puppet/util'
+
+SEPARATOR = [Regexp.escape(File::SEPARATOR.to_s), Regexp.escape(File::ALT_SEPARATOR.to_s)].join
+
+Puppet::Reports.register_report(:store) do
+  desc "Store the yaml report on disk.  Each host sends its report as a YAML dump
+    and this just stores the file on disk, in the `reportdir` directory.
+
+    These files collect quickly -- one every half hour -- so it is a good idea
+    to perform some maintenance on them if you use this report (it's the only
+    default report)."
+
+  def process
+    validate_host(host)
+
+    dir = File.join(Puppet[:reportdir], host)
+
+    if ! Puppet::FileSystem.exist?(dir)
+      FileUtils.mkdir_p(dir)
+      FileUtils.chmod_R(0750, dir)
+    end
+
+    # Now store the report.
+    now = Time.now.gmtime
+    name = %w{year month day hour min}.collect do |method|
+      # Make sure we're at least two digits everywhere
+      "%02d" % now.send(method).to_s
+    end.join("") + ".yaml"
+
+    file = File.join(dir, name)
+
+    begin
+      Puppet::Util.replace_file(file, 0640) do |fh|
+        fh.print to_yaml
+      end
+    rescue => detail
+       Puppet.log_exception(detail, "Could not write report for #{host} at #{file}: #{detail}")
+    end
+
+    # Only testing cares about the return value
+    file
+  end
+
+  # removes all reports for a given host?
+  def self.destroy(host)
+    validate_host(host)
+
+    dir = File.join(Puppet[:reportdir], host)
+
+    if Puppet::FileSystem.exist?(dir)
+      Dir.entries(dir).each do |file|
+        next if ['.','..'].include?(file)
+        file = File.join(dir, file)
+        Puppet::FileSystem.unlink(file) if File.file?(file)
+      end
+      Dir.rmdir(dir)
+    end
+  end
+
+  def validate_host(host)
+    if host =~ Regexp.union(/[#{SEPARATOR}]/, /\A\.\.?\Z/)
+      raise ArgumentError, "Invalid node name #{host.inspect}"
+    end
+  end
+  module_function :validate_host
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reports/tagmail.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reports/tagmail.rb
new file mode 100644
index 0000000..eb9888e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/reports/tagmail.rb
@@ -0,0 +1,179 @@
+require 'puppet'
+require 'pp'
+
+require 'net/smtp'
+require 'time'
+
+Puppet::Reports.register_report(:tagmail) do
+  desc "This report sends specific log messages to specific email addresses
+    based on the tags in the log messages.
+
+    See the [documentation on tags](http://docs.puppetlabs.com/puppet/latest/reference/lang_tags.html) for more information.
+
+    To use this report, you must create a `tagmail.conf` file in the location
+    specified by the `tagmap` setting.  This is a simple file that maps tags to
+    email addresses:  Any log messages in the report that match the specified
+    tags will be sent to the specified email addresses.
+
+    Lines in the `tagmail.conf` file consist of a comma-separated list
+    of tags, a colon, and a comma-separated list of email addresses.
+    Tags can be !negated with a leading exclamation mark, which will
+    subtract any messages with that tag from the set of events handled
+    by that line.
+
+    Puppet's log levels (`debug`, `info`, `notice`, `warning`, `err`,
+    `alert`, `emerg`, `crit`, and `verbose`) can also be used as tags,
+    and there is an `all` tag that will always match all log messages.
+
+    An example `tagmail.conf`:
+
+        all: me@domain.com
+        webserver, !mailserver: httpadmins@domain.com
+
+    This will send all messages to `me@domain.com`, and all messages from
+    webservers that are not also from mailservers to `httpadmins@domain.com`.
+
+    If you are using anti-spam controls such as grey-listing on your mail
+    server, you should whitelist the sending email address (controlled by
+    `reportfrom` configuration option) to ensure your email is not discarded as spam.
+    "
+
+  # Find all matching messages.
+  def match(taglists)
+    matching_logs = []
+    taglists.each do |emails, pos, neg|
+      # First find all of the messages matched by our positive tags
+      messages = nil
+      if pos.include?("all")
+        messages = self.logs
+      else
+        # Find all of the messages that are tagged with any of our
+        # tags.
+        messages = self.logs.find_all do |log|
+          pos.detect { |tag| log.tagged?(tag) }
+        end
+      end
+
+      # Now go through and remove any messages that match our negative tags
+      messages = messages.reject do |log|
+        true if neg.detect do |tag| log.tagged?(tag) end
+      end
+
+      if messages.empty?
+        Puppet.info "No messages to report to #{emails.join(",")}"
+        next
+      else
+        matching_logs << [emails, messages.collect { |m| m.to_report }.join("\n")]
+      end
+    end
+
+    matching_logs
+  end
+
+  # Load the config file
+  def parse(text)
+    taglists = []
+    text.split("\n").each do |line|
+      taglist = emails = nil
+      case line.chomp
+      when /^\s*#/; next
+      when /^\s*$/; next
+      when /^\s*(.+)\s*:\s*(.+)\s*$/
+        taglist = $1
+        emails = $2.sub(/#.*$/,'')
+      else
+        raise ArgumentError, "Invalid tagmail config file"
+      end
+
+      pos = []
+      neg = []
+      taglist.sub(/\s+$/,'').split(/\s*,\s*/).each do |tag|
+        unless tag =~ /^!?[-\w\.]+$/
+          raise ArgumentError, "Invalid tag #{tag.inspect}"
+        end
+        case tag
+        when /^\w+/; pos << tag
+        when /^!\w+/; neg << tag.sub("!", '')
+        else
+          raise Puppet::Error, "Invalid tag '#{tag}'"
+        end
+      end
+
+      # Now split the emails
+      emails = emails.sub(/\s+$/,'').split(/\s*,\s*/)
+      taglists << [emails, pos, neg]
+    end
+    taglists
+  end
+
+  # Process the report.  This just calls the other associated messages.
+  def process
+    unless Puppet::FileSystem.exist?(Puppet[:tagmap])
+      Puppet.notice "Cannot send tagmail report; no tagmap file #{Puppet[:tagmap]}"
+      return
+    end
+
+    metrics = raw_summary['resources'] || {} rescue {}
+
+    if metrics['out_of_sync'] == 0 && metrics['changed'] == 0
+      Puppet.notice "Not sending tagmail report; no changes"
+      return
+    end
+
+    taglists = parse(File.read(Puppet[:tagmap]))
+
+    # Now find any appropriately tagged messages.
+    reports = match(taglists)
+
+    send(reports) unless reports.empty?
+  end
+
+  # Send the email reports.
+  def send(reports)
+    pid = Puppet::Util.safe_posix_fork do
+      if Puppet[:smtpserver] != "none"
+        begin
+          Net::SMTP.start(Puppet[:smtpserver], Puppet[:smtpport], Puppet[:smtphelo]) do |smtp|
+            reports.each do |emails, messages|
+              smtp.open_message_stream(Puppet[:reportfrom], *emails) do |p|
+                p.puts "From: #{Puppet[:reportfrom]}"
+                p.puts "Subject: Puppet Report for #{self.host}"
+                p.puts "To: " + emails.join(", ")
+                p.puts "Date: #{Time.now.rfc2822}"
+                p.puts
+                p.puts messages
+              end
+            end
+          end
+        rescue => detail
+          message = "Could not send report emails through smtp: #{detail}"
+          Puppet.log_exception(detail, message)
+          raise Puppet::Error, message, detail.backtrace
+        end
+      elsif Puppet[:sendmail] != ""
+        begin
+          reports.each do |emails, messages|
+            # We need to open a separate process for every set of email addresses
+            IO.popen(Puppet[:sendmail] + " " + emails.join(" "), "w") do |p|
+              p.puts "From: #{Puppet[:reportfrom]}"
+              p.puts "Subject: Puppet Report for #{self.host}"
+              p.puts "To: " + emails.join(", ")
+              p.puts
+              p.puts messages
+            end
+          end
+        rescue => detail
+          message = "Could not send report emails via sendmail: #{detail}"
+          Puppet.log_exception(detail, message)
+          raise Puppet::Error, message, detail.backtrace
+        end
+      else
+        raise Puppet::Error, "SMTP server is unset and could not find sendmail"
+      end
+    end
+
+    # Don't bother waiting for the pid to return.
+    Process.detach(pid)
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/resource.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/resource.rb
new file mode 100644
index 0000000..21ac52d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/resource.rb
@@ -0,0 +1,608 @@
+require 'puppet'
+require 'puppet/util/tagging'
+require 'puppet/util/pson'
+require 'puppet/parameter'
+
+# The simplest resource class.  Eventually it will function as the
+# base class for all resource-like behaviour.
+#
+# @api public
+class Puppet::Resource
+  # This stub class is only needed for serialization compatibility with 0.25.x.
+  # Specifically, it exists to provide a compatibility API when using YAML
+  # serialized objects loaded from StoreConfigs.
+  Reference = Puppet::Resource
+
+  include Puppet::Util::Tagging
+
+  extend Puppet::Util::Pson
+  include Enumerable
+  attr_accessor :file, :line, :catalog, :exported, :virtual, :validate_parameters, :strict
+  attr_reader :type, :title
+
+  require 'puppet/indirector'
+  extend Puppet::Indirector
+  indirects :resource, :terminus_class => :ral
+
+  ATTRIBUTES = [:file, :line, :exported]
+
+  def self.from_data_hash(data)
+    raise ArgumentError, "No resource type provided in serialized data" unless type = data['type']
+    raise ArgumentError, "No resource title provided in serialized data" unless title = data['title']
+
+    resource = new(type, title)
+
+    if params = data['parameters']
+      params.each { |param, value| resource[param] = value }
+    end
+
+    if tags = data['tags']
+      tags.each { |tag| resource.tag(tag) }
+    end
+
+    ATTRIBUTES.each do |a|
+      if value = data[a.to_s]
+        resource.send(a.to_s + "=", value)
+      end
+    end
+
+    resource
+  end
+
+  def self.from_pson(pson)
+    Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
+    self.from_data_hash(pson)
+  end
+
+  def inspect
+    "#{@type}[#{@title}]#{to_hash.inspect}"
+  end
+
+  def to_data_hash
+    data = ([:type, :title, :tags] + ATTRIBUTES).inject({}) do |hash, param|
+      next hash unless value = self.send(param)
+      hash[param.to_s] = value
+      hash
+    end
+
+    data["exported"] ||= false
+
+    params = self.to_hash.inject({}) do |hash, ary|
+      param, value = ary
+
+      # Don't duplicate the title as the namevar
+      next hash if param == namevar and value == title
+
+      hash[param] = Puppet::Resource.value_to_pson_data(value)
+      hash
+    end
+
+    data["parameters"] = params unless params.empty?
+
+    data
+  end
+
+  # This doesn't include document type as it is part of a catalog
+  def to_pson_data_hash
+    to_data_hash
+  end
+
+  def self.value_to_pson_data(value)
+    if value.is_a? Array
+      value.map{|v| value_to_pson_data(v) }
+    elsif value.is_a? Puppet::Resource
+      value.to_s
+    else
+      value
+    end
+  end
+
+  def yaml_property_munge(x)
+    case x
+    when Hash
+      x.inject({}) { |h,kv|
+        k,v = kv
+        h[k] = self.class.value_to_pson_data(v)
+        h
+      }
+    else self.class.value_to_pson_data(x)
+    end
+  end
+
+  YAML_ATTRIBUTES = [:@file, :@line, :@exported, :@type, :@title, :@tags, :@parameters]
+
+  # Explicitly list the instance variables that should be serialized when
+  # converting to YAML.
+  #
+  # @api private
+  # @return [Array<Symbol>] The intersection of our explicit variable list and
+  #   all of the instance variables defined on this class.
+  def to_yaml_properties
+    YAML_ATTRIBUTES & super
+  end
+
+  def to_pson(*args)
+    to_data_hash.to_pson(*args)
+  end
+
+  # Proxy these methods to the parameters hash.  It's likely they'll
+  # be overridden at some point, but this works for now.
+  %w{has_key? keys length delete empty? <<}.each do |method|
+    define_method(method) do |*args|
+      parameters.send(method, *args)
+    end
+  end
+
+  # Set a given parameter.  Converts all passed names
+  # to lower-case symbols.
+  def []=(param, value)
+    validate_parameter(param) if validate_parameters
+    parameters[parameter_name(param)] = value
+  end
+
+  # Return a given parameter's value.  Converts all passed names
+  # to lower-case symbols.
+  def [](param)
+    parameters[parameter_name(param)]
+  end
+
+  def ==(other)
+    return false unless other.respond_to?(:title) and self.type == other.type and self.title == other.title
+
+    return false unless to_hash == other.to_hash
+    true
+  end
+
+  # Compatibility method.
+  def builtin?
+    builtin_type?
+  end
+
+  # Is this a builtin resource type?
+  def builtin_type?
+    resource_type.is_a?(Class)
+  end
+
+  # Iterate over each param/value pair, as required for Enumerable.
+  def each
+    parameters.each { |p,v| yield p, v }
+  end
+
+  def include?(parameter)
+    super || parameters.keys.include?( parameter_name(parameter) )
+  end
+
+  %w{exported virtual strict}.each do |m|
+    define_method(m+"?") do
+      self.send(m)
+    end
+  end
+
+  def class?
+    @is_class ||= @type == "Class"
+  end
+
+  def stage?
+    @is_stage ||= @type.to_s.downcase == "stage"
+  end
+
+  # Construct a resource from data.
+  #
+  # Constructs a resource instance with the given `type` and `title`. Multiple
+  # type signatures are possible for these arguments and most will result in an
+  # expensive call to {Puppet::Node::Environment#known_resource_types} in order
+  # to resolve `String` and `Symbol` Types to actual Ruby classes.
+  #
+  # @param type [Symbol, String] The name of the Puppet Type, as a string or
+  #   symbol. The actual Type will be looked up using
+  #   {Puppet::Node::Environment#known_resource_types}. This lookup is expensive.
+  # @param type [String] The full resource name in the form of
+  #   `"Type[Title]"`. This method of calling should only be used when
+  #   `title` is `nil`.
+  # @param type [nil] If a `nil` is passed, the title argument must be a string
+  #   of the form `"Type[Title]"`.
+  # @param type [Class] A class that inherits from `Puppet::Type`. This method
+  #   of construction is much more efficient as it skips calls to
+  #   {Puppet::Node::Environment#known_resource_types}.
+  #
+  # @param title [String, :main, nil] The title of the resource. If type is `nil`, may also
+  #   be the full resource name in the form of `"Type[Title]"`.
+  #
+  # @api public
+  def initialize(type, title = nil, attributes = {})
+    @parameters = {}
+    environment = attributes[:environment]
+    if type.is_a?(Class) && type < Puppet::Type
+      # Set the resource type to avoid an expensive `known_resource_types`
+      # lookup.
+      self.resource_type = type
+      # From this point on, the constructor behaves the same as if `type` had
+      # been passed as a symbol.
+      type = type.name
+    end
+
+    # Set things like strictness first.
+    attributes.each do |attr, value|
+      next if attr == :parameters
+      send(attr.to_s + "=", value)
+    end
+
+    @type, @title = extract_type_and_title(type, title)
+
+    @type = munge_type_name(@type)
+
+    if self.class?
+      @title = :main if @title == ""
+      @title = munge_type_name(@title)
+    end
+
+    if params = attributes[:parameters]
+      extract_parameters(params)
+    end
+
+    if resource_type && resource_type.respond_to?(:deprecate_params)
+        resource_type.deprecate_params(title, attributes[:parameters])
+    end
+
+    tag(self.type)
+    tag(self.title) if valid_tag?(self.title)
+
+    @reference = self # for serialization compatibility with 0.25.x
+    if strict? and ! resource_type
+      if self.class?
+        raise ArgumentError, "Could not find declared class #{title}"
+      else
+        raise ArgumentError, "Invalid resource type #{type}"
+      end
+    end
+  end
+
+  def ref
+    to_s
+  end
+
+  # Find our resource.
+  def resolve
+    catalog ? catalog.resource(to_s) : nil
+  end
+
+  # The resource's type implementation
+  # @return [Puppet::Type, Puppet::Resource::Type]
+  # @api private
+  def resource_type
+    @rstype ||= case type
+    when "Class"; environment.known_resource_types.hostclass(title == :main ? "" : title)
+    when "Node"; environment.known_resource_types.node(title)
+    else
+      Puppet::Type.type(type) || environment.known_resource_types.definition(type)
+    end
+  end
+
+  # Set the resource's type implementation
+  # @param type [Puppet::Type, Puppet::Resource::Type]
+  # @api private
+  def resource_type=(type)
+    @rstype = type
+  end
+
+  def environment
+    @environment ||= if catalog
+                       catalog.environment_instance
+                     else
+                       Puppet.lookup(:current_environment) { Puppet::Node::Environment::NONE }
+                     end
+  end
+
+  def environment=(environment)
+    @environment = environment
+  end
+
+  # Produce a simple hash of our parameters.
+  def to_hash
+    parse_title.merge parameters
+  end
+
+  def to_s
+    "#{type}[#{title}]"
+  end
+
+  def uniqueness_key
+    # Temporary kludge to deal with inconsistant use patters
+    h = self.to_hash
+    h[namevar] ||= h[:name]
+    h[:name]   ||= h[namevar]
+    h.values_at(*key_attributes.sort_by { |k| k.to_s })
+  end
+
+  def key_attributes
+    resource_type.respond_to?(:key_attributes) ? resource_type.key_attributes : [:name]
+  end
+
+  # Convert our resource to Puppet code.
+  def to_manifest
+    # Collect list of attributes to align => and move ensure first
+    attr = parameters.keys
+    attr_max = attr.inject(0) { |max,k| k.to_s.length > max ? k.to_s.length : max }
+
+    attr.sort!
+    if attr.first != :ensure  && attr.include?(:ensure)
+      attr.delete(:ensure)
+      attr.unshift(:ensure)
+    end
+
+    attributes = attr.collect { |k|
+      v = parameters[k]
+      "  %-#{attr_max}s => %s,\n" % [k, Puppet::Parameter.format_value_for_display(v)]
+    }.join
+
+    "%s { '%s':\n%s}" % [self.type.to_s.downcase, self.title, attributes]
+  end
+
+  def to_ref
+    ref
+  end
+
+  # Convert our resource to a RAL resource instance.  Creates component
+  # instances for resource types that don't exist.
+  def to_ral
+    typeklass = Puppet::Type.type(self.type) || Puppet::Type.type(:component)
+    typeklass.new(self)
+  end
+
+  def name
+    # this is potential namespace conflict
+    # between the notion of an "indirector name"
+    # and a "resource name"
+    [ type, title ].join('/')
+  end
+
+  def missing_arguments
+    resource_type.arguments.select do |param, default|
+      the_param = parameters[param.to_sym]
+      the_param.nil? || the_param.value.nil? || the_param.value == :undef
+    end
+  end
+  private :missing_arguments
+
+  # Consult external data bindings for class parameter values which must be
+  # namespaced in the backend.
+  #
+  # Example:
+  #
+  #   class foo($port=0){ ... }
+  #
+  # We make a request to the backend for the key 'foo::port' not 'foo'
+  #
+  def lookup_external_default_for(param, scope)
+    # Only lookup parameters for host classes
+    return nil unless resource_type.type == :hostclass
+
+    name = "#{resource_type.name}::#{param}"
+    lookup_with_databinding(name, scope)
+  end
+
+  private :lookup_external_default_for
+
+  def lookup_with_databinding(name, scope)
+    begin
+      Puppet::DataBinding.indirection.find(
+        name,
+        :environment => scope.environment,
+        :variables => scope)
+    rescue Puppet::DataBinding::LookupError => e
+      raise Puppet::Error.new("Error from DataBinding '#{Puppet[:data_binding_terminus]}' while looking up '#{name}': #{e.message}", e)
+    end
+  end
+
+  private :lookup_with_databinding
+
+  def set_default_parameters(scope)
+    return [] unless resource_type and resource_type.respond_to?(:arguments)
+
+    unless is_a?(Puppet::Parser::Resource)
+      fail Puppet::DevError, "Cannot evaluate default parameters for #{self} - not a parser resource"
+    end
+
+    missing_arguments.collect do |param, default|
+      external_value = lookup_external_default_for(param, scope)
+
+      if external_value.nil? && default.nil?
+        next
+      elsif external_value.nil?
+        value = default.safeevaluate(scope)
+      else
+        value = external_value
+      end
+
+      self[param.to_sym] = value
+      param
+    end.compact
+  end
+
+  def copy_as_resource
+    result = Puppet::Resource.new(type, title)
+
+    result.file = self.file
+    result.line = self.line
+    result.exported = self.exported
+    result.virtual = self.virtual
+    result.tag(*self.tags)
+    result.environment = environment
+    result.instance_variable_set(:@rstype, resource_type)
+
+    future_parser_not_in_use = !Puppet.future_parser?(result.environment)
+
+    to_hash.each do |p, v|
+      if v.is_a?(Puppet::Resource)
+        v = Puppet::Resource.new(v.type, v.title)
+      elsif v.is_a?(Array)
+        # flatten resource references arrays
+        v = v.flatten if v.flatten.find { |av| av.is_a?(Puppet::Resource) }
+        v = v.collect do |av|
+          av = Puppet::Resource.new(av.type, av.title) if av.is_a?(Puppet::Resource)
+          av
+        end
+      end
+
+      if future_parser_not_in_use # !Puppet.future_parser?
+        # If the value is an array with only one value, then
+        # convert it to a single value.  This is largely so that
+        # the database interaction doesn't have to worry about
+        # whether it returns an array or a string.
+        #
+        # This behavior is not done in the future parser, but we can't issue a
+        # deprecation warning either since there isn't anything that a user can
+        # do about it.
+        result[p] = if v.is_a?(Array) and v.length == 1
+                      v[0]
+                    else
+                      v
+                    end
+      else
+        result[p] = v
+      end
+    end
+
+    result
+  end
+
+  def valid_parameter?(name)
+    resource_type.valid_parameter?(name)
+  end
+
+  # Verify that all required arguments are either present or
+  # have been provided with defaults.
+  # Must be called after 'set_default_parameters'.  We can't join the methods
+  # because Type#set_parameters needs specifically ordered behavior.
+  def validate_complete
+    return unless resource_type and resource_type.respond_to?(:arguments)
+
+    resource_type.arguments.each do |param, default|
+      param = param.to_sym
+      fail Puppet::ParseError, "Must pass #{param} to #{self}" unless parameters.include?(param)
+    end
+
+    # Perform optional type checking
+    if Puppet.future_parser?
+      # Perform type checking
+      arg_types = resource_type.argument_types
+      # Parameters is a map from name, to parameter, and the parameter again has name and value
+      parameters.each do |name, value|
+        next unless t = arg_types[name.to_s]  # untyped, and parameters are symbols here (aargh, strings in the type)
+        unless Puppet::Pops::Types::TypeCalculator.instance?(t, value.value)
+          inferred_type = Puppet::Pops::Types::TypeCalculator.infer_set(value.value)
+          actual = Puppet::Pops::Types::TypeCalculator.generalize!(inferred_type)
+          fail Puppet::ParseError, "Expected parameter '#{name}' of '#{self}' to have type #{t.to_s}, got #{actual.to_s}"
+        end
+      end
+    end
+  end
+
+  def validate_parameter(name)
+    raise ArgumentError, "Invalid parameter #{name}" unless valid_parameter?(name)
+  end
+
+  def prune_parameters(options = {})
+    properties = resource_type.properties.map(&:name)
+
+    dup.collect do |attribute, value|
+      if value.to_s.empty? or Array(value).empty?
+        delete(attribute)
+      elsif value.to_s == "absent" and attribute.to_s != "ensure"
+        delete(attribute)
+      end
+
+      parameters_to_include = options[:parameters_to_include] || []
+      delete(attribute) unless properties.include?(attribute) || parameters_to_include.include?(attribute)
+    end
+    self
+  end
+
+  private
+
+  # Produce a canonical method name.
+  def parameter_name(param)
+    param = param.to_s.downcase.to_sym
+    if param == :name and namevar
+      param = namevar
+    end
+    param
+  end
+
+  # The namevar for our resource type. If the type doesn't exist,
+  # always use :name.
+  def namevar
+    if builtin_type? and t = resource_type and t.key_attributes.length == 1
+      t.key_attributes.first
+    else
+      :name
+    end
+  end
+
+  def extract_parameters(params)
+    params.each do |param, value|
+      validate_parameter(param) if strict?
+      self[param] = value
+    end
+  end
+
+  def extract_type_and_title(argtype, argtitle)
+    if    (argtype.nil? || argtype == :component || argtype == :whit) &&
+           argtitle =~ /^([^\[\]]+)\[(.+)\]$/m                 then [ $1,                 $2            ]
+    elsif argtitle.nil? && argtype =~ /^([^\[\]]+)\[(.+)\]$/m  then [ $1,                 $2            ]
+    elsif argtitle                                             then [ argtype,            argtitle      ]
+    elsif argtype.is_a?(Puppet::Type)                          then [ argtype.class.name, argtype.title ]
+    elsif argtype.is_a?(Hash)                                  then
+      raise ArgumentError, "Puppet::Resource.new does not take a hash as the first argument. "+
+        "Did you mean (#{(argtype[:type] || argtype["type"]).inspect}, #{(argtype[:title] || argtype["title"]).inspect }) ?"
+    else raise ArgumentError, "No title provided and #{argtype.inspect} is not a valid resource reference"
+    end
+  end
+
+  def munge_type_name(value)
+    return :main if value == :main
+    return "Class" if value == "" or value.nil? or value.to_s.downcase == "component"
+
+    value.to_s.split("::").collect { |s| s.capitalize }.join("::")
+  end
+
+  def parse_title
+    h = {}
+    type = resource_type
+    if type.respond_to? :title_patterns
+      type.title_patterns.each { |regexp, symbols_and_lambdas|
+        if captures = regexp.match(title.to_s)
+          symbols_and_lambdas.zip(captures[1..-1]).each do |symbol_and_lambda,capture|
+            symbol, proc = symbol_and_lambda
+            # Many types pass "identity" as the proc; we might as well give
+            # them a shortcut to delivering that without the extra cost.
+            #
+            # Especially because the global type defines title_patterns and
+            # uses the identity patterns.
+            #
+            # This was worth about 8MB of memory allocation saved in my
+            # testing, so is worth the complexity for the API.
+            if proc then
+              h[symbol] = proc.call(capture)
+            else
+              h[symbol] = capture
+            end
+          end
+          return h
+        end
+      }
+      # If we've gotten this far, then none of the provided title patterns
+      # matched. Since there's no way to determine the title then the
+      # resource should fail here.
+      raise Puppet::Error, "No set of title patterns matched the title \"#{title}\"."
+    else
+      return { :name => title.to_s }
+    end
+  end
+
+  def parameters
+    # @parameters could have been loaded from YAML, causing it to be nil (by
+    # bypassing initialize).
+    @parameters ||= {}
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/resource/catalog.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/resource/catalog.rb
new file mode 100644
index 0000000..766c0ea
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/resource/catalog.rb
@@ -0,0 +1,562 @@
+require 'puppet/node'
+require 'puppet/indirector'
+require 'puppet/transaction'
+require 'puppet/util/pson'
+require 'puppet/util/tagging'
+require 'puppet/graph'
+
+# This class models a node catalog.  It is the thing meant to be passed
+# from server to client, and it contains all of the information in the
+# catalog, including the resources and the relationships between them.
+#
+# @api public
+
+class Puppet::Resource::Catalog < Puppet::Graph::SimpleGraph
+  class DuplicateResourceError < Puppet::Error
+    include Puppet::ExternalFileError
+  end
+
+  extend Puppet::Indirector
+  indirects :catalog, :terminus_setting => :catalog_terminus
+
+  include Puppet::Util::Tagging
+  extend Puppet::Util::Pson
+
+  # The host name this is a catalog for.
+  attr_accessor :name
+
+  # The catalog version.  Used for testing whether a catalog
+  # is up to date.
+  attr_accessor :version
+
+  # How long this catalog took to retrieve.  Used for reporting stats.
+  attr_accessor :retrieval_duration
+
+  # Whether this is a host catalog, which behaves very differently.
+  # In particular, reports are sent, graphs are made, and state is
+  # stored in the state database.  If this is set incorrectly, then you often
+  # end up in infinite loops, because catalogs are used to make things
+  # that the host catalog needs.
+  attr_accessor :host_config
+
+  # Whether this catalog was retrieved from the cache, which affects
+  # whether it is written back out again.
+  attr_accessor :from_cache
+
+  # Some metadata to help us compile and generally respond to the current state.
+  attr_accessor :client_version, :server_version
+
+  # A String representing the environment for this catalog
+  attr_accessor :environment
+
+  # The actual environment instance that was used during compilation
+  attr_accessor :environment_instance
+
+  # Add classes to our class list.
+  def add_class(*classes)
+    classes.each do |klass|
+      @classes << klass
+    end
+
+    # Add the class names as tags, too.
+    tag(*classes)
+  end
+
+  def title_key_for_ref( ref )
+    ref =~ /^([-\w:]+)\[(.*)\]$/m
+    [$1, $2]
+  end
+
+  def add_resource(*resources)
+    resources.each do |resource|
+      add_one_resource(resource)
+    end
+  end
+
+  # @param resource [A Resource] a resource in the catalog
+  # @return [A Resource, nil] the resource that contains the given resource
+  # @api public
+  def container_of(resource)
+    adjacent(resource, :direction => :in)[0]
+  end
+
+  def add_one_resource(resource)
+    title_key = title_key_for_ref(resource.ref)
+    if @resource_table[title_key]
+      fail_on_duplicate_type_and_title(resource, title_key)
+    end
+
+    add_resource_to_table(resource, title_key)
+    create_resource_aliases(resource)
+
+    resource.catalog = self if resource.respond_to?(:catalog=)
+    add_resource_to_graph(resource)
+  end
+  private :add_one_resource
+
+  def add_resource_to_table(resource, title_key)
+    @resource_table[title_key] = resource
+    @resources << title_key
+  end
+  private :add_resource_to_table
+
+  def add_resource_to_graph(resource)
+    add_vertex(resource)
+    @relationship_graph.add_vertex(resource) if @relationship_graph
+  end
+  private :add_resource_to_graph
+
+  def create_resource_aliases(resource)
+    if resource.respond_to?(:isomorphic?) and resource.isomorphic? and resource.name != resource.title
+      self.alias(resource, resource.uniqueness_key)
+    end
+  end
+  private :create_resource_aliases
+
+  # Create an alias for a resource.
+  def alias(resource, key)
+    resource.ref =~ /^(.+)\[/
+    class_name = $1 || resource.class.name
+
+    newref = [class_name, key].flatten
+
+    if key.is_a? String
+      ref_string = "#{class_name}[#{key}]"
+      return if ref_string == resource.ref
+    end
+
+    # LAK:NOTE It's important that we directly compare the references,
+    # because sometimes an alias is created before the resource is
+    # added to the catalog, so comparing inside the below if block
+    # isn't sufficient.
+    if existing = @resource_table[newref]
+      return if existing == resource
+      resource_declaration = " at #{resource.file}:#{resource.line}" if resource.file and resource.line
+      existing_declaration = " at #{existing.file}:#{existing.line}" if existing.file and existing.line
+      msg = "Cannot alias #{resource.ref} to #{key.inspect}#{resource_declaration}; resource #{newref.inspect} already declared#{existing_declaration}"
+      raise ArgumentError, msg
+    end
+    @resource_table[newref] = resource
+    @aliases[resource.ref] ||= []
+    @aliases[resource.ref] << newref
+  end
+
+  # Apply our catalog to the local host.
+  # @param options [Hash{Symbol => Object}] a hash of options
+  # @option options [Puppet::Transaction::Report] :report
+  #   The report object to log this transaction to. This is optional,
+  #   and the resulting transaction will create a report if not
+  #   supplied.
+  # @option options [Array[String]] :tags
+  #   Tags used to filter the transaction. If supplied then only
+  #   resources tagged with any of these tags will be evaluated.
+  # @option options [Boolean] :ignoreschedules
+  #   Ignore schedules when evaluating resources
+  # @option options [Boolean] :for_network_device
+  #   Whether this catalog is for a network device
+  #
+  # @return [Puppet::Transaction] the transaction created for this
+  #   application
+  #
+  # @api public
+  def apply(options = {})
+    Puppet::Util::Storage.load if host_config?
+
+    transaction = create_transaction(options)
+
+    begin
+      transaction.report.as_logging_destination do
+        transaction.evaluate
+      end
+    ensure
+      # Don't try to store state unless we're a host config
+      # too recursive.
+      Puppet::Util::Storage.store if host_config?
+    end
+
+    yield transaction if block_given?
+
+    transaction
+  end
+
+  # The relationship_graph form of the catalog. This contains all of the
+  # dependency edges that are used for determining order.
+  #
+  # @param given_prioritizer [Puppet::Graph::Prioritizer] The prioritization
+  #   strategy to use when constructing the relationship graph. Defaults the
+  #   being determined by the `ordering` setting.
+  # @return [Puppet::Graph::RelationshipGraph]
+  # @api public
+  def relationship_graph(given_prioritizer = nil)
+    if @relationship_graph.nil?
+      @relationship_graph = Puppet::Graph::RelationshipGraph.new(given_prioritizer || prioritizer)
+      @relationship_graph.populate_from(self)
+    end
+    @relationship_graph
+  end
+
+  def clear(remove_resources = true)
+    super()
+    # We have to do this so that the resources clean themselves up.
+    @resource_table.values.each { |resource| resource.remove } if remove_resources
+    @resource_table.clear
+    @resources = []
+
+    if @relationship_graph
+      @relationship_graph.clear
+      @relationship_graph = nil
+    end
+  end
+
+  def classes
+    @classes.dup
+  end
+
+  # Create a new resource and register it in the catalog.
+  def create_resource(type, options)
+    unless klass = Puppet::Type.type(type)
+      raise ArgumentError, "Unknown resource type #{type}"
+    end
+    return unless resource = klass.new(options)
+
+    add_resource(resource)
+    resource
+  end
+
+  # Make sure all of our resources are "finished".
+  def finalize
+    make_default_resources
+
+    @resource_table.values.each { |resource| resource.finish }
+
+    write_graph(:resources)
+  end
+
+  def host_config?
+    host_config
+  end
+
+  def initialize(name = nil, environment = Puppet::Node::Environment::NONE)
+    super()
+    @name = name
+    @classes = []
+    @resource_table = {}
+    @resources = []
+    @relationship_graph = nil
+
+    @host_config = true
+    @environment_instance = environment
+    @environment = environment.to_s
+
+    @aliases = {}
+
+    if block_given?
+      yield(self)
+      finalize
+    end
+  end
+
+  # Make the default objects necessary for function.
+  def make_default_resources
+    # We have to add the resources to the catalog, or else they won't get cleaned up after
+    # the transaction.
+
+    # First create the default scheduling objects
+    Puppet::Type.type(:schedule).mkdefaultschedules.each { |res| add_resource(res) unless resource(res.ref) }
+
+    # And filebuckets
+    if bucket = Puppet::Type.type(:filebucket).mkdefaultbucket
+      add_resource(bucket) unless resource(bucket.ref)
+    end
+  end
+
+  # Remove the resource from our catalog.  Notice that we also call
+  # 'remove' on the resource, at least until resource classes no longer maintain
+  # references to the resource instances.
+  def remove_resource(*resources)
+    resources.each do |resource|
+      title_key = title_key_for_ref(resource.ref)
+      @resource_table.delete(title_key)
+      if aliases = @aliases[resource.ref]
+        aliases.each { |res_alias| @resource_table.delete(res_alias) }
+        @aliases.delete(resource.ref)
+      end
+      remove_vertex!(resource) if vertex?(resource)
+      @relationship_graph.remove_vertex!(resource) if @relationship_graph and @relationship_graph.vertex?(resource)
+      @resources.delete(title_key)
+      resource.remove
+    end
+  end
+
+  # Look a resource up by its reference (e.g., File[/etc/passwd]).
+  def resource(type, title = nil)
+    # Always create a resource reference, so that it always
+    # canonicalizes how we are referring to them.
+    attributes = { :environment => environment_instance }
+    if title
+      res = Puppet::Resource.new(type, title, attributes)
+    else
+      # If they didn't provide a title, then we expect the first
+      # argument to be of the form 'Class[name]', which our
+      # Reference class canonicalizes for us.
+      res = Puppet::Resource.new(nil, type, attributes)
+    end
+    res.catalog = self
+    title_key      = [res.type, res.title.to_s]
+    uniqueness_key = [res.type, res.uniqueness_key].flatten
+    @resource_table[title_key] || @resource_table[uniqueness_key]
+  end
+
+  def resource_refs
+    resource_keys.collect{ |type, name| name.is_a?( String ) ? "#{type}[#{name}]" : nil}.compact
+  end
+
+  def resource_keys
+    @resource_table.keys
+  end
+
+  def resources
+    @resources.collect do |key|
+      @resource_table[key]
+    end
+  end
+
+  def self.from_data_hash(data)
+    result = new(data['name'], Puppet::Node::Environment::NONE)
+
+    if tags = data['tags']
+      result.tag(*tags)
+    end
+
+    if version = data['version']
+      result.version = version
+    end
+
+    if environment = data['environment']
+      result.environment = environment
+      result.environment_instance = Puppet::Node::Environment.remote(environment.to_sym)
+    end
+
+    if resources = data['resources']
+      result.add_resource(*resources.collect do |res|
+        Puppet::Resource.from_data_hash(res)
+      end)
+    end
+
+    if edges = data['edges']
+      edges.each do |edge_hash|
+        edge = Puppet::Relationship.from_data_hash(edge_hash)
+        unless source = result.resource(edge.source)
+          raise ArgumentError, "Could not intern from data: Could not find relationship source #{edge.source.inspect}"
+        end
+        edge.source = source
+
+        unless target = result.resource(edge.target)
+          raise ArgumentError, "Could not intern from data: Could not find relationship target #{edge.target.inspect}"
+        end
+        edge.target = target
+
+        result.add_edge(edge)
+      end
+    end
+
+    if classes = data['classes']
+      result.add_class(*classes)
+    end
+
+    result
+  end
+
+  def self.from_pson(data)
+    Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
+    self.from_data_hash(data)
+  end
+
+  def to_data_hash
+    {
+      'tags'      => tags,
+      'name'      => name,
+      'version'   => version,
+      'environment' => environment.to_s,
+      'resources' => @resources.collect { |v| @resource_table[v].to_pson_data_hash },
+      'edges'     => edges.   collect { |e| e.to_pson_data_hash },
+      'classes'   => classes
+    }
+  end
+
+  PSON.register_document_type('Catalog',self)
+  def to_pson_data_hash
+    {
+      'document_type' => 'Catalog',
+      'data'       => to_data_hash,
+      'metadata' => {
+        'api_version' => 1
+        }
+    }
+  end
+
+  def to_pson(*args)
+    to_pson_data_hash.to_pson(*args)
+  end
+
+  # Convert our catalog into a RAL catalog.
+  def to_ral
+    to_catalog :to_ral
+  end
+
+  # Convert our catalog into a catalog of Puppet::Resource instances.
+  def to_resource
+    to_catalog :to_resource
+  end
+
+  # filter out the catalog, applying +block+ to each resource.
+  # If the block result is false, the resource will
+  # be kept otherwise it will be skipped
+  def filter(&block)
+    # to_catalog must take place in a context where current_environment is set to the same env as the
+    # environment set in the catalog (if it is set)
+    # See PUP-3755
+    if environment_instance
+      Puppet.override({:current_environment => environment_instance}) do
+        to_catalog :to_resource, &block
+      end
+    else
+      # If catalog has no environment_instance, hope that the caller has made sure the context has the
+      # correct current_environment
+      to_catalog :to_resource, &block
+    end
+  end
+
+  # Store the classes in the classfile.
+  def write_class_file
+    ::File.open(Puppet[:classfile], "w") do |f|
+      f.puts classes.join("\n")
+    end
+  rescue => detail
+    Puppet.err "Could not create class file #{Puppet[:classfile]}: #{detail}"
+  end
+
+  # Store the list of resources we manage
+  def write_resource_file
+    ::File.open(Puppet[:resourcefile], "w") do |f|
+      to_print = resources.map do |resource|
+        next unless resource.managed?
+        if resource.name_var
+          "#{resource.type}[#{resource[resource.name_var]}]"
+        else
+          "#{resource.ref.downcase}"
+        end
+      end.compact
+      f.puts to_print.join("\n")
+    end
+  rescue => detail
+    Puppet.err "Could not create resource file #{Puppet[:resourcefile]}: #{detail}"
+  end
+
+  # Produce the graph files if requested.
+  def write_graph(name)
+    # We only want to graph the main host catalog.
+    return unless host_config?
+
+    super
+  end
+
+  private
+
+  def prioritizer
+    @prioritizer ||= case Puppet[:ordering]
+                     when "title-hash"
+                       Puppet::Graph::TitleHashPrioritizer.new
+                     when "manifest"
+                       Puppet::Graph::SequentialPrioritizer.new
+                     when "random"
+                       Puppet::Graph::RandomPrioritizer.new
+                     else
+                       raise Puppet::DevError, "Unknown ordering type #{Puppet[:ordering]}"
+                     end
+  end
+
+  def create_transaction(options)
+    transaction = Puppet::Transaction.new(self, options[:report], prioritizer)
+    transaction.tags = options[:tags] if options[:tags]
+    transaction.ignoreschedules = true if options[:ignoreschedules]
+    transaction.for_network_device = options[:network_device]
+
+    transaction
+  end
+
+  # Verify that the given resource isn't declared elsewhere.
+  def fail_on_duplicate_type_and_title(resource, title_key)
+    # Short-circuit the common case,
+    return unless existing_resource = @resource_table[title_key]
+
+    # If we've gotten this far, it's a real conflict
+    msg = "Duplicate declaration: #{resource.ref} is already declared"
+
+    msg << " in file #{existing_resource.file}:#{existing_resource.line}" if existing_resource.file and existing_resource.line
+
+    msg << "; cannot redeclare"
+
+    raise DuplicateResourceError.new(msg, resource.file, resource.line)
+  end
+
+  # An abstracted method for converting one catalog into another type of catalog.
+  # This pretty much just converts all of the resources from one class to another, using
+  # a conversion method.
+  def to_catalog(convert)
+    result = self.class.new(self.name, self.environment_instance)
+
+    result.version = self.version
+
+    map = {}
+    resources.each do |resource|
+      next if virtual_not_exported?(resource)
+      next if block_given? and yield resource
+
+      newres = resource.copy_as_resource
+      newres.catalog = result
+
+      if convert != :to_resource
+        newres = newres.to_ral
+      end
+
+      # We can't guarantee that resources don't munge their names
+      # (like files do with trailing slashes), so we have to keep track
+      # of what a resource got converted to.
+      map[resource.ref] = newres
+
+      result.add_resource newres
+    end
+
+    message = convert.to_s.gsub "_", " "
+    edges.each do |edge|
+      # Skip edges between virtual resources.
+      next if virtual_not_exported?(edge.source)
+      next if block_given? and yield edge.source
+
+      next if virtual_not_exported?(edge.target)
+      next if block_given? and yield edge.target
+
+      unless source = map[edge.source.ref]
+        raise Puppet::DevError, "Could not find resource #{edge.source.ref} when converting #{message} resources"
+      end
+
+      unless target = map[edge.target.ref]
+        raise Puppet::DevError, "Could not find resource #{edge.target.ref} when converting #{message} resources"
+      end
+
+      result.add_edge(source, target, edge.label)
+    end
+
+    map.clear
+
+    result.add_class(*self.classes)
+    result.tag(*self.tags)
+
+    result
+  end
+
+  def virtual_not_exported?(resource)
+    resource.virtual && !resource.exported
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/resource/status.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/resource/status.rb
new file mode 100644
index 0000000..c923c6f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/resource/status.rb
@@ -0,0 +1,155 @@
+require 'time'
+require 'puppet/network/format_support'
+
+module Puppet
+  class Resource
+    class Status
+      include Puppet::Util::Tagging
+      include Puppet::Util::Logging
+      include Puppet::Network::FormatSupport
+
+      attr_accessor :resource, :node, :file, :line, :current_values, :status, :evaluation_time
+
+      STATES = [:skipped, :failed, :failed_to_restart, :restarted, :changed, :out_of_sync, :scheduled]
+      attr_accessor *STATES
+
+      attr_reader :source_description, :containment_path,
+                  :default_log_level, :time, :resource, :change_count,
+                  :out_of_sync_count, :resource_type, :title
+
+      YAML_ATTRIBUTES = %w{@resource @file @line @evaluation_time @change_count
+                           @out_of_sync_count @tags @time @events @out_of_sync
+                           @changed @resource_type @title @skipped @failed
+                           @containment_path}.
+        map(&:to_sym)
+
+
+      def self.from_data_hash(data)
+        obj = self.allocate
+        obj.initialize_from_hash(data)
+        obj
+      end
+
+      def self.from_pson(data)
+        Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
+        self.from_data_hash(data)
+      end
+
+      # Provide a boolean method for each of the states.
+      STATES.each do |attr|
+        define_method("#{attr}?") do
+          !! send(attr)
+        end
+      end
+
+      def <<(event)
+        add_event(event)
+        self
+      end
+
+      def add_event(event)
+        @events << event
+        if event.status == 'failure'
+          self.failed = true
+        elsif event.status == 'success'
+          @change_count += 1
+          @changed = true
+        end
+        if event.status != 'audit'
+          @out_of_sync_count += 1
+          @out_of_sync = true
+        end
+      end
+
+      def events
+        @events
+      end
+
+      def failed_because(detail)
+        @real_resource.log_exception(detail, "Could not evaluate: #{detail}")
+        failed = true
+        # There's a contract (implicit unfortunately) that a status of failed
+        # will always be accompanied by an event with some explanatory power.  This
+        # is useful for reporting/diagnostics/etc.  So synthesize an event here
+        # with the exception detail as the message.
+        add_event(@real_resource.event(:name => :resource_error, :status => "failure", :message => detail.to_s))
+      end
+
+      def initialize(resource)
+        @real_resource = resource
+        @source_description = resource.path
+        @containment_path = resource.pathbuilder
+        @resource = resource.to_s
+        @change_count = 0
+        @out_of_sync_count = 0
+        @changed = false
+        @out_of_sync = false
+        @skipped = false
+        @failed = false
+
+        @file = resource.file
+        @line = resource.line
+
+        tag(*resource.tags)
+        @time = Time.now
+        @events = []
+        @resource_type = resource.type.to_s.capitalize
+        @title = resource.title
+      end
+
+      def initialize_from_hash(data)
+        @resource_type = data['resource_type']
+        @title = data['title']
+        @resource = data['resource']
+        @containment_path = data['containment_path']
+        @file = data['file']
+        @line = data['line']
+        @evaluation_time = data['evaluation_time']
+        @change_count = data['change_count']
+        @out_of_sync_count = data['out_of_sync_count']
+        @tags = Puppet::Util::TagSet.new(data['tags'])
+        @time = data['time']
+        @time = Time.parse(@time) if @time.is_a? String
+        @out_of_sync = data['out_of_sync']
+        @changed = data['changed']
+        @skipped = data['skipped']
+        @failed = data['failed']
+
+        @events = data['events'].map do |event|
+          Puppet::Transaction::Event.from_data_hash(event)
+        end
+      end
+
+      def to_data_hash
+        {
+          'title' => @title,
+          'file' => @file,
+          'line' => @line,
+          'resource' => @resource,
+          'resource_type' => @resource_type,
+          'containment_path' => @containment_path,
+          'evaluation_time' => @evaluation_time,
+          'tags' => @tags,
+          'time' => @time.iso8601(9),
+          'failed' => @failed,
+          'changed' => @changed,
+          'out_of_sync' => @out_of_sync,
+          'skipped' => @skipped,
+          'change_count' => @change_count,
+          'out_of_sync_count' => @out_of_sync_count,
+          'events' => @events,
+        }
+      end
+
+      def to_yaml_properties
+        YAML_ATTRIBUTES & super
+      end
+
+      private
+
+      def log_source
+        source_description
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/resource/type.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/resource/type.rb
new file mode 100644
index 0000000..acc7c63
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/resource/type.rb
@@ -0,0 +1,415 @@
+require 'puppet/parser'
+require 'puppet/util/warnings'
+require 'puppet/util/errors'
+require 'puppet/util/inline_docs'
+require 'puppet/parser/ast/leaf'
+require 'puppet/parser/ast/block_expression'
+require 'puppet/dsl'
+
+# Puppet::Resource::Type represents nodes, classes and defined types.
+#
+# It has a standard format for external consumption, usable from the
+# resource_type indirection via rest and the resource_type face. See the
+# {file:api_docs/http_resource_type.md#Schema resource type schema
+# description}.
+#
+# @api public
+class Puppet::Resource::Type
+  Puppet::ResourceType = self
+  include Puppet::Util::InlineDocs
+  include Puppet::Util::Warnings
+  include Puppet::Util::Errors
+
+  RESOURCE_KINDS = [:hostclass, :node, :definition]
+
+  # Map the names used in our documentation to the names used internally
+  RESOURCE_KINDS_TO_EXTERNAL_NAMES = {
+      :hostclass => "class",
+      :node => "node",
+      :definition => "defined_type",
+  }
+  RESOURCE_EXTERNAL_NAMES_TO_KINDS = RESOURCE_KINDS_TO_EXTERNAL_NAMES.invert
+
+  attr_accessor :file, :line, :doc, :code, :ruby_code, :parent, :resource_type_collection
+  attr_reader :namespace, :arguments, :behaves_like, :module_name
+
+  # Map from argument (aka parameter) names to Puppet Type
+  # @return [Hash<Symbol, Puppet::Pops::Types::PAnyType] map from name to type
+  #
+  attr_reader :argument_types
+
+  # This should probably be renamed to 'kind' eventually, in accordance with the changes
+  #  made for serialization and API usability (#14137).  At the moment that seems like
+  #  it would touch a whole lot of places in the code, though.  --cprice 2012-04-23
+  attr_reader :type
+
+  RESOURCE_KINDS.each do |t|
+    define_method("#{t}?") { self.type == t }
+  end
+
+  require 'puppet/indirector'
+  extend Puppet::Indirector
+  indirects :resource_type, :terminus_class => :parser
+
+  def self.from_data_hash(data)
+    name = data.delete('name') or raise ArgumentError, "Resource Type names must be specified"
+    kind = data.delete('kind') || "definition"
+
+    unless type = RESOURCE_EXTERNAL_NAMES_TO_KINDS[kind]
+      raise ArgumentError, "Unsupported resource kind '#{kind}'"
+    end
+
+    data = data.inject({}) { |result, ary| result[ary[0].intern] = ary[1]; result }
+
+    # External documentation uses "parameters" but the internal name
+    # is "arguments"
+    data[:arguments] = data.delete(:parameters)
+
+    new(type, name, data)
+  end
+
+  def self.from_pson(data)
+    Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
+    self.from_data_hash(data)
+  end
+
+  def to_data_hash
+    data = [:doc, :line, :file, :parent].inject({}) do |hash, param|
+      next hash unless (value = self.send(param)) and (value != "")
+      hash[param.to_s] = value
+      hash
+    end
+
+    # External documentation uses "parameters" but the internal name
+    # is "arguments"
+    # Dump any arguments as source
+    data['parameters'] = Hash[arguments.map do |k,v|
+                                [k, v.respond_to?(:source_text) ? v.source_text : v]
+                              end]
+    data['name'] = name
+
+    unless RESOURCE_KINDS_TO_EXTERNAL_NAMES.has_key?(type)
+      raise ArgumentError, "Unsupported resource kind '#{type}'"
+    end
+    data['kind'] = RESOURCE_KINDS_TO_EXTERNAL_NAMES[type]
+    data
+  end
+
+  # Are we a child of the passed class?  Do a recursive search up our
+  # parentage tree to figure it out.
+  def child_of?(klass)
+    return false unless parent
+
+    return(klass == parent_type ? true : parent_type.child_of?(klass))
+  end
+
+  # Now evaluate the code associated with this class or definition.
+  def evaluate_code(resource)
+
+    static_parent = evaluate_parent_type(resource)
+    scope = static_parent || resource.scope
+
+    scope = scope.newscope(:namespace => namespace, :source => self, :resource => resource) unless resource.title == :main
+    scope.compiler.add_class(name) unless definition?
+
+    set_resource_parameters(resource, scope)
+
+    resource.add_edge_to_stage
+
+    if code
+      if @match # Only bother setting up the ephemeral scope if there are match variables to add into it
+        begin
+          elevel = scope.ephemeral_level
+          scope.ephemeral_from(@match, file, line)
+          code.safeevaluate(scope)
+        ensure
+          scope.unset_ephemeral_var(elevel)
+        end
+      else
+        code.safeevaluate(scope)
+      end
+    end
+
+    evaluate_ruby_code(resource, scope) if ruby_code
+  end
+
+  def initialize(type, name, options = {})
+    @type = type.to_s.downcase.to_sym
+    raise ArgumentError, "Invalid resource supertype '#{type}'" unless RESOURCE_KINDS.include?(@type)
+
+    name = convert_from_ast(name) if name.is_a?(Puppet::Parser::AST::HostName)
+
+    set_name_and_namespace(name)
+
+    [:code, :doc, :line, :file, :parent].each do |param|
+      next unless value = options[param]
+      send(param.to_s + "=", value)
+    end
+
+    set_arguments(options[:arguments])
+    set_argument_types(options[:argument_types])
+
+    @match = nil
+
+    @module_name = options[:module_name]
+  end
+
+  # This is only used for node names, and really only when the node name
+  # is a regexp.
+  def match(string)
+    return string.to_s.downcase == name unless name_is_regex?
+
+    @match = @name.match(string)
+  end
+
+  # Add code from a new instance to our code.
+  def merge(other)
+    fail "#{name} is not a class; cannot add code to it" unless type == :hostclass
+    fail "#{other.name} is not a class; cannot add code from it" unless other.type == :hostclass
+    fail "Cannot have code outside of a class/node/define because 'freeze_main' is enabled" if name == "" and Puppet.settings[:freeze_main]
+
+    if parent and other.parent and parent != other.parent
+      fail "Cannot merge classes with different parent classes (#{name} => #{parent} vs. #{other.name} => #{other.parent})"
+    end
+
+    # We know they're either equal or only one is set, so keep whichever parent is specified.
+    self.parent ||= other.parent
+
+    if other.doc
+      self.doc ||= ""
+      self.doc += other.doc
+    end
+
+    # This might just be an empty, stub class.
+    return unless other.code
+
+    unless self.code
+      self.code = other.code
+      return
+    end
+
+    self.code = Puppet::Parser::ParserFactory.code_merger.concatenate([self, other])
+#    self.code = self.code.sequence_with(other.code)
+  end
+
+  # Make an instance of the resource type, and place it in the catalog
+  # if it isn't in the catalog already.  This is only possible for
+  # classes and nodes.  No parameters are be supplied--if this is a
+  # parameterized class, then all parameters take on their default
+  # values.
+  def ensure_in_catalog(scope, parameters=nil)
+    type == :definition and raise ArgumentError, "Cannot create resources for defined resource types"
+    resource_type = type == :hostclass ? :class : :node
+
+    # Do nothing if the resource already exists; this makes sure we don't
+    # get multiple copies of the class resource, which helps provide the
+    # singleton nature of classes.
+    # we should not do this for classes with parameters
+    # if parameters are passed, we should still try to create the resource
+    # even if it exists so that we can fail
+    # this prevents us from being able to combine param classes with include
+    if resource = scope.catalog.resource(resource_type, name) and !parameters
+      return resource
+    end
+    resource = Puppet::Parser::Resource.new(resource_type, name, :scope => scope, :source => self)
+    assign_parameter_values(parameters, resource)
+    instantiate_resource(scope, resource)
+    scope.compiler.add_resource(scope, resource)
+    resource
+  end
+
+  def instantiate_resource(scope, resource)
+    # Make sure our parent class has been evaluated, if we have one.
+    if parent && !scope.catalog.resource(resource.type, parent)
+      parent_type(scope).ensure_in_catalog(scope)
+    end
+
+    if ['Class', 'Node'].include? resource.type
+      scope.catalog.tag(*resource.tags)
+    end
+  end
+
+  def name
+    return @name unless @name.is_a?(Regexp)
+    @name.source.downcase.gsub(/[^-\w:.]/,'').sub(/^\.+/,'')
+  end
+
+  def name_is_regex?
+    @name.is_a?(Regexp)
+  end
+
+  def assign_parameter_values(parameters, resource)
+    return unless parameters
+
+    # It'd be nice to assign default parameter values here,
+    # but we can't because they often rely on local variables
+    # created during set_resource_parameters.
+    parameters.each do |name, value|
+      resource.set_parameter name, value
+    end
+  end
+
+  # MQR TODO:
+  #
+  # The change(s) introduced by the fix for #4270 are mostly silly & should be
+  # removed, though we didn't realize it at the time.  If it can be established/
+  # ensured that nodes never call parent_type and that resource_types are always
+  # (as they should be) members of exactly one resource_type_collection the
+  # following method could / should be replaced with:
+  #
+  # def parent_type
+  #   @parent_type ||= parent && (
+  #     resource_type_collection.find_or_load([name],parent,type.to_sym) ||
+  #     fail Puppet::ParseError, "Could not find parent resource type '#{parent}' of type #{type} in #{resource_type_collection.environment}"
+  #   )
+  # end
+  #
+  # ...and then the rest of the changes around passing in scope reverted.
+  #
+  def parent_type(scope = nil)
+    return nil unless parent
+
+    unless @parent_type
+      raise "Must pass scope to parent_type when called first time" unless scope
+      unless @parent_type = scope.environment.known_resource_types.send("find_#{type}", [name], parent)
+        fail Puppet::ParseError, "Could not find parent resource type '#{parent}' of type #{type} in #{scope.environment}"
+      end
+    end
+
+    @parent_type
+  end
+
+  # Set any arguments passed by the resource as variables in the scope.
+  def set_resource_parameters(resource, scope)
+    set = {}
+    resource.to_hash.each do |param, value|
+      param = param.to_sym
+      fail Puppet::ParseError, "#{resource.ref} does not accept attribute #{param}" unless valid_parameter?(param)
+
+      exceptwrap { scope[param.to_s] = value }
+
+      set[param] = true
+    end
+
+    if @type == :hostclass
+      scope["title"] = resource.title.to_s.downcase unless set.include? :title
+      scope["name"] =  resource.name.to_s.downcase  unless set.include? :name
+    else
+      scope["title"] = resource.title               unless set.include? :title
+      scope["name"] =  resource.name                unless set.include? :name
+    end
+    scope["module_name"] = module_name if module_name and ! set.include? :module_name
+
+    if caller_name = scope.parent_module_name and ! set.include?(:caller_module_name)
+      scope["caller_module_name"] = caller_name
+    end
+    scope.class_set(self.name,scope) if hostclass? or node?
+
+    # Evaluate the default parameters, now that all other variables are set
+    default_params = resource.set_default_parameters(scope)
+    default_params.each { |param| scope[param] = resource[param] }
+
+    # This has to come after the above parameters so that default values
+    # can use their values
+    resource.validate_complete
+  end
+
+  # Check whether a given argument is valid.
+  def valid_parameter?(param)
+    param = param.to_s
+
+    return true if param == "name"
+    return true if Puppet::Type.metaparam?(param)
+    return false unless defined?(@arguments)
+    return(arguments.include?(param) ? true : false)
+  end
+
+  def set_arguments(arguments)
+    @arguments = {}
+    return if arguments.nil?
+
+    arguments.each do |arg, default|
+      arg = arg.to_s
+      warn_if_metaparam(arg, default)
+      @arguments[arg] = default
+    end
+  end
+
+  # Sets the argument name to Puppet Type hash used for type checking.
+  # Names must correspond to available arguments (they must be defined first).
+  # Arguments not mentioned will not be type-checked. Only supported when parser == "future"
+  #
+  def set_argument_types(name_to_type_hash)
+    @argument_types = {}
+    # Stop here if not running under future parser, the rest requires pops to be initialized
+    # and that the type system is available
+    return unless Puppet.future_parser? && name_to_type_hash
+    name_to_type_hash.each do |name, t|
+      # catch internal errors
+      unless @arguments.include?(name)
+        raise Puppet::DevError, "Parameter '#{name}' is given a type, but is not a valid parameter."
+      end
+      unless t.is_a? Puppet::Pops::Types::PAnyType
+        raise Puppet::DevError, "Parameter '#{name}' is given a type that is not a Puppet Type, got #{t.class}"
+      end
+      @argument_types[name] = t
+    end
+  end
+
+  private
+
+  def convert_from_ast(name)
+    value = name.value
+    if value.is_a?(Puppet::Parser::AST::Regex)
+      name = value.value
+    else
+      name = value
+    end
+  end
+
+  def evaluate_parent_type(resource)
+    return unless klass = parent_type(resource.scope) and parent_resource = resource.scope.compiler.catalog.resource(:class, klass.name) || resource.scope.compiler.catalog.resource(:node, klass.name)
+    parent_resource.evaluate unless parent_resource.evaluated?
+    parent_scope(resource.scope, klass)
+  end
+
+  def evaluate_ruby_code(resource, scope)
+    Puppet::DSL::ResourceAPI.new(resource, scope, ruby_code).evaluate
+  end
+
+  # Split an fq name into a namespace and name
+  def namesplit(fullname)
+    ary = fullname.split("::")
+    n = ary.pop || ""
+    ns = ary.join("::")
+    return ns, n
+  end
+
+  def parent_scope(scope, klass)
+    scope.class_scope(klass) || raise(Puppet::DevError, "Could not find scope for #{klass.name}")
+  end
+
+  def set_name_and_namespace(name)
+    if name.is_a?(Regexp)
+      @name = name
+      @namespace = ""
+    else
+      @name = name.to_s.downcase
+
+      # Note we're doing something somewhat weird here -- we're setting
+      # the class's namespace to its fully qualified name.  This means
+      # anything inside that class starts looking in that namespace first.
+      @namespace, ignored_shortname = @type == :hostclass ? [@name, ''] : namesplit(@name)
+    end
+  end
+
+  def warn_if_metaparam(param, default)
+    return unless Puppet::Type.metaparamclass(param)
+
+    if default
+      warnonce "#{param} is a metaparam; this value will inherit to all contained resources in the #{self.name} definition"
+    else
+      raise Puppet::ParseError, "#{param} is a metaparameter; please choose another parameter name in the #{self.name} definition"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/resource/type_collection.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/resource/type_collection.rb
new file mode 100644
index 0000000..f5b0bda
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/resource/type_collection.rb
@@ -0,0 +1,230 @@
+require 'puppet/parser/type_loader'
+require 'puppet/util/file_watcher'
+require 'puppet/util/warnings'
+
+class Puppet::Resource::TypeCollection
+  attr_reader :environment
+  attr_accessor :parse_failed
+
+  include Puppet::Util::Warnings
+
+  def clear
+    @hostclasses.clear
+    @definitions.clear
+    @nodes.clear
+    @watched_files.clear
+    @notfound.clear
+  end
+
+  def initialize(env)
+    @environment = env
+    @hostclasses = {}
+    @definitions = {}
+    @nodes = {}
+    @notfound = {}
+
+    # So we can keep a list and match the first-defined regex
+    @node_list = []
+
+    @watched_files = Puppet::Util::FileWatcher.new
+  end
+
+  def import_ast(ast, modname)
+    ast.instantiate(modname).each do |instance|
+      add(instance)
+    end
+  end
+
+  def inspect
+    "TypeCollection" + { :hostclasses => @hostclasses.keys, :definitions => @definitions.keys, :nodes => @nodes.keys }.inspect
+  end
+
+  def <<(thing)
+    add(thing)
+    self
+  end
+
+  def add(instance)
+    if instance.type == :hostclass and other = @hostclasses[instance.name] and other.type == :hostclass
+      other.merge(instance)
+      return other
+    end
+    method = "add_#{instance.type}"
+    send(method, instance)
+    instance.resource_type_collection = self
+    instance
+  end
+
+  def add_hostclass(instance)
+    dupe_check(instance, @hostclasses) { |dupe| "Class '#{instance.name}' is already defined#{dupe.error_context}; cannot redefine" }
+    dupe_check(instance, @definitions) { |dupe| "Definition '#{instance.name}' is already defined#{dupe.error_context}; cannot be redefined as a class" }
+
+    @hostclasses[instance.name] = instance
+    instance
+  end
+
+  def hostclass(name)
+    @hostclasses[munge_name(name)]
+  end
+
+  def add_node(instance)
+    dupe_check(instance, @nodes) { |dupe| "Node '#{instance.name}' is already defined#{dupe.error_context}; cannot redefine" }
+
+    @node_list << instance
+    @nodes[instance.name] = instance
+    instance
+  end
+
+  def loader
+    @loader ||= Puppet::Parser::TypeLoader.new(environment)
+  end
+
+  def node(name)
+    name = munge_name(name)
+
+    if node = @nodes[name]
+      return node
+    end
+
+    @node_list.each do |node|
+      next unless node.name_is_regex?
+      return node if node.match(name)
+    end
+    nil
+  end
+
+  def node_exists?(name)
+    @nodes[munge_name(name)]
+  end
+
+  def nodes?
+    @nodes.length > 0
+  end
+
+  def add_definition(instance)
+    dupe_check(instance, @hostclasses) { |dupe| "'#{instance.name}' is already defined#{dupe.error_context} as a class; cannot redefine as a definition" }
+    dupe_check(instance, @definitions) { |dupe| "Definition '#{instance.name}' is already defined#{dupe.error_context}; cannot be redefined" }
+    @definitions[instance.name] = instance
+  end
+
+  def definition(name)
+    @definitions[munge_name(name)]
+  end
+
+  def find_node(namespaces, name)
+    @nodes[munge_name(name)]
+  end
+
+  def find_hostclass(namespaces, name, options = {})
+    find_or_load(namespaces, name, :hostclass, options)
+  end
+
+  def find_definition(namespaces, name)
+    find_or_load(namespaces, name, :definition)
+  end
+
+  [:hostclasses, :nodes, :definitions].each do |m|
+    define_method(m) do
+      instance_variable_get("@#{m}").dup
+    end
+  end
+
+  def require_reparse?
+    @parse_failed || stale?
+  end
+
+  def stale?
+    @watched_files.changed?
+  end
+
+  def version
+    if !defined?(@version)
+      if environment.config_version.nil? || environment.config_version == ""
+        @version = Time.now.to_i
+      else
+        @version = Puppet::Util::Execution.execute([environment.config_version]).strip
+      end
+    end
+
+    @version
+  rescue Puppet::ExecutionFailure => e
+    raise Puppet::ParseError, "Execution of config_version command `#{environment.config_version}` failed: #{e.message}", e.backtrace
+  end
+
+  def watch_file(filename)
+    @watched_files.watch(filename)
+  end
+
+  def watching_file?(filename)
+    @watched_files.watching?(filename)
+  end
+
+  private
+
+  # Return a list of all possible fully-qualified names that might be
+  # meant by the given name, in the context of namespaces.
+  def resolve_namespaces(namespaces, name)
+    name      = name.downcase
+    if name =~ /^::/
+      # name is explicitly fully qualified, so just return it, sans
+      # initial "::".
+      return [name.sub(/^::/, '')]
+    end
+    if name == ""
+      # The name "" has special meaning--it always refers to a "main"
+      # hostclass which contains all toplevel resources.
+      return [""]
+    end
+
+    namespaces = [namespaces] unless namespaces.is_a?(Array)
+    namespaces = namespaces.collect { |ns| ns.downcase }
+
+    result = []
+    namespaces.each do |namespace|
+      ary = namespace.split("::")
+
+      # Search each namespace nesting in innermost-to-outermost order.
+      while ary.length > 0
+        result << "#{ary.join("::")}::#{name}"
+        ary.pop
+      end
+
+      # Finally, search the toplevel namespace.
+      result << name
+    end
+
+    return result.uniq
+  end
+
+  # Resolve namespaces and find the given object.  Autoload it if
+  # necessary.
+  def find_or_load(namespaces, name, type, options = {})
+    searchspace = options[:assume_fqname] ? [name].flatten : resolve_namespaces(namespaces, name)
+    searchspace.each do |fqname|
+      result = send(type, fqname)
+      unless result
+        if @notfound[fqname] and Puppet[:ignoremissingtypes]
+          # do not try to autoload if we already tried and it wasn't conclusive
+          # as this is a time consuming operation. Warn the user.
+          debug_once "Not attempting to load #{type} #{fqname} as this object was missing during a prior compilation"
+        else
+          result = loader.try_load_fqname(type, fqname)
+          @notfound[fqname] = result.nil?
+        end
+      end
+      return result if result
+    end
+
+    return nil
+  end
+
+  def munge_name(name)
+    name.to_s.downcase
+  end
+
+  def dupe_check(instance, hash)
+    return unless dupe = hash[instance.name]
+    message = yield dupe
+    instance.fail Puppet::ParseError, message
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/resource/type_collection_helper.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/resource/type_collection_helper.rb
new file mode 100644
index 0000000..9dc3cce
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/resource/type_collection_helper.rb
@@ -0,0 +1,7 @@
+require 'puppet/resource/type_collection'
+
+module Puppet::Resource::TypeCollectionHelper
+  def known_resource_types
+    environment.known_resource_types
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/run.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/run.rb
new file mode 100644
index 0000000..b94fb77
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/run.rb
@@ -0,0 +1,109 @@
+require 'puppet/agent'
+require 'puppet/configurer'
+require 'puppet/indirector'
+
+# A basic class for running the agent.  Used by
+# `puppet kick` to kick off agents remotely.
+class Puppet::Run
+  extend Puppet::Indirector
+  indirects :run, :terminus_class => :local
+
+  attr_reader :status, :background, :options
+
+  def agent
+    # Forking disabled for "puppet kick" runs
+    Puppet::Agent.new(Puppet::Configurer, false)
+  end
+
+  def background?
+    background
+  end
+
+  def initialize(options = {})
+    if options.include?(:background)
+      @background = options[:background]
+      options.delete(:background)
+    end
+
+    valid_options = [:tags, :ignoreschedules, :pluginsync]
+    options.each do |key, value|
+      raise ArgumentError, "Run does not accept #{key}" unless valid_options.include?(key)
+    end
+
+    @options = options
+  end
+
+  def initialize_from_hash(hash)
+    @options = {}
+
+    hash['options'].each do |key, value|
+      @options[key.to_sym] = value
+    end
+
+    @background = hash['background']
+    @status = hash['status']
+  end
+
+  def log_run
+    msg = ""
+    msg += "triggered run" % if options[:tags]
+      msg += " with tags #{options[:tags].inspect}"
+    end
+
+    msg += " ignoring schedules" if options[:ignoreschedules]
+
+    Puppet.notice msg
+  end
+
+  def run
+    if agent.running?
+      @status = "running"
+      return self
+    end
+
+    log_run
+
+    if background?
+      Thread.new { agent.run(options) }
+    else
+      agent.run(options)
+    end
+
+    @status = "success"
+
+    self
+  end
+
+  def self.from_hash(hash)
+    obj = allocate
+    obj.initialize_from_hash(hash)
+    obj
+  end
+
+  def self.from_data_hash(data)
+    if data['options']
+      return from_hash(data)
+    end
+
+    options = { :pluginsync => Puppet[:pluginsync] }
+
+    data.each do |key, value|
+      options[key.to_sym] = value
+    end
+
+    new(options)
+  end
+
+  def self.from_pson(hash)
+    Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
+    self.from_data_hash(hash)
+  end
+
+  def to_data_hash
+    {
+      :options => @options,
+      :background => @background,
+      :status => @status
+    }
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/scheduler.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/scheduler.rb
new file mode 100644
index 0000000..e9697a1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/scheduler.rb
@@ -0,0 +1,16 @@
+module Puppet::Scheduler
+  require 'puppet/scheduler/job'
+  require 'puppet/scheduler/splay_job'
+  require 'puppet/scheduler/scheduler'
+  require 'puppet/scheduler/timer'
+
+  module_function
+
+  def create_job(interval, splay=false, splay_limit=0, &block)
+    if splay
+      Puppet::Scheduler::SplayJob.new(interval, splay_limit, &block)
+    else
+      Puppet::Scheduler::Job.new(interval, &block)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/scheduler/job.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/scheduler/job.rb
new file mode 100644
index 0000000..a29a1c8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/scheduler/job.rb
@@ -0,0 +1,53 @@
+module Puppet::Scheduler
+  class Job
+    attr_reader :run_interval
+    attr_accessor :last_run
+    attr_accessor :start_time
+
+    def initialize(run_interval, &block)
+      self.run_interval = run_interval
+      @last_run = nil
+      @run_proc = block
+      @enabled = true
+    end
+
+    def run_interval=(interval)
+      @run_interval = [interval, 0].max
+    end
+
+    def ready?(time)
+      if @last_run
+        @last_run + @run_interval <= time
+      else
+        true
+      end
+    end
+
+    def enabled?
+      @enabled
+    end
+
+    def enable
+      @enabled = true
+    end
+
+    def disable
+      @enabled = false
+    end
+
+    def interval_to_next_from(time)
+      if ready?(time)
+        0
+      else
+        @run_interval - (time - @last_run)
+      end
+    end
+
+    def run(now)
+      @last_run = now
+      if @run_proc
+        @run_proc.call(self)
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/scheduler/scheduler.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/scheduler/scheduler.rb
new file mode 100644
index 0000000..2057669
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/scheduler/scheduler.rb
@@ -0,0 +1,44 @@
+module Puppet::Scheduler
+  class Scheduler
+    def initialize(timer=Puppet::Scheduler::Timer.new)
+      @timer = timer
+    end
+
+    def run_loop(jobs)
+      mark_start_times(jobs, @timer.now)
+      while not enabled(jobs).empty?
+        @timer.wait_for(min_interval_to_next_run_from(jobs, @timer.now))
+        run_ready(jobs, @timer.now)
+      end
+    end
+
+    private
+
+    def enabled(jobs)
+      jobs.select(&:enabled?)
+    end
+
+    def mark_start_times(jobs, start_time)
+      jobs.each do |job|
+        job.start_time = start_time
+      end
+    end
+
+    def min_interval_to_next_run_from(jobs, from_time)
+      enabled(jobs).map do |j|
+        j.interval_to_next_from(from_time)
+      end.min
+    end
+
+    def run_ready(jobs, at_time)
+      enabled(jobs).each do |j|
+        # This check intentionally happens right before each run,
+        # instead of filtering on ready schedulers, since one may adjust
+        # the readiness of a later one
+        if j.ready?(at_time)
+          j.run(at_time)
+        end
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/scheduler/splay_job.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/scheduler/splay_job.rb
new file mode 100644
index 0000000..1e0c116
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/scheduler/splay_job.rb
@@ -0,0 +1,32 @@
+module Puppet::Scheduler
+  class SplayJob < Job
+    attr_reader :splay
+
+    def initialize(run_interval, splay_limit, &block)
+      @splay = calculate_splay(splay_limit)
+      super(run_interval, &block)
+    end
+
+    def interval_to_next_from(time)
+      if last_run
+        super
+      else
+        (start_time + splay) - time
+      end
+    end
+
+    def ready?(time)
+      if last_run
+        super
+      else
+        start_time + splay <= time
+      end
+    end
+
+    private
+
+    def calculate_splay(limit)
+      rand(limit + 1)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/scheduler/timer.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/scheduler/timer.rb
new file mode 100644
index 0000000..bbb2065
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/scheduler/timer.rb
@@ -0,0 +1,13 @@
+module Puppet::Scheduler
+  class Timer
+    def wait_for(seconds)
+      if seconds > 0
+        sleep(seconds)
+      end
+    end
+
+    def now
+      Time.now
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings.rb
new file mode 100644
index 0000000..a4d843f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings.rb
@@ -0,0 +1,1442 @@
+require 'puppet'
+require 'getoptlong'
+require 'puppet/util/watched_file'
+require 'puppet/util/command_line/puppet_option_parser'
+require 'forwardable'
+
+# The class for handling configuration files.
+class Puppet::Settings
+  extend Forwardable
+  include Enumerable
+
+  require 'puppet/settings/errors'
+  require 'puppet/settings/base_setting'
+  require 'puppet/settings/string_setting'
+  require 'puppet/settings/enum_setting'
+  require 'puppet/settings/array_setting'
+  require 'puppet/settings/file_setting'
+  require 'puppet/settings/directory_setting'
+  require 'puppet/settings/file_or_directory_setting'
+  require 'puppet/settings/path_setting'
+  require 'puppet/settings/boolean_setting'
+  require 'puppet/settings/terminus_setting'
+  require 'puppet/settings/duration_setting'
+  require 'puppet/settings/ttl_setting'
+  require 'puppet/settings/priority_setting'
+  require 'puppet/settings/autosign_setting'
+  require 'puppet/settings/config_file'
+  require 'puppet/settings/value_translator'
+  require 'puppet/settings/environment_conf'
+
+  # local reference for convenience
+  PuppetOptionParser = Puppet::Util::CommandLine::PuppetOptionParser
+
+  attr_accessor :files
+  attr_reader :timer
+
+  # These are the settings that every app is required to specify; there are reasonable defaults defined in application.rb.
+  REQUIRED_APP_SETTINGS = [:logdir, :confdir, :vardir]
+
+  # This method is intended for puppet internal use only; it is a convenience method that
+  # returns reasonable application default settings values for a given run_mode.
+  def self.app_defaults_for_run_mode(run_mode)
+    {
+        :name     => run_mode.to_s,
+        :run_mode => run_mode.name,
+        :confdir  => run_mode.conf_dir,
+        :vardir   => run_mode.var_dir,
+        :rundir   => run_mode.run_dir,
+        :logdir   => run_mode.log_dir,
+    }
+  end
+
+  def self.default_certname()
+    hostname = hostname_fact
+    domain = domain_fact
+    if domain and domain != ""
+      fqdn = [hostname, domain].join(".")
+    else
+      fqdn = hostname
+    end
+    fqdn.to_s.gsub(/\.$/, '')
+  end
+
+  def self.hostname_fact()
+    Facter["hostname"].value
+  end
+
+  def self.domain_fact()
+    Facter["domain"].value
+  end
+
+  def self.default_config_file_name
+    "puppet.conf"
+  end
+
+  # Create a new collection of config settings.
+  def initialize
+    @config = {}
+    @shortnames = {}
+
+    @created = []
+
+    # Keep track of set values.
+    @value_sets = {
+      :cli => Values.new(:cli, @config),
+      :memory => Values.new(:memory, @config),
+      :application_defaults => Values.new(:application_defaults, @config),
+      :overridden_defaults => Values.new(:overridden_defaults, @config),
+    }
+    @configuration_file = nil
+
+    # And keep a per-environment cache
+    @cache = Hash.new { |hash, key| hash[key] = {} }
+    @values = Hash.new { |hash, key| hash[key] = {} }
+
+    # The list of sections we've used.
+    @used = []
+
+    @hooks_to_call_on_application_initialization = []
+    @deprecated_setting_names = []
+    @deprecated_settings_that_have_been_configured = []
+
+    @translate = Puppet::Settings::ValueTranslator.new
+    @config_file_parser = Puppet::Settings::ConfigFile.new(@translate)
+  end
+
+  # @param name [Symbol] The name of the setting to fetch
+  # @return [Puppet::Settings::BaseSetting] The setting object
+  def setting(name)
+    @config[name]
+  end
+
+  # Retrieve a config value
+  # @param param [Symbol] the name of the setting
+  # @return [Object] the value of the setting
+  # @api private
+  def [](param)
+    if @deprecated_setting_names.include?(param)
+      issue_deprecation_warning(setting(param), "Accessing '#{param}' as a setting is deprecated.")
+    end
+    value(param)
+  end
+
+  # Set a config value.  This doesn't set the defaults, it sets the value itself.
+  # @param param [Symbol] the name of the setting
+  # @param value [Object] the new value of the setting
+  # @api private
+  def []=(param, value)
+    if @deprecated_setting_names.include?(param)
+      issue_deprecation_warning(setting(param), "Modifying '#{param}' as a setting is deprecated.")
+    end
+    @value_sets[:memory].set(param, value)
+    unsafe_flush_cache
+  end
+
+  # Create a new default value for the given setting. The default overrides are
+  # higher precedence than the defaults given in defaults.rb, but lower
+  # precedence than any other values for the setting. This allows one setting
+  # `a` to change the default of setting `b`, but still allow a user to provide
+  # a value for setting `b`.
+  #
+  # @param param [Symbol] the name of the setting
+  # @param value [Object] the new default value for the setting
+  # @api private
+  def override_default(param, value)
+    @value_sets[:overridden_defaults].set(param, value)
+    unsafe_flush_cache
+  end
+
+  # Generate the list of valid arguments, in a format that GetoptLong can
+  # understand, and add them to the passed option list.
+  def addargs(options)
+    # Add all of the settings as valid options.
+    self.each { |name, setting|
+      setting.getopt_args.each { |args| options << args }
+    }
+
+    options
+  end
+
+  # Generate the list of valid arguments, in a format that OptionParser can
+  # understand, and add them to the passed option list.
+  def optparse_addargs(options)
+    # Add all of the settings as valid options.
+    self.each { |name, setting|
+      options << setting.optparse_args
+    }
+
+    options
+  end
+
+  # Is our setting a boolean setting?
+  def boolean?(param)
+    param = param.to_sym
+    @config.include?(param) and @config[param].kind_of?(BooleanSetting)
+  end
+
+  # Remove all set values, potentially skipping cli values.
+  def clear
+    unsafe_clear
+  end
+
+  # Remove all set values, potentially skipping cli values.
+  def unsafe_clear(clear_cli = true, clear_application_defaults = false)
+    if clear_application_defaults
+      @value_sets[:application_defaults] = Values.new(:application_defaults, @config)
+      @app_defaults_initialized = false
+    end
+
+    if clear_cli
+      @value_sets[:cli] = Values.new(:cli, @config)
+
+      # Only clear the 'used' values if we were explicitly asked to clear out
+      #  :cli values; otherwise, it may be just a config file reparse,
+      #  and we want to retain this cli values.
+      @used = []
+    end
+
+    @value_sets[:memory] = Values.new(:memory, @config)
+    @value_sets[:overridden_defaults] = Values.new(:overridden_defaults, @config)
+
+    @deprecated_settings_that_have_been_configured.clear
+    @values.clear
+    @cache.clear
+  end
+  private :unsafe_clear
+
+  # Clears all cached settings for a particular environment to ensure
+  # that changes to environment.conf are reflected in the settings if
+  # the environment timeout has expired.
+  #
+  # param [String, Symbol] environment the  name of environment to clear settings for
+  #
+  # @api private
+  def clear_environment_settings(environment)
+
+    if environment.nil?
+      return
+    end
+
+    @cache[environment.to_sym].clear
+    @values[environment.to_sym] = {}
+  end
+
+  # Clear @cache, @used and the Environment.
+  #
+  # Whenever an object is returned by Settings, a copy is stored in @cache.
+  # As long as Setting attributes that determine the content of returned
+  # objects remain unchanged, Settings can keep returning objects from @cache
+  # without re-fetching or re-generating them.
+  #
+  # Whenever a Settings attribute changes, such as @values or @preferred_run_mode,
+  # this method must be called to clear out the caches so that updated
+  # objects will be returned.
+  def flush_cache
+    unsafe_flush_cache
+  end
+
+  def unsafe_flush_cache
+    clearused
+
+    # Clear the list of environments, because they cache, at least, the module path.
+    # We *could* preferentially just clear them if the modulepath is changed,
+    # but we don't really know if, say, the vardir is changed and the modulepath
+    # is defined relative to it. We need the defined?(stuff) because of loading
+    # order issues.
+    Puppet::Node::Environment.clear if defined?(Puppet::Node) and defined?(Puppet::Node::Environment)
+  end
+  private :unsafe_flush_cache
+
+  def clearused
+    @cache.clear
+    @used = []
+  end
+
+  def global_defaults_initialized?()
+    @global_defaults_initialized
+  end
+
+  def initialize_global_settings(args = [])
+    raise Puppet::DevError, "Attempting to initialize global default settings more than once!" if global_defaults_initialized?
+
+    # The first two phases of the lifecycle of a puppet application are:
+    # 1) Parse the command line options and handle any of them that are
+    #    registered, defined "global" puppet settings (mostly from defaults.rb).
+    # 2) Parse the puppet config file(s).
+
+    parse_global_options(args)
+    parse_config_files
+
+    @global_defaults_initialized = true
+  end
+
+  # This method is called during application bootstrapping.  It is responsible for parsing all of the
+  # command line options and initializing the settings accordingly.
+  #
+  # It will ignore options that are not defined in the global puppet settings list, because they may
+  # be valid options for the specific application that we are about to launch... however, at this point
+  # in the bootstrapping lifecycle, we don't yet know what that application is.
+  def parse_global_options(args)
+    # Create an option parser
+    option_parser = PuppetOptionParser.new
+    option_parser.ignore_invalid_options = true
+
+    # Add all global options to it.
+    self.optparse_addargs([]).each do |option|
+      option_parser.on(*option) do |arg|
+        opt, val = Puppet::Settings.clean_opt(option[0], arg)
+        handlearg(opt, val)
+      end
+    end
+
+    option_parser.on('--run_mode',
+                     "The effective 'run mode' of the application: master, agent, or user.",
+                     :REQUIRED) do |arg|
+      Puppet.settings.preferred_run_mode = arg
+    end
+
+    option_parser.parse(args)
+
+    # remove run_mode options from the arguments so that later parses don't think
+    # it is an unknown option.
+    while option_index = args.index('--run_mode') do
+      args.delete_at option_index
+      args.delete_at option_index
+    end
+    args.reject! { |arg| arg.start_with? '--run_mode=' }
+  end
+  private :parse_global_options
+
+  # A utility method (public, is used by application.rb and perhaps elsewhere) that munges a command-line
+  # option string into the format that Puppet.settings expects.  (This mostly has to deal with handling the
+  # "no-" prefix on flag/boolean options).
+  #
+  # @param [String] opt the command line option that we are munging
+  # @param [String, TrueClass, FalseClass] val the value for the setting (as determined by the OptionParser)
+  def self.clean_opt(opt, val)
+    # rewrite --[no-]option to --no-option if that's what was given
+    if opt =~ /\[no-\]/ and !val
+      opt = opt.gsub(/\[no-\]/,'no-')
+    end
+    # otherwise remove the [no-] prefix to not confuse everybody
+    opt = opt.gsub(/\[no-\]/, '')
+    [opt, val]
+  end
+
+
+  def app_defaults_initialized?
+    @app_defaults_initialized
+  end
+
+  def initialize_app_defaults(app_defaults)
+    REQUIRED_APP_SETTINGS.each do |key|
+      raise SettingsError, "missing required app default setting '#{key}'" unless app_defaults.has_key?(key)
+    end
+
+    app_defaults.each do |key, value|
+      if key == :run_mode
+        self.preferred_run_mode = value
+      else
+        @value_sets[:application_defaults].set(key, value)
+        unsafe_flush_cache
+      end
+    end
+    apply_metadata
+    call_hooks_deferred_to_application_initialization
+    issue_deprecations
+
+    @app_defaults_initialized = true
+  end
+
+  def call_hooks_deferred_to_application_initialization(options = {})
+    @hooks_to_call_on_application_initialization.each do |setting|
+      begin
+        setting.handle(self.value(setting.name))
+      rescue InterpolationError => err
+        raise InterpolationError, err, err.backtrace unless options[:ignore_interpolation_dependency_errors]
+        #swallow. We're not concerned if we can't call hooks because dependencies don't exist yet
+        #we'll get another chance after application defaults are initialized
+      end
+    end
+  end
+  private :call_hooks_deferred_to_application_initialization
+
+  # Return a value's description.
+  def description(name)
+    if obj = @config[name.to_sym]
+      obj.desc
+    else
+      nil
+    end
+  end
+
+  def_delegator :@config, :each
+
+  # Iterate over each section name.
+  def eachsection
+    yielded = []
+    @config.each do |name, object|
+      section = object.section
+      unless yielded.include? section
+        yield section
+        yielded << section
+      end
+    end
+  end
+
+  # Return an object by name.
+  def setting(param)
+    param = param.to_sym
+    @config[param]
+  end
+
+  # Handle a command-line argument.
+  def handlearg(opt, value = nil)
+    @cache.clear
+
+    if value.is_a?(FalseClass)
+      value = "false"
+    elsif value.is_a?(TrueClass)
+      value = "true"
+    end
+
+    value &&= @translate[value]
+    str = opt.sub(/^--/,'')
+
+    bool = true
+    newstr = str.sub(/^no-/, '')
+    if newstr != str
+      str = newstr
+      bool = false
+    end
+    str = str.intern
+
+    if @config[str].is_a?(Puppet::Settings::BooleanSetting)
+      if value == "" or value.nil?
+        value = bool
+      end
+    end
+
+    if s = @config[str]
+      @deprecated_settings_that_have_been_configured << s if s.completely_deprecated?
+    end
+
+    @value_sets[:cli].set(str, value)
+    unsafe_flush_cache
+  end
+
+  def include?(name)
+    name = name.intern if name.is_a? String
+    @config.include?(name)
+  end
+
+  # check to see if a short name is already defined
+  def shortinclude?(short)
+    short = short.intern if name.is_a? String
+    @shortnames.include?(short)
+  end
+
+  # Prints the contents of a config file with the available config settings, or it
+  # prints a single value of a config setting.
+  def print_config_options
+    env = value(:environment)
+    val = value(:configprint)
+    if val == "all"
+      hash = {}
+      each do |name, obj|
+        val = value(name,env)
+        val = val.inspect if val == ""
+        hash[name] = val
+      end
+      hash.sort { |a,b| a[0].to_s <=> b[0].to_s }.each do |name, val|
+        puts "#{name} = #{val}"
+      end
+    else
+      val.split(/\s*,\s*/).sort.each do |v|
+        if include?(v)
+          #if there is only one value, just print it for back compatibility
+          if v == val
+            puts value(val,env)
+            break
+          end
+          puts "#{v} = #{value(v,env)}"
+        else
+          puts "invalid setting: #{v}"
+          return false
+        end
+      end
+    end
+    true
+  end
+
+  def generate_config
+    puts to_config
+    true
+  end
+
+  def generate_manifest
+    puts to_manifest
+    true
+  end
+
+  def print_configs
+    return print_config_options if value(:configprint) != ""
+    return generate_config if value(:genconfig)
+    generate_manifest if value(:genmanifest)
+  end
+
+  def print_configs?
+    (value(:configprint) != "" || value(:genconfig) || value(:genmanifest)) && true
+  end
+
+  # Return a given object's file metadata.
+  def metadata(param)
+    if obj = @config[param.to_sym] and obj.is_a?(FileSetting)
+      {
+        :owner => obj.owner,
+        :group => obj.group,
+        :mode => obj.mode
+      }.delete_if { |key, value| value.nil? }
+    else
+      nil
+    end
+  end
+
+  # Make a directory with the appropriate user, group, and mode
+  def mkdir(default)
+    obj = get_config_file_default(default)
+
+    Puppet::Util::SUIDManager.asuser(obj.owner, obj.group) do
+      mode = obj.mode || 0750
+      Dir.mkdir(obj.value, mode)
+    end
+  end
+
+  # The currently configured run mode that is preferred for constructing the application configuration.
+  def preferred_run_mode
+    @preferred_run_mode_name || :user
+  end
+
+  # PRIVATE!  This only exists because we need a hook to validate the run mode when it's being set, and
+  #  it should never, ever, ever, ever be called from outside of this file.
+  # This method is also called when --run_mode MODE is used on the command line to set the default
+  #
+  # @param mode [String|Symbol] the name of the mode to have in effect
+  # @api private
+  def preferred_run_mode=(mode)
+    mode = mode.to_s.downcase.intern
+    raise ValidationError, "Invalid run mode '#{mode}'" unless [:master, :agent, :user].include?(mode)
+    @preferred_run_mode_name = mode
+    # Changing the run mode has far-reaching consequences. Flush any cached
+    # settings so they will be re-generated.
+    flush_cache
+    mode
+  end
+
+  # Return all of the settings associated with a given section.
+  def params(section = nil)
+    if section
+      section = section.intern if section.is_a? String
+      @config.find_all { |name, obj|
+        obj.section == section
+      }.collect { |name, obj|
+        name
+      }
+    else
+      @config.keys
+    end
+  end
+
+  def parse_config(text, file = "text")
+    begin
+      data = @config_file_parser.parse_file(file, text)
+    rescue => detail
+      Puppet.log_exception(detail, "Could not parse #{file}: #{detail}")
+      return
+    end
+
+    # If we get here and don't have any data, we just return and don't muck with the current state of the world.
+    return if data.nil?
+
+    # If we get here then we have some data, so we need to clear out any
+    # previous settings that may have come from config files.
+    unsafe_clear(false, false)
+
+    record_deprecations_from_puppet_conf(data)
+
+    # And now we can repopulate with the values from our last parsing of the config files.
+    @configuration_file = data
+
+    # Determine our environment, if we have one.
+    if @config[:environment]
+      env = self.value(:environment).to_sym
+    else
+      env = "none"
+    end
+
+    # Call any hooks we should be calling.
+    value_sets = value_sets_for(env, preferred_run_mode)
+    @config.values.select(&:has_hook?).each do |setting|
+      value_sets.each do |source|
+        if source.include?(setting.name)
+          # We still have to use value to retrieve the value, since
+          # we want the fully interpolated value, not $vardir/lib or whatever.
+          # This results in extra work, but so few of the settings
+          # will have associated hooks that it ends up being less work this
+          # way overall.
+          if setting.call_hook_on_initialize?
+            @hooks_to_call_on_application_initialization << setting
+          else
+            setting.handle(ChainedValues.new(
+              preferred_run_mode,
+              env,
+              value_sets,
+              @config).interpolate(setting.name))
+          end
+          break
+        end
+      end
+    end
+
+    call_hooks_deferred_to_application_initialization :ignore_interpolation_dependency_errors => true
+    apply_metadata
+  end
+
+  # Parse the configuration file.  Just provides thread safety.
+  def parse_config_files
+    file = which_configuration_file
+    if Puppet::FileSystem.exist?(file)
+      begin
+        text = read_file(file)
+      rescue => detail
+        Puppet.log_exception(detail, "Could not load #{file}: #{detail}")
+        return
+      end
+    else
+      return
+    end
+
+    parse_config(text, file)
+  end
+  private :parse_config_files
+
+  def main_config_file
+    if explicit_config_file?
+      return self[:config]
+    else
+      return File.join(Puppet::Util::RunMode[:master].conf_dir, config_file_name)
+    end
+  end
+  private :main_config_file
+
+  def user_config_file
+    return File.join(Puppet::Util::RunMode[:user].conf_dir, config_file_name)
+  end
+  private :user_config_file
+
+  # This method is here to get around some life-cycle issues.  We need to be
+  # able to determine the config file name before the settings / defaults are
+  # fully loaded.  However, we also need to respect any overrides of this value
+  # that the user may have specified on the command line.
+  #
+  # The easiest way to do this is to attempt to read the setting, and if we
+  # catch an error (meaning that it hasn't been set yet), we'll fall back to
+  # the default value.
+  def config_file_name
+    begin
+      return self[:config_file_name] if self[:config_file_name]
+    rescue SettingsError
+      # This just means that the setting wasn't explicitly set on the command line, so we will ignore it and
+      #  fall through to the default name.
+    end
+    return self.class.default_config_file_name
+  end
+  private :config_file_name
+
+  def apply_metadata
+    # We have to do it in the reverse of the search path,
+    # because multiple sections could set the same value
+    # and I'm too lazy to only set the metadata once.
+    if @configuration_file
+      searchpath.reverse.each do |source|
+        source = preferred_run_mode if source == :run_mode
+        if section = @configuration_file.sections[source]
+          apply_metadata_from_section(section)
+        end
+      end
+    end
+  end
+  private :apply_metadata
+
+  def apply_metadata_from_section(section)
+    section.settings.each do |setting|
+      if setting.has_metadata? && type = @config[setting.name]
+        type.set_meta(setting.meta)
+      end
+    end
+  end
+
+  SETTING_TYPES = {
+      :string     => StringSetting,
+      :file       => FileSetting,
+      :directory  => DirectorySetting,
+      :file_or_directory => FileOrDirectorySetting,
+      :path       => PathSetting,
+      :boolean    => BooleanSetting,
+      :terminus   => TerminusSetting,
+      :duration   => DurationSetting,
+      :ttl        => TTLSetting,
+      :array      => ArraySetting,
+      :enum       => EnumSetting,
+      :priority   => PrioritySetting,
+      :autosign   => AutosignSetting,
+  }
+
+  # Create a new setting.  The value is passed in because it's used to determine
+  # what kind of setting we're creating, but the value itself might be either
+  # a default or a value, so we can't actually assign it.
+  #
+  # See #define_settings for documentation on the legal values for the ":type" option.
+  def newsetting(hash)
+    klass = nil
+    hash[:section] = hash[:section].to_sym if hash[:section]
+
+    if type = hash[:type]
+      unless klass = SETTING_TYPES[type]
+        raise ArgumentError, "Invalid setting type '#{type}'"
+      end
+      hash.delete(:type)
+    else
+      # The only implicit typing we still do for settings is to fall back to "String" type if they didn't explicitly
+      # specify a type.  Personally I'd like to get rid of this too, and make the "type" option mandatory... but
+      # there was a little resistance to taking things quite that far for now.  --cprice 2012-03-19
+      klass = StringSetting
+    end
+    hash[:settings] = self
+    setting = klass.new(hash)
+
+    setting
+  end
+
+  # This has to be private, because it doesn't add the settings to @config
+  private :newsetting
+
+  # Iterate across all of the objects in a given section.
+  def persection(section)
+    section = section.to_sym
+    self.each { |name, obj|
+      if obj.section == section
+        yield obj
+      end
+    }
+  end
+
+  # Reparse our config file, if necessary.
+  def reparse_config_files
+    if files
+      if filename = any_files_changed?
+        Puppet.notice "Config file #{filename} changed; triggering re-parse of all config files."
+        parse_config_files
+        reuse
+      end
+    end
+  end
+
+  def files
+    return @files if @files
+    @files = []
+    [main_config_file, user_config_file].each do |path|
+      if Puppet::FileSystem.exist?(path)
+        @files << Puppet::Util::WatchedFile.new(path)
+      end
+    end
+    @files
+  end
+  private :files
+
+  # Checks to see if any of the config files have been modified
+  # @return the filename of the first file that is found to have changed, or
+  #   nil if no files have changed
+  def any_files_changed?
+    files.each do |file|
+      return file.to_str if file.changed?
+    end
+    nil
+  end
+  private :any_files_changed?
+
+  def reuse
+    return unless defined?(@used)
+    new = @used
+    @used = []
+    self.use(*new)
+  end
+
+  # The order in which to search for values.
+  def searchpath(environment = nil)
+    [:memory, :cli, environment, :run_mode, :main, :application_defaults, :overridden_defaults].compact
+  end
+
+  # Get a list of objects per section
+  def sectionlist
+    sectionlist = []
+    self.each { |name, obj|
+      section = obj.section || "puppet"
+      sections[section] ||= []
+      sectionlist << section unless sectionlist.include?(section)
+      sections[section] << obj
+    }
+
+    return sectionlist, sections
+  end
+
+  def service_user_available?
+    return @service_user_available if defined?(@service_user_available)
+
+    if self[:user]
+      user = Puppet::Type.type(:user).new :name => self[:user], :audit => :ensure
+
+      @service_user_available = user.exists?
+    else
+      @service_user_available = false
+    end
+  end
+
+  def service_group_available?
+    return @service_group_available if defined?(@service_group_available)
+
+    if self[:group]
+      group = Puppet::Type.type(:group).new :name => self[:group], :audit => :ensure
+
+      @service_group_available = group.exists?
+    else
+      @service_group_available = false
+    end
+  end
+
+  # Allow later inspection to determine if the setting was set on the
+  # command line, or through some other code path.  Used for the
+  # `dns_alt_names` option during cert generate. --daniel 2011-10-18
+  def set_by_cli?(param)
+    param = param.to_sym
+    !@value_sets[:cli].lookup(param).nil?
+  end
+
+  def set_value(param, value, type, options = {})
+    Puppet.deprecation_warning("Puppet.settings.set_value is deprecated. Use Puppet[]= instead.")
+    if @value_sets[type]
+      @value_sets[type].set(param, value)
+      unsafe_flush_cache
+    end
+  end
+
+  # Deprecated; use #define_settings instead
+  def setdefaults(section, defs)
+    Puppet.deprecation_warning("'setdefaults' is deprecated and will be removed; please call 'define_settings' instead")
+    define_settings(section, defs)
+  end
+
+  # Define a group of settings.
+  #
+  # @param [Symbol] section a symbol to use for grouping multiple settings together into a conceptual unit.  This value
+  #   (and the conceptual separation) is not used very often; the main place where it will have a potential impact
+  #   is when code calls Settings#use method.  See docs on that method for further details, but basically that method
+  #   just attempts to do any preparation that may be necessary before code attempts to leverage the value of a particular
+  #   setting.  This has the most impact for file/directory settings, where #use will attempt to "ensure" those
+  #   files / directories.
+  # @param [Hash[Hash]] defs the settings to be defined.  This argument is a hash of hashes; each key should be a symbol,
+  #   which is basically the name of the setting that you are defining.  The value should be another hash that specifies
+  #   the parameters for the particular setting.  Legal values include:
+  #    [:default] => not required; this is the value for the setting if no other value is specified (via cli, config file, etc.)
+  #       For string settings this may include "variables", demarcated with $ or ${} which will be interpolated with values of other settings.
+  #       The default value may also be a Proc that will be called only once to evaluate the default when the setting's value is retrieved.
+  #    [:desc] => required; a description of the setting, used in documentation / help generation
+  #    [:type] => not required, but highly encouraged!  This specifies the data type that the setting represents.  If
+  #       you do not specify it, it will default to "string".  Legal values include:
+  #       :string - A generic string setting
+  #       :boolean - A boolean setting; values are expected to be "true" or "false"
+  #       :file - A (single) file path; puppet may attempt to create this file depending on how the settings are used.  This type
+  #           also supports additional options such as "mode", "owner", "group"
+  #       :directory - A (single) directory path; puppet may attempt to create this file depending on how the settings are used.  This type
+  #           also supports additional options such as "mode", "owner", "group"
+  #       :path - This is intended to be used for settings whose value can contain multiple directory paths, respresented
+  #           as strings separated by the system path separator (e.g. system path, module path, etc.).
+  #     [:mode] => an (optional) octal value to be used as the permissions/mode for :file and :directory settings
+  #     [:owner] => optional owner username/uid for :file and :directory settings
+  #     [:group] => optional group name/gid for :file and :directory settings
+  #
+  def define_settings(section, defs)
+    section = section.to_sym
+    call = []
+    defs.each do |name, hash|
+      raise ArgumentError, "setting definition for '#{name}' is not a hash!" unless hash.is_a? Hash
+
+      name = name.to_sym
+      hash[:name] = name
+      hash[:section] = section
+      raise ArgumentError, "Setting #{name} is already defined" if @config.include?(name)
+      tryconfig = newsetting(hash)
+      if short = tryconfig.short
+        if other = @shortnames[short]
+          raise ArgumentError, "Setting #{other.name} is already using short name '#{short}'"
+        end
+        @shortnames[short] = tryconfig
+      end
+      @config[name] = tryconfig
+
+      # Collect the settings that need to have their hooks called immediately.
+      # We have to collect them so that we can be sure we're fully initialized before
+      # the hook is called.
+      if tryconfig.has_hook?
+        if tryconfig.call_hook_on_define?
+          call << tryconfig
+        elsif tryconfig.call_hook_on_initialize?
+          @hooks_to_call_on_application_initialization << tryconfig
+        end
+      end
+
+      @deprecated_setting_names << name if tryconfig.deprecated?
+    end
+
+    call.each do |setting|
+      setting.handle(self.value(setting.name))
+    end
+  end
+
+  # Convert the settings we manage into a catalog full of resources that model those settings.
+  def to_catalog(*sections)
+    sections = nil if sections.empty?
+
+    catalog = Puppet::Resource::Catalog.new("Settings", Puppet::Node::Environment::NONE)
+    @config.keys.find_all { |key| @config[key].is_a?(FileSetting) }.each do |key|
+      next if (key == :manifestdir && should_skip_manifestdir?())
+      file = @config[key]
+      next unless (sections.nil? or sections.include?(file.section))
+      next unless resource = file.to_resource
+      next if catalog.resource(resource.ref)
+
+      Puppet.debug("Using settings: adding file resource '#{key}': '#{resource.inspect}'")
+
+      catalog.add_resource(resource)
+    end
+
+    add_user_resources(catalog, sections)
+    add_environment_resources(catalog, sections)
+
+    catalog
+  end
+
+  def should_skip_manifestdir?()
+    setting = @config[:environmentpath]
+    !(setting.nil? || setting.value.nil? || setting.value.empty?)
+  end
+
+  private :should_skip_manifestdir?
+
+  # Convert our list of config settings into a configuration file.
+  def to_config
+    str = %{The configuration file for #{Puppet.run_mode.name}.  Note that this file
+is likely to have unused settings in it; any setting that's
+valid anywhere in Puppet can be in any config file, even if it's not used.
+
+Every section can specify three special parameters: owner, group, and mode.
+These parameters affect the required permissions of any files specified after
+their specification.  Puppet will sometimes use these parameters to check its
+own configured state, so they can be used to make Puppet a bit more self-managing.
+
+The file format supports octothorpe-commented lines, but not partial-line comments.
+
+Generated on #{Time.now}.
+
+}.gsub(/^/, "# ")
+
+#         Add a section heading that matches our name.
+    str += "[#{preferred_run_mode}]\n"
+    eachsection do |section|
+      persection(section) do |obj|
+        str += obj.to_config + "\n" unless obj.name == :genconfig
+      end
+    end
+
+    return str
+  end
+
+  # Convert to a parseable manifest
+  def to_manifest
+    catalog = to_catalog
+    catalog.resource_refs.collect do |ref|
+      catalog.resource(ref).to_manifest
+    end.join("\n\n")
+  end
+
+  # Create the necessary objects to use a section.  This is idempotent;
+  # you can 'use' a section as many times as you want.
+  def use(*sections)
+    sections = sections.collect { |s| s.to_sym }
+    sections = sections.reject { |s| @used.include?(s) }
+
+    return if sections.empty?
+
+    begin
+      catalog = to_catalog(*sections).to_ral
+    rescue => detail
+      Puppet.log_and_raise(detail, "Could not create resources for managing Puppet's files and directories in sections #{sections.inspect}: #{detail}")
+    end
+
+    catalog.host_config = false
+    catalog.apply do |transaction|
+      if transaction.any_failed?
+        report = transaction.report
+        status_failures = report.resource_statuses.values.select { |r| r.failed? }
+        status_fail_msg = status_failures.
+          collect(&:events).
+          flatten.
+          select { |event| event.status == 'failure' }.
+          collect { |event| "#{event.resource}: #{event.message}" }.join("; ")
+
+        raise "Got #{status_failures.length} failure(s) while initializing: #{status_fail_msg}"
+      end
+    end
+
+    sections.each { |s| @used << s }
+    @used.uniq!
+  end
+
+  def valid?(param)
+    param = param.to_sym
+    @config.has_key?(param)
+  end
+
+  def uninterpolated_value(param, environment = nil)
+    Puppet.deprecation_warning("Puppet.settings.uninterpolated_value is deprecated. Use Puppet.settings.value instead")
+    param = param.to_sym
+    environment &&= environment.to_sym
+
+    values(environment, self.preferred_run_mode).lookup(param)
+  end
+
+  # Retrieve an object that can be used for looking up values of configuration
+  # settings.
+  #
+  # @param environment [Symbol] The name of the environment in which to lookup
+  # @param section [Symbol] The name of the configuration section in which to lookup
+  # @return [Puppet::Settings::ChainedValues] An object to perform lookups
+  # @api public
+  def values(environment, section)
+    @values[environment][section] ||= ChainedValues.new(
+      section,
+      environment,
+      value_sets_for(environment, section),
+      @config)
+  end
+
+  # Find the correct value using our search path.
+  #
+  # @param param [String, Symbol] The value to look up
+  # @param environment [String, Symbol] The environment to check for the value
+  # @param bypass_interpolation [true, false] Whether to skip interpolation
+  #
+  # @return [Object] The looked up value
+  #
+  # @raise [InterpolationError]
+  def value(param, environment = nil, bypass_interpolation = false)
+    param = param.to_sym
+    environment &&= environment.to_sym
+
+    setting = @config[param]
+
+    # Short circuit to nil for undefined settings.
+    return nil if setting.nil?
+
+    # Check the cache first.  It needs to be a per-environment
+    # cache so that we don't spread values from one env
+    # to another.
+    if @cache[environment||"none"].has_key?(param)
+      return @cache[environment||"none"][param]
+    elsif bypass_interpolation
+      val = values(environment, self.preferred_run_mode).lookup(param)
+    else
+      val = values(environment, self.preferred_run_mode).interpolate(param)
+    end
+
+    @cache[environment||"none"][param] = val
+    val
+  end
+
+  ##
+  # (#15337) All of the logic to determine the configuration file to use
+  #   should be centralized into this method.  The simplified approach is:
+  #
+  # 1. If there is an explicit configuration file, use that.  (--confdir or
+  #    --config)
+  # 2. If we're running as a root process, use the system puppet.conf
+  #    (usually /etc/puppet/puppet.conf)
+  # 3. Otherwise, use the user puppet.conf (usually ~/.puppet/puppet.conf)
+  #
+  # @api private
+  # @todo this code duplicates {Puppet::Util::RunMode#which_dir} as described
+  #   in {http://projects.puppetlabs.com/issues/16637 #16637}
+  def which_configuration_file
+    if explicit_config_file? or Puppet.features.root? then
+      return main_config_file
+    else
+      return user_config_file
+    end
+  end
+
+  # This method just turns a file into a new ConfigFile::Conf instance
+  # @param file [String] absolute path to the configuration file
+  # @return [Puppet::Settings::ConfigFile::Conf]
+  # @api private
+  def parse_file(file)
+    @config_file_parser.parse_file(file, read_file(file))
+  end
+
+  private
+
+  DEPRECATION_REFS = {
+    [:manifest, :modulepath, :config_version, :templatedir, :manifestdir] =>
+      "See http://links.puppetlabs.com/env-settings-deprecations"
+  }.freeze
+
+  # Record that we want to issue a deprecation warning later in the application
+  # initialization cycle when we have settings bootstrapped to the point where
+  # we can read the Puppet[:disable_warnings] setting.
+  #
+  # We are only recording warnings applicable to settings set in puppet.conf
+  # itself.
+  def record_deprecations_from_puppet_conf(puppet_conf)
+    conf_sections = puppet_conf.sections.inject([]) do |accum,entry|
+      accum << entry[1] if [:main, :master, :agent, :user].include?(entry[0])
+      accum
+    end
+
+    conf_sections.each do |section|
+      section.settings.each do |conf_setting|
+        if setting = self.setting(conf_setting.name)
+          @deprecated_settings_that_have_been_configured << setting if setting.deprecated?
+        end
+      end
+    end
+  end
+
+  def issue_deprecations
+    @deprecated_settings_that_have_been_configured.each do |setting|
+      issue_deprecation_warning(setting)
+    end
+  end
+
+  def issue_deprecation_warning(setting, msg = nil)
+    name = setting.name
+    ref = DEPRECATION_REFS.find { |params,reference| params.include?(name) }
+    ref = ref[1] if ref
+    case
+    when msg
+      msg << " #{ref}" if ref
+      Puppet.deprecation_warning(msg)
+    when setting.completely_deprecated?
+      Puppet.deprecation_warning("Setting #{name} is deprecated. #{ref}", "setting-#{name}")
+    when setting.allowed_on_commandline?
+      Puppet.deprecation_warning("Setting #{name} is deprecated in puppet.conf. #{ref}", "puppet-conf-setting-#{name}")
+    end
+  end
+
+  def get_config_file_default(default)
+    obj = nil
+    unless obj = @config[default]
+      raise ArgumentError, "Unknown default #{default}"
+    end
+
+    raise ArgumentError, "Default #{default} is not a file" unless obj.is_a? FileSetting
+
+    obj
+  end
+
+  def add_environment_resources(catalog, sections)
+    path = self[:environmentpath]
+    envdir = path.split(File::PATH_SEPARATOR).first if path
+    configured_environment = self[:environment]
+    if configured_environment == "production" && envdir && Puppet::FileSystem.exist?(envdir)
+      configured_environment_path = File.join(envdir, configured_environment)
+      if !Puppet::FileSystem.symlink?(configured_environment_path)
+        catalog.add_resource(
+          Puppet::Resource.new(:file,
+                               configured_environment_path,
+                               :parameters => { :ensure => 'directory' })
+        )
+      end
+    end
+  end
+
+  def add_user_resources(catalog, sections)
+    return unless Puppet.features.root?
+    return if Puppet.features.microsoft_windows?
+    return unless self[:mkusers]
+
+    @config.each do |name, setting|
+      next unless setting.respond_to?(:owner)
+      next unless sections.nil? or sections.include?(setting.section)
+
+      if user = setting.owner and user != "root" and catalog.resource(:user, user).nil?
+        resource = Puppet::Resource.new(:user, user, :parameters => {:ensure => :present})
+        resource[:gid] = self[:group] if self[:group]
+        catalog.add_resource resource
+      end
+      if group = setting.group and ! %w{root wheel}.include?(group) and catalog.resource(:group, group).nil?
+        catalog.add_resource Puppet::Resource.new(:group, group, :parameters => {:ensure => :present})
+      end
+    end
+  end
+
+  # Yield each search source in turn.
+  def value_sets_for(environment, mode)
+    searchpath(environment).collect do |name|
+      case name
+      when :cli, :memory, :application_defaults, :overridden_defaults
+        @value_sets[name]
+      when :run_mode
+        if @configuration_file
+          section = @configuration_file.sections[mode]
+          if section
+            ValuesFromSection.new(mode, section)
+          end
+        end
+      else
+        values_from_section = nil
+        if @configuration_file
+          if section = @configuration_file.sections[name]
+            values_from_section = ValuesFromSection.new(name, section)
+          end
+        end
+        if values_from_section.nil? && global_defaults_initialized?
+          values_from_section = ValuesFromEnvironmentConf.new(name)
+        end
+        values_from_section
+      end
+    end.compact
+  end
+
+  # Read the file in.
+  # @api private
+  def read_file(file)
+    return Puppet::FileSystem.read(file)
+  end
+
+  # Private method for internal test use only; allows to do a comprehensive clear of all settings between tests.
+  #
+  # @return nil
+  def clear_everything_for_tests()
+    unsafe_clear(true, true)
+    @configuration_file = nil
+    @global_defaults_initialized = false
+    @app_defaults_initialized = false
+  end
+  private :clear_everything_for_tests
+
+  def explicit_config_file?
+    # Figure out if the user has provided an explicit configuration file.  If
+    # so, return the path to the file, if not return nil.
+    #
+    # The easiest way to determine whether an explicit one has been specified
+    #  is to simply attempt to evaluate the value of ":config".  This will
+    #  obviously be successful if they've passed an explicit value for :config,
+    #  but it will also result in successful interpolation if they've only
+    #  passed an explicit value for :confdir.
+    #
+    # If they've specified neither, then the interpolation will fail and we'll
+    #  get an exception.
+    #
+    begin
+      return true if self[:config]
+    rescue InterpolationError
+      # This means we failed to interpolate, which means that they didn't
+      #  explicitly specify either :config or :confdir... so we'll fall out to
+      #  the default value.
+      return false
+    end
+  end
+  private :explicit_config_file?
+
+  # Lookup configuration setting value through a chain of different value sources.
+  #
+  # @api public
+  class ChainedValues
+    ENVIRONMENT_SETTING = "environment".freeze
+    ENVIRONMENT_INTERPOLATION_ALLOWED = ['config_version'].freeze
+
+    # @see Puppet::Settings.values
+    # @api private
+    def initialize(mode, environment, value_sets, defaults)
+      @mode = mode
+      @environment = environment
+      @value_sets = value_sets
+      @defaults = defaults
+    end
+
+    # Lookup the uninterpolated value.
+    #
+    # @param name [Symbol] The configuration setting name to look up
+    # @return [Object] The configuration setting value or nil if the setting is not known
+    # @api public
+    def lookup(name)
+      set = @value_sets.find do |set|
+        set.include?(name)
+      end
+      if set
+        value = set.lookup(name)
+        if !value.nil?
+          return value
+        end
+      end
+
+      @defaults[name].default
+    end
+
+    # Lookup the interpolated value. All instances of `$name` in the value will
+    # be replaced by performing a lookup of `name` and substituting the text
+    # for `$name` in the original value. This interpolation is only performed
+    # if the looked up value is a String.
+    #
+    # @param name [Symbol] The configuration setting name to look up
+    # @return [Object] The configuration setting value or nil if the setting is not known
+    # @api public
+    def interpolate(name)
+      setting = @defaults[name]
+
+      if setting
+        val = lookup(name)
+        # if we interpolate code, all hell breaks loose.
+        if name == :code
+          val
+        else
+          # Convert it if necessary
+          begin
+            val = convert(val, name)
+          rescue InterpolationError => err
+            # This happens because we don't have access to the param name when the
+            # exception is originally raised, but we want it in the message
+            raise InterpolationError, "Error converting value for param '#{name}': #{err}", err.backtrace
+          end
+
+          setting.munge(val)
+        end
+      else
+        nil
+      end
+    end
+
+    private
+
+    def convert(value, setting_name)
+      case value
+      when nil
+        nil
+      when String
+        failed_environment_interpolation = false
+        interpolated_value = value.gsub(/\$(\w+)|\$\{(\w+)\}/) do |expression|
+          varname = $2 || $1
+          interpolated_expression =
+          if varname != ENVIRONMENT_SETTING || ok_to_interpolate_environment(setting_name)
+            if varname == ENVIRONMENT_SETTING && @environment
+              @environment
+            elsif varname == "run_mode"
+              @mode
+            elsif !(pval = interpolate(varname.to_sym)).nil?
+              pval
+            else
+              raise InterpolationError, "Could not find value for #{expression}"
+            end
+          else
+            failed_environment_interpolation = true
+            expression
+          end
+          interpolated_expression
+        end
+        if failed_environment_interpolation
+          Puppet.warning("You cannot interpolate $environment within '#{setting_name}' when using directory environments.  Its value will remain #{interpolated_value}.")
+        end
+        interpolated_value
+      else
+        value
+      end
+    end
+
+    def ok_to_interpolate_environment(setting_name)
+      return true if Puppet.settings.value(:environmentpath, nil, true).empty?
+
+      ENVIRONMENT_INTERPOLATION_ALLOWED.include?(setting_name.to_s)
+    end
+  end
+
+  class Values
+    extend Forwardable
+
+    def initialize(name, defaults)
+      @name = name
+      @values = {}
+      @defaults = defaults
+    end
+
+    def_delegator :@values, :include?
+    def_delegator :@values, :[], :lookup
+
+    def set(name, value)
+      default = @defaults[name]
+
+      if !default
+        raise ArgumentError,
+          "Attempt to assign a value to unknown setting #{name.inspect}"
+      end
+
+      if default.has_hook?
+        default.handle(value)
+      end
+
+      @values[name] = value
+    end
+  end
+
+  class ValuesFromSection
+    def initialize(name, section)
+      @name = name
+      @section = section
+    end
+
+    def include?(name)
+      !@section.setting(name).nil?
+    end
+
+    def lookup(name)
+      setting = @section.setting(name)
+      if setting
+        setting.value
+      end
+    end
+  end
+
+  # @api private
+  class ValuesFromEnvironmentConf
+    def initialize(environment_name)
+      @environment_name = environment_name
+    end
+
+    def include?(name)
+      if Puppet::Settings::EnvironmentConf::VALID_SETTINGS.include?(name) && conf
+        return true
+      end
+      false
+    end
+
+    def lookup(name)
+      return nil unless Puppet::Settings::EnvironmentConf::VALID_SETTINGS.include?(name)
+      conf.send(name) if conf
+    end
+
+    def conf
+      @conf ||= if environments = Puppet.lookup(:environments)
+                  environments.get_conf(@environment_name)
+                end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/array_setting.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/array_setting.rb
new file mode 100644
index 0000000..82558c3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/array_setting.rb
@@ -0,0 +1,17 @@
+class Puppet::Settings::ArraySetting < Puppet::Settings::BaseSetting
+
+  def type
+    :array
+  end
+
+  def munge(value)
+    case value
+    when String
+      value.split(/\s*,\s*/)
+    when Array
+      value
+    else
+      raise ArgumentError, "Expected an Array or String, got a #{value.class}"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/autosign_setting.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/autosign_setting.rb
new file mode 100644
index 0000000..c09361f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/autosign_setting.rb
@@ -0,0 +1,22 @@
+require 'puppet/settings/base_setting'
+
+# A specialization of the file setting to allow boolean values.
+#
+# The autosign value can be either a boolean or a file path, and if the setting
+# is a file path then it may have a owner/group/mode specified.
+#
+# @api private
+class Puppet::Settings::AutosignSetting < Puppet::Settings::FileSetting
+
+  def munge(value)
+    if ['true', true].include? value
+      true
+    elsif ['false', false, nil].include? value
+      false
+    elsif Puppet::Util.absolute_path?(value)
+      value
+    else
+      raise Puppet::Settings::ValidationError, "Invalid autosign value #{value}: must be 'true'/'false' or an absolute path"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/base_setting.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/base_setting.rb
new file mode 100644
index 0000000..e7c8cf1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/base_setting.rb
@@ -0,0 +1,195 @@
+require 'puppet/settings/errors'
+
+# The base setting type
+class Puppet::Settings::BaseSetting
+  attr_accessor :name, :desc, :section, :default, :call_on_define, :call_hook
+  attr_reader :short, :deprecated
+
+  def self.available_call_hook_values
+    [:on_define_and_write, :on_initialize_and_write, :on_write_only]
+  end
+
+  def call_on_define
+    Puppet.deprecation_warning "call_on_define has been deprecated.  Please use call_hook_on_define?"
+    call_hook_on_define?
+  end
+
+  def call_on_define=(value)
+    if value
+      Puppet.deprecation_warning ":call_on_define has been changed to :call_hook => :on_define_and_write. Please change #{name}."
+      @call_hook = :on_define_and_write
+    else
+      Puppet.deprecation_warning ":call_on_define => :false has been changed to :call_hook => :on_write_only. Please change #{name}."
+      @call_hook = :on_write_only
+    end
+  end
+
+  def call_hook=(value)
+    if value.nil?
+      Puppet.warning "Setting :#{name} :call_hook is nil, defaulting to :on_write_only"
+      value ||= :on_write_only
+    end
+    raise ArgumentError, "Invalid option #{value} for call_hook" unless self.class.available_call_hook_values.include? value
+    @call_hook = value
+  end
+
+  def call_hook_on_define?
+    call_hook == :on_define_and_write
+  end
+
+  def call_hook_on_initialize?
+    call_hook == :on_initialize_and_write
+  end
+
+  #added as a proper method, only to generate a deprecation warning
+  #and return value from
+  def setbycli
+    Puppet.deprecation_warning "Puppet.settings.setting(#{name}).setbycli is deprecated. Use Puppet.settings.set_by_cli?(#{name}) instead."
+    @settings.set_by_cli?(name)
+  end
+
+  def setbycli=(value)
+    Puppet.deprecation_warning "Puppet.settings.setting(#{name}).setbycli= is deprecated. You should not manually set that values were specified on the command line."
+    @settings.set_value(name, @settings[name], :cli) if value
+    raise ArgumentError, "Cannot unset setbycli" unless value
+  end
+
+  # get the arguments in getopt format
+  def getopt_args
+    if short
+      [["--#{name}", "-#{short}", GetoptLong::REQUIRED_ARGUMENT]]
+    else
+      [["--#{name}", GetoptLong::REQUIRED_ARGUMENT]]
+    end
+  end
+
+  # get the arguments in OptionParser format
+  def optparse_args
+    if short
+      ["--#{name}", "-#{short}", desc, :REQUIRED]
+    else
+      ["--#{name}", desc, :REQUIRED]
+    end
+  end
+
+  def hook=(block)
+    @has_hook = true
+    meta_def :handle, &block
+  end
+
+  def has_hook?
+    @has_hook
+  end
+
+  # Create the new element.  Pretty much just sets the name.
+  def initialize(args = {})
+    unless @settings = args.delete(:settings)
+      raise ArgumentError.new("You must refer to a settings object")
+    end
+
+    # explicitly set name prior to calling other param= methods to provide meaningful feedback during
+    # other warnings
+    @name = args[:name] if args.include? :name
+
+    #set the default value for call_hook
+    @call_hook = :on_write_only if args[:hook] and not args[:call_hook]
+    @has_hook = false
+
+    raise ArgumentError, "Cannot reference :call_hook for :#{@name} if no :hook is defined" if args[:call_hook] and not args[:hook]
+
+    args.each do |param, value|
+      method = param.to_s + "="
+      raise ArgumentError, "#{self.class} (setting '#{args[:name]}') does not accept #{param}" unless self.respond_to? method
+
+      self.send(method, value)
+    end
+
+    raise ArgumentError, "You must provide a description for the #{self.name} config option" unless self.desc
+  end
+
+  def iscreated
+    @iscreated = true
+  end
+
+  def iscreated?
+    @iscreated
+  end
+
+  # short name for the celement
+  def short=(value)
+    raise ArgumentError, "Short names can only be one character." if value.to_s.length != 1
+    @short = value.to_s
+  end
+
+  def default(check_application_defaults_first = false)
+    if @default.is_a? Proc
+      @default = @default.call
+    end
+    return @default unless check_application_defaults_first
+    return @settings.value(name, :application_defaults, true) || @default
+  end
+
+  # Convert the object to a config statement.
+  def to_config
+    require 'puppet/util/docs'
+    # Scrub any funky indentation; comment out description.
+    str = Puppet::Util::Docs.scrub(@desc).gsub(/^/, "# ") + "\n"
+
+    # Add in a statement about the default.
+    str << "# The default value is '#{default(true)}'.\n" if default(true)
+
+    # If the value has not been overridden, then print it out commented
+    # and unconverted, so it's clear that that's the default and how it
+    # works.
+    value = @settings.value(self.name)
+
+    if value != @default
+      line = "#{@name} = #{value}"
+    else
+      line = "# #{@name} = #{@default}"
+    end
+
+    str << (line + "\n")
+
+    # Indent
+    str.gsub(/^/, "    ")
+  end
+
+  # @param bypass_interpolation [Boolean] Set this true to skip the
+  #   interpolation step, returning the raw setting value.  Defaults to false.
+  # @return [String] Retrieves the value, or if it's not set, retrieves the default.
+  # @api public
+  def value(bypass_interpolation = false)
+    @settings.value(self.name, nil, bypass_interpolation)
+  end
+
+  # Modify the value when it is first evaluated
+  def munge(value)
+    value
+  end
+
+  def set_meta(meta)
+    Puppet.notice("#{name} does not support meta data. Ignoring.")
+  end
+
+  def deprecated=(deprecation)
+    raise(ArgumentError, "'#{deprecation}' is an unknown setting deprecation state.  Must be either :completely or :allowed_on_commandline") unless [:completely, :allowed_on_commandline].include?(deprecation)
+    @deprecated = deprecation
+  end
+
+  def deprecated?
+    !!@deprecated
+  end
+
+  # True if we should raise a deprecation_warning if the setting is submitted
+  # on the commandline or is set in puppet.conf.
+  def completely_deprecated?
+    @deprecated == :completely
+  end
+
+  # True if we should raise a deprecation_warning if the setting is found in
+  # puppet.conf, but not if the user sets it on the commandline
+  def allowed_on_commandline?
+    @deprecated == :allowed_on_commandline
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/boolean_setting.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/boolean_setting.rb
new file mode 100644
index 0000000..b933116
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/boolean_setting.rb
@@ -0,0 +1,32 @@
+# A simple boolean.
+class Puppet::Settings::BooleanSetting < Puppet::Settings::BaseSetting
+  # get the arguments in getopt format
+  def getopt_args
+    if short
+      [["--#{name}", "-#{short}", GetoptLong::NO_ARGUMENT], ["--no-#{name}", GetoptLong::NO_ARGUMENT]]
+    else
+      [["--#{name}", GetoptLong::NO_ARGUMENT], ["--no-#{name}", GetoptLong::NO_ARGUMENT]]
+    end
+  end
+
+  def optparse_args
+    if short
+      ["--[no-]#{name}", "-#{short}", desc, :NONE ]
+    else
+      ["--[no-]#{name}", desc, :NONE]
+    end
+  end
+
+  def munge(value)
+    case value
+    when true, "true"; return true
+    when false, "false"; return false
+    else
+      raise Puppet::Settings::ValidationError, "Invalid value '#{value.inspect}' for boolean parameter: #{@name}"
+    end
+  end
+
+  def type
+    :boolean
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/config_file.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/config_file.rb
new file mode 100644
index 0000000..e53e900
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/config_file.rb
@@ -0,0 +1,139 @@
+require 'puppet/settings/ini_file'
+
+##
+# @api private
+#
+# Parses puppet configuration files
+#
+class Puppet::Settings::ConfigFile
+
+  ALLOWED_SECTION_NAMES = ['main', 'master', 'agent', 'user'].freeze
+
+  ##
+  # @param value_converter [Proc] a function that will convert strings into ruby types
+  #
+  def initialize(value_converter)
+    @value_converter = value_converter
+  end
+
+  def parse_file(file, text)
+    result = Conf.new
+
+    ini = Puppet::Settings::IniFile.parse(StringIO.new(text))
+    unique_sections_in(ini, file).each do |section_name|
+      section = Section.new(section_name.to_sym)
+      result.with_section(section)
+
+      ini.lines_in(section_name).each do |line|
+        if line.is_a?(Puppet::Settings::IniFile::SettingLine)
+          parse_setting(line, section)
+        elsif line.text !~ /^\s*#|^\s*$/
+          raise Puppet::Settings::ParseError.new("Could not match line #{line.text}", file, line.line_number)
+        end
+      end
+    end
+
+    result
+  end
+
+  Conf = Struct.new(:sections) do
+    def initialize
+      super({})
+    end
+
+    def with_section(section)
+      sections[section.name] = section
+      self
+    end
+  end
+
+  Section = Struct.new(:name, :settings) do
+    def initialize(name)
+      super(name, [])
+    end
+
+    def with_setting(name, value, meta)
+      settings << Setting.new(name, value, meta)
+      self
+    end
+
+    def setting(name)
+      settings.find { |setting| setting.name == name }
+    end
+  end
+
+  Setting = Struct.new(:name, :value, :meta) do
+    def has_metadata?
+      meta != NO_META
+    end
+  end
+
+  Meta = Struct.new(:owner, :group, :mode)
+  NO_META = Meta.new(nil, nil, nil)
+
+private
+
+  def unique_sections_in(ini, file)
+    ini.section_lines.collect do |section|
+      if section.name == "application_defaults" || section.name == "global_defaults"
+        raise Puppet::Error, "Illegal section '#{section.name}' in config file #{file} at line #{section.line_number}"
+      end
+      if !ALLOWED_SECTION_NAMES.include?(section.name)
+        Puppet.deprecation_warning("Sections other than #{ALLOWED_SECTION_NAMES.join(', ')} are deprecated in puppet.conf. Please use the directory environments feature to specify environments. (See http://docs.puppetlabs.com/puppet/latest/reference/environments.html)")
+      end
+      section.name
+    end.uniq
+  end
+
+  def parse_setting(setting, section)
+    var = setting.name.intern
+
+    # We don't want to munge modes, because they're specified in octal, so we'll
+    # just leave them as a String, since Puppet handles that case correctly.
+    if var == :mode
+      value = setting.value
+    else
+      value = @value_converter[setting.value]
+    end
+
+    # Check to see if this is a file argument and it has extra options
+    begin
+      if value.is_a?(String) and options = extract_fileinfo(value)
+        section.with_setting(var, options[:value], Meta.new(options[:owner],
+                                                            options[:group],
+                                                            options[:mode]))
+      else
+        section.with_setting(var, value, NO_META)
+      end
+    rescue Puppet::Error => detail
+      raise Puppet::Settings::ParseError.new(detail.message, file, setting.line_number, detail)
+    end
+  end
+
+  def empty_section
+    { :_meta => {} }
+  end
+
+  def extract_fileinfo(string)
+    result = {}
+    value = string.sub(/\{\s*([^}]+)\s*\}/) do
+      params = $1
+      params.split(/\s*,\s*/).each do |str|
+        if str =~ /^\s*(\w+)\s*=\s*([\w\d]+)\s*$/
+          param, value = $1.intern, $2
+          result[param] = value
+          raise ArgumentError, "Invalid file option '#{param}'" unless [:owner, :mode, :group].include?(param)
+
+          if param == :mode and value !~ /^\d+$/
+            raise ArgumentError, "File modes must be numbers"
+          end
+        else
+          raise ArgumentError, "Could not parse '#{string}'"
+        end
+      end
+      ''
+    end
+    result[:value] = value.sub(/\s*$/, '')
+    result
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/directory_setting.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/directory_setting.rb
new file mode 100644
index 0000000..ea795e3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/directory_setting.rb
@@ -0,0 +1,12 @@
+class Puppet::Settings::DirectorySetting < Puppet::Settings::FileSetting
+  def type
+    :directory
+  end
+
+  # @api private
+  def open_file(filename, option = 'r', &block)
+    controlled_access do |mode|
+      Puppet::FileSystem.open(filename, mode, option, &block)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/duration_setting.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/duration_setting.rb
new file mode 100644
index 0000000..3bbb3aa
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/duration_setting.rb
@@ -0,0 +1,32 @@
+# A setting that represents a span of time, and evaluates to an integer
+# number of seconds after being parsed
+class Puppet::Settings::DurationSetting < Puppet::Settings::BaseSetting
+  # How we convert from various units to seconds.
+  UNITMAP = {
+    # 365 days isn't technically a year, but is sufficient for most purposes
+    "y" => 365 * 24 * 60 * 60,
+    "d" => 24 * 60 * 60,
+    "h" => 60 * 60,
+    "m" => 60,
+    "s" => 1
+  }
+
+  # A regex describing valid formats with groups for capturing the value and units
+  FORMAT = /^(\d+)(y|d|h|m|s)?$/
+
+  def type
+    :duration
+  end
+
+  # Convert the value to an integer, parsing numeric string with units if necessary.
+  def munge(value)
+    case
+    when value.is_a?(Integer)
+      value
+    when (value.is_a?(String) and value =~ FORMAT)
+      $1.to_i * UNITMAP[$2 || 's']
+    else
+      raise Puppet::Settings::ValidationError, "Invalid duration format '#{value.inspect}' for parameter: #{@name}"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/enum_setting.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/enum_setting.rb
new file mode 100644
index 0000000..d1f2108
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/enum_setting.rb
@@ -0,0 +1,16 @@
+class Puppet::Settings::EnumSetting < Puppet::Settings::BaseSetting
+  attr_accessor :values
+
+  def type
+    :enum
+  end
+
+  def munge(value)
+    if values.include?(value)
+      value
+    else
+      raise Puppet::Settings::ValidationError,
+        "Invalid value '#{value}' for parameter #{@name}. Allowed values are '#{values.join("', '")}'"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/environment_conf.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/environment_conf.rb
new file mode 100644
index 0000000..19e18dc
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/environment_conf.rb
@@ -0,0 +1,182 @@
+# Configuration settings for a single directory Environment.
+# @api private
+class Puppet::Settings::EnvironmentConf
+  VALID_SETTINGS = [:modulepath, :manifest, :config_version, :environment_timeout, :parser].freeze
+
+  # Given a path to a directory environment, attempts to load and parse an
+  # environment.conf in ini format, and return an EnvironmentConf instance.
+  #
+  # An environment.conf is optional, so if the file itself is missing, or
+  # empty, an EnvironmentConf with default values will be returned.
+  #
+  # @note logs warnings if the environment.conf contains any ini sections,
+  # or has settings other than the three handled for directory environments
+  # (:manifest, :modulepath, :config_version)
+  #
+  # @param path_to_env [String] path to the directory environment
+  # @param global_module_path [Array<String>] the installation's base modulepath
+  #   setting, appended to default environment modulepaths
+  # @return [EnvironmentConf] the parsed EnvironmentConf object
+  def self.load_from(path_to_env, global_module_path)
+    path_to_env = File.expand_path(path_to_env)
+    conf_file = File.join(path_to_env, 'environment.conf')
+    config = nil
+
+    begin
+      config = Puppet.settings.parse_file(conf_file)
+      validate(conf_file, config)
+      section = config.sections[:main]
+    rescue Errno::ENOENT
+      # environment.conf is an optional file
+    end
+
+    new(path_to_env, section, global_module_path)
+  end
+
+  # Provides a configuration object tied directly to the passed environment.
+  # Configuration values are exactly those returned by the environment object,
+  # without interpolation.  This is a special case for the default configured
+  # environment returned by the Puppet::Environments::StaticPrivate loader.
+  def self.static_for(environment, parser, environment_timeout = 0)
+    Static.new(environment, environment_timeout, parser)
+  end
+
+  attr_reader :section, :path_to_env, :global_modulepath
+
+  # Create through EnvironmentConf.load_from()
+  def initialize(path_to_env, section, global_module_path)
+    @path_to_env = path_to_env
+    @section = section
+    @global_module_path = global_module_path
+  end
+
+  def manifest
+    puppet_conf_manifest = Pathname.new(Puppet.settings.value(:default_manifest))
+    disable_per_environment_manifest = Puppet.settings.value(:disable_per_environment_manifest)
+
+    fallback_manifest_directory =
+    if puppet_conf_manifest.absolute?
+      puppet_conf_manifest.to_s
+    else
+      File.join(@path_to_env, puppet_conf_manifest.to_s)
+    end
+
+    if disable_per_environment_manifest
+      environment_conf_manifest = absolute(raw_setting(:manifest))
+      if environment_conf_manifest && fallback_manifest_directory != environment_conf_manifest
+        errmsg = ["The 'disable_per_environment_manifest' setting is true, but the",
+        "environment located at #{@path_to_env} has a manifest setting in its",
+        "environment.conf of '#{environment_conf_manifest}' which does not match",
+        "the default_manifest setting '#{puppet_conf_manifest}'. If this",
+        "environment is expecting to find modules in",
+        "'#{environment_conf_manifest}', they will not be available!"]
+        Puppet.err(errmsg.join(' '))
+      end
+      fallback_manifest_directory.to_s
+    else
+      get_setting(:manifest, fallback_manifest_directory) do |manifest|
+        absolute(manifest)
+      end
+    end
+  end
+
+  def environment_timeout
+    # gen env specific config or use the default value
+    get_setting(:environment_timeout, Puppet.settings.value(:environment_timeout)) do |ttl|
+      # munges the string form statically without really needed the settings system, only
+      # its ability to munge "4s, 3m, 5d, and 'unlimited' into seconds - if already munged into
+      # numeric form, the TTLSetting handles that.
+      Puppet::Settings::TTLSetting.munge(ttl, 'environment_timeout')
+    end
+  end
+
+  def modulepath
+    default_modulepath = [File.join(@path_to_env, "modules")] + @global_module_path
+    get_setting(:modulepath, default_modulepath) do |modulepath|
+      path = modulepath.kind_of?(String) ?
+        modulepath.split(File::PATH_SEPARATOR) :
+        modulepath
+      path.map { |p| absolute(p) }.join(File::PATH_SEPARATOR)
+    end
+  end
+
+  def parser
+    get_setting(:parser, Puppet.settings.value(:parser)) do |value|
+      value
+    end
+  end
+
+  def config_version
+    get_setting(:config_version) do |config_version|
+      absolute(config_version)
+    end
+  end
+
+  def raw_setting(setting_name)
+    setting = section.setting(setting_name) if section
+    setting.value if setting
+  end
+
+  private
+
+  def self.validate(path_to_conf_file, config)
+    valid = true
+    section_keys = config.sections.keys
+    main = config.sections[:main]
+    if section_keys.size > 1
+      Puppet.warning("Invalid sections in environment.conf at '#{path_to_conf_file}'. Environment conf may not have sections. The following sections are being ignored: '#{(section_keys - [:main]).join(',')}'")
+      valid = false
+    end
+
+    extraneous_settings = main.settings.map(&:name) - VALID_SETTINGS
+    if !extraneous_settings.empty?
+      Puppet.warning("Invalid settings in environment.conf at '#{path_to_conf_file}'. The following unknown setting(s) are being ignored: #{extraneous_settings.join(', ')}")
+      valid = false
+    end
+
+    return valid
+  end
+
+  def get_setting(setting_name, default = nil)
+    value = raw_setting(setting_name)
+    value ||= default
+    yield value
+  end
+
+  def absolute(path)
+    return nil if path.nil?
+    if path =~ /^\$/
+      # Path begins with $something interpolatable
+      path
+    else
+      File.expand_path(path, @path_to_env)
+    end
+  end
+
+  # Models configuration for an environment that is not loaded from a directory.
+  #
+  # @api private
+  class Static
+    attr_reader :environment_timeout
+    attr_reader :parser
+
+    def initialize(environment, environment_timeout, parser)
+      @environment = environment
+      @environment_timeout = environment_timeout
+      @parser = parser
+    end
+
+    def manifest
+      @environment.manifest
+    end
+
+    def modulepath
+      @environment.modulepath.join(File::PATH_SEPARATOR)
+    end
+
+    def config_version
+      @environment.config_version
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/errors.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/errors.rb
new file mode 100644
index 0000000..25a009e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/errors.rb
@@ -0,0 +1,11 @@
+# Exceptions for the settings module
+require 'puppet/error'
+
+class Puppet::Settings
+  class SettingsError < Puppet::Error ; end
+  class ValidationError < SettingsError ; end
+  class InterpolationError < SettingsError ; end
+  class ParseError < SettingsError
+    include Puppet::ExternalFileError
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/file_or_directory_setting.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/file_or_directory_setting.rb
new file mode 100644
index 0000000..88c3a04
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/file_or_directory_setting.rb
@@ -0,0 +1,34 @@
+class Puppet::Settings::FileOrDirectorySetting < Puppet::Settings::FileSetting
+
+  def initialize(args)
+    super
+  end
+
+  def type
+    if Puppet::FileSystem.directory?(self.value) || @path_ends_with_slash
+      :directory
+    else
+      :file
+    end
+  end
+
+  # Overrides munge to be able to read the un-munged value (the FileSetting.munch removes trailing slash)
+  #
+  def munge(value)
+    if value.is_a?(String) && value =~ /[\\\/]$/
+      @path_ends_with_slash = true
+    end
+    super
+  end
+
+  # @api private
+  def open_file(filename, option = 'r', &block)
+    if type == :file
+      super
+    else
+      controlled_access do |mode|
+        Puppet::FileSystem.open(filename, mode, option, &block)
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/file_setting.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/file_setting.rb
new file mode 100644
index 0000000..5aa6195
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/file_setting.rb
@@ -0,0 +1,235 @@
+# A file.
+class Puppet::Settings::FileSetting < Puppet::Settings::StringSetting
+  class SettingError < StandardError; end
+
+  # An unspecified user or group
+  #
+  # @api private
+  class Unspecified
+    def value
+      nil
+    end
+  end
+
+  # A "root" user or group
+  #
+  # @api private
+  class Root
+    def value
+      "root"
+    end
+  end
+
+  # A "service" user or group that picks up values from settings when the
+  # referenced user or group is safe to use (it exists or will be created), and
+  # uses the given fallback value when not safe.
+  #
+  # @api private
+  class Service
+    # @param name [Symbol] the name of the setting to use as the service value
+    # @param fallback [String, nil] the value to use when the service value cannot be used
+    # @param settings [Puppet::Settings] the puppet settings object
+    # @param available_method [Symbol] the name of the method to call on
+    #   settings to determine if the value in settings is available on the system
+    #
+    def initialize(name, fallback, settings, available_method)
+      @settings = settings
+      @available_method = available_method
+      @name = name
+      @fallback = fallback
+    end
+
+    def value
+      if safe_to_use_settings_value?
+        @settings[@name]
+      else
+        @fallback
+      end
+    end
+
+  private
+    def safe_to_use_settings_value?
+      @settings[:mkusers] or @settings.send(@available_method)
+    end
+  end
+
+  attr_accessor :mode, :create
+
+  def initialize(args)
+    @group = Unspecified.new
+    @owner = Unspecified.new
+    super(args)
+  end
+
+  # Should we create files, rather than just directories?
+  def create_files?
+    create
+  end
+
+  # @param value [String] the group to use on the created file (can only be "root" or "service")
+  # @api public
+  def group=(value)
+    @group = case value
+             when "root"
+               Root.new
+             when "service"
+               # Group falls back to `nil` because we cannot assume that a "root" group exists.
+               # Some systems have root group, others have wheel, others have something else.
+               Service.new(:group, nil, @settings, :service_group_available?)
+             else
+               unknown_value(':group', value)
+             end
+  end
+
+  # @param value [String] the owner to use on the created file (can only be "root" or "service")
+  # @api public
+  def owner=(value)
+    @owner = case value
+             when "root"
+               Root.new
+             when "service"
+               Service.new(:user, "root", @settings, :service_user_available?)
+             else
+               unknown_value(':owner', value)
+             end
+  end
+
+  # @return [String, nil] the name of the group to use for the file or nil if the group should not be managed
+  # @api public
+  def group
+    @group.value
+  end
+
+  # @return [String, nil] the name of the user to use for the file or nil if the user should not be managed
+  # @api public
+  def owner
+    @owner.value
+  end
+
+  def set_meta(meta)
+    self.owner = meta.owner if meta.owner
+    self.group = meta.group if meta.group
+    self.mode = meta.mode if meta.mode
+  end
+
+  def munge(value)
+    if value.is_a?(String) and value != ':memory:' # for sqlite3 in-memory tests
+      value = File.expand_path(value)
+    end
+    value
+  end
+
+  def type
+    :file
+  end
+
+  # Turn our setting thing into a Puppet::Resource instance.
+  def to_resource
+    return nil unless type = self.type
+
+    path = self.value
+
+    return nil unless path.is_a?(String)
+
+    # Make sure the paths are fully qualified.
+    path = File.expand_path(path)
+
+    return nil unless type == :directory or create_files? or Puppet::FileSystem.exist?(path)
+    return nil if path =~ /^\/dev/ or path =~ /^[A-Z]:\/dev/i
+
+    resource = Puppet::Resource.new(:file, path)
+
+    if Puppet[:manage_internal_file_permissions]
+      if self.mode
+        # This ends up mimicking the munge method of the mode
+        # parameter to make sure that we're always passing the string
+        # version of the octal number.  If we were setting the
+        # 'should' value for mode rather than the 'is', then the munge
+        # method would be called for us automatically.  Normally, one
+        # wouldn't need to call the munge method manually, since
+        # 'should' gets set by the provider and it should be able to
+        # provide the data in the appropriate format.
+        mode = self.mode
+        mode = mode.to_i(8) if mode.is_a?(String)
+        mode = mode.to_s(8)
+        resource[:mode] = mode
+      end
+
+      # REMIND fails on Windows because chown/chgrp functionality not supported yet
+      if Puppet.features.root? and !Puppet.features.microsoft_windows?
+        resource[:owner] = self.owner if self.owner
+        resource[:group] = self.group if self.group
+      end
+    end
+
+    resource[:ensure] = type
+    resource[:loglevel] = :debug
+    resource[:links] = :follow
+    resource[:backup] = false
+
+    resource.tag(self.section, self.name, "settings")
+
+    resource
+  end
+
+  # Make sure any provided variables look up to something.
+  def validate(value)
+    return true unless value.is_a? String
+    value.scan(/\$(\w+)/) { |name|
+      name = $1
+      unless @settings.include?(name)
+        raise ArgumentError,
+          "Settings parameter '#{name}' is undefined"
+      end
+    }
+  end
+
+  # @api private
+  def exclusive_open(option = 'r', &block)
+    controlled_access do |mode|
+      Puppet::FileSystem.exclusive_open(file(), mode, option, &block)
+    end
+  end
+
+  # @api private
+  def open(option = 'r', &block)
+    controlled_access do |mode|
+      Puppet::FileSystem.open(file, mode, option, &block)
+    end
+  end
+
+  private
+
+  def file
+    Puppet::FileSystem.pathname(value)
+  end
+
+  def unknown_value(parameter, value)
+    raise SettingError, "The #{parameter} parameter for the setting '#{name}' must be either 'root' or 'service', not '#{value}'"
+  end
+
+  def controlled_access(&block)
+    chown = nil
+    if Puppet.features.root?
+      chown = [owner, group]
+    else
+      chown = [nil, nil]
+    end
+
+    Puppet::Util::SUIDManager.asuser(*chown) do
+      # Update the umask to make non-executable files
+      Puppet::Util.withumask(File.umask ^ 0111) do
+        yielded_value = case self.mode
+                        when String
+                          self.mode.to_i(8)
+                        when NilClass
+                          0640
+                        else
+                          self.mode
+                        end
+
+        yield yielded_value
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/ini_file.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/ini_file.rb
new file mode 100644
index 0000000..5bf4bc0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/ini_file.rb
@@ -0,0 +1,171 @@
+# @api private
+class Puppet::Settings::IniFile
+  DEFAULT_SECTION_NAME = "main"
+
+  def self.update(config_fh, &block)
+    config = parse(config_fh)
+    manipulator = Manipulator.new(config)
+    yield manipulator
+    config.write(config_fh)
+  end
+
+  def self.parse(config_fh)
+    config = new([DefaultSection.new])
+    config_fh.each_line do |line|
+      case line
+      when /^(\s*)\[(\w+)\](\s*)$/
+        config.append(SectionLine.new($1, $2, $3))
+      when /^(\s*)(\w+)(\s*=\s*)(.*?)(\s*)$/
+        config.append(SettingLine.new($1, $2, $3, $4, $5))
+      else
+        config.append(Line.new(line))
+      end
+    end
+
+    config
+  end
+
+  def initialize(lines = [])
+    @lines = lines
+  end
+
+  def append(line)
+    line.previous = @lines.last
+    @lines << line
+  end
+
+  def insert_after(line, new_line)
+    new_line.previous = line
+
+    insertion_point = @lines.index(line)
+    @lines.insert(insertion_point + 1, new_line)
+    if @lines.length > insertion_point + 2
+      @lines[insertion_point + 2].previous = new_line
+    end
+  end
+
+  def section_lines
+    @lines.select { |line| line.is_a?(SectionLine) }
+  end
+
+  def section_line(name)
+    section_lines.find { |section| section.name == name }
+  end
+
+  def setting(section, name)
+    settings_in(lines_in(section)).find do |line|
+      line.name == name
+    end
+  end
+
+  def lines_in(section_name)
+    section_lines = []
+    current_section_name = DEFAULT_SECTION_NAME
+    @lines.each do |line|
+      if line.is_a?(SectionLine)
+        current_section_name = line.name
+      elsif current_section_name == section_name
+        section_lines << line
+      end
+    end
+
+    section_lines
+  end
+
+  def settings_in(lines)
+    lines.select { |line| line.is_a?(SettingLine) }
+  end
+
+  def write(fh)
+    fh.truncate(0)
+    fh.rewind
+    @lines.each do |line|
+      line.write(fh)
+    end
+    fh.flush
+  end
+
+  class Manipulator
+    def initialize(config)
+      @config = config
+    end
+
+    def set(section, name, value)
+      setting = @config.setting(section, name)
+      if setting
+        setting.value = value
+      else
+        add_setting(section, name, value)
+      end
+    end
+
+    private
+
+    def add_setting(section_name, name, value)
+      section = @config.section_line(section_name)
+      if section.nil?
+        previous_line = SectionLine.new("", section_name, "")
+        @config.append(previous_line)
+      else
+        previous_line = @config.settings_in(@config.lines_in(section_name)).last || section
+      end
+
+      @config.insert_after(previous_line, SettingLine.new("", name, " = ", value, ""))
+    end
+  end
+
+  module LineNumber
+    attr_accessor :previous
+
+    def line_number
+      line = 0
+      previous_line = previous
+      while previous_line
+        line += 1
+        previous_line = previous_line.previous
+      end
+      line
+    end
+  end
+
+  Line = Struct.new(:text) do
+    include LineNumber
+
+    def write(fh)
+      fh.puts(text)
+    end
+  end
+
+  SettingLine = Struct.new(:prefix, :name, :infix, :value, :suffix) do
+    include LineNumber
+
+    def write(fh)
+      fh.write(prefix)
+      fh.write(name)
+      fh.write(infix)
+      fh.write(value)
+      fh.puts(suffix)
+    end
+  end
+
+  SectionLine = Struct.new(:prefix, :name, :suffix) do
+    include LineNumber
+
+    def write(fh)
+      fh.write(prefix)
+      fh.write("[")
+      fh.write(name)
+      fh.write("]")
+      fh.puts(suffix)
+    end
+  end
+
+  class DefaultSection < SectionLine
+    def initialize
+      super("", DEFAULT_SECTION_NAME, "")
+    end
+
+    def write(fh)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/path_setting.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/path_setting.rb
new file mode 100644
index 0000000..1679657
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/path_setting.rb
@@ -0,0 +1,8 @@
+class Puppet::Settings::PathSetting < Puppet::Settings::StringSetting
+  def munge(value)
+    if value.is_a?(String)
+      value = value.split(File::PATH_SEPARATOR).map { |d| File.expand_path(d) }.join(File::PATH_SEPARATOR)
+    end
+    value
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/priority_setting.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/priority_setting.rb
new file mode 100644
index 0000000..6644339
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/priority_setting.rb
@@ -0,0 +1,42 @@
+require 'puppet/settings/base_setting'
+
+# A setting that represents a scheduling priority, and evaluates to an
+# OS-specific priority level.
+class Puppet::Settings::PrioritySetting < Puppet::Settings::BaseSetting
+  PRIORITY_MAP =
+    if Puppet::Util::Platform.windows?
+      require 'puppet/util/windows/process'
+      {
+        :high    => Puppet::Util::Windows::Process::HIGH_PRIORITY_CLASS,
+        :normal  => Puppet::Util::Windows::Process::NORMAL_PRIORITY_CLASS,
+        :low     => Puppet::Util::Windows::Process::BELOW_NORMAL_PRIORITY_CLASS,
+        :idle    => Puppet::Util::Windows::Process::IDLE_PRIORITY_CLASS
+      }
+    else
+      {
+        :high    => -10,
+        :normal  => 0,
+        :low     => 10,
+        :idle    => 19
+      }
+    end
+
+  def type
+    :priority
+  end
+
+  def munge(value)
+    return unless value
+
+    case
+    when value.is_a?(Integer)
+      value
+    when (value.is_a?(String) and value =~ /\d+/)
+      value.to_i
+    when (value.is_a?(String) and PRIORITY_MAP[value.to_sym])
+      PRIORITY_MAP[value.to_sym]
+    else
+      raise Puppet::Settings::ValidationError, "Invalid priority format '#{value.inspect}' for parameter: #{@name}"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/string_setting.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/string_setting.rb
new file mode 100644
index 0000000..30be173
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/string_setting.rb
@@ -0,0 +1,9 @@
+class Puppet::Settings::StringSetting < Puppet::Settings::BaseSetting
+  def type
+    :string
+  end
+
+  def validate(value)
+    value.nil? or value.is_a?(String)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/terminus_setting.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/terminus_setting.rb
new file mode 100644
index 0000000..376565b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/terminus_setting.rb
@@ -0,0 +1,14 @@
+class Puppet::Settings::TerminusSetting < Puppet::Settings::BaseSetting
+  def munge(value)
+    case value
+    when '', nil
+      nil
+    when String
+      value.intern
+    when Symbol
+      value
+    else
+      raise Puppet::Settings::ValidationError, "Invalid terminus setting: #{value}"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/ttl_setting.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/ttl_setting.rb
new file mode 100644
index 0000000..505066d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/ttl_setting.rb
@@ -0,0 +1,48 @@
+# A setting that represents a span of time to live, and evaluates to Numeric
+# seconds to live where 0 means shortest possible time to live, a positive numeric value means time
+# to live in seconds, and the symbolic entry 'unlimited' is an infinite amount of time.
+#
+class Puppet::Settings::TTLSetting < Puppet::Settings::BaseSetting
+  INFINITY = 1.0 / 0.0
+
+  # How we convert from various units to seconds.
+  UNITMAP = {
+    # 365 days isn't technically a year, but is sufficient for most purposes
+    "y" => 365 * 24 * 60 * 60,
+    "d" => 24 * 60 * 60,
+    "h" => 60 * 60,
+    "m" => 60,
+    "s" => 1
+  }
+
+  # A regex describing valid formats with groups for capturing the value and units
+  FORMAT = /^(\d+)(y|d|h|m|s)?$/
+
+  def type
+    :ttl
+  end
+
+  # Convert the value to Numeric, parsing numeric string with units if necessary.
+  def munge(value)
+    self.class.munge(value, @name)
+  end
+
+  # Convert the value to Numeric, parsing numeric string with units if necessary.
+  def self.munge(value, param_name)
+    case
+    when value.is_a?(Numeric)
+      if value < 0
+        raise Puppet::Settings::ValidationError, "Invalid negative 'time to live' #{value.inspect} - did you mean 'unlimited'?"
+      end
+      value
+
+    when value == 'unlimited'
+      INFINITY
+
+    when (value.is_a?(String) and value =~ FORMAT)
+      $1.to_i * UNITMAP[$2 || 's']
+    else
+      raise Puppet::Settings::ValidationError, "Invalid 'time to live' format '#{value.inspect}' for parameter: #{param_name}"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/value_translator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/value_translator.rb
new file mode 100644
index 0000000..58a3e27
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/settings/value_translator.rb
@@ -0,0 +1,15 @@
+# Convert arguments into booleans, integers, or whatever.
+class Puppet::Settings::ValueTranslator
+  def [](value)
+    # Handle different data types correctly
+    return case value
+      when /^false$/i; false
+      when /^true$/i; true
+      when /^\d+$/i; Integer(value)
+      when true; true
+      when false; false
+      else
+        value.gsub(/^["']|["']$/,'').sub(/\s+$/, '')
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl.rb
new file mode 100644
index 0000000..f22c82d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl.rb
@@ -0,0 +1,13 @@
+# Just to make the constants work out.
+require 'puppet'
+require 'openssl'
+
+module Puppet::SSL # :nodoc:
+  CA_NAME = "ca"
+  require 'puppet/ssl/configuration'
+  require 'puppet/ssl/host'
+  require 'puppet/ssl/oids'
+  require 'puppet/ssl/validator'
+  require 'puppet/ssl/validator/no_validator'
+  require 'puppet/ssl/validator/default_validator'
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/base.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/base.rb
new file mode 100644
index 0000000..0889ba7
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/base.rb
@@ -0,0 +1,140 @@
+require 'openssl'
+require 'puppet/ssl'
+require 'puppet/ssl/digest'
+require 'puppet/util/ssl'
+
+# The base class for wrapping SSL instances.
+class Puppet::SSL::Base
+  # For now, use the YAML separator.
+  SEPARATOR = "\n---\n"
+
+  # Only allow printing ascii characters, excluding /
+  VALID_CERTNAME = /\A[ -.0-~]+\Z/
+
+  def self.from_multiple_s(text)
+    text.split(SEPARATOR).collect { |inst| from_s(inst) }
+  end
+
+  def self.to_multiple_s(instances)
+    instances.collect { |inst| inst.to_s }.join(SEPARATOR)
+  end
+
+  def self.wraps(klass)
+    @wrapped_class = klass
+  end
+
+  def self.wrapped_class
+    raise(Puppet::DevError, "#{self} has not declared what class it wraps") unless defined?(@wrapped_class)
+    @wrapped_class
+  end
+
+  def self.validate_certname(name)
+    raise "Certname #{name.inspect} must not contain unprintable or non-ASCII characters" unless name =~ VALID_CERTNAME
+  end
+
+  attr_accessor :name, :content
+
+  # Is this file for the CA?
+  def ca?
+    name == Puppet::SSL::Host.ca_name
+  end
+
+  def generate
+    raise Puppet::DevError, "#{self.class} did not override 'generate'"
+  end
+
+  def initialize(name)
+    @name = name.to_s.downcase
+    self.class.validate_certname(@name)
+  end
+
+  ##
+  # name_from_subject extracts the common name attribute from the subject of an
+  # x.509 certificate certificate
+  #
+  # @api private
+  #
+  # @param [OpenSSL::X509::Name] subject The full subject (distinguished name) of the x.509
+  #   certificate.
+  #
+  # @return [String] the name (CN) extracted from the subject.
+  def self.name_from_subject(subject)
+    Puppet::Util::SSL.cn_from_subject(subject)
+  end
+
+  # Create an instance of our Puppet::SSL::* class using a given instance of the wrapped class
+  def self.from_instance(instance, name = nil)
+    raise ArgumentError, "Object must be an instance of #{wrapped_class}, #{instance.class} given" unless instance.is_a? wrapped_class
+    raise ArgumentError, "Name must be supplied if it cannot be determined from the instance" if name.nil? and !instance.respond_to?(:subject)
+
+    name ||= name_from_subject(instance.subject)
+    result = new(name)
+    result.content = instance
+    result
+  end
+
+  # Convert a string into an instance
+  def self.from_s(string, name = nil)
+    instance = wrapped_class.new(string)
+    from_instance(instance, name)
+  end
+
+  # Read content from disk appropriately.
+  def read(path)
+    @content = wrapped_class.new(File.read(path))
+  end
+
+  # Convert our thing to pem.
+  def to_s
+    return "" unless content
+    content.to_pem
+  end
+
+  def to_data_hash
+    to_s
+  end
+
+  # Provide the full text of the thing we're dealing with.
+  def to_text
+    return "" unless content
+    content.to_text
+  end
+
+  def fingerprint(md = :SHA256)
+    mds = md.to_s.upcase
+    digest(mds).to_hex
+  end
+
+  def digest(algorithm=nil)
+    unless algorithm
+      algorithm = digest_algorithm
+    end
+
+    Puppet::SSL::Digest.new(algorithm, content.to_der)
+  end
+
+  def digest_algorithm
+    # The signature_algorithm on the X509 cert is a combination of the digest
+    # algorithm and the encryption algorithm
+    # e.g. md5WithRSAEncryption, sha256WithRSAEncryption
+    # Unfortunately there isn't a consistent pattern
+    # See RFCs 3279, 5758
+    digest_re = Regexp.union(
+      /ripemd160/i,
+      /md[245]/i,
+      /sha\d*/i
+    )
+    ln = content.signature_algorithm
+    if match = digest_re.match(ln)
+      match[0].downcase
+    else
+      raise Puppet::Error, "Unknown signature algorithm '#{ln}'"
+    end
+  end
+
+  private
+
+  def wrapped_class
+    self.class.wrapped_class
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate.rb
new file mode 100644
index 0000000..a8ed118
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate.rb
@@ -0,0 +1,65 @@
+require 'puppet/ssl/base'
+
+# Manage certificates themselves.  This class has no
+# 'generate' method because the CA is responsible
+# for turning CSRs into certificates; we can only
+# retrieve them from the CA (or not, as is often
+# the case).
+class Puppet::SSL::Certificate < Puppet::SSL::Base
+  # This is defined from the base class
+  wraps OpenSSL::X509::Certificate
+
+  extend Puppet::Indirector
+  indirects :certificate, :terminus_class => :file, :doc => <<DOC
+    This indirection wraps an `OpenSSL::X509::Certificate` object, representing a certificate (signed public key).
+    The indirection key is the certificate CN (generally a hostname).
+DOC
+
+  # Because of how the format handler class is included, this
+  # can't be in the base class.
+  def self.supported_formats
+    [:s]
+  end
+
+  def subject_alt_names
+    alts = content.extensions.find{|ext| ext.oid == "subjectAltName"}
+    return [] unless alts
+    alts.value.split(/\s*,\s*/)
+  end
+
+  def expiration
+    return nil unless content
+    content.not_after
+  end
+
+  def near_expiration?(interval = nil)
+    return false unless expiration
+    interval ||= Puppet[:certificate_expire_warning]
+    # Certificate expiration timestamps are always in UTC
+    expiration < Time.now.utc + interval
+  end
+
+  # This name is what gets extracted from the subject before being passed
+  # to the constructor, so it's not downcased
+  def unmunged_name
+    self.class.name_from_subject(content.subject)
+  end
+
+  # Any extensions registered with custom OIDs as defined in module
+  # Puppet::SSL::Oids may be looked up here.
+  #
+  # A cert with a 'pp_uuid' extension having the value 'abcd' would return:
+  #
+  # [{ 'oid' => 'pp_uuid', 'value' => 'abcd'}]
+  #
+  # @return [Array<Hash{String => String}>] An array of two element hashes,
+  # with key/value pairs for the extension's oid, and its value.
+  def custom_extensions
+    custom_exts = content.extensions.select do |ext|
+      Puppet::SSL::Oids.subtree_of?('ppRegCertExt', ext.oid) or
+        Puppet::SSL::Oids.subtree_of?('ppPrivCertExt', ext.oid)
+    end
+
+    custom_exts.map { |ext| {'oid' => ext.oid, 'value' => ext.value} }
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_authority.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_authority.rb
new file mode 100644
index 0000000..3ffc584
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_authority.rb
@@ -0,0 +1,517 @@
+require 'puppet/ssl/host'
+require 'puppet/ssl/certificate_request'
+require 'puppet/ssl/certificate_signer'
+require 'puppet/util'
+
+# The class that knows how to sign certificates.  It creates
+# a 'special' SSL::Host whose name is 'ca', thus indicating
+# that, well, it's the CA.  There's some magic in the
+# indirector/ssl_file terminus base class that does that
+# for us.
+#   This class mostly just signs certs for us, but
+# it can also be seen as a general interface into all of the
+# SSL stuff.
+class Puppet::SSL::CertificateAuthority
+  # We will only sign extensions on this whitelist, ever.  Any CSR with a
+  # requested extension that we don't recognize is rejected, against the risk
+  # that it will introduce some security issue through our ignorance of it.
+  #
+  # Adding an extension to this whitelist simply means we will consider it
+  # further, not that we will always accept a certificate with an extension
+  # requested on this list.
+  RequestExtensionWhitelist = %w{subjectAltName}
+
+  require 'puppet/ssl/certificate_factory'
+  require 'puppet/ssl/inventory'
+  require 'puppet/ssl/certificate_revocation_list'
+  require 'puppet/ssl/certificate_authority/interface'
+  require 'puppet/ssl/certificate_authority/autosign_command'
+  require 'puppet/network/authstore'
+
+  class CertificateVerificationError < RuntimeError
+    attr_accessor :error_code
+
+    def initialize(code)
+      @error_code = code
+    end
+  end
+
+  def self.singleton_instance
+    @singleton_instance ||= new
+  end
+
+  class CertificateSigningError < RuntimeError
+    attr_accessor :host
+
+    def initialize(host)
+      @host = host
+    end
+  end
+
+  def self.ca?
+    # running as ca? - ensure boolean answer
+    !!(Puppet[:ca] && Puppet.run_mode.master?)
+  end
+
+  # If this process can function as a CA, then return a singleton instance.
+  def self.instance
+    ca? ? singleton_instance : nil
+  end
+
+  attr_reader :name, :host
+
+  # If autosign is configured, autosign the csr we are passed.
+  # @param csr [Puppet::SSL::CertificateRequest] The csr to sign.
+  # @return [Void]
+  # @api private
+  def autosign(csr)
+    if autosign?(csr)
+      Puppet.info "Autosigning #{csr.name}"
+      sign(csr.name)
+    end
+  end
+
+  # Determine if a CSR can be autosigned by the autosign store or autosign command
+  #
+  # @param csr [Puppet::SSL::CertificateRequest] The CSR to check
+  # @return [true, false]
+  # @api private
+  def autosign?(csr)
+    auto = Puppet[:autosign]
+
+    decider = case auto
+      when false
+        AutosignNever.new
+      when true
+        AutosignAlways.new
+      else
+        file = Puppet::FileSystem.pathname(auto)
+        if Puppet::FileSystem.executable?(file)
+          Puppet::SSL::CertificateAuthority::AutosignCommand.new(auto)
+        elsif Puppet::FileSystem.exist?(file)
+          AutosignConfig.new(file)
+        else
+          AutosignNever.new
+        end
+      end
+
+    decider.allowed?(csr)
+  end
+
+  # Retrieves (or creates, if necessary) the certificate revocation list.
+  def crl
+    unless defined?(@crl)
+      unless @crl = Puppet::SSL::CertificateRevocationList.indirection.find(Puppet::SSL::CA_NAME)
+        @crl = Puppet::SSL::CertificateRevocationList.new(Puppet::SSL::CA_NAME)
+        @crl.generate(host.certificate.content, host.key.content)
+        Puppet::SSL::CertificateRevocationList.indirection.save(@crl)
+      end
+    end
+    @crl
+  end
+
+  # Delegates this to our Host class.
+  def destroy(name)
+    Puppet::SSL::Host.destroy(name)
+  end
+
+  # Generates a new certificate.
+  # @return Puppet::SSL::Certificate
+  def generate(name, options = {})
+    raise ArgumentError, "A Certificate already exists for #{name}" if Puppet::SSL::Certificate.indirection.find(name)
+
+    # Pass on any requested subjectAltName field.
+    san = options[:dns_alt_names]
+
+    host = Puppet::SSL::Host.new(name)
+    host.generate_certificate_request(:dns_alt_names => san)
+    # CSR may have been implicitly autosigned, generating a certificate
+    # Or sign explicitly
+    host.certificate || sign(name, !!san)
+  end
+
+  # Generate our CA certificate.
+  def generate_ca_certificate
+    generate_password unless password?
+
+    host.generate_key unless host.key
+
+    # Create a new cert request.  We do this specially, because we don't want
+    # to actually save the request anywhere.
+    request = Puppet::SSL::CertificateRequest.new(host.name)
+
+    # We deliberately do not put any subjectAltName in here: the CA
+    # certificate absolutely does not need them. --daniel 2011-10-13
+    request.generate(host.key)
+
+    # Create a self-signed certificate.
+    @certificate = sign(host.name, false, request)
+
+    # And make sure we initialize our CRL.
+    crl
+  end
+
+  def initialize
+    Puppet.settings.use :main, :ssl, :ca
+
+    @name = Puppet[:certname]
+
+    @host = Puppet::SSL::Host.new(Puppet::SSL::Host.ca_name)
+
+    setup
+  end
+
+  # Retrieve (or create, if necessary) our inventory manager.
+  def inventory
+    @inventory ||= Puppet::SSL::Inventory.new
+  end
+
+  # Generate a new password for the CA.
+  def generate_password
+    pass = ""
+    20.times { pass += (rand(74) + 48).chr }
+
+    begin
+      Puppet.settings.setting(:capass).open('w') { |f| f.print pass }
+    rescue Errno::EACCES => detail
+      raise Puppet::Error, "Could not write CA password: #{detail}", detail.backtrace
+    end
+
+    @password = pass
+
+    pass
+  end
+
+  # Lists the names of all signed certificates.
+  #
+  # @param name [Array<string>] filter to cerificate names
+  #
+  # @return [Array<String>]
+  def list(name='*')
+    list_certificates(name).collect { |c| c.name }
+  end
+
+  # Return all the certificate objects as found by the indirector
+  # API for PE license checking.
+  #
+  # Created to prevent the case of reading all certs from disk, getting
+  # just their names and verifying the cert for each name, which then
+  # causes the cert to again be read from disk.
+  #
+  # @author Jeff Weiss <jeff.weiss@puppetlabs.com>
+  # @api Puppet Enterprise Licensing
+  #
+  # @param name [Array<string>] filter to cerificate names
+  #
+  # @return [Array<Puppet::SSL::Certificate>]
+  def list_certificates(name='*')
+    Puppet::SSL::Certificate.indirection.search(name)
+  end
+
+  # Read the next serial from the serial file, and increment the
+  # file so this one is considered used.
+  def next_serial
+    serial = 1
+    Puppet.settings.setting(:serial).exclusive_open('a+') do |f|
+      f.rewind
+      serial = f.read.chomp.hex
+      if serial == 0
+        serial = 1
+      end
+
+      f.truncate(0)
+      f.rewind
+
+      # We store the next valid serial, not the one we just used.
+      f << "%04X" % (serial + 1)
+    end
+
+    serial
+  end
+
+  # Does the password file exist?
+  def password?
+    Puppet::FileSystem.exist?(Puppet[:capass])
+  end
+
+  # Print a given host's certificate as text.
+  def print(name)
+    (cert = Puppet::SSL::Certificate.indirection.find(name)) ? cert.to_text : nil
+  end
+
+  # Revoke a given certificate.
+  def revoke(name)
+    raise ArgumentError, "Cannot revoke certificates when the CRL is disabled" unless crl
+
+    cert = Puppet::SSL::Certificate.indirection.find(name)
+
+    serials = if cert
+                [cert.content.serial]
+              elsif name =~ /^0x[0-9A-Fa-f]+$/
+                [name.hex]
+              else
+                inventory.serials(name)
+              end
+
+    if serials.empty?
+      raise ArgumentError, "Could not find a serial number for #{name}"
+    end
+
+    serials.each do |s|
+      crl.revoke(s, host.key.content)
+    end
+  end
+
+  # This initializes our CA so it actually works.  This should be a private
+  # method, except that you can't any-instance stub private methods, which is
+  # *awesome*.  This method only really exists to provide a stub-point during
+  # testing.
+  def setup
+    generate_ca_certificate unless @host.certificate
+  end
+
+  # Sign a given certificate request.
+  def sign(hostname, allow_dns_alt_names = false, self_signing_csr = nil)
+    # This is a self-signed certificate
+    if self_signing_csr
+      # # This is a self-signed certificate, which is for the CA.  Since this
+      # # forces the certificate to be self-signed, anyone who manages to trick
+      # # the system into going through this path gets a certificate they could
+      # # generate anyway.  There should be no security risk from that.
+      csr = self_signing_csr
+      cert_type = :ca
+      issuer = csr.content
+    else
+      allow_dns_alt_names = true if hostname == Puppet[:certname].downcase
+      unless csr = Puppet::SSL::CertificateRequest.indirection.find(hostname)
+        raise ArgumentError, "Could not find certificate request for #{hostname}"
+      end
+
+      cert_type = :server
+      issuer = host.certificate.content
+
+      # Make sure that the CSR conforms to our internal signing policies.
+      # This will raise if the CSR doesn't conform, but just in case...
+      check_internal_signing_policies(hostname, csr, allow_dns_alt_names) or
+        raise CertificateSigningError.new(hostname), "CSR had an unknown failure checking internal signing policies, will not sign!"
+    end
+
+    cert = Puppet::SSL::Certificate.new(hostname)
+    cert.content = Puppet::SSL::CertificateFactory.
+      build(cert_type, csr, issuer, next_serial)
+
+    signer = Puppet::SSL::CertificateSigner.new
+    signer.sign(cert.content, host.key.content)
+
+    Puppet.notice "Signed certificate request for #{hostname}"
+
+    # Add the cert to the inventory before we save it, since
+    # otherwise we could end up with it being duplicated, if
+    # this is the first time we build the inventory file.
+    inventory.add(cert)
+
+    # Save the now-signed cert.  This should get routed correctly depending
+    # on the certificate type.
+    Puppet::SSL::Certificate.indirection.save(cert)
+
+    # And remove the CSR if this wasn't self signed.
+    Puppet::SSL::CertificateRequest.indirection.destroy(csr.name) unless self_signing_csr
+
+    cert
+  end
+
+  def check_internal_signing_policies(hostname, csr, allow_dns_alt_names)
+    # Reject unknown request extensions.
+    unknown_req = csr.request_extensions.reject do |x|
+      RequestExtensionWhitelist.include? x["oid"] or
+        Puppet::SSL::Oids.subtree_of?('ppRegCertExt', x["oid"], true) or
+        Puppet::SSL::Oids.subtree_of?('ppPrivCertExt', x["oid"], true)
+    end
+
+    if unknown_req and not unknown_req.empty?
+      names = unknown_req.map {|x| x["oid"] }.sort.uniq.join(", ")
+      raise CertificateSigningError.new(hostname), "CSR has request extensions that are not permitted: #{names}"
+    end
+
+    # Do not sign misleading CSRs
+    cn = csr.content.subject.to_a.assoc("CN")[1]
+    if hostname != cn
+      raise CertificateSigningError.new(hostname), "CSR subject common name #{cn.inspect} does not match expected certname #{hostname.inspect}"
+    end
+
+    if hostname !~ Puppet::SSL::Base::VALID_CERTNAME
+      raise CertificateSigningError.new(hostname), "CSR #{hostname.inspect} subject contains unprintable or non-ASCII characters"
+    end
+
+    # Wildcards: we don't allow 'em at any point.
+    #
+    # The stringification here makes the content visible, and saves us having
+    # to scrobble through the content of the CSR subject field to make sure it
+    # is what we expect where we expect it.
+    if csr.content.subject.to_s.include? '*'
+      raise CertificateSigningError.new(hostname), "CSR subject contains a wildcard, which is not allowed: #{csr.content.subject.to_s}"
+    end
+
+    unless csr.content.verify(csr.content.public_key)
+      raise CertificateSigningError.new(hostname), "CSR contains a public key that does not correspond to the signing key"
+    end
+
+    unless csr.subject_alt_names.empty?
+      # If you alt names are allowed, they are required. Otherwise they are
+      # disallowed. Self-signed certs are implicitly trusted, however.
+      unless allow_dns_alt_names
+        raise CertificateSigningError.new(hostname), "CSR '#{csr.name}' contains subject alternative names (#{csr.subject_alt_names.join(', ')}), which are disallowed. Use `puppet cert --allow-dns-alt-names sign #{csr.name}` to sign this request."
+      end
+
+      # If subjectAltNames are present, validate that they are only for DNS
+      # labels, not any other kind.
+      unless csr.subject_alt_names.all? {|x| x =~ /^DNS:/ }
+        raise CertificateSigningError.new(hostname), "CSR '#{csr.name}' contains a subjectAltName outside the DNS label space: #{csr.subject_alt_names.join(', ')}.  To continue, this CSR needs to be cleaned."
+      end
+
+      # Check for wildcards in the subjectAltName fields too.
+      if csr.subject_alt_names.any? {|x| x.include? '*' }
+        raise CertificateSigningError.new(hostname), "CSR '#{csr.name}' subjectAltName contains a wildcard, which is not allowed: #{csr.subject_alt_names.join(', ')}  To continue, this CSR needs to be cleaned."
+      end
+    end
+
+    return true                 # good enough for us!
+  end
+
+  # Utility method for optionally caching the X509 Store for verifying a
+  # large number of certificates in a short amount of time--exactly the
+  # case we have during PE license checking.
+  #
+  # @example Use the cached X509 store
+  #   x509store(:cache => true)
+  #
+  # @example Use a freshly create X509 store
+  #   x509store
+  #   x509store(:cache => false)
+  #
+  # @param [Hash] options the options used for retrieving the X509 Store
+  # @option options [Boolean] :cache whether or not to use a cached version
+  #   of the X509 Store
+  #
+  # @return [OpenSSL::X509::Store]
+  def x509_store(options = {})
+    if (options[:cache])
+      return @x509store unless @x509store.nil?
+      @x509store = create_x509_store
+    else
+      create_x509_store
+    end
+  end
+  private :x509_store
+
+  # Creates a brand new OpenSSL::X509::Store with the appropriate
+  # Certificate Revocation List and flags
+  #
+  # @return [OpenSSL::X509::Store]
+  def create_x509_store
+    store = OpenSSL::X509::Store.new()
+    store.add_file(Puppet[:cacert])
+    store.add_crl(crl.content) if self.crl
+    store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
+    if Puppet.settings[:certificate_revocation]
+      store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL | OpenSSL::X509::V_FLAG_CRL_CHECK
+    end
+    store
+  end
+  private :create_x509_store
+
+  # Utility method which is API for PE license checking.
+  # This is used rather than `verify` because
+  #  1) We have already read the certificate from disk into memory.
+  #     To read the certificate from disk again is just wasteful.
+  #  2) Because we're checking a large number of certificates against
+  #     a transient CertificateAuthority, we can relatively safely cache
+  #     the X509 Store that actually does the verification.
+  #
+  # Long running instances of CertificateAuthority will certainly
+  # want to use `verify` because it will recreate the X509 Store with
+  # the absolutely latest CRL.
+  #
+  # Additionally, this method explicitly returns a boolean whereas
+  # `verify` will raise an error if the certificate has been revoked.
+  #
+  # @author Jeff Weiss <jeff.weiss@puppetlabs.com>
+  # @api Puppet Enterprise Licensing
+  #
+  # @param cert [Puppet::SSL::Certificate] the certificate to check validity of
+  #
+  # @return [Boolean] true if signed, false if unsigned or revoked
+  def certificate_is_alive?(cert)
+    x509_store(:cache => true).verify(cert.content)
+  end
+
+  # Verify a given host's certificate. The certname is passed in, and
+  # the indirector will be used to locate the actual contents of the
+  # certificate with that name.
+  #
+  # @param name [String] certificate name to verify
+  #
+  # @raise [ArgumentError] if the certificate name cannot be found
+  #   (i.e. doesn't exist or is unsigned)
+  # @raise [CertificateVerficationError] if the certificate has been revoked
+  #
+  # @return [Boolean] true if signed, there are no cases where false is returned
+  def verify(name)
+    unless cert = Puppet::SSL::Certificate.indirection.find(name)
+      raise ArgumentError, "Could not find a certificate for #{name}"
+    end
+    store = x509_store
+
+    raise CertificateVerificationError.new(store.error), store.error_string unless store.verify(cert.content)
+  end
+
+  def fingerprint(name, md = :SHA256)
+    unless cert = Puppet::SSL::Certificate.indirection.find(name) || Puppet::SSL::CertificateRequest.indirection.find(name)
+      raise ArgumentError, "Could not find a certificate or csr for #{name}"
+    end
+    cert.fingerprint(md)
+  end
+
+  # List the waiting certificate requests.
+  def waiting?
+    Puppet::SSL::CertificateRequest.indirection.search("*").collect { |r| r.name }
+  end
+
+  # @api private
+  class AutosignAlways
+    def allowed?(csr)
+      true
+    end
+  end
+
+  # @api private
+  class AutosignNever
+    def allowed?(csr)
+      false
+    end
+  end
+
+  # @api private
+  class AutosignConfig
+    def initialize(config_file)
+      @config = config_file
+    end
+
+    def allowed?(csr)
+      autosign_store.allowed?(csr.name, '127.1.1.1')
+    end
+
+    private
+
+    def autosign_store
+      auth = Puppet::Network::AuthStore.new
+      Puppet::FileSystem.each_line(@config) do |line|
+        next if line =~ /^\s*#/
+        next if line =~ /^\s*$/
+        auth.allow(line.chomp)
+      end
+
+      auth
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_authority/autosign_command.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_authority/autosign_command.rb
new file mode 100644
index 0000000..822b374
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_authority/autosign_command.rb
@@ -0,0 +1,45 @@
+require 'puppet/ssl/certificate_authority'
+require 'puppet/file_system/uniquefile'
+
+# This class wraps a given command and invokes it with a CSR name and body to
+# determine if the given CSR should be autosigned
+#
+# @api private
+class Puppet::SSL::CertificateAuthority::AutosignCommand
+
+  class CheckFailure < Puppet::Error; end
+
+  def initialize(path)
+    @path = path
+  end
+
+  # Run the autosign command with the given CSR name as an argument and the
+  # CSR body on stdin.
+  #
+  # @param csr [String] The CSR name to check for autosigning
+  # @return [true, false] If the CSR should be autosigned
+  def allowed?(csr)
+    name = csr.name
+    cmd = [@path, name]
+
+    output = Puppet::FileSystem::Uniquefile.open_tmp('puppet-csr') do |csr_file|
+      csr_file.write(csr.to_s)
+      csr_file.flush
+
+      execute_options = {:stdinfile => csr_file.path, :combine => true, :failonfail => false}
+      Puppet::Util::Execution.execute(cmd, execute_options)
+    end
+
+    output.chomp!
+
+    Puppet.debug "Autosign command '#{@path}' exit status: #{output.exitstatus}"
+    Puppet.debug "Autosign command '#{@path}' output: #{output}"
+
+    case output.exitstatus
+    when 0
+      true
+    else
+      false
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_authority/interface.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_authority/interface.rb
new file mode 100644
index 0000000..20f4d87
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_authority/interface.rb
@@ -0,0 +1,178 @@
+module Puppet
+  module SSL
+    class CertificateAuthority
+      # This class is basically a hidden class that knows how to act on the
+      # CA.  Its job is to provide a CLI-like interface to the CA class.
+      class Interface
+        INTERFACE_METHODS = [:destroy, :list, :revoke, :generate, :sign, :print, :verify, :fingerprint, :reinventory]
+
+        SUBJECTLESS_METHODS = [:list, :reinventory]
+
+        class InterfaceError < ArgumentError; end
+
+        attr_reader :method, :subjects, :digest, :options
+
+        # Actually perform the work.
+        def apply(ca)
+          unless subjects || SUBJECTLESS_METHODS.include?(method)
+            raise ArgumentError, "You must provide hosts or --all when using #{method}"
+          end
+
+          # if the interface implements the method, use it instead of the ca's method
+          if respond_to?(method)
+            send(method, ca)
+          else
+            (subjects == :all ? ca.list : subjects).each do |host|
+              ca.send(method, host)
+            end
+          end
+        end
+
+        def generate(ca)
+          raise InterfaceError, "It makes no sense to generate all hosts; you must specify a list" if subjects == :all
+
+          subjects.each do |host|
+            ca.generate(host, options)
+          end
+        end
+
+        def initialize(method, options)
+          self.method = method
+          self.subjects = options.delete(:to)
+          @digest = options.delete(:digest)
+          @options = options
+        end
+
+        # List the hosts.
+        def list(ca)
+          signed = ca.list if [:signed, :all].include?(subjects)
+          requests = ca.waiting?
+
+          case subjects
+          when :all
+            hosts = [signed, requests].flatten
+          when :signed
+            hosts = signed.flatten
+          when nil
+            hosts = requests
+          else
+            hosts = subjects
+            signed = ca.list(hosts)
+          end
+
+          certs = {:signed => {}, :invalid => {}, :request => {}}
+
+          return if hosts.empty?
+
+          hosts.uniq.sort.each do |host|
+            begin
+              ca.verify(host) unless requests.include?(host)
+            rescue Puppet::SSL::CertificateAuthority::CertificateVerificationError => details
+              verify_error = details.to_s
+            end
+
+            if verify_error
+              certs[:invalid][host] = [ Puppet::SSL::Certificate.indirection.find(host), verify_error ]
+            elsif (signed and signed.include?(host))
+              certs[:signed][host]  = Puppet::SSL::Certificate.indirection.find(host)
+            else
+              certs[:request][host] = Puppet::SSL::CertificateRequest.indirection.find(host)
+            end
+          end
+
+          names = certs.values.map(&:keys).flatten
+
+          name_width = names.sort_by(&:length).last.length rescue 0
+          # We quote these names, so account for those characters
+          name_width += 2
+
+          output = [:request, :signed, :invalid].map do |type|
+            next if certs[type].empty?
+
+            certs[type].map do |host,info|
+              format_host(ca, host, type, info, name_width)
+            end
+          end.flatten.compact.sort.join("\n")
+
+          puts output
+        end
+
+        def format_host(ca, host, type, info, width)
+          cert, verify_error = info
+          alt_names = case type
+                      when :signed
+                        cert.subject_alt_names
+                      when :request
+                        cert.subject_alt_names
+                      else
+                        []
+                      end
+
+          alt_names.delete(host)
+
+          alt_str = "(alt names: #{alt_names.map(&:inspect).join(', ')})" unless alt_names.empty?
+
+          glyph = {:signed => '+', :request => ' ', :invalid => '-'}[type]
+
+          name = host.inspect.ljust(width)
+          fingerprint = cert.digest(@digest).to_s
+
+          explanation = "(#{verify_error})" if verify_error
+
+          [glyph, name, fingerprint, alt_str, explanation].compact.join(' ')
+        end
+
+        # Set the method to apply.
+        def method=(method)
+          raise ArgumentError, "Invalid method #{method} to apply" unless INTERFACE_METHODS.include?(method)
+          @method = method
+        end
+
+        # Print certificate information.
+        def print(ca)
+          (subjects == :all ? ca.list  : subjects).each do |host|
+            if value = ca.print(host)
+              puts value
+            else
+              Puppet.err "Could not find certificate for #{host}"
+            end
+          end
+        end
+
+        # Print certificate information.
+        def fingerprint(ca)
+          (subjects == :all ? ca.list + ca.waiting?: subjects).each do |host|
+            if cert = (Puppet::SSL::Certificate.indirection.find(host) || Puppet::SSL::CertificateRequest.indirection.find(host))
+              puts "#{host} #{cert.digest(@digest)}"
+            else
+              Puppet.err "Could not find certificate for #{host}"
+            end
+          end
+        end
+
+        # Signs given certificates or waiting of subjects == :all
+        def sign(ca)
+          list = subjects == :all ? ca.waiting? : subjects
+          raise InterfaceError, "No waiting certificate requests to sign" if list.empty?
+          list.each do |host|
+            ca.sign(host, options[:allow_dns_alt_names])
+          end
+        end
+
+        def reinventory(ca)
+          ca.inventory.rebuild
+        end
+
+        # Set the list of hosts we're operating on.  Also supports keywords.
+        def subjects=(value)
+          unless value == :all || value == :signed || value.is_a?(Array)
+            raise ArgumentError, "Subjects must be an array or :all; not #{value}"
+          end
+
+          @subjects = (value == []) ? nil : value
+        end
+      end
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_factory.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_factory.rb
new file mode 100644
index 0000000..124ce4b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_factory.rb
@@ -0,0 +1,219 @@
+require 'puppet/ssl'
+
+# This class encapsulates the logic of creating and adding extensions to X509
+# certificates.
+#
+# @api private
+module Puppet::SSL::CertificateFactory
+
+  # Create, add extensions to, and sign a new X509 certificate.
+  #
+  # @param cert_type [Symbol] The certificate type to create, which specifies
+  #   what extensions are added to the certificate.
+  #   One of (:ca, :terminalsubca, :server, :ocsp, :client)
+  # @param csr [OpenSSL::X509::Request] The signing request associated with
+  #   the certificate being created.
+  # @param issuer [OpenSSL::X509::Certificate, OpenSSL::X509::Request] An X509 CSR
+  #   if this is a self signed certificate, or the X509 certificate of the CA if
+  #   this is a CA signed certificate.
+  # @param serial [Integer] The serial number for the given certificate, which
+  #   MUST be unique for the given CA.
+  # @param ttl [String] The duration of the validity for the given certificate.
+  #   defaults to Puppet[:ca_ttl]
+  #
+  # @api public
+  #
+  # @return [OpenSSL::X509::Certificate]
+  def self.build(cert_type, csr, issuer, serial, ttl = nil)
+    # Work out if we can even build the requested type of certificate.
+    build_extensions = "build_#{cert_type.to_s}_extensions"
+    respond_to?(build_extensions) or
+      raise ArgumentError, "#{cert_type.to_s} is an invalid certificate type!"
+
+    raise ArgumentError, "Certificate TTL must be an integer" unless ttl.nil? || ttl.is_a?(Fixnum)
+
+    # set up the certificate, and start building the content.
+    cert = OpenSSL::X509::Certificate.new
+
+    cert.version    = 2 # X509v3
+    cert.subject    = csr.content.subject
+    cert.issuer     = issuer.subject
+    cert.public_key = csr.content.public_key
+    cert.serial     = serial
+
+    # Make the certificate valid as of yesterday, because so many people's
+    # clocks are out of sync.  This gives one more day of validity than people
+    # might expect, but is better than making every person who has a messed up
+    # clock fail, and better than having every cert we generate expire a day
+    # before the user expected it to when they asked for "one year".
+    cert.not_before = Time.now - (60*60*24)
+    cert.not_after  = Time.now + (ttl || Puppet[:ca_ttl])
+
+    add_extensions_to(cert, csr, issuer, send(build_extensions))
+
+    return cert
+  end
+
+  private
+
+  # Add X509v3 extensions to the given certificate.
+  #
+  # @param cert [OpenSSL::X509::Certificate] The certificate to add the
+  #   extensions to.
+  # @param csr [OpenSSL::X509::Request] The CSR associated with the given
+  #   certificate, which may specify requested extensions for the given cert.
+  #   See http://tools.ietf.org/html/rfc2985 Section 5.4.2 Extension request
+  # @param issuer [OpenSSL::X509::Certificate, OpenSSL::X509::Request] An X509 CSR
+  #   if this is a self signed certificate, or the X509 certificate of the CA if
+  #   this is a CA signed certificate.
+  # @param extensions [Hash<String, Array<String> | String>] The extensions to
+  #   add to the certificate, based on the certificate type being created (CA,
+  #   server, client, etc)
+  #
+  # @api private
+  #
+  # @return [void]
+  def self.add_extensions_to(cert, csr, issuer, extensions)
+    ef = OpenSSL::X509::ExtensionFactory.new
+    ef.subject_certificate = cert
+    ef.issuer_certificate  = issuer.is_a?(OpenSSL::X509::Request) ? cert : issuer
+
+    # Extract the requested extensions from the CSR.
+    requested_exts = csr.request_extensions.inject({}) do |hash, re|
+      hash[re["oid"]] = [re["value"], re["critical"]]
+      hash
+    end
+
+    # Produce our final set of extensions.  We deliberately order these to
+    # build the way we want:
+    # 1. "safe" default values, like the comment, that no one cares about.
+    # 2. request extensions, from the CSR
+    # 3. extensions based on the type we are generating
+    # 4. overrides, which we always want to have in their form
+    #
+    # This ordering *is* security-critical, but we want to allow the user
+    # enough rope to shoot themselves in the foot, if they want to ignore our
+    # advice and externally approve a CSR that sets the basicConstraints.
+    #
+    # Swapping the order of 2 and 3 would ensure that you couldn't slip a
+    # certificate through where the CA constraint was true, though, if
+    # something went wrong up there. --daniel 2011-10-11
+    defaults = { "nsComment" => "Puppet Ruby/OpenSSL Internal Certificate" }
+
+    # See http://www.openssl.org/docs/apps/x509v3_config.html
+    # for information about the special meanings of 'hash', 'keyid', 'issuer'
+    override = {
+      "subjectKeyIdentifier"   => "hash",
+      "authorityKeyIdentifier" => "keyid,issuer"
+    }
+
+    exts = [defaults, requested_exts, extensions, override].
+      inject({}) {|ret, val| ret.merge(val) }
+
+    cert.extensions = exts.map do |oid, val|
+      generate_extension(ef, oid, *val)
+    end
+  end
+
+  # Woot! We're a CA.
+  def self.build_ca_extensions
+    {
+      # This was accidentally omitted in the previous version of this code: an
+      # effort was made to add it last, but that actually managed to avoid
+      # adding it to the certificate at all.
+      #
+      # We have some sort of bug, which means that when we add it we get a
+      # complaint that the issuer keyid can't be fetched, which breaks all
+      # sorts of things in our test suite and, e.g., bootstrapping the CA.
+      #
+      # http://tools.ietf.org/html/rfc5280#section-4.2.1.1 says that, to be a
+      # conforming CA we MAY omit the field if we are self-signed, which I
+      # think gives us a pass in the specific case.
+      #
+      # It also notes that we MAY derive the ID from the subject and serial
+      # number of the issuer, or from the key ID, and we definitely have the
+      # former data, should we want to restore this...
+      #
+      # Anyway, preserving this bug means we don't risk breaking anything in
+      # the field, even though it would be nice to have. --daniel 2011-10-11
+      #
+      # "authorityKeyIdentifier" => "keyid:always,issuer:always",
+      "keyUsage"               => [%w{cRLSign keyCertSign}, true],
+      "basicConstraints"       => ["CA:TRUE", true],
+    }
+  end
+
+  # We're a terminal CA, probably not self-signed.
+  def self.build_terminalsubca_extensions
+    {
+      "keyUsage"         => [%w{cRLSign keyCertSign}, true],
+      "basicConstraints" => ["CA:TRUE,pathlen:0", true],
+    }
+  end
+
+  # We're a normal server.
+  def self.build_server_extensions
+    {
+      "keyUsage"         => [%w{digitalSignature keyEncipherment}, true],
+      "extendedKeyUsage" => [%w{serverAuth clientAuth}, true],
+      "basicConstraints" => ["CA:FALSE", true],
+    }
+  end
+
+  # Um, no idea.
+  def self.build_ocsp_extensions
+    {
+      "keyUsage"         => [%w{nonRepudiation digitalSignature}, true],
+      "extendedKeyUsage" => [%w{serverAuth OCSPSigning}, true],
+      "basicConstraints" => ["CA:FALSE", true],
+    }
+  end
+
+  # Normal client.
+  def self.build_client_extensions
+    {
+      "keyUsage"         => [%w{nonRepudiation digitalSignature keyEncipherment}, true],
+      # We don't seem to use this, but that seems much more reasonable here...
+      "extendedKeyUsage" => [%w{clientAuth emailProtection}, true],
+      "basicConstraints" => ["CA:FALSE", true],
+      "nsCertType"       => "client,email",
+    }
+  end
+
+  # Generate an extension with the given OID, value, and critical state
+  #
+  # @param oid [String] The numeric value or short name of a given OID. X509v3
+  #   extensions must be passed by short name or long name, while custom
+  #   extensions may be passed by short name, long name, oid numeric OID.
+  # @param ef [OpenSSL::X509::ExtensionFactory] The extension factory to use
+  #   when generating the extension.
+  # @param val [String, Array<String>] The extension value.
+  # @param crit [true, false] Whether the given extension is critical, defaults
+  #   to false.
+  #
+  # @return [OpenSSL::X509::Extension]
+  #
+  # @api private
+  def self.generate_extension(ef, oid, val, crit = false)
+
+    val = val.join(', ') unless val.is_a? String
+
+    # Enforce the X509v3 rules about subjectAltName being critical:
+    # specifically, it SHOULD NOT be critical if we have a subject, which we
+    # always do. --daniel 2011-10-18
+    crit = false if oid == "subjectAltName"
+
+    if Puppet::SSL::Oids.subtree_of?('id-ce', oid) or Puppet::SSL::Oids.subtree_of?('id-pkix', oid)
+      # Attempt to create a X509v3 certificate extension. Standard certificate
+      # extensions may need access to the associated subject certificate and
+      # issuing certificate, so must be created by the OpenSSL::X509::ExtensionFactory
+      # which provides that context.
+      ef.create_ext(oid, val, crit)
+    else
+      # This is not an X509v3 extension which means that the extension
+      # factory cannot generate it. We need to generate the extension
+      # manually.
+      OpenSSL::X509::Extension.new(oid, val, crit)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_request.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_request.rb
new file mode 100644
index 0000000..7b44057
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_request.rb
@@ -0,0 +1,299 @@
+require 'puppet/ssl/base'
+require 'puppet/ssl/certificate_signer'
+
+# This class creates and manages X509 certificate signing requests.
+#
+# ## CSR attributes
+#
+# CSRs may contain a set of attributes that includes supplementary information
+# about the CSR or information for the signed certificate.
+#
+# PKCS#9/RFC 2985 section 5.4 formally defines the "Challenge password",
+# "Extension request", and "Extended-certificate attributes", but this
+# implementation only handles the "Extension request" attribute. Other
+# attributes may be defined on a CSR, but the RFC doesn't define behavior for
+# any other attributes so we treat them as only informational.
+#
+# ## CSR Extension request attribute
+#
+# CSRs may contain an optional set of extension requests, which allow CSRs to
+# include additional information that may be included in the signed
+# certificate. Any additional information that should be copied from the CSR
+# to the signed certificate MUST be included in this attribute.
+#
+# This behavior is dictated by PKCS#9/RFC 2985 section 5.4.2.
+#
+# @see http://tools.ietf.org/html/rfc2985 "RFC 2985 Section 5.4.2 Extension request"
+#
+class Puppet::SSL::CertificateRequest < Puppet::SSL::Base
+  wraps OpenSSL::X509::Request
+
+  extend Puppet::Indirector
+
+  # If auto-signing is on, sign any certificate requests as they are saved.
+  module AutoSigner
+    def save(instance, key = nil)
+      super
+
+      # Try to autosign the CSR.
+      if ca = Puppet::SSL::CertificateAuthority.instance
+        ca.autosign(instance)
+      end
+    end
+  end
+
+  indirects :certificate_request, :terminus_class => :file, :extend => AutoSigner, :doc => <<DOC
+    This indirection wraps an `OpenSSL::X509::Request` object, representing a certificate signing request (CSR).
+    The indirection key is the certificate CN (generally a hostname).
+DOC
+
+  # Because of how the format handler class is included, this
+  # can't be in the base class.
+  def self.supported_formats
+    [:s]
+  end
+
+  def extension_factory
+    @ef ||= OpenSSL::X509::ExtensionFactory.new
+  end
+
+  # Create a certificate request with our system settings.
+  #
+  # @param key [OpenSSL::X509::Key, Puppet::SSL::Key] The key pair associated
+  #   with this CSR.
+  # @param options [Hash]
+  # @option options [String] :dns_alt_names A comma separated list of
+  #   Subject Alternative Names to include in the CSR extension request.
+  # @option options [Hash<String, String, Array<String>>] :csr_attributes A hash
+  #   of OIDs and values that are either a string or array of strings.
+  # @option options [Array<String, String>] :extension_requests A hash of
+  #   certificate extensions to add to the CSR extReq attribute, excluding
+  #   the Subject Alternative Names extension.
+  #
+  # @raise [Puppet::Error] If the generated CSR signature couldn't be verified
+  #
+  # @return [OpenSSL::X509::Request] The generated CSR
+  def generate(key, options = {})
+    Puppet.info "Creating a new SSL certificate request for #{name}"
+
+    # Support either an actual SSL key, or a Puppet key.
+    key = key.content if key.is_a?(Puppet::SSL::Key)
+
+    # If we're a CSR for the CA, then use the real ca_name, rather than the
+    # fake 'ca' name.  This is mostly for backward compatibility with 0.24.x,
+    # but it's also just a good idea.
+    common_name = name == Puppet::SSL::CA_NAME ? Puppet.settings[:ca_name] : name
+
+    csr = OpenSSL::X509::Request.new
+    csr.version = 0
+    csr.subject = OpenSSL::X509::Name.new([["CN", common_name]])
+    csr.public_key = key.public_key
+
+    if options[:csr_attributes]
+      add_csr_attributes(csr, options[:csr_attributes])
+    end
+
+    if (ext_req_attribute = extension_request_attribute(options))
+      csr.add_attribute(ext_req_attribute)
+    end
+
+    signer = Puppet::SSL::CertificateSigner.new
+    signer.sign(csr, key)
+
+    raise Puppet::Error, "CSR sign verification failed; you need to clean the certificate request for #{name} on the server" unless csr.verify(key.public_key)
+
+    @content = csr
+    Puppet.info "Certificate Request fingerprint (#{digest.name}): #{digest.to_hex}"
+    @content
+  end
+
+  # Return the set of extensions requested on this CSR, in a form designed to
+  # be useful to Ruby: an array of hashes.  Which, not coincidentally, you can pass
+  # successfully to the OpenSSL constructor later, if you want.
+  #
+  # @return [Array<Hash{String => String}>] An array of two or three element
+  # hashes, with key/value pairs for the extension's oid, its value, and
+  # optionally its critical state.
+  def request_extensions
+    raise Puppet::Error, "CSR needs content to extract fields" unless @content
+
+    # Prefer the standard extReq, but accept the Microsoft specific version as
+    # a fallback, if the standard version isn't found.
+    attribute   = @content.attributes.find {|x| x.oid == "extReq" }
+    attribute ||= @content.attributes.find {|x| x.oid == "msExtReq" }
+    return [] unless attribute
+
+    extensions = unpack_extension_request(attribute)
+
+    index = -1
+    extensions.map do |ext_values|
+      index += 1
+      context = "#{attribute.oid} extension index #{index}"
+
+      # OK, turn that into an extension, to unpack the content.  Lovely that
+      # we have to swap the order of arguments to the underlying method, or
+      # perhaps that the ASN.1 representation chose to pack them in a
+      # strange order where the optional component comes *earlier* than the
+      # fixed component in the sequence.
+      case ext_values.length
+      when 2
+        ev = OpenSSL::X509::Extension.new(ext_values[0].value, ext_values[1].value)
+        { "oid" => ev.oid, "value" => ev.value }
+
+      when 3
+        ev = OpenSSL::X509::Extension.new(ext_values[0].value, ext_values[2].value, ext_values[1].value)
+        { "oid" => ev.oid, "value" => ev.value, "critical" => ev.critical? }
+
+      else
+        raise Puppet::Error, "In #{attribute.oid}, expected extension record #{index} to have two or three items, but found #{ext_values.length}"
+      end
+    end
+  end
+
+  def subject_alt_names
+    @subject_alt_names ||= request_extensions.
+      select {|x| x["oid"] == "subjectAltName" }.
+      map {|x| x["value"].split(/\s*,\s*/) }.
+      flatten.
+      sort.
+      uniq
+  end
+
+  # Return all user specified attributes attached to this CSR as a hash. IF an
+  # OID has a single value it is returned as a string, otherwise all values are
+  # returned as an array.
+  #
+  # The format of CSR attributes is specified in PKCS#10/RFC 2986
+  #
+  # @see http://tools.ietf.org/html/rfc2986 "RFC 2986 Certification Request Syntax Specification"
+  #
+  # @api public
+  #
+  # @return [Hash<String, String>]
+  def custom_attributes
+    x509_attributes = @content.attributes.reject do |attr|
+      PRIVATE_CSR_ATTRIBUTES.include? attr.oid
+    end
+
+    x509_attributes.map do |attr|
+      {"oid" => attr.oid, "value" => attr.value.first.value}
+    end
+  end
+
+  private
+
+  # Exclude OIDs that may conflict with how Puppet creates CSRs.
+  #
+  # We only have nominal support for Microsoft extension requests, but since we
+  # ultimately respect that field when looking for extension requests in a CSR
+  # we need to prevent that field from being written to directly.
+  PRIVATE_CSR_ATTRIBUTES = [
+    'extReq',   '1.2.840.113549.1.9.14',
+    'msExtReq', '1.3.6.1.4.1.311.2.1.14',
+  ]
+
+  def add_csr_attributes(csr, csr_attributes)
+    csr_attributes.each do |oid, value|
+      begin
+        if PRIVATE_CSR_ATTRIBUTES.include? oid
+          raise ArgumentError, "Cannot specify CSR attribute #{oid}: conflicts with internally used CSR attribute"
+        end
+
+        encoded = OpenSSL::ASN1::PrintableString.new(value.to_s)
+
+        attr_set = OpenSSL::ASN1::Set.new([encoded])
+        csr.add_attribute(OpenSSL::X509::Attribute.new(oid, attr_set))
+        Puppet.debug("Added csr attribute: #{oid} => #{attr_set.inspect}")
+      rescue OpenSSL::X509::AttributeError => e
+        raise Puppet::Error, "Cannot create CSR with attribute #{oid}: #{e.message}", e.backtrace
+      end
+    end
+  end
+
+  private
+
+  PRIVATE_EXTENSIONS = [
+    'subjectAltName', '2.5.29.17',
+  ]
+
+  # @api private
+  def extension_request_attribute(options)
+    extensions = []
+
+    if options[:extension_requests]
+      options[:extension_requests].each_pair do |oid, value|
+        begin
+          if PRIVATE_EXTENSIONS.include? oid
+            raise Puppet::Error, "Cannot specify CSR extension request #{oid}: conflicts with internally used extension request"
+          end
+
+          ext = OpenSSL::X509::Extension.new(oid, value.to_s, false)
+          extensions << ext
+        rescue OpenSSL::X509::ExtensionError => e
+          raise Puppet::Error, "Cannot create CSR with extension request #{oid}: #{e.message}", e.backtrace
+        end
+      end
+    end
+
+    if options[:dns_alt_names]
+      names = options[:dns_alt_names].split(/\s*,\s*/).map(&:strip) + [name]
+      names = names.sort.uniq.map {|name| "DNS:#{name}" }.join(", ")
+      alt_names_ext = extension_factory.create_extension("subjectAltName", names, false)
+
+      extensions << alt_names_ext
+    end
+
+    unless extensions.empty?
+      seq = OpenSSL::ASN1::Sequence(extensions)
+      ext_req = OpenSSL::ASN1::Set([seq])
+      OpenSSL::X509::Attribute.new("extReq", ext_req)
+    end
+  end
+
+  # Unpack the extReq attribute into an array of Extensions.
+  #
+  # The extension request attribute is structured like
+  # `Set[Sequence[Extensions]]` where the outer Set only contains a single
+  # sequence.
+  #
+  # In addition the Ruby implementation of ASN1 requires that all ASN1 values
+  # contain a single value, so Sets and Sequence have to contain an array
+  # that in turn holds the elements. This is why we have to unpack an array
+  # every time we unpack a Set/Seq.
+  #
+  # @see http://tools.ietf.org/html/rfc2985#ref-10 5.4.2 CSR Extension Request structure
+  # @see http://tools.ietf.org/html/rfc5280 4.1 Certificate Extension structure
+  #
+  # @api private
+  #
+  # @param attribute [OpenSSL::X509::Attribute] The X509 extension request
+  #
+  # @return [Array<Array<Object>>] A array of arrays containing the extension
+  #   OID the critical state if present, and the extension value.
+  def unpack_extension_request(attribute)
+
+    unless attribute.value.is_a? OpenSSL::ASN1::Set
+      raise Puppet::Error, "In #{attribute.oid}, expected Set but found #{attribute.value.class}"
+    end
+
+    unless attribute.value.value.is_a? Array
+      raise Puppet::Error, "In #{attribute.oid}, expected Set[Array] but found #{attribute.value.value.class}"
+    end
+
+    unless attribute.value.value.size == 1
+      raise Puppet::Error, "In #{attribute.oid}, expected Set[Array] with one value but found #{attribute.value.value.size} elements"
+    end
+
+    unless attribute.value.value.first.is_a? OpenSSL::ASN1::Sequence
+      raise Puppet::Error, "In #{attribute.oid}, expected Set[Array[Sequence[...]]], but found #{extension.class}"
+    end
+
+    unless attribute.value.value.first.value.is_a? Array
+      raise Puppet::Error, "In #{attribute.oid}, expected Set[Array[Sequence[Array[...]]]], but found #{extension.value.class}"
+    end
+
+    extensions = attribute.value.value.first.value
+
+    extensions.map(&:value)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_request_attributes.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_request_attributes.rb
new file mode 100644
index 0000000..9a2a467
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_request_attributes.rb
@@ -0,0 +1,37 @@
+require 'puppet/ssl'
+require 'puppet/util/yaml'
+
+# This class transforms simple key/value pairs into the equivalent ASN1
+# structures. Values may be strings or arrays of strings.
+#
+# @api private
+class Puppet::SSL::CertificateRequestAttributes
+
+  attr_reader :path, :custom_attributes, :extension_requests
+
+  def initialize(path)
+    @path = path
+    @custom_attributes = {}
+    @extension_requests = {}
+  end
+
+  # Attempt to load a yaml file at the given @path.
+  # @return true if we are able to load the file, false otherwise
+  # @raise [Puppet::Error] if there are unexpected attribute keys
+  def load
+    Puppet.info("csr_attributes file loading from #{path}")
+    if Puppet::FileSystem.exist?(path)
+      hash = Puppet::Util::Yaml.load_file(path, {})
+      if ! hash.is_a?(Hash)
+        raise Puppet::Error, "invalid CSR attributes, expected instance of Hash, received instance of #{hash.class}"
+      end
+      @custom_attributes = hash.delete('custom_attributes') || {}
+      @extension_requests = hash.delete('extension_requests') || {}
+      if not hash.keys.empty?
+        raise Puppet::Error, "unexpected attributes #{hash.keys.inspect} in #{@path.inspect}"
+      end
+      return true
+    end
+    return false
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_revocation_list.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_revocation_list.rb
new file mode 100644
index 0000000..f686ed0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_revocation_list.rb
@@ -0,0 +1,110 @@
+require 'puppet/ssl/base'
+require 'puppet/indirector'
+
+# Manage the CRL.
+class Puppet::SSL::CertificateRevocationList < Puppet::SSL::Base
+  FIVE_YEARS = 5 * 365*24*60*60
+
+  wraps OpenSSL::X509::CRL
+
+  extend Puppet::Indirector
+  indirects :certificate_revocation_list, :terminus_class => :file, :doc => <<DOC
+    This indirection wraps an `OpenSSL::X509::CRL` object, representing a certificate revocation list (CRL).
+    The indirection key is the CA name (usually literally `ca`).
+DOC
+
+  # Convert a string into an instance.
+  def self.from_s(string)
+    super(string, 'foo') # The name doesn't matter
+  end
+
+  # Because of how the format handler class is included, this
+  # can't be in the base class.
+  def self.supported_formats
+    [:s]
+  end
+
+  # Knows how to create a CRL with our system defaults.
+  def generate(cert, cakey)
+    Puppet.info "Creating a new certificate revocation list"
+
+    create_crl_issued_by(cert)
+    start_at_initial_crl_number
+    update_valid_time_range_to_start_at(Time.now)
+    sign_with(cakey)
+
+    @content
+  end
+
+  # The name doesn't actually matter; there's only one CRL.
+  # We just need the name so our Indirector stuff all works more easily.
+  def initialize(fakename)
+    @name = "crl"
+  end
+
+  # Revoke the certificate with serial number SERIAL issued by this
+  # CA, then write the CRL back to disk. The REASON must be one of the
+  # OpenSSL::OCSP::REVOKED_* reasons
+  def revoke(serial, cakey, reason = OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE)
+    Puppet.notice "Revoked certificate with serial #{serial}"
+    time = Time.now
+
+    add_certificate_revocation_for(serial, reason, time)
+    update_to_next_crl_number
+    update_valid_time_range_to_start_at(time)
+    sign_with(cakey)
+
+    Puppet::SSL::CertificateRevocationList.indirection.save(self)
+  end
+
+private
+
+  def create_crl_issued_by(cert)
+    ef = OpenSSL::X509::ExtensionFactory.new(cert)
+    @content = wrapped_class.new
+    @content.issuer = cert.subject
+    @content.add_extension(ef.create_ext("authorityKeyIdentifier", "keyid:always"))
+    @content.version = 1
+  end
+
+  def start_at_initial_crl_number
+    @content.add_extension(crl_number_of(0))
+  end
+
+  def add_certificate_revocation_for(serial, reason, time)
+    revoked = OpenSSL::X509::Revoked.new
+    revoked.serial = serial
+    revoked.time = time
+    enum = OpenSSL::ASN1::Enumerated(reason)
+    ext = OpenSSL::X509::Extension.new("CRLReason", enum)
+    revoked.add_extension(ext)
+    @content.add_revoked(revoked)
+  end
+
+  def update_valid_time_range_to_start_at(time)
+    # The CRL is not valid if the time of checking == the time of last_update.
+    # So to have it valid right now we need to say that it was updated one second ago.
+    @content.last_update = time - 1
+    @content.next_update = time + FIVE_YEARS
+  end
+
+  def update_to_next_crl_number
+    @content.extensions = with_next_crl_number_from(@content.extensions)
+  end
+
+  def with_next_crl_number_from(existing_extensions)
+    existing_crl_num = existing_extensions.find { |e| e.oid == 'crlNumber' }
+    new_crl_num = existing_crl_num ? existing_crl_num.value.to_i + 1 : 0
+
+    extensions_without_crl_num = existing_extensions.reject { |e| e.oid == 'crlNumber' }
+    extensions_without_crl_num + [crl_number_of(new_crl_num)]
+  end
+
+  def crl_number_of(number)
+    OpenSSL::X509::Extension.new('crlNumber', OpenSSL::ASN1::Integer(number))
+  end
+
+  def sign_with(cakey)
+    @content.sign(cakey, OpenSSL::Digest::SHA1.new)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_signer.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_signer.rb
new file mode 100644
index 0000000..acaff01
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/certificate_signer.rb
@@ -0,0 +1,22 @@
+# Take care of signing a certificate in a FIPS 140-2 compliant manner.
+#
+# @see http://projects.puppetlabs.com/issues/17295
+#
+# @api private
+class Puppet::SSL::CertificateSigner
+  def initialize
+    if OpenSSL::Digest.const_defined?('SHA256')
+      @digest = OpenSSL::Digest::SHA256
+    elsif OpenSSL::Digest.const_defined?('SHA1')
+      @digest = OpenSSL::Digest::SHA1
+    else
+      raise Puppet::Error,
+        "No FIPS 140-2 compliant digest algorithm in OpenSSL::Digest"
+    end
+    @digest
+  end
+
+  def sign(content, key)
+    content.sign(key, @digest.new)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/configuration.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/configuration.rb
new file mode 100644
index 0000000..eee52c2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/configuration.rb
@@ -0,0 +1,64 @@
+require 'puppet/ssl'
+require 'openssl'
+module Puppet
+module SSL
+  # Puppet::SSL::Configuration is intended to separate out the following concerns:
+  # * CA certificates that authenticate peers (ca_auth_file)
+  # * CA certificates that build trust but do not authenticate (ca_chain_file)
+  # * Who clients trust as distinct from who servers trust.  We should not
+  #   assume one single self signed CA cert for everyone.
+class Configuration
+  def initialize(localcacert, options={})
+    if (options[:ca_chain_file] and not options[:ca_auth_file])
+      raise ArgumentError, "The CA auth chain is required if the chain file is provided"
+    end
+    @localcacert = localcacert
+    @ca_chain_file = options[:ca_chain_file]
+    @ca_auth_file = options[:ca_auth_file]
+  end
+
+  # The ca_chain_file method is intended to return the PEM bundle of CA certs
+  # establishing trust but not used for peer authentication.
+  def ca_chain_file
+    @ca_chain_file || ca_auth_file
+  end
+
+  # The ca_auth_file method is intended to return the PEM bundle of CA certs
+  # used to authenticate peer connections.
+  def ca_auth_file
+    @ca_auth_file || @localcacert
+  end
+
+  ##
+  # ca_auth_certificates returns an Array of OpenSSL::X509::Certificate
+  # instances intended to be used in the connection verify_callback.  This
+  # method loads and parses the {#ca_auth_file} from the filesystem.
+  #
+  # @api private
+  #
+  # @return [Array<OpenSSL::X509::Certificate>]
+  def ca_auth_certificates
+    @ca_auth_certificates ||= decode_cert_bundle(read_file(ca_auth_file))
+  end
+
+  ##
+  # Decode a string of concatenated certificates
+  #
+  # @return [Array<OpenSSL::X509::Certificate>]
+  def decode_cert_bundle(bundle_str)
+    re = /-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----/m
+    pem_ary = bundle_str.scan(re)
+    pem_ary.map do |pem_str|
+      OpenSSL::X509::Certificate.new(pem_str)
+    end
+  end
+  private :decode_cert_bundle
+
+  # read_file makes testing easier.
+  def read_file(path)
+    File.read(path)
+  end
+  private :read_file
+end
+end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/digest.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/digest.rb
new file mode 100644
index 0000000..a16de58
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/digest.rb
@@ -0,0 +1,20 @@
+class Puppet::SSL::Digest
+  attr_reader :digest
+
+  def initialize(algorithm, content)
+    algorithm ||= 'SHA256'
+    @digest = OpenSSL::Digest.new(algorithm, content)
+  end
+
+  def to_s
+    "(#{name}) #{to_hex}"
+  end
+
+  def to_hex
+    @digest.hexdigest.scan(/../).join(':').upcase
+  end
+
+  def name
+    @digest.name.upcase
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/host.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/host.rb
new file mode 100644
index 0000000..442c648
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/host.rb
@@ -0,0 +1,372 @@
+require 'puppet/indirector'
+require 'puppet/ssl'
+require 'puppet/ssl/key'
+require 'puppet/ssl/certificate'
+require 'puppet/ssl/certificate_request'
+require 'puppet/ssl/certificate_revocation_list'
+require 'puppet/ssl/certificate_request_attributes'
+
+# The class that manages all aspects of our SSL certificates --
+# private keys, public keys, requests, etc.
+class Puppet::SSL::Host
+  # Yay, ruby's strange constant lookups.
+  Key = Puppet::SSL::Key
+  CA_NAME = Puppet::SSL::CA_NAME
+  Certificate = Puppet::SSL::Certificate
+  CertificateRequest = Puppet::SSL::CertificateRequest
+  CertificateRevocationList = Puppet::SSL::CertificateRevocationList
+
+  extend Puppet::Indirector
+  indirects :certificate_status, :terminus_class => :file, :doc => <<DOC
+    This indirection represents the host that ties a key, certificate, and certificate request together.
+    The indirection key is the certificate CN (generally a hostname).
+DOC
+
+  attr_reader :name
+  attr_accessor :ca
+
+  attr_writer :key, :certificate, :certificate_request
+
+  # This accessor is used in instances for indirector requests to hold desired state
+  attr_accessor :desired_state
+
+  def self.localhost
+    return @localhost if @localhost
+    @localhost = new
+    @localhost.generate unless @localhost.certificate
+    @localhost.key
+    @localhost
+  end
+
+  def self.reset
+    @localhost = nil
+  end
+
+  # This is the constant that people will use to mark that a given host is
+  # a certificate authority.
+  def self.ca_name
+    CA_NAME
+  end
+
+  class << self
+    attr_reader :ca_location
+  end
+
+  # Configure how our various classes interact with their various terminuses.
+  def self.configure_indirection(terminus, cache = nil)
+    Certificate.indirection.terminus_class = terminus
+    CertificateRequest.indirection.terminus_class = terminus
+    CertificateRevocationList.indirection.terminus_class = terminus
+
+    host_map = {:ca => :file, :disabled_ca => nil, :file => nil, :rest => :rest}
+    if term = host_map[terminus]
+      self.indirection.terminus_class = term
+    else
+      self.indirection.reset_terminus_class
+    end
+
+    if cache
+      # This is weird; we don't actually cache our keys, we
+      # use what would otherwise be the cache as our normal
+      # terminus.
+      Key.indirection.terminus_class = cache
+    else
+      Key.indirection.terminus_class = terminus
+    end
+
+    if cache
+      Certificate.indirection.cache_class = cache
+      CertificateRequest.indirection.cache_class = cache
+      CertificateRevocationList.indirection.cache_class = cache
+    else
+      # Make sure we have no cache configured.  puppet master
+      # switches the configurations around a bit, so it's important
+      # that we specify the configs for absolutely everything, every
+      # time.
+      Certificate.indirection.cache_class = nil
+      CertificateRequest.indirection.cache_class = nil
+      CertificateRevocationList.indirection.cache_class = nil
+    end
+  end
+
+  CA_MODES = {
+    # Our ca is local, so we use it as the ultimate source of information
+    # And we cache files locally.
+    :local => [:ca, :file],
+    # We're a remote CA client.
+    :remote => [:rest, :file],
+    # We are the CA, so we don't have read/write access to the normal certificates.
+    :only => [:ca],
+    # We have no CA, so we just look in the local file store.
+    :none => [:disabled_ca]
+  }
+
+  # Specify how we expect to interact with our certificate authority.
+  def self.ca_location=(mode)
+    modes = CA_MODES.collect { |m, vals| m.to_s }.join(", ")
+    raise ArgumentError, "CA Mode can only be one of: #{modes}" unless CA_MODES.include?(mode)
+
+    @ca_location = mode
+
+    configure_indirection(*CA_MODES[@ca_location])
+  end
+
+  # Puppet::SSL::Host is actually indirected now so the original implementation
+  # has been moved into the certificate_status indirector.  This method is in-use
+  # in `puppet cert -c <certname>`.
+  def self.destroy(name)
+    indirection.destroy(name)
+  end
+
+  def self.from_data_hash(data)
+    instance = new(data["name"])
+    if data["desired_state"]
+      instance.desired_state = data["desired_state"]
+    end
+    instance
+  end
+
+  def self.from_pson(pson)
+    Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
+    self.from_data_hash(pson)
+  end
+
+  # Puppet::SSL::Host is actually indirected now so the original implementation
+  # has been moved into the certificate_status indirector.  This method does not
+  # appear to be in use in `puppet cert -l`.
+  def self.search(options = {})
+    indirection.search("*", options)
+  end
+
+  # Is this a ca host, meaning that all of its files go in the CA location?
+  def ca?
+    ca
+  end
+
+  def key
+    @key ||= Key.indirection.find(name)
+  end
+
+  # This is the private key; we can create it from scratch
+  # with no inputs.
+  def generate_key
+    @key = Key.new(name)
+    @key.generate
+    begin
+      Key.indirection.save(@key)
+    rescue
+      @key = nil
+      raise
+    end
+    true
+  end
+
+  def certificate_request
+    @certificate_request ||= CertificateRequest.indirection.find(name)
+  end
+
+  # Our certificate request requires the key but that's all.
+  def generate_certificate_request(options = {})
+    generate_key unless key
+
+    # If this CSR is for the current machine...
+    if name == Puppet[:certname].downcase
+      # ...add our configured dns_alt_names
+      if Puppet[:dns_alt_names] and Puppet[:dns_alt_names] != ''
+        options[:dns_alt_names] ||= Puppet[:dns_alt_names]
+      elsif Puppet::SSL::CertificateAuthority.ca? and fqdn = Facter.value(:fqdn) and domain = Facter.value(:domain)
+        options[:dns_alt_names] = "puppet, #{fqdn}, puppet.#{domain}"
+      end
+    end
+
+    csr_attributes = Puppet::SSL::CertificateRequestAttributes.new(Puppet[:csr_attributes])
+    if csr_attributes.load
+      options[:csr_attributes] = csr_attributes.custom_attributes
+      options[:extension_requests] = csr_attributes.extension_requests
+    end
+
+    @certificate_request = CertificateRequest.new(name)
+    @certificate_request.generate(key.content, options)
+    begin
+      CertificateRequest.indirection.save(@certificate_request)
+    rescue
+      @certificate_request = nil
+      raise
+    end
+
+    true
+  end
+
+  def certificate
+    unless @certificate
+      generate_key unless key
+
+      # get the CA cert first, since it's required for the normal cert
+      # to be of any use.
+      return nil unless Certificate.indirection.find("ca", :fail_on_404 => true) unless ca?
+      return nil unless @certificate = Certificate.indirection.find(name)
+
+      validate_certificate_with_key
+    end
+    @certificate
+  end
+
+  def validate_certificate_with_key
+    raise Puppet::Error, "No certificate to validate." unless certificate
+    raise Puppet::Error, "No private key with which to validate certificate with fingerprint: #{certificate.fingerprint}" unless key
+    unless certificate.content.check_private_key(key.content)
+      raise Puppet::Error, <<ERROR_STRING
+The certificate retrieved from the master does not match the agent's private key.
+Certificate fingerprint: #{certificate.fingerprint}
+To fix this, remove the certificate from both the master and the agent and then start a puppet run, which will automatically regenerate a certficate.
+On the master:
+  puppet cert clean #{Puppet[:certname]}
+On the agent:
+  1a. On most platforms: find #{Puppet[:ssldir]} -name #{Puppet[:certname]}.pem -delete
+  1b. On Windows: del "#{Puppet[:ssldir]}/#{Puppet[:certname]}.pem" /f
+  2. puppet agent -t
+ERROR_STRING
+    end
+  end
+
+  # Generate all necessary parts of our ssl host.
+  def generate
+    generate_key unless key
+    generate_certificate_request unless certificate_request
+
+    # If we can get a CA instance, then we're a valid CA, and we
+    # should use it to sign our request; else, just try to read
+    # the cert.
+    if ! certificate and ca = Puppet::SSL::CertificateAuthority.instance
+      ca.sign(self.name, true)
+    end
+  end
+
+  def initialize(name = nil)
+    @name = (name || Puppet[:certname]).downcase
+    Puppet::SSL::Base.validate_certname(@name)
+    @key = @certificate = @certificate_request = nil
+    @ca = (name == self.class.ca_name)
+  end
+
+  # Extract the public key from the private key.
+  def public_key
+    key.content.public_key
+  end
+
+  # Create/return a store that uses our SSL info to validate
+  # connections.
+  def ssl_store(purpose = OpenSSL::X509::PURPOSE_ANY)
+    unless @ssl_store
+      @ssl_store = OpenSSL::X509::Store.new
+      @ssl_store.purpose = purpose
+
+      # Use the file path here, because we don't want to cause
+      # a lookup in the middle of setting our ssl connection.
+      @ssl_store.add_file(Puppet[:localcacert])
+
+      # If we're doing revocation and there's a CRL, add it to our store.
+      if Puppet.settings[:certificate_revocation]
+        if crl = Puppet::SSL::CertificateRevocationList.indirection.find(CA_NAME)
+          @ssl_store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK
+          @ssl_store.add_crl(crl.content)
+        end
+      end
+      return @ssl_store
+    end
+    @ssl_store
+  end
+
+  def to_data_hash
+    my_cert = Puppet::SSL::Certificate.indirection.find(name)
+    result = { :name  => name }
+
+    my_state = state
+
+    result[:state] = my_state
+    result[:desired_state] = desired_state if desired_state
+
+    thing_to_use = (my_state == 'requested') ? certificate_request : my_cert
+
+    # this is for backwards-compatibility
+    # we should deprecate it and transition people to using
+    # pson[:fingerprints][:default]
+    # It appears that we have no internal consumers of this api
+    # --jeffweiss 30 aug 2012
+    result[:fingerprint] = thing_to_use.fingerprint
+
+    # The above fingerprint doesn't tell us what message digest algorithm was used
+    # No problem, except that the default is changing between 2.7 and 3.0. Also, as
+    # we move to FIPS 140-2 compliance, MD5 is no longer allowed (and, gasp, will
+    # segfault in rubies older than 1.9.3)
+    # So, when we add the newer fingerprints, we're explicit about the hashing
+    # algorithm used.
+    # --jeffweiss 31 july 2012
+    result[:fingerprints] = {}
+    result[:fingerprints][:default] = thing_to_use.fingerprint
+
+    suitable_message_digest_algorithms.each do |md|
+      result[:fingerprints][md] = thing_to_use.fingerprint md
+    end
+    result[:dns_alt_names] = thing_to_use.subject_alt_names
+
+    result
+  end
+
+  # eventually we'll probably want to move this somewhere else or make it
+  # configurable
+  # --jeffweiss 29 aug 2012
+  def suitable_message_digest_algorithms
+    [:SHA1, :SHA256, :SHA512]
+  end
+
+  # Attempt to retrieve a cert, if we don't already have one.
+  def wait_for_cert(time)
+    begin
+      return if certificate
+      generate
+      return if certificate
+    rescue SystemExit,NoMemoryError
+      raise
+    rescue Exception => detail
+      Puppet.log_exception(detail, "Could not request certificate: #{detail.message}")
+      if time < 1
+        puts "Exiting; failed to retrieve certificate and waitforcert is disabled"
+        exit(1)
+      else
+        sleep(time)
+      end
+      retry
+    end
+
+    if time < 1
+      puts "Exiting; no certificate found and waitforcert is disabled"
+      exit(1)
+    end
+
+    while true
+      sleep time
+      begin
+        break if certificate
+        Puppet.notice "Did not receive certificate"
+      rescue StandardError => detail
+        Puppet.log_exception(detail, "Could not request certificate: #{detail.message}")
+      end
+    end
+  end
+
+  def state
+    if certificate_request
+      return 'requested'
+    end
+
+    begin
+      Puppet::SSL::CertificateAuthority.new.verify(name)
+      return 'signed'
+    rescue Puppet::SSL::CertificateAuthority::CertificateVerificationError
+      return 'revoked'
+    end
+  end
+end
+
+require 'puppet/ssl/certificate_authority'
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/inventory.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/inventory.rb
new file mode 100644
index 0000000..83b5388
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/inventory.rb
@@ -0,0 +1,55 @@
+require 'puppet/ssl'
+require 'puppet/ssl/certificate'
+
+# Keep track of all of our known certificates.
+class Puppet::SSL::Inventory
+  attr_reader :path
+
+  # Add a certificate to our inventory.
+  def add(cert)
+    cert = cert.content if cert.is_a?(Puppet::SSL::Certificate)
+    Puppet.settings.setting(:cert_inventory).open("a") do |f|
+      f.print format(cert)
+    end
+  end
+
+  # Format our certificate for output.
+  def format(cert)
+    iso = '%Y-%m-%dT%H:%M:%S%Z'
+    "0x%04x %s %s %s\n" % [cert.serial,  cert.not_before.strftime(iso), cert.not_after.strftime(iso), cert.subject]
+  end
+
+  def initialize
+    @path = Puppet[:cert_inventory]
+  end
+
+  # Rebuild the inventory from scratch.  This should happen if
+  # the file is entirely missing or if it's somehow corrupted.
+  def rebuild
+    Puppet.notice "Rebuilding inventory file"
+
+    Puppet.settings.setting(:cert_inventory).open('w') do |f|
+      Puppet::SSL::Certificate.indirection.search("*").each do |cert|
+        f.print format(cert.content)
+      end
+    end
+  end
+
+  # Find the serial number for a given certificate.
+  def serial(name)
+    Puppet.deprecation_warning 'Inventory#serial is deprecated, use Inventory#serials instead.'
+    return nil unless Puppet::FileSystem.exist?(@path)
+    serials(name).first
+  end
+
+  # Find all serial numbers for a given certificate. If none can be found, returns
+  # an empty array.
+  def serials(name)
+    return [] unless Puppet::FileSystem.exist?(@path)
+
+    File.readlines(@path).collect do |line|
+      /^(\S+).+\/CN=#{name}$/.match(line)
+    end.compact.map { |m| Integer(m[1]) }
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/key.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/key.rb
new file mode 100644
index 0000000..f8440b0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/key.rb
@@ -0,0 +1,59 @@
+require 'puppet/ssl/base'
+require 'puppet/indirector'
+
+# Manage private and public keys as a pair.
+class Puppet::SSL::Key < Puppet::SSL::Base
+  wraps OpenSSL::PKey::RSA
+
+  extend Puppet::Indirector
+  indirects :key, :terminus_class => :file, :doc => <<DOC
+    This indirection wraps an `OpenSSL::PKey::RSA object, representing a private key.
+    The indirection key is the certificate CN (generally a hostname).
+DOC
+
+  # Because of how the format handler class is included, this
+  # can't be in the base class.
+  def self.supported_formats
+    [:s]
+  end
+
+  attr_accessor :password_file
+
+  # Knows how to create keys with our system defaults.
+  def generate
+    Puppet.info "Creating a new SSL key for #{name}"
+    @content = OpenSSL::PKey::RSA.new(Puppet[:keylength].to_i)
+  end
+
+  def initialize(name)
+    super
+
+    if ca?
+      @password_file = Puppet[:capass]
+    else
+      @password_file = Puppet[:passfile]
+    end
+  end
+
+  def password
+    return nil unless password_file and Puppet::FileSystem.exist?(password_file)
+
+    ::File.read(password_file)
+  end
+
+  # Optionally support specifying a password file.
+  def read(path)
+    return super unless password_file
+
+    #@content = wrapped_class.new(::File.read(path), password)
+    @content = wrapped_class.new(::File.read(path), password)
+  end
+
+  def to_s
+    if pass = password
+      @content.export(OpenSSL::Cipher::DES.new(:EDE3, :CBC), pass)
+    else
+      return super
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/oids.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/oids.rb
new file mode 100644
index 0000000..6d0a8d0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/oids.rb
@@ -0,0 +1,78 @@
+require 'puppet/ssl'
+
+# This module defines OIDs for use within Puppet.
+#
+# == ASN.1 Definition
+#
+# The following is the formal definition of OIDs specified in this file.
+#
+# puppetCertExtensions OBJECT IDENTIFIER ::= {iso(1) identified-organization(3)
+#    dod(6) internet(1) private(4) enterprise(1) 34380 1}
+#
+# -- the tree under registeredExtensions 'belongs' to puppetlabs
+# -- privateExtensions can be extended by enterprises to suit their own needs
+# registeredExtensions OBJECT IDENTIFIER ::= { puppetCertExtensions 1 }
+# privateExtensions OBJECT IDENTIFIER ::= { puppetCertExtensions 2 }
+#
+# -- subtree of common registered extensions
+# -- The short names for these OIDs are intentionally lowercased and formatted
+# -- since they may be exposed inside the Puppet DSL as variables.
+# pp_uuid  OBJECT IDENTIFIER ::= { registeredExtensions 1 }
+# pp_instance_id OBJECT IDENTIFIER ::= { registeredExtensions 2 }
+# pp_image_name OBJECT IDENTIFIER ::= { registeredExtensions 3 }
+# pp_preshared_key OBJECT IDENTIFIER ::= { registeredExtensions 4 }
+#
+# @api private
+module Puppet::SSL::Oids
+
+  PUPPET_OIDS = [
+    ["1.3.6.1.4.1.34380", 'puppetlabs', 'Puppet Labs'],
+    ["1.3.6.1.4.1.34380.1", 'ppCertExt', 'Puppet Certificate Extension'],
+
+    ["1.3.6.1.4.1.34380.1.1", 'ppRegCertExt', 'Puppet Registered Certificate Extension'],
+
+    ["1.3.6.1.4.1.34380.1.1.1", 'pp_uuid', 'Puppet Node UUID'],
+    ["1.3.6.1.4.1.34380.1.1.2", 'pp_instance_id', 'Puppet Node Instance ID'],
+    ["1.3.6.1.4.1.34380.1.1.3", 'pp_image_name', 'Puppet Node Image Name'],
+    ["1.3.6.1.4.1.34380.1.1.4", 'pp_preshared_key', 'Puppet Node Preshared Key'],
+
+    ["1.3.6.1.4.1.34380.1.2", 'ppPrivCertExt', 'Puppet Private Certificate Extension'],
+  ]
+
+  PUPPET_OIDS.each do |oid_defn|
+    OpenSSL::ASN1::ObjectId.register(*oid_defn)
+  end
+
+  # Determine if the first OID contains the second OID
+  #
+  # @param first [String] The containing OID, in dotted form or as the short name
+  # @param second [String] The contained OID, in dotted form or as the short name
+  # @param exclusive [true, false] If an OID should not be considered as a subtree of itself
+  #
+  # @example Comparing two dotted OIDs
+  #   Puppet::SSL::Oids.subtree_of?('1.3.6.1', '1.3.6.1.4.1') #=> true
+  #   Puppet::SSL::Oids.subtree_of?('1.3.6.1', '1.3.6') #=> false
+  #
+  # @example Comparing an OID short name with a dotted OID
+  #   Puppet::SSL::Oids.subtree_of?('IANA', '1.3.6.1.4.1') #=> true
+  #   Puppet::SSL::Oids.subtree_of?('1.3.6.1', 'enterprises') #=> true
+  #
+  # @example Comparing an OID against itself
+  #   Puppet::SSL::Oids.subtree_of?('IANA', 'IANA') #=> true
+  #   Puppet::SSL::Oids.subtree_of?('IANA', 'IANA', true) #=> false
+  #
+  # @return [true, false]
+  def self.subtree_of?(first, second, exclusive = false)
+    first_oid = OpenSSL::ASN1::ObjectId.new(first).oid
+    second_oid = OpenSSL::ASN1::ObjectId.new(second).oid
+
+
+    if exclusive and first_oid == second_oid
+      false
+    else
+      second_oid.index(first_oid) == 0
+    end
+  rescue OpenSSL::ASN1::ASN1Error
+    false
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/validator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/validator.rb
new file mode 100644
index 0000000..754a742
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/validator.rb
@@ -0,0 +1,60 @@
+require 'openssl'
+
+# API for certificate verification
+#
+# @api public
+class Puppet::SSL::Validator
+
+  # Factory method for creating an instance of a null/no validator.
+  # This method does not have to be implemented by concrete implementations of this API.
+  #
+  # @return [Puppet::SSL::Validator] produces a validator that performs no validation
+  #
+  # @api public
+  #
+  def self.no_validator()
+    @@no_validator_cache ||= Puppet::SSL::Validator::NoValidator.new()
+  end
+
+  # Factory method for creating an instance of the default Puppet validator.
+  # This method does not have to be implemented by concrete implementations of this API.
+  #
+  # @return [Puppet::SSL::Validator] produces a validator that performs no validation
+  #
+  # @api public
+  #
+  def self.default_validator()
+    Puppet::SSL::Validator::DefaultValidator.new()
+  end
+
+  # Array of peer certificates
+  # @return [Array<Puppet::SSL::Certificate>] peer certificates
+  #
+  # @api public
+  #
+  def peer_certs
+    raise NotImplementedError, "Concrete class should have implemented this method"
+  end
+
+  # Contains the result of validation
+  # @return [Array<String>, nil] nil, empty Array, or Array with messages
+  #
+  # @api public
+  #
+  def verify_errors
+    raise NotImplementedError, "Concrete class should have implemented this method"
+  end
+
+  # Registers the connection to validate.
+  #
+  # @param [Net::HTTP] connection The connection to validate
+  #
+  # @return [void]
+  #
+  # @api public
+  #
+  def setup_connection(connection)
+    raise NotImplementedError, "Concrete class should have implemented this method"
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/validator/default_validator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/validator/default_validator.rb
new file mode 100644
index 0000000..674b3c2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/validator/default_validator.rb
@@ -0,0 +1,175 @@
+require 'openssl'
+require 'puppet/ssl'
+
+# Perform peer certificate verification against the known CA.
+# If there is no CA information known, then no verification is performed
+#
+# @api private
+#
+class Puppet::SSL::Validator::DefaultValidator #< class Puppet::SSL::Validator
+  attr_reader :peer_certs
+  attr_reader :verify_errors
+  attr_reader :ssl_configuration
+
+  FIVE_MINUTES_AS_SECONDS = 5 * 60
+
+  # Creates a new DefaultValidator, optionally with an SSL Configuration and SSL Host.
+  #
+  # @param ssl_configuration [Puppet::SSL::Configuration] (a default configuration) ssl_configuration the SSL configuration to use
+  # @param ssl_host [Puppet::SSL::Host] (Puppet::SSL::Host.localhost) the SSL host to use
+  #
+  # @api private
+  #
+  def initialize(
+      ssl_configuration = Puppet::SSL::Configuration.new(
+                                        Puppet[:localcacert], {
+                                          :ca_chain_file => Puppet[:ssl_client_ca_chain],
+                                          :ca_auth_file  => Puppet[:ssl_client_ca_auth]
+                                        }),
+      ssl_host = Puppet::SSL::Host.localhost)
+
+    reset!
+    @ssl_configuration = ssl_configuration
+    @ssl_host = ssl_host
+  end
+
+
+  # Resets this validator to its initial validation state. The ssl configuration is not changed.
+  #
+  # @api private
+  #
+  def reset!
+    @peer_certs = []
+    @verify_errors = []
+  end
+
+  # Performs verification of the SSL connection and collection of the
+  # certificates for use in constructing the error message if the verification
+  # failed.  This callback will be executed once for each certificate in a
+  # chain being verified.
+  #
+  # From the [OpenSSL
+  # documentation](http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html):
+  # The `verify_callback` function is used to control the behaviour when the
+  # SSL_VERIFY_PEER flag is set. It must be supplied by the application and
+  # receives two arguments: preverify_ok indicates, whether the verification of
+  # the certificate in question was passed (preverify_ok=1) or not
+  # (preverify_ok=0). x509_store_ctx is a pointer to the complete context used for
+  # the certificate chain verification.
+  #
+  # See {Puppet::Network::HTTP::Connection} for more information and where this
+  # class is intended to be used.
+  #
+  # @param [Boolean] preverify_ok indicates whether the verification of the
+  #   certificate in question was passed (preverify_ok=true)
+  # @param [OpenSSL::X509::StoreContext] store_context holds the X509 store context
+  #   for the chain being verified.
+  #
+  # @return [Boolean] false if the peer is invalid, true otherwise.
+  #
+  # @api private
+  #
+  def call(preverify_ok, store_context)
+    # We must make a copy since the scope of the store_context will be lost
+    # across invocations of this method.
+    if preverify_ok
+      current_cert = store_context.current_cert
+      @peer_certs << Puppet::SSL::Certificate.from_instance(current_cert)
+
+      # If we've copied all of the certs in the chain out of the SSL library
+      if @peer_certs.length == store_context.chain.length
+        # (#20027) The peer cert must be issued by a specific authority
+        preverify_ok = valid_peer?
+      end
+    else
+      error = store_context.error || 0
+      error_string = store_context.error_string || "OpenSSL error #{error}"
+
+      case error
+      when OpenSSL::X509::V_ERR_CRL_NOT_YET_VALID
+        # current_crl can be nil
+        # https://github.com/ruby/ruby/blob/ruby_1_9_3/ext/openssl/ossl_x509store.c#L501-L510
+        crl = store_context.current_crl
+        if crl
+          if crl.last_update && crl.last_update < Time.now + FIVE_MINUTES_AS_SECONDS
+            Puppet.debug("Ignoring CRL not yet valid, current time #{Time.now.utc}, CRL last updated #{crl.last_update.utc}")
+            preverify_ok = true
+          else
+            @verify_errors << "#{error_string} for #{crl.issuer}"
+          end
+        else
+          @verify_errors << error_string
+        end
+      else
+        current_cert = store_context.current_cert
+        @verify_errors << "#{error_string} for #{current_cert.subject}"
+      end
+    end
+    preverify_ok
+  rescue => ex
+    @verify_errors << ex.message
+    false
+  end
+
+  # Registers the instance's call method with the connection.
+  #
+  # @param [Net::HTTP] connection The connection to validate
+  #
+  # @return [void]
+  #
+  # @api private
+  #
+  def setup_connection(connection)
+    if ssl_certificates_are_present?
+      connection.cert_store = @ssl_host.ssl_store
+      connection.ca_file = @ssl_configuration.ca_auth_file
+      connection.cert = @ssl_host.certificate.content
+      connection.key = @ssl_host.key.content
+      connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
+      connection.verify_callback = self
+    else
+      connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
+    end
+  end
+
+  # Validates the peer certificates against the authorized certificates.
+  #
+  # @api private
+  #
+  def valid_peer?
+    descending_cert_chain = @peer_certs.reverse.map {|c| c.content }
+    authz_ca_certs = ssl_configuration.ca_auth_certificates
+
+    if not has_authz_peer_cert(descending_cert_chain, authz_ca_certs)
+      msg = "The server presented a SSL certificate chain which does not include a " <<
+        "CA listed in the ssl_client_ca_auth file.  "
+      msg << "Authorized Issuers: #{authz_ca_certs.collect {|c| c.subject}.join(', ')}  " <<
+        "Peer Chain: #{descending_cert_chain.collect {|c| c.subject}.join(' => ')}"
+      @verify_errors << msg
+      false
+    else
+      true
+    end
+  end
+
+  # Checks if the set of peer_certs contains at least one certificate issued
+  # by a certificate listed in authz_certs
+  #
+  # @return [Boolean]
+  #
+  # @api private
+  #
+  def has_authz_peer_cert(peer_certs, authz_certs)
+    peer_certs.any? do |peer_cert|
+      authz_certs.any? do |authz_cert|
+        peer_cert.verify(authz_cert.public_key)
+      end
+    end
+  end
+
+  # @api private
+  #
+  def ssl_certificates_are_present?
+    Puppet::FileSystem.exist?(Puppet[:hostcert]) && Puppet::FileSystem.exist?(@ssl_configuration.ca_auth_file)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/validator/no_validator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/validator/no_validator.rb
new file mode 100644
index 0000000..b019369
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/ssl/validator/no_validator.rb
@@ -0,0 +1,20 @@
+require 'openssl'
+require 'puppet/ssl'
+
+# Performs no SSL verification
+# @api private
+#
+class Puppet::SSL::Validator::NoValidator < Puppet::SSL::Validator
+
+  def setup_connection(connection)
+    connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
+  end
+
+  def peer_certs
+    []
+  end
+
+  def verify_errors
+    []
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/status.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/status.rb
new file mode 100644
index 0000000..eebb958
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/status.rb
@@ -0,0 +1,45 @@
+require 'puppet/indirector'
+
+class Puppet::Status
+  extend Puppet::Indirector
+  indirects :status, :terminus_class => :local
+
+  attr_accessor :status
+
+  def initialize( status = nil )
+    @status = status || {"is_alive" => true}
+  end
+
+  def to_data_hash
+    @status
+  end
+
+  def self.from_data_hash(data)
+    if data.include?('status')
+      self.new(data['status'])
+    else
+      self.new(data)
+    end
+  end
+
+  def self.from_pson(pson)
+    Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
+    self.from_data_hash(pson)
+  end
+
+  def name
+    "status"
+  end
+
+  def name=(name)
+    # NOOP
+  end
+
+  def version
+    @status['version']
+  end
+
+  def version=(version)
+    @status['version'] = version
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/test/test_helper.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/test/test_helper.rb
new file mode 100644
index 0000000..72e312f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/test/test_helper.rb
@@ -0,0 +1,243 @@
+require 'puppet/indirector/data_binding/hiera'
+
+require 'tmpdir'
+require 'fileutils'
+
+module Puppet::Test
+  # This class is intended to provide an API to be used by external projects
+  #  when they are running tests that depend on puppet core.  This should
+  #  allow us to vary the implementation details of managing puppet's state
+  #  for testing, from one version of puppet to the next--without forcing
+  #  the external projects to do any of that state management or be aware of
+  #  the implementation details.
+  #
+  # For now, this consists of a few very simple signatures.  The plan is
+  #  that it should be the responsibility of the puppetlabs_spec_helper
+  #  to broker between external projects and this API; thus, if any
+  #  hacks are required (e.g. to determine whether or not a particular)
+  #  version of puppet supports this API, those hacks will be consolidated in
+  #  one place and won't need to be duplicated in every external project.
+  #
+  # This should also alleviate the anti-pattern that we've been following,
+  #  wherein each external project starts off with a copy of puppet core's
+  #  test_helper.rb and is exposed to risk of that code getting out of
+  #  sync with core.
+  #
+  # Since this class will be "library code" that ships with puppet, it does
+  #  not use API from any existing test framework such as rspec.  This should
+  #  theoretically allow it to be used with other unit test frameworks in the
+  #  future, if desired.
+  #
+  # Note that in the future this API could potentially be expanded to handle
+  #  other features such as "around_test", but we didn't see a compelling
+  #  reason to deal with that right now.
+  class TestHelper
+    # Call this method once, as early as possible, such as before loading tests
+    # that call Puppet.
+    # @return nil
+    def self.initialize()
+      # This meta class instance variable is used as a guard to ensure that
+      # before_each, and after_each are only called once. This problem occurs
+      # when there are more than one puppet test infrastructure "orchestrator in us.
+      # The use of both puppetabs-spec_helper, and rodjek-rspec_puppet will cause
+      # two resets of the puppet environment, and will cause problem rolling back to
+      # a known point as there is no way to differentiate where the calls are coming
+      # from. See more information in #before_each_test, and #after_each_test
+      # Note that the variable is only initialized to 0 if nil. This is important
+      # as more than one orchestrator will call initialize. A second call can not
+      # simply set it to 0 since that would potentially destroy an active guard.
+      #
+      @@reentry_count ||= 0
+
+      owner = Process.pid
+      Puppet.push_context(Puppet.base_context({
+        :environmentpath => "",
+        :basemodulepath => "",
+        :manifest => "/dev/null"
+      }), "Initial for specs")
+      Puppet::Parser::Functions.reset
+    end
+
+    # Call this method once, when beginning a test run--prior to running
+    #  any individual tests.
+    # @return nil
+    def self.before_all_tests()
+      # Make sure that all of the setup is also done for any before(:all) blocks
+    end
+
+    # Call this method once, at the end of a test run, when no more tests
+    #  will be run.
+    # @return nil
+    def self.after_all_tests()
+    end
+
+    # The name of the rollback mark used in the Puppet.context. This is what
+    # the test infrastructure returns to for each test.
+    #
+    ROLLBACK_MARK = "initial testing state"
+
+    # Call this method once per test, prior to execution of each invididual test.
+    # @return nil
+    def self.before_each_test()
+      # When using both rspec-puppet and puppet-rspec-helper, there are two packages trying
+      # to be helpful and orchestrate the callback sequence. We let only the first win, the
+      # second callback results in a no-op.
+      # Likewise when entering after_each_test(), a check is made to make tear down happen
+      # only once.
+      #
+      return unless @@reentry_count == 0
+      @@reentry_count = 1
+
+      Puppet.mark_context(ROLLBACK_MARK)
+
+      # We need to preserve the current state of all our indirection cache and
+      # terminus classes.  This is pretty important, because changes to these
+      # are global and lead to order dependencies in our testing.
+      #
+      # We go direct to the implementation because there is no safe, sane public
+      # API to manage restoration of these to their default values.  This
+      # should, once the value is proved, be moved to a standard API on the
+      # indirector.
+      #
+      # To make things worse, a number of the tests stub parts of the
+      # indirector.  These stubs have very specific expectations that what
+      # little of the public API we could use is, well, likely to explode
+      # randomly in some tests.  So, direct access.  --daniel 2011-08-30
+      $saved_indirection_state = {}
+      indirections = Puppet::Indirector::Indirection.send(:class_variable_get, :@@indirections)
+      indirections.each do |indirector|
+        $saved_indirection_state[indirector.name] = {
+            :@terminus_class => indirector.instance_variable_get(:@terminus_class),
+            :@cache_class    => indirector.instance_variable_get(:@cache_class)
+        }
+      end
+
+      # The process environment is a shared, persistent resource.
+      $old_env = ENV.to_hash
+
+      # So is the load_path
+      $old_load_path = $LOAD_PATH.dup
+
+      initialize_settings_before_each()
+
+      Puppet.push_context(
+        {
+          :trusted_information =>
+            Puppet::Context::TrustedInformation.new('local', 'testing', {}),
+        },
+        "Context for specs")
+
+      Puppet::Parser::Functions.reset
+      Puppet::Node::Environment.clear
+      Puppet::Application.clear!
+      Puppet::Util::Profiler.clear
+
+      Puppet.clear_deprecation_warnings
+
+      Puppet::DataBinding::Hiera.instance_variable_set("@hiera", nil)
+    end
+
+    # Call this method once per test, after execution of each individual test.
+    # @return nil
+    def self.after_each_test()
+      # Ensure that a matching tear down only happens once per completed setup
+      # (see #before_each_test).
+      return unless @@reentry_count == 1
+      @@reentry_count = 0
+
+      Puppet.settings.send(:clear_everything_for_tests)
+
+      Puppet::Util::Storage.clear
+      Puppet::Util::ExecutionStub.reset
+
+      Puppet.clear_deprecation_warnings
+
+      # uncommenting and manipulating this can be useful when tracking down calls to deprecated code
+      #Puppet.log_deprecations_to_file("deprecations.txt", /^Puppet::Util.exec/)
+
+      # Restore the indirector configuration.  See before hook.
+      indirections = Puppet::Indirector::Indirection.send(:class_variable_get, :@@indirections)
+      indirections.each do |indirector|
+        $saved_indirection_state.fetch(indirector.name, {}).each do |variable, value|
+          indirector.instance_variable_set(variable, value)
+        end
+      end
+      $saved_indirection_state = nil
+
+      # Restore the global process environment.  Can't just assign because this
+      # is a magic variable, sadly, and doesn't do that™.  It is sufficiently
+      # faster to use the compare-then-set model to avoid excessive work that it
+      # justifies the complexity.  --daniel 2012-03-15
+      unless ENV.to_hash == $old_env
+        ENV.clear
+        $old_env.each {|k, v| ENV[k] = v }
+      end
+
+
+      # Some tests can cause us to connect, in which case the lingering
+      # connection is a resource that can cause unexpected failure in later
+      # tests, as well as sharing state accidentally.
+      # We're testing if ActiveRecord::Base is defined because some test cases
+      # may stub Puppet.features.rails? which is how we should normally
+      # introspect for this functionality.
+      ActiveRecord::Base.remove_connection if defined?(ActiveRecord::Base)
+
+      # Restore the load_path late, to avoid messing with stubs from the test.
+      $LOAD_PATH.clear
+      $old_load_path.each {|x| $LOAD_PATH << x }
+
+      Puppet.rollback_context(ROLLBACK_MARK)
+    end
+
+
+    #########################################################################################
+    # PRIVATE METHODS (not part of the public TestHelper API--do not call these from outside
+    #  of this class!)
+    #########################################################################################
+
+    def self.app_defaults_for_tests()
+      {
+          :logdir     => "/dev/null",
+          :confdir    => "/dev/null",
+          :vardir     => "/dev/null",
+          :rundir     => "/dev/null",
+          :hiera_config => "/dev/null",
+      }
+    end
+    private_class_method :app_defaults_for_tests
+
+    def self.initialize_settings_before_each()
+      Puppet.settings.preferred_run_mode = "user"
+      # Initialize "app defaults" settings to a good set of test values
+      Puppet.settings.initialize_app_defaults(app_defaults_for_tests)
+
+      # Avoid opening ports to the outside world
+      Puppet.settings[:bindaddress] = "127.0.0.1"
+
+      # We don't want to depend upon the reported domain name of the
+      # machine running the tests, nor upon the DNS setup of that
+      # domain.
+      Puppet.settings[:use_srv_records] = false
+
+      # Longer keys are secure, but they sure make for some slow testing - both
+      # in terms of generating keys, and in terms of anything the next step down
+      # the line doing validation or whatever.  Most tests don't care how long
+      # or secure it is, just that it exists, so these are better and faster
+      # defaults, in testing only.
+      #
+      # I would make these even shorter, but OpenSSL doesn't support anything
+      # below 512 bits.  Sad, really, because a 0 bit key would be just fine.
+      Puppet[:req_bits]  = 512
+      Puppet[:keylength] = 512
+
+      # Although we setup a testing context during initialization, some tests
+      # will end up creating their own context using the real context objects
+      # and use the setting for the environments. In order to avoid those tests
+      # having to deal with a missing environmentpath we can just set it right
+      # here.
+      Puppet[:environmentpath] = @environmentpath
+      Puppet[:environment_timeout] = 0
+    end
+    private_class_method :initialize_settings_before_each
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/transaction.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/transaction.rb
new file mode 100644
index 0000000..8bec4fc
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/transaction.rb
@@ -0,0 +1,368 @@
+require 'puppet'
+require 'puppet/util/tagging'
+require 'puppet/application'
+require 'digest/sha1'
+require 'set'
+
+# the class that actually walks our resource/property tree, collects the changes,
+# and performs them
+#
+# @api private
+class Puppet::Transaction
+  require 'puppet/transaction/additional_resource_generator'
+  require 'puppet/transaction/event'
+  require 'puppet/transaction/event_manager'
+  require 'puppet/transaction/resource_harness'
+  require 'puppet/resource/status'
+
+  attr_accessor :catalog, :ignoreschedules, :for_network_device
+
+  # The report, once generated.
+  attr_reader :report
+
+  # Routes and stores any events and subscriptions.
+  attr_reader :event_manager
+
+  # Handles most of the actual interacting with resources
+  attr_reader :resource_harness
+
+  attr_reader :prefetched_providers
+
+  include Puppet::Util
+  include Puppet::Util::Tagging
+
+  def initialize(catalog, report, prioritizer)
+    @catalog = catalog
+
+    @report = report || Puppet::Transaction::Report.new("apply", catalog.version, catalog.environment)
+
+    @prioritizer = prioritizer
+
+    @report.add_times(:config_retrieval, @catalog.retrieval_duration || 0)
+
+    @event_manager = Puppet::Transaction::EventManager.new(self)
+
+    @resource_harness = Puppet::Transaction::ResourceHarness.new(self)
+
+    @prefetched_providers = Hash.new { |h,k| h[k] = {} }
+  end
+
+  # Invoke the pre_run_check hook in every resource in the catalog.
+  # This should (only) be called by Transaction#evaluate before applying
+  # the catalog.
+  #
+  # @see Puppet::Transaction#evaluate
+  # @see Puppet::Type#pre_run_check
+  # @raise [Puppet::Error] If any pre-run checks failed.
+  # @return [void]
+  def perform_pre_run_checks
+    prerun_errors = {}
+
+    @catalog.vertices.each do |res|
+      begin
+        res.pre_run_check
+      rescue Puppet::Error => detail
+        prerun_errors[res] = detail
+      end
+    end
+
+    unless prerun_errors.empty?
+      prerun_errors.each do |res, detail|
+        res.log_exception(detail)
+      end
+      raise Puppet::Error, "Some pre-run checks failed"
+    end
+  end
+
+  # This method does all the actual work of running a transaction.  It
+  # collects all of the changes, executes them, and responds to any
+  # necessary events.
+  def evaluate(&block)
+    block ||= method(:eval_resource)
+    generator = AdditionalResourceGenerator.new(@catalog, relationship_graph, @prioritizer)
+    @catalog.vertices.each { |resource| generator.generate_additional_resources(resource) }
+
+    perform_pre_run_checks
+
+    Puppet.info "Applying configuration version '#{catalog.version}'" if catalog.version
+
+    continue_while = lambda { !stop_processing? }
+
+    post_evalable_providers = Set.new
+    pre_process = lambda do |resource|
+      prov_class = resource.provider.class
+      post_evalable_providers << prov_class if prov_class.respond_to?(:post_resource_eval)
+
+      prefetch_if_necessary(resource)
+
+      # If we generated resources, we don't know what they are now
+      # blocking, so we opt to recompute it, rather than try to track every
+      # change that would affect the number.
+      relationship_graph.clear_blockers if generator.eval_generate(resource)
+    end
+
+    providerless_types = []
+    overly_deferred_resource_handler = lambda do |resource|
+      # We don't automatically assign unsuitable providers, so if there
+      # is one, it must have been selected by the user.
+      return if missing_tags?(resource)
+      if resource.provider
+        resource.err "Provider #{resource.provider.class.name} is not functional on this host"
+      else
+        providerless_types << resource.type
+      end
+
+      resource_status(resource).failed = true
+    end
+
+    canceled_resource_handler = lambda do |resource|
+      resource_status(resource).skipped = true
+      resource.debug "Transaction canceled, skipping"
+    end
+
+    teardown = lambda do
+      # Just once per type. No need to punish the user.
+      providerless_types.uniq.each do |type|
+        Puppet.err "Could not find a suitable provider for #{type}"
+      end
+
+      post_evalable_providers.each do |provider|
+        begin
+          provider.post_resource_eval
+        rescue => detail
+          Puppet.log_exception(detail, "post_resource_eval failed for provider #{provider}")
+        end
+      end
+    end
+
+    relationship_graph.traverse(:while => continue_while,
+                                :pre_process => pre_process,
+                                :overly_deferred_resource_handler => overly_deferred_resource_handler,
+                                :canceled_resource_handler => canceled_resource_handler,
+                                :teardown => teardown) do |resource|
+      if resource.is_a?(Puppet::Type::Component)
+        Puppet.warning "Somehow left a component in the relationship graph"
+      else
+        resource.info "Starting to evaluate the resource" if Puppet[:evaltrace] and @catalog.host_config?
+        seconds = thinmark { block.call(resource) }
+        resource.info "Evaluated in %0.2f seconds" % seconds if Puppet[:evaltrace] and @catalog.host_config?
+      end
+    end
+
+    Puppet.debug "Finishing transaction #{object_id}"
+  end
+
+  # Wraps application run state check to flag need to interrupt processing
+  def stop_processing?
+    Puppet::Application.stop_requested? && catalog.host_config?
+  end
+
+  # Are there any failed resources in this transaction?
+  def any_failed?
+    report.resource_statuses.values.detect { |status| status.failed? }
+  end
+
+  # Find all of the changed resources.
+  def changed?
+    report.resource_statuses.values.find_all { |status| status.changed }.collect { |status| catalog.resource(status.resource) }
+  end
+
+  def relationship_graph
+    catalog.relationship_graph(@prioritizer)
+  end
+
+  def resource_status(resource)
+    report.resource_statuses[resource.to_s] || add_resource_status(Puppet::Resource::Status.new(resource))
+  end
+
+  # The tags we should be checking.
+  def tags
+    self.tags = Puppet[:tags] unless defined?(@tags)
+
+    super
+  end
+
+  def prefetch_if_necessary(resource)
+    provider_class = resource.provider.class
+    return unless provider_class.respond_to?(:prefetch) and !prefetched_providers[resource.type][provider_class.name]
+
+    resources = resources_by_provider(resource.type, provider_class.name)
+
+    if provider_class == resource.class.defaultprovider
+      providerless_resources = resources_by_provider(resource.type, nil)
+      providerless_resources.values.each {|res| res.provider = provider_class.name}
+      resources.merge! providerless_resources
+    end
+
+    prefetch(provider_class, resources)
+  end
+
+  private
+
+  # Apply all changes for a resource
+  def apply(resource, ancestor = nil)
+    status = resource_harness.evaluate(resource)
+    add_resource_status(status)
+    event_manager.queue_events(ancestor || resource, status.events) unless status.failed?
+  rescue => detail
+    resource.err "Could not evaluate: #{detail}"
+  end
+
+  # Evaluate a single resource.
+  def eval_resource(resource, ancestor = nil)
+    if skip?(resource)
+      resource_status(resource).skipped = true
+    else
+      resource_status(resource).scheduled = true
+      apply(resource, ancestor)
+    end
+
+    # Check to see if there are any events queued for this resource
+    event_manager.process_events(resource)
+  end
+
+  def failed?(resource)
+    s = resource_status(resource) and s.failed?
+  end
+
+  # Does this resource have any failed dependencies?
+  def failed_dependencies?(resource)
+    # First make sure there are no failed dependencies.  To do this,
+    # we check for failures in any of the vertexes above us.  It's not
+    # enough to check the immediate dependencies, which is why we use
+    # a tree from the reversed graph.
+    found_failed = false
+
+
+    # When we introduced the :whit into the graph, to reduce the combinatorial
+    # explosion of edges, we also ended up reporting failures for containers
+    # like class and stage.  This is undesirable; while just skipping the
+    # output isn't perfect, it is RC-safe. --daniel 2011-06-07
+    suppress_report = (resource.class == Puppet::Type.type(:whit))
+
+    relationship_graph.dependencies(resource).each do |dep|
+      next unless failed?(dep)
+      found_failed = true
+
+      # See above. --daniel 2011-06-06
+      unless suppress_report then
+        resource.notice "Dependency #{dep} has failures: #{resource_status(dep).failed}"
+      end
+    end
+
+    found_failed
+  end
+
+  # A general method for recursively generating new resources from a
+  # resource.
+  def generate_additional_resources(resource)
+    return unless resource.respond_to?(:generate)
+    begin
+      made = resource.generate
+    rescue => detail
+      resource.log_exception(detail, "Failed to generate additional resources using 'generate': #{detail}")
+    end
+    return unless made
+    made = [made] unless made.is_a?(Array)
+    made.uniq.each do |res|
+      begin
+        res.tag(*resource.tags)
+        @catalog.add_resource(res)
+        res.finish
+        add_conditional_directed_dependency(resource, res)
+        generate_additional_resources(res)
+      rescue Puppet::Resource::Catalog::DuplicateResourceError
+        res.info "Duplicate generated resource; skipping"
+      end
+    end
+  end
+
+  # Should we ignore tags?
+  def ignore_tags?
+    ! @catalog.host_config?
+  end
+
+  def resources_by_provider(type_name, provider_name)
+    unless @resources_by_provider
+      @resources_by_provider = Hash.new { |h, k| h[k] = Hash.new { |h, k| h[k] = {} } }
+
+      @catalog.vertices.each do |resource|
+        if resource.class.attrclass(:provider)
+          prov = resource.provider && resource.provider.class.name
+          @resources_by_provider[resource.type][prov][resource.name] = resource
+        end
+      end
+    end
+
+    @resources_by_provider[type_name][provider_name] || {}
+  end
+
+  # Prefetch any providers that support it, yo.  We don't support prefetching
+  # types, just providers.
+  def prefetch(provider_class, resources)
+    type_name = provider_class.resource_type.name
+    return if @prefetched_providers[type_name][provider_class.name]
+    Puppet.debug "Prefetching #{provider_class.name} resources for #{type_name}"
+    begin
+      provider_class.prefetch(resources)
+    rescue => detail
+      Puppet.log_exception(detail, "Could not prefetch #{type_name} provider '#{provider_class.name}': #{detail}")
+    end
+    @prefetched_providers[type_name][provider_class.name] = true
+  end
+
+  def add_resource_status(status)
+    report.add_resource_status(status)
+  end
+
+  # Is the resource currently scheduled?
+  def scheduled?(resource)
+    self.ignoreschedules or resource_harness.scheduled?(resource)
+  end
+
+  # Should this resource be skipped?
+  def skip?(resource)
+    if missing_tags?(resource)
+      resource.debug "Not tagged with #{tags.join(", ")}"
+    elsif ! scheduled?(resource)
+      resource.debug "Not scheduled"
+    elsif failed_dependencies?(resource)
+      # When we introduced the :whit into the graph, to reduce the combinatorial
+      # explosion of edges, we also ended up reporting failures for containers
+      # like class and stage.  This is undesirable; while just skipping the
+      # output isn't perfect, it is RC-safe. --daniel 2011-06-07
+      unless resource.class == Puppet::Type.type(:whit) then
+        resource.warning "Skipping because of failed dependencies"
+      end
+    elsif resource.virtual?
+      resource.debug "Skipping because virtual"
+    elsif !host_and_device_resource?(resource) && resource.appliable_to_host? && for_network_device
+      resource.debug "Skipping host resources because running on a device"
+    elsif !host_and_device_resource?(resource) && resource.appliable_to_device? && !for_network_device
+      resource.debug "Skipping device resources because running on a posix host"
+    else
+      return false
+    end
+    true
+  end
+
+  def host_and_device_resource?(resource)
+    resource.appliable_to_host? && resource.appliable_to_device?
+  end
+
+  def split_qualified_tags?
+    false
+  end
+
+  # Is this resource tagged appropriately?
+  def missing_tags?(resource)
+    return false if ignore_tags?
+    return false if tags.empty?
+
+    not resource.tagged?(*tags)
+  end
+
+end
+
+require 'puppet/transaction/report'
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/transaction/additional_resource_generator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/transaction/additional_resource_generator.rb
new file mode 100644
index 0000000..ef59ce2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/transaction/additional_resource_generator.rb
@@ -0,0 +1,126 @@
+# Adds additional resources to the catalog and relationship graph that are
+# generated by existing resources. There are two ways that a resource can
+# generate additional resources, either through the #generate method or the
+# #eval_generate method.
+#
+# @api private
+class Puppet::Transaction::AdditionalResourceGenerator
+  def initialize(catalog, relationship_graph, prioritizer)
+    @catalog = catalog
+    @relationship_graph = relationship_graph
+    @prioritizer = prioritizer
+  end
+
+  def generate_additional_resources(resource)
+    return unless resource.respond_to?(:generate)
+    begin
+      generated = resource.generate
+    rescue => detail
+      resource.log_exception(detail, "Failed to generate additional resources using 'generate': #{detail}")
+    end
+    return unless generated
+    generated = [generated] unless generated.is_a?(Array)
+    generated.collect do |res|
+      @catalog.resource(res.ref) || res
+    end.each do |res|
+      priority = @prioritizer.generate_priority_contained_in(resource, res)
+      add_resource(res, resource, priority)
+
+      add_conditional_directed_dependency(resource, res)
+      generate_additional_resources(res)
+    end
+  end
+
+  def eval_generate(resource)
+    return false unless resource.respond_to?(:eval_generate)
+    raise Puppet::DevError,"Depthfirst resources are not supported by eval_generate" if resource.depthfirst?
+    begin
+      generated = replace_duplicates_with_catalog_resources(resource.eval_generate)
+      return false if generated.empty?
+    rescue => detail
+      resource.log_exception(detail, "Failed to generate additional resources using 'eval_generate': #{detail}")
+      return false
+    end
+    add_resources(generated, resource)
+
+    made = Hash[generated.map(&:name).zip(generated)]
+    contain_generated_resources_in(resource, made)
+    connect_resources_to_ancestors(resource, made)
+
+    true
+  end
+
+  private
+
+  def replace_duplicates_with_catalog_resources(generated)
+    generated.collect do |generated_resource|
+      @catalog.resource(generated_resource.ref) || generated_resource
+    end
+  end
+
+  def contain_generated_resources_in(resource, made)
+    sentinel = Puppet::Type.type(:whit).new(:name => "completed_#{resource.title}", :catalog => resource.catalog)
+    priority = @prioritizer.generate_priority_contained_in(resource, sentinel)
+    @relationship_graph.add_vertex(sentinel, priority)
+
+    redirect_edges_to_sentinel(resource, sentinel, made)
+
+    made.values.each do |res|
+      # This resource isn't 'completed' until each child has run
+      add_conditional_directed_dependency(res, sentinel, Puppet::Graph::RelationshipGraph::Default_label)
+    end
+
+    # This edge allows the resource's events to propagate, though it isn't
+    # strictly necessary for ordering purposes
+    add_conditional_directed_dependency(resource, sentinel, Puppet::Graph::RelationshipGraph::Default_label)
+  end
+
+  def redirect_edges_to_sentinel(resource, sentinel, made)
+    @relationship_graph.adjacent(resource, :direction => :out, :type => :edges).each do |e|
+      next if made[e.target.name]
+
+      @relationship_graph.add_relationship(sentinel, e.target, e.label)
+      @relationship_graph.remove_edge! e
+    end
+  end
+
+  def connect_resources_to_ancestors(resource, made)
+    made.values.each do |res|
+      # Depend on the nearest ancestor we generated, falling back to the
+      # resource if we have none
+      parent_name = res.ancestors.find { |a| made[a] and made[a] != res }
+      parent = made[parent_name] || resource
+
+      add_conditional_directed_dependency(parent, res)
+    end
+  end
+
+  def add_resources(generated, resource)
+    generated.each do |res|
+      priority = @prioritizer.generate_priority_contained_in(resource, res)
+      add_resource(res, resource, priority)
+    end
+  end
+
+  def add_resource(res, parent_resource, priority)
+    if @catalog.resource(res.ref).nil?
+      res.tag(*parent_resource.tags)
+      @catalog.add_resource(res)
+      @relationship_graph.add_vertex(res, priority)
+      @catalog.add_edge(@catalog.container_of(parent_resource), res)
+      res.finish
+    end
+  end
+
+  # Copy an important relationships from the parent to the newly-generated
+  # child resource.
+  def add_conditional_directed_dependency(parent, child, label=nil)
+    @relationship_graph.add_vertex(child)
+    edge = parent.depthfirst? ? [child, parent] : [parent, child]
+    if @relationship_graph.edge?(*edge.reverse)
+      parent.debug "Skipping automatic relationship to #{child}"
+    else
+      @relationship_graph.add_relationship(edge[0],edge[1],label)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/transaction/event.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/transaction/event.rb
new file mode 100644
index 0000000..fc635a7
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/transaction/event.rb
@@ -0,0 +1,107 @@
+require 'puppet/transaction'
+require 'puppet/util/tagging'
+require 'puppet/util/logging'
+require 'puppet/util/methodhelper'
+require 'puppet/network/format_support'
+
+# A simple struct for storing what happens on the system.
+class Puppet::Transaction::Event
+  include Puppet::Util::MethodHelper
+  include Puppet::Util::Tagging
+  include Puppet::Util::Logging
+  include Puppet::Network::FormatSupport
+
+  ATTRIBUTES = [:name, :resource, :property, :previous_value, :desired_value, :historical_value, :status, :message, :file, :line, :source_description, :audited, :invalidate_refreshes]
+  YAML_ATTRIBUTES = %w{@audited @property @previous_value @desired_value @historical_value @message @name @status @time}.map(&:to_sym)
+  attr_accessor *ATTRIBUTES
+  attr_accessor :time
+  attr_reader :default_log_level
+
+  EVENT_STATUSES = %w{noop success failure audit}
+
+  def self.from_data_hash(data)
+    obj = self.allocate
+    obj.initialize_from_hash(data)
+    obj
+  end
+
+  def self.from_pson(data)
+    Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
+    self.from_data_hash(data)
+  end
+
+  def initialize(options = {})
+    @audited = false
+
+    set_options(options)
+    @time = Time.now
+  end
+
+  def initialize_from_hash(data)
+    @audited = data['audited']
+    @property = data['property']
+    @previous_value = data['previous_value']
+    @desired_value = data['desired_value']
+    @historical_value = data['historical_value']
+    @message = data['message']
+    @name = data['name'].intern if data['name']
+    @status = data['status']
+    @time = data['time']
+    @time = Time.parse(@time) if @time.is_a? String
+  end
+
+  def to_data_hash
+    {
+      'audited' => @audited,
+      'property' => @property,
+      'previous_value' => @previous_value,
+      'desired_value' => @desired_value,
+      'historical_value' => @historical_value,
+      'message' => @message,
+      'name' => @name,
+      'status' => @status,
+      'time' => @time.iso8601(9),
+    }
+  end
+
+  def property=(prop)
+    @property = prop.to_s
+  end
+
+  def resource=(res)
+    if res.respond_to?(:[]) and level = res[:loglevel]
+      @default_log_level = level
+    end
+    @resource = res.to_s
+  end
+
+  def send_log
+    super(log_level, message)
+  end
+
+  def status=(value)
+    raise ArgumentError, "Event status can only be #{EVENT_STATUSES.join(', ')}" unless EVENT_STATUSES.include?(value)
+    @status = value
+  end
+
+  def to_s
+    message
+  end
+
+  def to_yaml_properties
+    YAML_ATTRIBUTES & super
+  end
+
+  private
+
+  # If it's a failure, use 'err', else use either the resource's log level (if available)
+  # or 'notice'.
+  def log_level
+    status == "failure" ? :err : (@default_log_level || :notice)
+  end
+
+  # Used by the Logging module
+  def log_source
+    source_description || property || resource
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/transaction/event_manager.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/transaction/event_manager.rb
new file mode 100644
index 0000000..187f27a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/transaction/event_manager.rb
@@ -0,0 +1,122 @@
+require 'puppet/transaction'
+
+class Puppet::Transaction::EventManager
+  attr_reader :transaction, :events
+
+  def initialize(transaction)
+    @transaction = transaction
+    @event_queues = {}
+    @events = []
+  end
+
+  def relationship_graph
+    transaction.relationship_graph
+  end
+
+  # Respond to any queued events for this resource.
+  def process_events(resource)
+    restarted = false
+    queued_events(resource) do |callback, events|
+      r = process_callback(resource, callback, events)
+      restarted ||= r
+    end
+
+    if restarted
+      queue_events(resource, [resource.event(:name => :restarted, :status => "success")])
+
+      transaction.resource_status(resource).restarted = true
+    end
+  end
+
+  # Queue events for other resources to respond to.  All of these events have
+  # to be from the same resource.
+  def queue_events(resource, events)
+    #@events += events
+
+    # Do some basic normalization so we're not doing so many
+    # graph queries for large sets of events.
+    events.inject({}) do |collection, event|
+      collection[event.name] ||= []
+      collection[event.name] << event
+      collection
+    end.collect do |name, list|
+      # It doesn't matter which event we use - they all have the same source
+      # and name here.
+      event = list[0]
+
+      # Collect the targets of any subscriptions to those events.  We pass
+      # the parent resource in so it will override the source in the events,
+      # since eval_generated children can't have direct relationships.
+      received = (event.name != :restarted)
+      relationship_graph.matching_edges(event, resource).each do |edge|
+        received ||= true unless edge.target.is_a?(Puppet::Type.type(:whit))
+        next unless method = edge.callback
+        next unless edge.target.respond_to?(method)
+
+        queue_events_for_resource(resource, edge.target, method, list)
+      end
+      @events << event if received
+
+      queue_events_for_resource(resource, resource, :refresh, [event]) if resource.self_refresh? and ! resource.deleting?
+    end
+
+    dequeue_events_for_resource(resource, :refresh) if events.detect { |e| e.invalidate_refreshes }
+  end
+
+  def dequeue_events_for_resource(target, callback)
+    target.info "Unscheduling #{callback} on #{target}"
+    @event_queues[target][callback] = {} if @event_queues[target]
+  end
+
+  def queue_events_for_resource(source, target, callback, events)
+    whit = Puppet::Type.type(:whit)
+
+    # The message that a resource is refreshing the completed-whit for its own class
+    # is extremely counter-intuitive. Basically everything else is easy to understand,
+    # if you suppress the whit-lookingness of the whit resources
+    refreshing_c_whit = target.is_a?(whit) && target.name =~ /^completed_/
+
+    if refreshing_c_whit
+      source.debug "The container #{target} will propagate my #{callback} event"
+    else
+      source.info "Scheduling #{callback} of #{target}"
+    end
+
+    @event_queues[target] ||= {}
+    @event_queues[target][callback] ||= []
+    @event_queues[target][callback].concat(events)
+  end
+
+  def queued_events(resource)
+    return unless callbacks = @event_queues[resource]
+    callbacks.each do |callback, events|
+      yield callback, events unless events.empty?
+    end
+  end
+
+  private
+
+  def process_callback(resource, callback, events)
+    process_noop_events(resource, callback, events) and return false unless events.detect { |e| e.status != "noop" }
+    resource.send(callback)
+
+    if not resource.is_a?(Puppet::Type.type(:whit))
+      resource.notice "Triggered '#{callback}' from #{events.length} events"
+    end
+    return true
+  rescue => detail
+    resource.err "Failed to call #{callback}: #{detail}"
+
+    transaction.resource_status(resource).failed_to_restart = true
+    resource.log_exception(detail)
+    return false
+  end
+
+  def process_noop_events(resource, callback, events)
+    resource.notice "Would have triggered '#{callback}' from #{events.length} events"
+
+    # And then add an event for it.
+    queue_events(resource, [resource.event(:status => "noop", :name => :noop_restart)])
+    true # so the 'and if' works
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/transaction/report.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/transaction/report.rb
new file mode 100644
index 0000000..0530654
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/transaction/report.rb
@@ -0,0 +1,383 @@
+require 'puppet'
+require 'puppet/indirector'
+
+# This class is used to report what happens on a client.
+# There are two types of data in a report; _Logs_ and _Metrics_.
+#
+# * **Logs** - are the output that each change produces.
+# * **Metrics** - are all of the numerical data involved in the transaction.
+#
+# Use {Puppet::Reports} class to create a new custom report type. This class is indirectly used
+# as a source of data to report in such a registered report.
+#
+# ##Metrics
+# There are three types of metrics in each report, and each type of metric has one or more values.
+#
+# * Time: Keeps track of how long things took.
+#   * Total: Total time for the configuration run
+#   * File:
+#   * Exec:
+#   * User:
+#   * Group:
+#   * Config Retrieval: How long the configuration took to retrieve
+#   * Service:
+#   * Package:
+# * Resources: Keeps track of the following stats:
+#   * Total: The total number of resources being managed
+#   * Skipped: How many resources were skipped, because of either tagging or scheduling restrictions
+#   * Scheduled: How many resources met any scheduling restrictions
+#   * Out of Sync: How many resources were out of sync
+#   * Applied: How many resources were attempted to be fixed
+#   * Failed: How many resources were not successfully fixed
+#   * Restarted: How many resources were restarted because their dependencies changed
+#   * Failed Restarts: How many resources could not be restarted
+# * Changes: The total number of changes in the transaction.
+#
+# @api public
+class Puppet::Transaction::Report
+  extend Puppet::Indirector
+
+  indirects :report, :terminus_class => :processor
+
+  # The version of the configuration
+  # @todo Uncertain what this is?
+  # @return [???] the configuration version
+  attr_accessor :configuration_version
+
+  # An agent generated transaction uuid, useful for connecting catalog and report
+  # @return [String] uuid
+  attr_accessor :transaction_uuid
+
+  # The host name for which the report is generated
+  # @return [String] the host name
+  attr_accessor :host
+
+  # The name of the environment the host is in
+  # @return [String] the environment name
+  attr_accessor :environment
+
+  # A hash with a map from resource to status
+  # @return [Hash{String => Puppet::Resource::Status}] Resource name to status.
+  attr_reader :resource_statuses
+
+  # A list of log messages.
+  # @return [Array<Puppet::Util::Log>] logged messages
+  attr_reader :logs
+
+  # A hash of metric name to metric value.
+  # @return [Hash<{String => Object}>] A map of metric name to value.
+  # @todo Uncertain if all values are numbers - now marked as Object.
+  #
+  attr_reader :metrics
+
+  # The time when the report data was generated.
+  # @return [Time] A time object indicating when the report data was generated
+  #
+  attr_reader :time
+
+  # The 'kind' of report is the name of operation that triggered the report to be produced.
+  # Typically "apply".
+  # @return [String] the kind of operation that triggered the generation of the report.
+  #
+  attr_reader :kind
+
+  # The status of the client run is an enumeration: 'failed', 'changed' or 'unchanged'
+  # @return [String] the status of the run - one of the values 'failed', 'changed', or 'unchanged'
+  #
+  attr_reader :status
+
+  # @return [String] The Puppet version in String form.
+  # @see Puppet::version()
+  #
+  attr_reader :puppet_version
+
+  # @return [Integer] report format version number.  This value is constant for
+  #    a given version of Puppet; it is incremented when a new release of Puppet
+  #    changes the API for the various objects that make up a report.
+  #
+  attr_reader :report_format
+
+  def self.from_data_hash(data)
+    obj = self.allocate
+    obj.initialize_from_hash(data)
+    obj
+  end
+
+  def self.from_pson(data)
+    Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
+    self.from_data_hash(data)
+  end
+
+  def as_logging_destination(&block)
+    Puppet::Util::Log.with_destination(self, &block)
+  end
+
+  # @api private
+  def <<(msg)
+    @logs << msg
+    self
+  end
+
+  # @api private
+  def add_times(name, value)
+    @external_times[name] = value
+  end
+
+  # @api private
+  def add_metric(name, hash)
+    metric = Puppet::Util::Metric.new(name)
+
+    hash.each do |name, value|
+      metric.newvalue(name, value)
+    end
+
+    @metrics[metric.name] = metric
+    metric
+  end
+
+  # @api private
+  def add_resource_status(status)
+    @resource_statuses[status.resource] = status
+  end
+
+  # @api private
+  def compute_status(resource_metrics, change_metric)
+    if (resource_metrics["failed"] || 0) > 0
+      'failed'
+    elsif change_metric > 0
+      'changed'
+    else
+      'unchanged'
+    end
+  end
+
+  # @api private
+  def prune_internal_data
+    resource_statuses.delete_if {|name,res| res.resource_type == 'Whit'}
+  end
+
+  # @api private
+  def finalize_report
+    prune_internal_data
+
+    resource_metrics = add_metric(:resources, calculate_resource_metrics)
+    add_metric(:time, calculate_time_metrics)
+    change_metric = calculate_change_metric
+    add_metric(:changes, {"total" => change_metric})
+    add_metric(:events, calculate_event_metrics)
+    @status = compute_status(resource_metrics, change_metric)
+  end
+
+  # @api private
+  def initialize(kind, configuration_version=nil, environment=nil, transaction_uuid=nil)
+    @metrics = {}
+    @logs = []
+    @resource_statuses = {}
+    @external_times ||= {}
+    @host = Puppet[:node_name_value]
+    @time = Time.now
+    @kind = kind
+    @report_format = 4
+    @puppet_version = Puppet.version
+    @configuration_version = configuration_version
+    @transaction_uuid = transaction_uuid
+    @environment = environment
+    @status = 'failed' # assume failed until the report is finalized
+  end
+
+  # @api private
+  def initialize_from_hash(data)
+    @puppet_version = data['puppet_version']
+    @report_format = data['report_format']
+    @configuration_version = data['configuration_version']
+    @transaction_uuid = data['transaction_uuid']
+    @environment = data['environment']
+    @status = data['status']
+    @host = data['host']
+    @time = data['time']
+    if @time.is_a? String
+      @time = Time.parse(@time)
+    end
+    @kind = data['kind']
+
+    @metrics = {}
+    data['metrics'].each do |name, hash|
+      @metrics[name] = Puppet::Util::Metric.from_data_hash(hash)
+    end
+
+    @logs = data['logs'].map do |record|
+      Puppet::Util::Log.from_data_hash(record)
+    end
+
+    @resource_statuses = {}
+    data['resource_statuses'].map do |record|
+      if record[1] == {}
+        status = nil
+      else
+        status = Puppet::Resource::Status.from_data_hash(record[1])
+      end
+      @resource_statuses[record[0]] = status
+    end
+  end
+
+  def to_data_hash
+    {
+      'host' => @host,
+      'time' => @time.iso8601(9),
+      'configuration_version' => @configuration_version,
+      'transaction_uuid' => @transaction_uuid,
+      'report_format' => @report_format,
+      'puppet_version' => @puppet_version,
+      'kind' => @kind,
+      'status' => @status,
+      'environment' => @environment,
+
+      'logs' => @logs,
+      'metrics' => @metrics,
+      'resource_statuses' => @resource_statuses,
+    }
+  end
+
+  # @return [String] the host name
+  # @api public
+  #
+  def name
+    host
+  end
+
+  # Provide a human readable textual summary of this report.
+  # @note This is intended for debugging purposes
+  # @return [String] A string with a textual summary of this report.
+  # @api public
+  #
+  def summary
+    report = raw_summary
+
+    ret = ""
+    report.keys.sort { |a,b| a.to_s <=> b.to_s }.each do |key|
+      ret += "#{Puppet::Util::Metric.labelize(key)}:\n"
+
+      report[key].keys.sort { |a,b|
+        # sort by label
+        if a == :total
+          1
+        elsif b == :total
+          -1
+        else
+          report[key][a].to_s <=> report[key][b].to_s
+        end
+      }.each do |label|
+        value = report[key][label]
+        next if value == 0
+        value = "%0.2f" % value if value.is_a?(Float)
+        ret += "   %15s %s\n" % [Puppet::Util::Metric.labelize(label) + ":", value]
+      end
+    end
+    ret
+  end
+
+  # Provides a raw hash summary of this report.
+  # @return [Hash<{String => Object}>] A hash with metrics key to value map
+  # @api public
+  #
+  def raw_summary
+    report = { "version" => { "config" => configuration_version, "puppet" => Puppet.version  } }
+
+    @metrics.each do |name, metric|
+      key = metric.name.to_s
+      report[key] = {}
+      metric.values.each do |name, label, value|
+        report[key][name.to_s] = value
+      end
+      report[key]["total"] = 0 unless key == "time" or report[key].include?("total")
+    end
+    (report["time"] ||= {})["last_run"] = Time.now.tv_sec
+    report
+  end
+
+  # Computes a single number that represents the report's status.
+  # The computation is based on the contents of this report's metrics.
+  # The resulting number is a bitmask where
+  # individual bits represent the presence of different metrics.
+  #
+  # * 0x2 set if there are changes
+  # * 0x4 set if there are resource failures or resources that failed to restart
+  # @return [Integer] A bitmask where 0x2 is set if there are changes, and 0x4 is set of there are failures.
+  # @api public
+  #
+  def exit_status
+    status = 0
+    status |= 2 if @metrics["changes"]["total"] > 0
+    status |= 4 if @metrics["resources"]["failed"] > 0
+    status |= 4 if @metrics["resources"]["failed_to_restart"] > 0
+    status
+  end
+
+  # @api private
+  #
+  def to_yaml_properties
+    super - [:@external_times]
+  end
+
+  def self.supported_formats
+    [:pson, :yaml]
+  end
+
+  def self.default_format
+    Puppet[:report_serialization_format].intern
+  end
+
+  private
+
+  def calculate_change_metric
+    resource_statuses.map { |name, status| status.change_count || 0 }.inject(0) { |a,b| a+b }
+  end
+
+  def calculate_event_metrics
+    metrics = Hash.new(0)
+    %w{total failure success}.each { |m| metrics[m] = 0 }
+    resource_statuses.each do |name, status|
+      metrics["total"] += status.events.length
+      status.events.each do |event|
+        metrics[event.status] += 1
+      end
+    end
+
+    metrics
+  end
+
+  def calculate_resource_metrics
+    metrics = {}
+    metrics["total"] = resource_statuses.length
+
+    # force every resource key in the report to be present
+    # even if no resources is in this given state
+    Puppet::Resource::Status::STATES.each do |state|
+      metrics[state.to_s] = 0
+    end
+
+    resource_statuses.each do |name, status|
+      Puppet::Resource::Status::STATES.each do |state|
+        metrics[state.to_s] += 1 if status.send(state)
+      end
+    end
+
+    metrics
+  end
+
+  def calculate_time_metrics
+    metrics = Hash.new(0)
+    resource_statuses.each do |name, status|
+      type = Puppet::Resource.new(name).type
+      metrics[type.to_s.downcase] += status.evaluation_time if status.evaluation_time
+    end
+
+    @external_times.each do |name, value|
+      metrics[name.to_s.downcase] = value
+    end
+
+    metrics["total"] = metrics.values.inject(0) { |a,b| a+b }
+
+    metrics
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/transaction/resource_harness.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/transaction/resource_harness.rb
new file mode 100644
index 0000000..f57677c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/transaction/resource_harness.rb
@@ -0,0 +1,251 @@
+require 'puppet/resource/status'
+
+class Puppet::Transaction::ResourceHarness
+  NO_ACTION = Object.new
+
+  extend Forwardable
+  def_delegators :@transaction, :relationship_graph
+
+  attr_reader :transaction
+
+  def initialize(transaction)
+    @transaction = transaction
+  end
+
+  def evaluate(resource)
+    status = Puppet::Resource::Status.new(resource)
+
+    begin
+      context = ResourceApplicationContext.from_resource(resource, status)
+      perform_changes(resource, context)
+
+      if status.changed? && ! resource.noop?
+        cache(resource, :synced, Time.now)
+        resource.flush if resource.respond_to?(:flush)
+      end
+    rescue => detail
+      status.failed_because(detail)
+    ensure
+      status.evaluation_time = Time.now - status.time
+    end
+
+    status
+  end
+
+  def scheduled?(resource)
+    return true if Puppet[:ignoreschedules]
+    return true unless schedule = schedule(resource)
+
+    # We use 'checked' here instead of 'synced' because otherwise we'll
+    # end up checking most resources most times, because they will generally
+    # have been synced a long time ago (e.g., a file only gets updated
+    # once a month on the server and its schedule is daily; the last sync time
+    # will have been a month ago, so we'd end up checking every run).
+    schedule.match?(cached(resource, :checked).to_i)
+  end
+
+  def schedule(resource)
+    unless resource.catalog
+      resource.warning "Cannot schedule without a schedule-containing catalog"
+      return nil
+    end
+
+    return nil unless name = resource[:schedule]
+    resource.catalog.resource(:schedule, name) || resource.fail("Could not find schedule #{name}")
+  end
+
+  # Used mostly for scheduling and auditing at this point.
+  def cached(resource, name)
+    Puppet::Util::Storage.cache(resource)[name]
+  end
+
+  # Used mostly for scheduling and auditing at this point.
+  def cache(resource, name, value)
+    Puppet::Util::Storage.cache(resource)[name] = value
+  end
+
+  private
+
+  def perform_changes(resource, context)
+    cache(resource, :checked, Time.now)
+
+    return [] if ! allow_changes?(resource)
+
+    # Record the current state in state.yml.
+    context.audited_params.each do |param|
+      cache(resource, param, context.current_values[param])
+    end
+
+    ensure_param = resource.parameter(:ensure)
+    if ensure_param && ensure_param.should
+      ensure_event = sync_if_needed(ensure_param, context)
+    else
+      ensure_event = NO_ACTION
+    end
+
+    if ensure_event == NO_ACTION
+      if context.resource_present?
+        resource.properties.each do |param|
+          sync_if_needed(param, context)
+        end
+      else
+        resource.debug("Nothing to manage: no ensure and the resource doesn't exist")
+      end
+    end
+
+    capture_audit_events(resource, context)
+  end
+
+  def allow_changes?(resource)
+    if resource.purging? and resource.deleting? and deps = relationship_graph.dependents(resource) \
+            and ! deps.empty? and deps.detect { |d| ! d.deleting? }
+      deplabel = deps.collect { |r| r.ref }.join(",")
+      plurality = deps.length > 1 ? "":"s"
+      resource.warning "#{deplabel} still depend#{plurality} on me -- not purging"
+      false
+    else
+      true
+    end
+  end
+
+  def sync_if_needed(param, context)
+    historical_value = context.historical_values[param.name]
+    current_value = context.current_values[param.name]
+    do_audit = context.audited_params.include?(param.name)
+
+    begin
+      if param.should && !param.safe_insync?(current_value)
+        event = create_change_event(param, current_value, historical_value)
+        if do_audit
+          event = audit_event(event, param)
+        end
+
+        brief_audit_message = audit_message(param, do_audit, historical_value, current_value)
+
+        if param.noop
+          noop(event, param, current_value, brief_audit_message)
+        else
+          sync(event, param, current_value, brief_audit_message)
+        end
+
+        event
+      else
+        NO_ACTION
+      end
+    rescue => detail
+      # Execution will continue on StandardErrors, just store the event
+      Puppet.log_exception(detail)
+
+      event = create_change_event(param, current_value, historical_value)
+      event.status = "failure"
+      event.message = "change from #{param.is_to_s(current_value)} to #{param.should_to_s(param.should)} failed: #{detail}"
+      event
+    rescue Exception => detail
+      # Execution will halt on Exceptions, they get raised to the application
+      event = create_change_event(param, current_value, historical_value)
+      event.status = "failure"
+      event.message = "change from #{param.is_to_s(current_value)} to #{param.should_to_s(param.should)} failed: #{detail}"
+      raise
+    ensure
+      if event
+        context.record(event)
+        event.send_log
+        context.synced_params << param.name
+      end
+    end
+  end
+
+  def create_change_event(property, current_value, historical_value)
+    event = property.event
+    event.previous_value = current_value
+    event.desired_value = property.should
+    event.historical_value = historical_value
+
+    event
+  end
+
+  # This method is an ugly hack because, given a Time object with nanosecond
+  # resolution, roundtripped through YAML serialization, the Time object will
+  # be truncated to microseconds.
+  # For audit purposes, this code special cases this comparison, and compares
+  # the two objects by their second and microsecond components. tv_sec is the
+  # number of seconds since the epoch, and tv_usec is only the microsecond
+  # portion of time.  This compare satisfies compatibility requirements for
+  # Ruby 1.8.7, where to_r does not exist on the Time class.
+  def are_audited_values_equal(a, b)
+    a == b || (a.is_a?(Time) && b.is_a?(Time) && a.tv_sec == b.tv_sec && a.tv_usec == b.tv_usec)
+  end
+  private :are_audited_values_equal
+
+  def audit_event(event, property)
+    event.audited = true
+    event.status = "audit"
+    if !are_audited_values_equal(event.historical_value, event.previous_value)
+      event.message = "audit change: previously recorded value #{property.is_to_s(event.historical_value)} has been changed to #{property.is_to_s(event.previous_value)}"
+    end
+
+    event
+  end
+
+  def audit_message(param, do_audit, historical_value, current_value)
+    if do_audit && historical_value && !are_audited_values_equal(historical_value, current_value)
+      " (previously recorded value was #{param.is_to_s(historical_value)})"
+    else
+      ""
+    end
+  end
+
+  def noop(event, param, current_value, audit_message)
+    event.message = "current_value #{param.is_to_s(current_value)}, should be #{param.should_to_s(param.should)} (noop)#{audit_message}"
+    event.status = "noop"
+  end
+
+  def sync(event, param, current_value, audit_message)
+    param.sync
+    event.message = "#{param.change_to_s(current_value, param.should)}#{audit_message}"
+    event.status = "success"
+  end
+
+  def capture_audit_events(resource, context)
+    context.audited_params.each do |param_name|
+      if context.historical_values.include?(param_name)
+        if !are_audited_values_equal(context.historical_values[param_name], context.current_values[param_name]) && !context.synced_params.include?(param_name)
+          parameter = resource.parameter(param_name)
+          event = audit_event(create_change_event(parameter,
+                                                  context.current_values[param_name],
+                                                  context.historical_values[param_name]),
+                              parameter)
+          event.send_log
+          context.record(event)
+        end
+      else
+        resource.property(param_name).notice "audit change: newly-recorded value #{context.current_values[param_name]}"
+      end
+    end
+  end
+
+  # @api private
+  ResourceApplicationContext = Struct.new(:resource,
+                                          :current_values,
+                                          :historical_values,
+                                          :audited_params,
+                                          :synced_params,
+                                          :status) do
+    def self.from_resource(resource, status)
+      ResourceApplicationContext.new(resource,
+                                     resource.retrieve_resource.to_hash,
+                                     Puppet::Util::Storage.cache(resource).dup,
+                                     (resource[:audit] || []).map { |p| p.to_sym },
+                                     [],
+                                     status)
+    end
+
+    def resource_present?
+      resource.present?(current_values)
+    end
+
+    def record(event)
+      status << event
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type.rb
new file mode 100644
index 0000000..208d860
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type.rb
@@ -0,0 +1,2452 @@
+require 'puppet'
+require 'puppet/util/log'
+require 'puppet/util/metric'
+require 'puppet/property'
+require 'puppet/parameter'
+require 'puppet/util'
+require 'puppet/util/autoload'
+require 'puppet/metatype/manager'
+require 'puppet/util/errors'
+require 'puppet/util/logging'
+require 'puppet/util/tagging'
+
+# see the bottom of the file for the rest of the inclusions
+
+
+module Puppet
+# The base class for all Puppet types.
+#
+# A type describes:
+#--
+# * **Attributes** - properties, parameters, and meta-parameters are different types of attributes of a type.
+#   * **Properties** - these are the properties of the managed resource (attributes of the entity being managed; like
+#     a file's owner, group and mode). A property describes two states; the 'is' (current state) and the 'should' (wanted
+#     state).
+#       * **Ensurable** - a set of traits that control the lifecycle (create, remove, etc.) of a managed entity.
+#         There is a default set of operations associated with being _ensurable_, but this can be changed.
+#       * **Name/Identity** - one property is the name/identity of a resource, the _namevar_ that uniquely identifies
+#         one instance of a type from all others.
+#   * **Parameters** - additional attributes of the type (that does not directly related to an instance of the managed
+#     resource; if an operation is recursive or not, where to look for things, etc.). A Parameter (in contrast to Property)
+#     has one current value where a Property has two (current-state and wanted-state).
+#   * **Meta-Parameters** - parameters that are available across all types. A meta-parameter typically has
+#     additional semantics; like the `require` meta-parameter. A new type typically does not add new meta-parameters,
+#     but you need to be aware of their existence so you do not inadvertently shadow an existing meta-parameters.
+# * **Parent** - a type can have a super type (that it inherits from).
+# * **Validation** - If not just a basic data type, or an enumeration of symbolic values, it is possible to provide
+#     validation logic for a type, properties and parameters.
+# * **Munging** - munging/unmunging is the process of turning a value in external representation (as used
+#     by a provider) into an internal representation and vice versa. A Type supports adding custom logic for these.
+# * **Auto Requirements** - a type can specify automatic relationships to resources to ensure that if they are being
+#     managed, they will be processed before this type.
+# * **Providers** - a provider is an implementation of a type's behavior - the management of a resource in the
+#     system being managed. A provider is often platform specific and is selected at runtime based on
+#     criteria/predicates specified in the configured providers. See {Puppet::Provider} for details.
+# * **Device Support** - A type has some support for being applied to a device; i.e. something that is managed
+#     by running logic external to the device itself. There are several methods that deals with type
+#     applicability for these special cases such as {apply_to_device}.
+#
+# Additional Concepts:
+# --
+# * **Resource-type** - A _resource type_ is a term used to denote the type of a resource; internally a resource
+#     is really an instance of a Ruby class i.e. {Puppet::Resource} which defines its behavior as "resource data".
+#     Conceptually however, a resource is an instance of a subclass of Type (e.g. File), where such a class describes
+#     its interface (what can be said/what is known about a resource of this type),
+# * **Managed Entity** - This is not a term in general use, but is used here when there is a need to make
+#     a distinction between a resource (a description of what/how something should be managed), and what it is
+#     managing (a file in the file system). The term _managed entity_ is a reference to the "file in the file system"
+# * **Isomorphism** - the quality of being _isomorphic_ means that two resource instances with the same name
+#     refers to the same managed entity. Or put differently; _an isomorphic name is the identity of a resource_.
+#     As an example, `exec` resources (that executes some command) have the command (i.e. the command line string) as
+#     their name, and these resources are said to be non-isomorphic.
+#
+# @note The Type class deals with multiple concerns; some methods provide an internal DSL for convenient definition
+#   of types, other methods deal with various aspects while running; wiring up a resource (expressed in Puppet DSL
+#   or Ruby DSL) with its _resource type_ (i.e. an instance of Type) to enable validation, transformation of values
+#   (munge/unmunge), etc. Lastly, Type is also responsible for dealing with Providers; the concrete implementations
+#   of the behavior that constitutes how a particular Type behaves on a particular type of system (e.g. how
+#   commands are executed on a flavor of Linux, on Windows, etc.). This means that as you are reading through the
+#   documentation of this class, you will be switching between these concepts, as well as switching between
+#   the conceptual level "a resource is an instance of a resource-type" and the actual implementation classes
+#   (Type, Resource, Provider, and various utility and helper classes).
+#
+# @api public
+#
+#
+class Type
+  include Puppet::Util
+  include Puppet::Util::Errors
+  include Puppet::Util::Logging
+  include Puppet::Util::Tagging
+
+  # Comparing type instances.
+  include Comparable
+
+  # Compares this type against the given _other_ (type) and returns -1, 0, or +1 depending on the order.
+  # @param other [Object] the object to compare against (produces nil, if not kind of Type}
+  # @return [-1, 0, +1, nil] produces -1 if this type is before the given _other_ type, 0 if equals, and 1 if after.
+  #   Returns nil, if the given _other_ is not a kind of Type.
+  # @see Comparable
+  #
+  def <=>(other)
+    # We only order against other types, not arbitrary objects.
+    return nil unless other.is_a? Puppet::Type
+    # Our natural order is based on the reference name we use when comparing
+    # against other type instances.
+    self.ref <=> other.ref
+  end
+
+  # Code related to resource type attributes.
+  class << self
+    include Puppet::Util::ClassGen
+    include Puppet::Util::Warnings
+
+    # @return [Array<Puppet::Property>] The list of declared properties for the resource type.
+    # The returned lists contains instances if Puppet::Property or its subclasses.
+    attr_reader :properties
+  end
+
+  # Returns all the attribute names of the type in the appropriate order.
+  # The {key_attributes} come first, then the {provider}, then the {properties}, and finally
+  # the {parameters} and {metaparams},
+  # all in the order they were specified in the respective files.
+  # @return [Array<String>] all type attribute names in a defined order.
+  #
+  def self.allattrs
+    key_attributes | (parameters & [:provider]) | properties.collect { |property| property.name } | parameters | metaparams
+  end
+
+  # Returns the class associated with the given attribute name.
+  # @param name [String] the name of the attribute to obtain the class for
+  # @return [Class, nil] the class for the given attribute, or nil if the name does not refer to an existing attribute
+  #
+  def self.attrclass(name)
+    @attrclasses ||= {}
+
+    # We cache the value, since this method gets called such a huge number
+    # of times (as in, hundreds of thousands in a given run).
+    unless @attrclasses.include?(name)
+      @attrclasses[name] = case self.attrtype(name)
+      when :property; @validproperties[name]
+      when :meta; @@metaparamhash[name]
+      when :param; @paramhash[name]
+      end
+    end
+    @attrclasses[name]
+  end
+
+  # Returns the attribute type (`:property`, `;param`, `:meta`).
+  # @comment What type of parameter are we dealing with? Cache the results, because
+  #   this method gets called so many times.
+  # @return [Symbol] a symbol describing the type of attribute (`:property`, `;param`, `:meta`)
+  #
+  def self.attrtype(attr)
+    @attrtypes ||= {}
+    unless @attrtypes.include?(attr)
+      @attrtypes[attr] = case
+        when @validproperties.include?(attr); :property
+        when @paramhash.include?(attr); :param
+        when @@metaparamhash.include?(attr); :meta
+        end
+    end
+
+    @attrtypes[attr]
+  end
+
+  # Provides iteration over meta-parameters.
+  # @yieldparam p [Puppet::Parameter] each meta parameter
+  # @return [void]
+  #
+  def self.eachmetaparam
+    @@metaparams.each { |p| yield p.name }
+  end
+
+  # Creates a new `ensure` property with configured default values or with configuration by an optional block.
+  # This method is a convenience method for creating a property `ensure` with default accepted values.
+  # If no block is specified, the new `ensure` property will accept the default symbolic
+  # values `:present`, and `:absent` - see {Puppet::Property::Ensure}.
+  # If something else is wanted, pass a block and make calls to {Puppet::Property.newvalue} from this block
+  # to define each possible value. If a block is passed, the defaults are not automatically added to the set of
+  # valid values.
+  #
+  # @note This method will be automatically called without a block if the type implements the methods
+  #   specified by {ensurable?}. It is recommended to always call this method and not rely on this automatic
+  #   specification to clearly state that the type is ensurable.
+  #
+  # @overload ensurable()
+  # @overload ensurable({|| ... })
+  # @yield [ ] A block evaluated in scope of the new Parameter
+  # @yieldreturn [void]
+  # @return [void]
+  # @dsl type
+  # @api public
+  #
+  def self.ensurable(&block)
+    if block_given?
+      self.newproperty(:ensure, :parent => Puppet::Property::Ensure, &block)
+    else
+      self.newproperty(:ensure, :parent => Puppet::Property::Ensure) do
+        self.defaultvalues
+      end
+    end
+  end
+
+  # Returns true if the type implements the default behavior expected by being _ensurable_ "by default".
+  # A type is _ensurable_ by default if it responds to `:exists`, `:create`, and `:destroy`.
+  # If a type implements these methods and have not already specified that it is _ensurable_, it will be
+  # made so with the defaults specified in {ensurable}.
+  # @return [Boolean] whether the type is _ensurable_ or not.
+  #
+  def self.ensurable?
+    # If the class has all three of these methods defined, then it's
+    # ensurable.
+    [:exists?, :create, :destroy].all? { |method|
+      self.public_method_defined?(method)
+    }
+  end
+
+  # @comment These `apply_to` methods are horrible.  They should really be implemented
+  #   as part of the usual system of constraints that apply to a type and
+  #   provider pair, but were implemented as a separate shadow system.
+  #
+  # @comment We should rip them out in favour of a real constraint pattern around the
+  #   target device - whatever that looks like - and not have this additional
+  #   magic here. --daniel 2012-03-08
+  #
+  # Makes this type applicable to `:device`.
+  # @return [Symbol] Returns `:device`
+  # @api private
+  #
+  def self.apply_to_device
+    @apply_to = :device
+  end
+
+  # Makes this type applicable to `:host`.
+  # @return [Symbol] Returns `:host`
+  # @api private
+  #
+  def self.apply_to_host
+    @apply_to = :host
+  end
+
+  # Makes this type applicable to `:both` (i.e. `:host` and `:device`).
+  # @return [Symbol] Returns `:both`
+  # @api private
+  #
+  def self.apply_to_all
+    @apply_to = :both
+  end
+
+  # Makes this type apply to `:host` if not already applied to something else.
+  # @return [Symbol] a `:device`, `:host`, or `:both` enumeration
+  # @api private
+  def self.apply_to
+    @apply_to ||= :host
+  end
+
+  # Returns true if this type is applicable to the given target.
+  # @param target [Symbol] should be :device, :host or :target, if anything else, :host is enforced
+  # @return [Boolean] true
+  # @api private
+  #
+  def self.can_apply_to(target)
+    [ target == :device ? :device : :host, :both ].include?(apply_to)
+  end
+
+  # Processes the options for a named parameter.
+  # @param name [String] the name of a parameter
+  # @param options [Hash] a hash of options
+  # @option options [Boolean] :boolean if option set to true, an access method on the form _name_? is added for the param
+  # @return [void]
+  #
+  def self.handle_param_options(name, options)
+    # If it's a boolean parameter, create a method to test the value easily
+    if options[:boolean]
+      define_method(name.to_s + "?") do
+        val = self[name]
+        if val == :true or val == true
+          return true
+        end
+      end
+    end
+  end
+
+  # Is the given parameter a meta-parameter?
+  # @return [Boolean] true if the given parameter is a meta-parameter.
+  #
+  def self.metaparam?(param)
+    @@metaparamhash.include?(param.intern)
+  end
+
+  # Returns the meta-parameter class associated with the given meta-parameter name.
+  # Accepts a `nil` name, and return nil.
+  # @param name [String, nil] the name of a meta-parameter
+  # @return [Class,nil] the class for the given meta-parameter, or `nil` if no such meta-parameter exists, (or if
+  #   the given meta-parameter name is `nil`.
+  #
+  def self.metaparamclass(name)
+    return nil if name.nil?
+    @@metaparamhash[name.intern]
+  end
+
+  # Returns all meta-parameter names.
+  # @return [Array<String>] all meta-parameter names
+  #
+  def self.metaparams
+    @@metaparams.collect { |param| param.name }
+  end
+
+  # Returns the documentation for a given meta-parameter of this type.
+  # @param metaparam [Puppet::Parameter] the meta-parameter to get documentation for.
+  # @return [String] the documentation associated with the given meta-parameter, or nil of no such documentation
+  #   exists.
+  # @raise if the given metaparam is not a meta-parameter in this type
+  #
+  def self.metaparamdoc(metaparam)
+    @@metaparamhash[metaparam].doc
+  end
+
+  # Creates a new meta-parameter.
+  # This creates a new meta-parameter that is added to this and all inheriting types.
+  # @param name [Symbol] the name of the parameter
+  # @param options [Hash] a hash with options.
+  # @option options [Class<inherits Puppet::Parameter>] :parent (Puppet::Parameter) the super class of this parameter
+  # @option options [Hash{String => Object}] :attributes a hash that is applied to the generated class
+  #   by calling setter methods corresponding to this hash's keys/value pairs. This is done before the given
+  #   block is evaluated.
+  # @option options [Boolean] :boolean (false) specifies if this is a boolean parameter
+  # @option options [Boolean] :namevar  (false) specifies if this parameter is the namevar
+  # @option options [Symbol, Array<Symbol>] :required_features  specifies required provider features by name
+  # @return [Class<inherits Puppet::Parameter>] the created parameter
+  # @yield [ ] a required block that is evaluated in the scope of the new meta-parameter
+  # @api public
+  # @dsl type
+  # @todo Verify that this description is ok
+  #
+  def self.newmetaparam(name, options = {}, &block)
+    @@metaparams ||= []
+    @@metaparamhash ||= {}
+    name = name.intern
+
+    param = genclass(
+      name,
+      :parent => options[:parent] || Puppet::Parameter,
+      :prefix => "MetaParam",
+      :hash => @@metaparamhash,
+      :array => @@metaparams,
+      :attributes => options[:attributes],
+      &block
+    )
+
+    # Grr.
+    param.required_features = options[:required_features] if options[:required_features]
+
+    handle_param_options(name, options)
+
+    param.metaparam = true
+
+    param
+  end
+
+  # Returns the list of parameters that comprise the composite key / "uniqueness key".
+  # All parameters that return true from #isnamevar? or is named `:name` are included in the returned result.
+  # @see uniqueness_key
+  # @return [Array<Puppet::Parameter>] WARNING: this return type is uncertain
+  def self.key_attribute_parameters
+    @key_attribute_parameters ||= (
+      @parameters.find_all { |param|
+        param.isnamevar? or param.name == :name
+      }
+    )
+  end
+
+  # Returns cached {key_attribute_parameters} names.
+  # Key attributes are properties and parameters that comprise a composite key
+  # or "uniqueness key".
+  # @return [Array<String>] cached key_attribute names
+  #
+  def self.key_attributes
+    # This is a cache miss around 0.05 percent of the time. --daniel 2012-07-17
+    @key_attributes_cache ||= key_attribute_parameters.collect { |p| p.name }
+  end
+
+  # Returns a mapping from the title string to setting of attribute value(s).
+  # This default implementation provides a mapping of title to the one and only _namevar_ present
+  # in the type's definition.
+  # @note Advanced: some logic requires this mapping to be done differently, using a different
+  #   validation/pattern, breaking up the title
+  #   into several parts assigning each to an individual attribute, or even use a composite identity where
+  #   all namevars are seen as part of the unique identity (such computation is done by the {#uniqueness} method.
+  #   These advanced options are rarely used (only one of the built in puppet types use this, and then only
+  #   a small part of the available functionality), and the support for these advanced mappings is not
+  #   implemented in a straight forward way. For these reasons, this method has been marked as private).
+  #
+  # @raise [Puppet::DevError] if there is no title pattern and there are two or more key attributes
+  # @return [Array<Array<Regexp, Array<Array <Symbol, Proc>>>>, nil] a structure with a regexp and the first key_attribute ???
+  # @comment This wonderful piece of logic creates a structure used by Resource.parse_title which
+  #   has the capability to assign parts of the title to one or more attributes; It looks like an implementation
+  #   of a composite identity key (all parts of the key_attributes array are in the key). This can also
+  #   be seen in the method uniqueness_key.
+  #   The implementation in this method simply assigns the title to the one and only namevar (which is name
+  #   or a variable marked as namevar).
+  #   If there are multiple namevars (any in addition to :name?) then this method MUST be implemented
+  #   as it raises an exception if there is more than 1. Note that in puppet, it is only File that uses this
+  #   to create a different pattern for assigning to the :path attribute
+  #   This requires further digging.
+  #   The entire construct is somewhat strange, since resource checks if the method "title_patterns" is
+  #   implemented (it seems it always is) - why take this more expensive regexp mathching route for all
+  #   other types?
+  # @api private
+  #
+  def self.title_patterns
+    case key_attributes.length
+    when 0; []
+    when 1;
+      [ [ /(.*)/m, [ [key_attributes.first] ] ] ]
+    else
+      raise Puppet::DevError,"you must specify title patterns when there are two or more key attributes"
+    end
+  end
+
+  # Produces a resource's _uniqueness_key_ (or composite key).
+  # This key is an array of all key attributes' values. Each distinct tuple must be unique for each resource type.
+  # @see key_attributes
+  # @return [Object] an object that is a _uniqueness_key_ for this object
+  #
+  def uniqueness_key
+    self.class.key_attributes.sort_by { |attribute_name| attribute_name.to_s }.map{ |attribute_name| self[attribute_name] }
+  end
+
+  # Creates a new parameter.
+  # @param name [Symbol] the name of the parameter
+  # @param options [Hash] a hash with options.
+  # @option options [Class<inherits Puppet::Parameter>] :parent (Puppet::Parameter) the super class of this parameter
+  # @option options [Hash{String => Object}] :attributes a hash that is applied to the generated class
+  #   by calling setter methods corresponding to this hash's keys/value pairs. This is done before the given
+  #   block is evaluated.
+  # @option options [Boolean] :boolean (false) specifies if this is a boolean parameter
+  # @option options [Boolean] :namevar  (false) specifies if this parameter is the namevar
+  # @option options [Symbol, Array<Symbol>] :required_features  specifies required provider features by name
+  # @return [Class<inherits Puppet::Parameter>] the created parameter
+  # @yield [ ] a required block that is evaluated in the scope of the new parameter
+  # @api public
+  # @dsl type
+  #
+  def self.newparam(name, options = {}, &block)
+    options[:attributes] ||= {}
+
+    param = genclass(
+      name,
+      :parent     => options[:parent] || Puppet::Parameter,
+      :attributes => options[:attributes],
+      :block      => block,
+      :prefix     => "Parameter",
+      :array      => @parameters,
+      :hash       => @paramhash
+    )
+
+    handle_param_options(name, options)
+
+    # Grr.
+    param.required_features = options[:required_features] if options[:required_features]
+
+    param.isnamevar if options[:namevar]
+
+    param
+  end
+
+  # Creates a new property.
+  # @param name [Symbol] the name of the property
+  # @param options [Hash] a hash with options.
+  # @option options [Symbol] :array_matching (:first) specifies how the current state is matched against
+  #   the wanted state. Use `:first` if the property is single valued, and (`:all`) otherwise.
+  # @option options [Class<inherits Puppet::Property>] :parent (Puppet::Property) the super class of this property
+  # @option options [Hash{String => Object}] :attributes a hash that is applied to the generated class
+  #   by calling setter methods corresponding to this hash's keys/value pairs. This is done before the given
+  #   block is evaluated.
+  # @option options [Boolean] :boolean (false) specifies if this is a boolean parameter
+  # @option options [Symbol] :retrieve the method to call on the provider (or `parent` if `provider` is not set)
+  #   to retrieve the current value of this property.
+  # @option options [Symbol, Array<Symbol>] :required_features  specifies required provider features by name
+  # @return [Class<inherits Puppet::Property>] the created property
+  # @yield [ ] a required block that is evaluated in the scope of the new property
+  # @api public
+  # @dsl type
+  #
+  def self.newproperty(name, options = {}, &block)
+    name = name.intern
+
+    # This is here for types that might still have the old method of defining
+    # a parent class.
+    unless options.is_a? Hash
+      raise Puppet::DevError,
+        "Options must be a hash, not #{options.inspect}"
+    end
+
+    raise Puppet::DevError, "Class #{self.name} already has a property named #{name}" if @validproperties.include?(name)
+
+    if parent = options[:parent]
+      options.delete(:parent)
+    else
+      parent = Puppet::Property
+    end
+
+    # We have to create our own, new block here because we want to define
+    # an initial :retrieve method, if told to, and then eval the passed
+    # block if available.
+    prop = genclass(name, :parent => parent, :hash => @validproperties, :attributes => options) do
+      # If they've passed a retrieve method, then override the retrieve
+      # method on the class.
+      if options[:retrieve]
+        define_method(:retrieve) do
+          provider.send(options[:retrieve])
+        end
+      end
+
+      class_eval(&block) if block
+    end
+
+    # If it's the 'ensure' property, always put it first.
+    if name == :ensure
+      @properties.unshift prop
+    else
+      @properties << prop
+    end
+
+    prop
+  end
+
+  def self.paramdoc(param)
+    @paramhash[param].doc
+  end
+
+  # @return [Array<String>] Returns the parameter names
+  def self.parameters
+    return [] unless defined?(@parameters)
+    @parameters.collect { |klass| klass.name }
+  end
+
+  # @return [Puppet::Parameter] Returns the parameter class associated with the given parameter name.
+  def self.paramclass(name)
+    @paramhash[name]
+  end
+
+  # @return [Puppet::Property] Returns the property class ??? associated with the given property name
+  def self.propertybyname(name)
+    @validproperties[name]
+  end
+
+  # Returns whether or not the given name is the name of a property, parameter or meta-parameter
+  # @return [Boolean] true if the given attribute name is the name of an existing property, parameter or meta-parameter
+  #
+  def self.validattr?(name)
+    name = name.intern
+    return true if name == :name
+    @validattrs ||= {}
+
+    unless @validattrs.include?(name)
+      @validattrs[name] = !!(self.validproperty?(name) or self.validparameter?(name) or self.metaparam?(name))
+    end
+
+    @validattrs[name]
+  end
+
+  # @return [Boolean] Returns true if the given name is the name of an existing property
+  def self.validproperty?(name)
+    name = name.intern
+    @validproperties.include?(name) && @validproperties[name]
+  end
+
+  # @return [Array<Symbol>, {}] Returns a list of valid property names, or an empty hash if there are none.
+  # @todo An empty hash is returned if there are no defined parameters (not an empty array). This looks like
+  #   a bug.
+  #
+  def self.validproperties
+    return {} unless defined?(@parameters)
+
+    @validproperties.keys
+  end
+
+  # @return [Boolean] Returns true if the given name is the name of an existing parameter
+  def self.validparameter?(name)
+    raise Puppet::DevError, "Class #{self} has not defined parameters" unless defined?(@parameters)
+    !!(@paramhash.include?(name) or @@metaparamhash.include?(name))
+  end
+
+  # (see validattr?)
+  # @note see comment in code - how should this be documented? Are some of the other query methods deprecated?
+  #   (or should be).
+  # @comment This is a forward-compatibility method - it's the validity interface we'll use in Puppet::Resource.
+  def self.valid_parameter?(name)
+    validattr?(name)
+  end
+
+  # @return [Boolean] Returns true if the wanted state of the resoure is that it should be absent (i.e. to be deleted).
+  def deleting?
+    obj = @parameters[:ensure] and obj.should == :absent
+  end
+
+  # Creates a new property value holder for the resource if it is valid and does not already exist
+  # @return [Boolean] true if a new parameter was added, false otherwise
+  def add_property_parameter(prop_name)
+    if self.class.validproperty?(prop_name) && !@parameters[prop_name]
+      self.newattr(prop_name)
+      return true
+    end
+    false
+  end
+
+  # @return [Symbol, Boolean] Returns the name of the namevar if there is only one or false otherwise.
+  # @comment This is really convoluted and part of the support for multiple namevars (?).
+  #   If there is only one namevar, the produced value is naturally this namevar, but if there are several?
+  #   The logic caches the name of the namevar if it is a single name, but otherwise always
+  #   calls key_attributes, and then caches the first if there was only one, otherwise it returns
+  #   false and caches this (which is then subsequently returned as a cache hit).
+  #
+  def name_var
+    return @name_var_cache unless @name_var_cache.nil?
+    key_attributes = self.class.key_attributes
+    @name_var_cache = (key_attributes.length == 1) && key_attributes.first
+  end
+
+  # Gets the 'should' (wanted state) value of a parameter or property by name.
+  # To explicitly get the 'is' (current state) value use `o.is(:name)`, and to explicitly get the 'should' value
+  # use `o.should(:name)`
+  # @param name [String] the name of the attribute to obtain the 'should' value for.
+  # @return [Object] 'should'/wanted value of the given attribute
+  def [](name)
+    name = name.intern
+    fail("Invalid parameter #{name}(#{name.inspect})") unless self.class.validattr?(name)
+
+    if name == :name && nv = name_var
+      name = nv
+    end
+
+    if obj = @parameters[name]
+      # Note that if this is a property, then the value is the "should" value,
+      # not the current value.
+      obj.value
+    else
+      return nil
+    end
+  end
+
+  # Sets the 'should' (wanted state) value of a property, or the value of a parameter.
+  # @return
+  # @raise [Puppet::Error] if the setting of the value fails, or if the given name is nil.
+  # @raise [Puppet::ResourceError] when the parameter validation raises Puppet::Error or
+  #   ArgumentError
+  def []=(name,value)
+    name = name.intern
+
+    fail("Invalid parameter #{name}") unless self.class.validattr?(name)
+
+    if name == :name && nv = name_var
+      name = nv
+    end
+    raise Puppet::Error.new("Got nil value for #{name}") if value.nil?
+
+    property = self.newattr(name)
+
+    if property
+      begin
+        # make sure the parameter doesn't have any errors
+        property.value = value
+      rescue Puppet::Error, ArgumentError => detail
+        error = Puppet::ResourceError.new("Parameter #{name} failed on #{ref}: #{detail}")
+        adderrorcontext(error, detail)
+        raise error
+      end
+    end
+
+    nil
+  end
+
+  # Removes an attribute from the object; useful in testing or in cleanup
+  # when an error has been encountered
+  # @todo Don't know what the attr is (name or Property/Parameter?). Guessing it is a String name...
+  # @todo Is it possible to delete a meta-parameter?
+  # @todo What does delete mean? Is it deleted from the type or is its value state 'is'/'should' deleted?
+  # @param attr [String] the attribute to delete from this object. WHAT IS THE TYPE?
+  # @raise [Puppet::DecError] when an attempt is made to delete an attribute that does not exists.
+  #
+  def delete(attr)
+    attr = attr.intern
+    if @parameters.has_key?(attr)
+      @parameters.delete(attr)
+    else
+      raise Puppet::DevError.new("Undefined attribute '#{attr}' in #{self}")
+    end
+  end
+
+  # Iterates over the properties that were set on this resource.
+  # @yieldparam property [Puppet::Property] each property
+  # @return [void]
+  def eachproperty
+    # properties is a private method
+    properties.each { |property|
+      yield property
+    }
+  end
+
+  # Return the parameters, metaparams, and properties that have a value or were set by a default. Properties are
+  # included since they are a subclass of parameter.
+  # @return [Array<Puppet::Parameter>] Array of parameter objects ( or subclass thereof )
+  def parameters_with_value
+    self.class.allattrs.collect { |attr| parameter(attr) }.compact
+  end
+
+  # Iterates over all parameters with value currently set.
+  # @yieldparam parameter [Puppet::Parameter] or a subclass thereof
+  # @return [void]
+  def eachparameter
+    parameters_with_value.each { |parameter| yield parameter }
+  end
+
+  # Creates a transaction event.
+  # Called by Transaction or by a property.
+  # Merges the given options with the options `:resource`, `:file`, `:line`, and `:tags`, initialized from
+  # values in this object. For possible options to pass (if any ????) see {Puppet::Transaction::Event}.
+  # @todo Needs a better explanation "Why should I care who is calling this method?", What do I need to know
+  #   about events and how they work? Where can I read about them?
+  # @param options [Hash] options merged with a fixed set of options defined by this method, passed on to {Puppet::Transaction::Event}.
+  # @return [Puppet::Transaction::Event] the created event
+  def event(options = {})
+    Puppet::Transaction::Event.new({:resource => self, :file => file, :line => line, :tags => tags}.merge(options))
+  end
+
+  # @return [Object, nil] Returns the 'should' (wanted state) value for a specified property, or nil if the
+  #   given attribute name is not a property (i.e. if it is a parameter, meta-parameter, or does not exist).
+  def should(name)
+    name = name.intern
+    (prop = @parameters[name] and prop.is_a?(Puppet::Property)) ? prop.should : nil
+  end
+
+  # Registers an attribute to this resource type insance.
+  # Requires either the attribute name or class as its argument.
+  # This is a noop if the named property/parameter is not supported
+  # by this resource. Otherwise, an attribute instance is created
+  # and kept in this resource's parameters hash.
+  # @overload newattr(name)
+  #   @param name [Symbol] symbolic name of the attribute
+  # @overload newattr(klass)
+  #   @param klass [Class] a class supported as an attribute class, i.e. a subclass of
+  #     Parameter or Property
+  # @return [Object] An instance of the named Parameter or Property class associated
+  #   to this resource type instance, or nil if the attribute is not supported
+  #
+  def newattr(name)
+    if name.is_a?(Class)
+      klass = name
+      name = klass.name
+    end
+
+    unless klass = self.class.attrclass(name)
+      raise Puppet::Error, "Resource type #{self.class.name} does not support parameter #{name}"
+    end
+
+    if provider and ! provider.class.supports_parameter?(klass)
+      missing = klass.required_features.find_all { |f| ! provider.class.feature?(f) }
+      debug "Provider %s does not support features %s; not managing attribute %s" % [provider.class.name, missing.join(", "), name]
+      return nil
+    end
+
+    return @parameters[name] if @parameters.include?(name)
+
+    @parameters[name] = klass.new(:resource => self)
+  end
+
+  # Returns a string representation of the resource's containment path in
+  # the catalog.
+  # @return [String]
+  def path
+    @path ||= '/' + pathbuilder.join('/')
+  end
+
+  # Returns the value of this object's parameter given by name
+  # @param name [String] the name of the parameter
+  # @return [Object] the value
+  def parameter(name)
+    @parameters[name.to_sym]
+  end
+
+  # Returns a shallow copy of this object's hash of attributes by name.
+  # Note that his not only comprises parameters, but also properties and metaparameters.
+  # Changes to the contained parameters will have an effect on the parameters of this type, but changes to
+  # the returned hash does not.
+  # @return [Hash{String => Object}] a new hash being a shallow copy of the parameters map name to parameter
+  def parameters
+    @parameters.dup
+  end
+
+  # @return [Boolean] Returns whether the attribute given by name has been added
+  #   to this resource or not.
+  def propertydefined?(name)
+    name = name.intern unless name.is_a? Symbol
+    @parameters.include?(name)
+  end
+
+  # Returns a {Puppet::Property} instance by name.
+  # To return the value, use 'resource[param]'
+  # @todo LAK:NOTE(20081028) Since the 'parameter' method is now a superset of this method,
+  #   this one should probably go away at some point. - Does this mean it should be deprecated ?
+  # @return [Puppet::Property] the property with the given name, or nil if not a property or does not exist.
+  def property(name)
+    (obj = @parameters[name.intern] and obj.is_a?(Puppet::Property)) ? obj : nil
+  end
+
+  # @todo comment says "For any parameters or properties that have defaults and have not yet been
+  #   set, set them now.  This method can be handed a list of attributes,
+  #   and if so it will only set defaults for those attributes."
+  # @todo Needs a better explanation, and investigation about the claim an array can be passed (it is passed
+  #   to self.class.attrclass to produce a class on which a check is made if it has a method class :default (does
+  #   not seem to support an array...
+  # @return [void]
+  #
+  def set_default(attr)
+    return unless klass = self.class.attrclass(attr)
+    return unless klass.method_defined?(:default)
+    return if @parameters.include?(klass.name)
+
+    return unless parameter = newattr(klass.name)
+
+    if value = parameter.default and ! value.nil?
+      parameter.value = value
+    else
+      @parameters.delete(parameter.name)
+    end
+  end
+
+  # @todo the comment says: "Convert our object to a hash.  This just includes properties."
+  # @todo this is confused, again it is the @parameters instance variable that is consulted, and
+  #   each value is copied - does it contain "properties" and "parameters" or both? Does it contain
+  #   meta-parameters?
+  #
+  # @return [Hash{ ??? => ??? }] a hash of WHAT?. The hash is a shallow copy, any changes to the
+  #  objects returned in this hash will be reflected in the original resource having these attributes.
+  #
+  def to_hash
+    rethash = {}
+
+    @parameters.each do |name, obj|
+      rethash[name] = obj.value
+    end
+
+    rethash
+  end
+
+  # @return [String] the name of this object's class
+  # @todo Would that be "file" for the "File" resource type? of "File" or something else?
+  #
+  def type
+    self.class.name
+  end
+
+  # @todo Comment says "Return a specific value for an attribute.", as opposed to what "An upspecific value"???
+  # @todo is this the 'is' or the 'should' value?
+  # @todo why is the return restricted to things that respond to :value? (Only non structural basic data types
+  #   supported?
+  #
+  # @return [Object, nil] the value of the attribute having the given name, or nil if the given name is not
+  #   an attribute, or the referenced attribute does not respond to `:value`.
+  def value(name)
+    name = name.intern
+
+    (obj = @parameters[name] and obj.respond_to?(:value)) ? obj.value : nil
+  end
+
+  # @todo What is this used for? Needs a better explanation.
+  # @return [???] the version of the catalog or 0 if there is no catalog.
+  def version
+    return 0 unless catalog
+    catalog.version
+  end
+
+  # @return [Array<Puppet::Property>] Returns all of the property objects, in the order specified in the
+  #   class.
+  # @todo "what does the 'order specified in the class' mean? The order the properties where added in the
+  #   ruby file adding a new type with new properties?
+  #
+  def properties
+    self.class.properties.collect { |prop| @parameters[prop.name] }.compact
+  end
+
+  # Returns true if the type's notion of name is the identity of a resource.
+  # See the overview of this class for a longer explanation of the concept _isomorphism_.
+  # Defaults to true.
+  #
+  # @return [Boolan] true, if this type's name is isomorphic with the object
+  def self.isomorphic?
+    if defined?(@isomorphic)
+      return @isomorphic
+    else
+      return true
+    end
+  end
+
+  # @todo check that this gets documentation (it is at the class level as well as instance).
+  # (see isomorphic?)
+  def isomorphic?
+    self.class.isomorphic?
+  end
+
+  # Returns true if the instance is a managed instance.
+  # A 'yes' here means that the instance was created from the language, vs. being created
+  # in order resolve other questions, such as finding a package in a list.
+  # @note An object that is managed always stays managed, but an object that is not managed
+  #   may become managed later in its lifecycle.
+  # @return [Boolean] true if the object is managed
+  def managed?
+    # Once an object is managed, it always stays managed; but an object
+    # that is listed as unmanaged might become managed later in the process,
+    # so we have to check that every time
+    if @managed
+      return @managed
+    else
+      @managed = false
+      properties.each { |property|
+        s = property.should
+        if s and ! property.class.unmanaged
+          @managed = true
+          break
+        end
+      }
+      return @managed
+    end
+  end
+
+  ###############################
+  # Code related to the container behaviour.
+
+  # Returns true if the search should be done in depth-first order.
+  # This implementation always returns false.
+  # @todo What is this used for?
+  #
+  # @return [Boolean] true if the search should be done in depth first order.
+  #
+  def depthfirst?
+    false
+  end
+
+  # Removes this object (FROM WHERE?)
+  # @todo removes if from where?
+  # @overload remove(rmdeps)
+  #   @deprecated Use remove()
+  #   @param rmdeps [Boolean] intended to indicate that all subscriptions should also be removed, ignored.
+  # @overload remove()
+  # @return [void]
+  #
+  def remove(rmdeps = true)
+    # This is hackish (mmm, cut and paste), but it works for now, and it's
+    # better than warnings.
+    @parameters.each do |name, obj|
+      obj.remove
+    end
+    @parameters.clear
+
+    @parent = nil
+
+    # Remove the reference to the provider.
+    if self.provider
+      @provider.clear
+      @provider = nil
+    end
+  end
+
+  ###############################
+  # Code related to evaluating the resources.
+
+  # Returns the ancestors - WHAT?
+  # This implementation always returns an empty list.
+  # @todo WHAT IS THIS ?
+  # @return [Array<???>] returns a list of ancestors.
+  def ancestors
+    []
+  end
+
+  # Lifecycle method for a resource. This is called during graph creation.
+  # It should perform any consistency checking of the catalog and raise a
+  # Puppet::Error if the transaction should be aborted.
+  #
+  # It differs from the validate method, since it is called later during
+  # initialization and can rely on self.catalog to have references to all
+  # resources that comprise the catalog.
+  #
+  # @see Puppet::Transaction#add_vertex
+  # @raise [Puppet::Error] If the pre-run check failed.
+  # @return [void]
+  # @abstract a resource type may implement this method to perform
+  #   validation checks that can query the complete catalog
+  def pre_run_check
+  end
+
+  # Flushes the provider if supported by the provider, else no action.
+  # This is called by the transaction.
+  # @todo What does Flushing the provider mean? Why is it interesting to know that this is
+  #   called by the transaction? (It is not explained anywhere what a transaction is).
+  #
+  # @return [???, nil] WHAT DOES IT RETURN? GUESS IS VOID
+  def flush
+    self.provider.flush if self.provider and self.provider.respond_to?(:flush)
+  end
+
+  # Returns true if all contained objects are in sync.
+  # @todo "contained in what?" in the given "in" parameter?
+  #
+  # @todo deal with the comment _"FIXME I don't think this is used on the type instances any more,
+  #   it's really only used for testing"_
+  # @return [Boolean] true if in sync, false otherwise.
+  #
+  def insync?(is)
+    insync = true
+
+    if property = @parameters[:ensure]
+      unless is.include? property
+        raise Puppet::DevError,
+          "The is value is not in the is array for '#{property.name}'"
+      end
+      ensureis = is[property]
+      if property.safe_insync?(ensureis) and property.should == :absent
+        return true
+      end
+    end
+
+    properties.each { |property|
+      unless is.include? property
+        raise Puppet::DevError,
+          "The is value is not in the is array for '#{property.name}'"
+      end
+
+      propis = is[property]
+      unless property.safe_insync?(propis)
+        property.debug("Not in sync: #{propis.inspect} vs #{property.should.inspect}")
+        insync = false
+      #else
+      #    property.debug("In sync")
+      end
+    }
+
+    #self.debug("#{self} sync status is #{insync}")
+    insync
+  end
+
+  # Retrieves the current value of all contained properties.
+  # Parameters and meta-parameters are not included in the result.
+  # @todo As oposed to all non contained properties? How is this different than any of the other
+  #   methods that also "gets" properties/parameters/etc. ?
+  # @return [Puppet::Resource] array of all property values (mix of types)
+  # @raise [fail???] if there is a provider and it is not suitable for the host this is evaluated for.
+  def retrieve
+    fail "Provider #{provider.class.name} is not functional on this host" if self.provider.is_a?(Puppet::Provider) and ! provider.class.suitable?
+
+    result = Puppet::Resource.new(self.class, title)
+
+    # Provide the name, so we know we'll always refer to a real thing
+    result[:name] = self[:name] unless self[:name] == title
+
+    if ensure_prop = property(:ensure) or (self.class.validattr?(:ensure) and ensure_prop = newattr(:ensure))
+      result[:ensure] = ensure_state = ensure_prop.retrieve
+    else
+      ensure_state = nil
+    end
+
+    properties.each do |property|
+      next if property.name == :ensure
+      if ensure_state == :absent
+        result[property] = :absent
+      else
+        result[property] = property.retrieve
+      end
+    end
+
+    result
+  end
+
+  # Retrieve the current state of the system as a Puppet::Resource. For
+  # the base Puppet::Type this does the same thing as #retrieve, but
+  # specific types are free to implement #retrieve as returning a hash,
+  # and this will call #retrieve and convert the hash to a resource.
+  # This is used when determining when syncing a resource.
+  #
+  # @return [Puppet::Resource] A resource representing the current state
+  #   of the system.
+  #
+  # @api private
+  def retrieve_resource
+    resource = retrieve
+    resource = Resource.new(self.class, title, :parameters => resource) if resource.is_a? Hash
+    resource
+  end
+
+  # Given the hash of current properties, should this resource be treated as if it
+  # currently exists on the system. May need to be overridden by types that offer up
+  # more than just :absent and :present.
+  def present?(current_values)
+    current_values[:ensure] != :absent
+  end
+
+  # Returns a hash of the current properties and their values.
+  # If a resource is absent, its value is the symbol `:absent`
+  # @return [Hash{Puppet::Property => Object}] mapping of property instance to its value
+  #
+  def currentpropvalues
+    # It's important to use the 'properties' method here, as it follows the order
+    # in which they're defined in the class.  It also guarantees that 'ensure'
+    # is the first property, which is important for skipping 'retrieve' on
+    # all the properties if the resource is absent.
+    ensure_state = false
+    return properties.inject({}) do | prophash, property|
+      if property.name == :ensure
+        ensure_state = property.retrieve
+        prophash[property] = ensure_state
+      else
+        if ensure_state == :absent
+          prophash[property] = :absent
+        else
+          prophash[property] = property.retrieve
+        end
+      end
+      prophash
+    end
+  end
+
+  # Returns the `noop` run mode status of this.
+  # @return [Boolean] true if running in noop mode.
+  def noop?
+    # If we're not a host_config, we're almost certainly part of
+    # Settings, and we want to ignore 'noop'
+    return false if catalog and ! catalog.host_config?
+
+    if defined?(@noop)
+      @noop
+    else
+      Puppet[:noop]
+    end
+  end
+
+  # (see #noop?)
+  def noop
+    noop?
+  end
+
+  # Retrieves all known instances.
+  # @todo Retrieves them from where? Known to whom?
+  # Either requires providers or must be overridden.
+  # @raise [Puppet::DevError] when there are no providers and the implementation has not overridded this method.
+  def self.instances
+    raise Puppet::DevError, "#{self.name} has no providers and has not overridden 'instances'" if provider_hash.empty?
+
+    # Put the default provider first, then the rest of the suitable providers.
+    provider_instances = {}
+    providers_by_source.collect do |provider|
+      self.properties.find_all do |property|
+        provider.supports_parameter?(property)
+      end.collect do |property|
+        property.name
+      end
+
+      provider.instances.collect do |instance|
+        # We always want to use the "first" provider instance we find, unless the resource
+        # is already managed and has a different provider set
+        if other = provider_instances[instance.name]
+          Puppet.debug "%s %s found in both %s and %s; skipping the %s version" %
+            [self.name.to_s.capitalize, instance.name, other.class.name, instance.class.name, instance.class.name]
+          next
+        end
+        provider_instances[instance.name] = instance
+
+        result = new(:name => instance.name, :provider => instance)
+        properties.each { |name| result.newattr(name) }
+        result
+      end
+    end.flatten.compact
+  end
+
+  # Returns a list of one suitable provider per source, with the default provider first.
+  # @todo Needs better explanation; what does "source" mean in this context?
+  # @return [Array<Puppet::Provider>] list of providers
+  #
+  def self.providers_by_source
+    # Put the default provider first (can be nil), then the rest of the suitable providers.
+    sources = []
+    [defaultprovider, suitableprovider].flatten.uniq.collect do |provider|
+      next if provider.nil?
+      next if sources.include?(provider.source)
+
+      sources << provider.source
+      provider
+    end.compact
+  end
+
+  # Converts a simple hash into a Resource instance.
+  # @todo as opposed to a complex hash? Other raised exceptions?
+  # @param [Hash{Symbol, String => Object}] hash resource attribute to value map to initialize the created resource from
+  # @return [Puppet::Resource] the resource created from the hash
+  # @raise [Puppet::Error] if a title is missing in the given hash
+  def self.hash2resource(hash)
+    hash = hash.inject({}) { |result, ary| result[ary[0].to_sym] = ary[1]; result }
+
+    title = hash.delete(:title)
+    title ||= hash[:name]
+    title ||= hash[key_attributes.first] if key_attributes.length == 1
+
+    raise Puppet::Error, "Title or name must be provided" unless title
+
+    # Now create our resource.
+    resource = Puppet::Resource.new(self, title)
+    resource.catalog = hash.delete(:catalog)
+
+    hash.each do |param, value|
+      resource[param] = value
+    end
+    resource
+  end
+
+
+  # Returns an array of strings representing the containment heirarchy
+  # (types/classes) that make up the path to the resource from the root
+  # of the catalog.  This is mostly used for logging purposes.
+  #
+  # @api private
+  def pathbuilder
+    if p = parent
+      [p.pathbuilder, self.ref].flatten
+    else
+      [self.ref]
+    end
+  end
+
+  ###############################
+  # Add all of the meta-parameters.
+  newmetaparam(:noop) do
+    desc "Whether to apply this resource in noop mode.
+
+      When applying a resource in noop mode, Puppet will check whether it is in sync,
+      like it does when running normally. However, if a resource attribute is not in
+      the desired state (as declared in the catalog), Puppet will take no
+      action, and will instead report the changes it _would_ have made. These
+      simulated changes will appear in the report sent to the puppet master, or
+      be shown on the console if running puppet agent or puppet apply in the
+      foreground. The simulated changes will not send refresh events to any
+      subscribing or notified resources, although Puppet will log that a refresh
+      event _would_ have been sent.
+
+      **Important note:**
+      [The `noop` setting](http://docs.puppetlabs.com/references/latest/configuration.html#noop)
+      allows you to globally enable or disable noop mode, but it will _not_ override
+      the `noop` metaparameter on individual resources. That is, the value of the
+      global `noop` setting will _only_ affect resources that do not have an explicit
+      value set for their `noop` attribute."
+
+    newvalues(:true, :false)
+    munge do |value|
+      case value
+      when true, :true, "true"; @resource.noop = true
+      when false, :false, "false"; @resource.noop = false
+      end
+    end
+  end
+
+  newmetaparam(:schedule) do
+    desc "A schedule to govern when Puppet is allowed to manage this resource.
+      The value of this metaparameter must be the `name` of a `schedule`
+      resource. This means you must declare a schedule resource, then
+      refer to it by name; see
+      [the docs for the `schedule` type](http://docs.puppetlabs.com/references/latest/type.html#schedule)
+      for more info.
+
+          schedule { 'everyday':
+            period => daily,
+            range  => \"2-4\"
+          }
+
+          exec { \"/usr/bin/apt-get update\":
+            schedule => 'everyday'
+          }
+
+      Note that you can declare the schedule resource anywhere in your
+      manifests, as long as it ends up in the final compiled catalog."
+  end
+
+  newmetaparam(:audit) do
+    desc "Marks a subset of this resource's unmanaged attributes for auditing. Accepts an
+      attribute name, an array of attribute names, or `all`.
+
+      Auditing a resource attribute has two effects: First, whenever a catalog
+      is applied with puppet apply or puppet agent, Puppet will check whether
+      that attribute of the resource has been modified, comparing its current
+      value to the previous run; any change will be logged alongside any actions
+      performed by Puppet while applying the catalog.
+
+      Secondly, marking a resource attribute for auditing will include that
+      attribute in inspection reports generated by puppet inspect; see the
+      puppet inspect documentation for more details.
+
+      Managed attributes for a resource can also be audited, but note that
+      changes made by Puppet will be logged as additional modifications. (I.e.
+      if a user manually edits a file whose contents are audited and managed,
+      puppet agent's next two runs will both log an audit notice: the first run
+      will log the user's edit and then revert the file to the desired state,
+      and the second run will log the edit made by Puppet.)"
+
+    validate do |list|
+      list = Array(list).collect {|p| p.to_sym}
+      unless list == [:all]
+        list.each do |param|
+          next if @resource.class.validattr?(param)
+          fail "Cannot audit #{param}: not a valid attribute for #{resource}"
+        end
+      end
+    end
+
+    munge do |args|
+      properties_to_audit(args).each do |param|
+        next unless resource.class.validproperty?(param)
+        resource.newattr(param)
+      end
+    end
+
+    def all_properties
+      resource.class.properties.find_all do |property|
+        resource.provider.nil? or resource.provider.class.supports_parameter?(property)
+      end.collect do |property|
+        property.name
+      end
+    end
+
+    def properties_to_audit(list)
+      if !list.kind_of?(Array) && list.to_sym == :all
+        list = all_properties
+      else
+        list = Array(list).collect { |p| p.to_sym }
+      end
+    end
+  end
+
+  newmetaparam(:loglevel) do
+    desc "Sets the level that information will be logged.
+      The log levels have the biggest impact when logs are sent to
+      syslog (which is currently the default).
+
+      The order of the log levels, in decreasing priority, is:
+
+      * `crit`
+      * `emerg`
+      * `alert`
+      * `err`
+      * `warning`
+      * `notice`
+      * `info` / `verbose`
+      * `debug`
+      "
+    defaultto :notice
+
+    newvalues(*Puppet::Util::Log.levels)
+    newvalues(:verbose)
+
+    munge do |loglevel|
+      val = super(loglevel)
+      if val == :verbose
+        val = :info
+      end
+      val
+    end
+  end
+
+  newmetaparam(:alias) do
+    desc %q{Creates an alias for the resource.  Puppet uses this internally when you
+      provide a symbolic title and an explicit namevar value:
+
+          file { 'sshdconfig':
+            path => $operatingsystem ? {
+              solaris => '/usr/local/etc/ssh/sshd_config',
+              default => '/etc/ssh/sshd_config',
+            },
+            source => '...'
+          }
+
+          service { 'sshd':
+            subscribe => File['sshdconfig'],
+          }
+
+      When you use this feature, the parser sets `sshdconfig` as the title,
+      and the library sets that as an alias for the file so the dependency
+      lookup in `Service['sshd']` works.  You can use this metaparameter yourself,
+      but note that aliases generally only work for creating relationships; anything
+      else that refers to an existing resource (such as amending or overriding
+      resource attributes in an inherited class) must use the resource's exact
+      title. For example, the following code will not work:
+
+          file { '/etc/ssh/sshd_config':
+            owner => root,
+            group => root,
+            alias => 'sshdconfig',
+          }
+
+          File['sshdconfig'] {
+            mode => 644,
+          }
+
+      There's no way here for the Puppet parser to know that these two stanzas
+      should be affecting the same file.
+
+      }
+
+    munge do |aliases|
+      aliases = [aliases] unless aliases.is_a?(Array)
+
+      raise(ArgumentError, "Cannot add aliases without a catalog") unless @resource.catalog
+
+      aliases.each do |other|
+        if obj = @resource.catalog.resource(@resource.class.name, other)
+          unless obj.object_id == @resource.object_id
+            self.fail("#{@resource.title} can not create alias #{other}: object already exists")
+          end
+          next
+        end
+
+        # Newschool, add it to the catalog.
+        @resource.catalog.alias(@resource, other)
+      end
+    end
+  end
+
+  newmetaparam(:tag) do
+    desc "Add the specified tags to the associated resource.  While all resources
+      are automatically tagged with as much information as possible
+      (e.g., each class and definition containing the resource), it can
+      be useful to add your own tags to a given resource.
+
+      Multiple tags can be specified as an array:
+
+          file {'/etc/hosts':
+            ensure => file,
+            source => 'puppet:///modules/site/hosts',
+            mode   => 0644,
+            tag    => ['bootstrap', 'minimumrun', 'mediumrun'],
+          }
+
+      Tags are useful for things like applying a subset of a host's configuration
+      with [the `tags` setting](/references/latest/configuration.html#tags)
+      (e.g. `puppet agent --test --tags bootstrap`) or filtering alerts with
+      [the `tagmail` report processor](http://docs.puppetlabs.com/references/latest/report.html#tagmail)."
+
+    munge do |tags|
+      tags = [tags] unless tags.is_a? Array
+
+      tags.each do |tag|
+        @resource.tag(tag)
+      end
+    end
+  end
+
+  # RelationshipMetaparam is an implementation supporting the meta-parameters `:require`, `:subscribe`,
+  # `:notify`, and `:before`.
+  #
+  #
+  class RelationshipMetaparam < Puppet::Parameter
+    class << self
+      attr_accessor :direction, :events, :callback, :subclasses
+    end
+
+    @subclasses = []
+
+    def self.inherited(sub)
+      @subclasses << sub
+    end
+
+    # @return [Array<Puppet::Resource>] turns attribute value(s) into list of resources
+    def munge(references)
+      references = [references] unless references.is_a?(Array)
+      references.collect do |ref|
+        if ref.is_a?(Puppet::Resource)
+          ref
+        else
+          Puppet::Resource.new(ref)
+        end
+      end
+    end
+
+    # Checks each reference to assert that what it references exists in the catalog.
+    #
+    # @raise [???fail] if the referenced resource can not be found
+    # @return [void]
+    def validate_relationship
+      @value.each do |ref|
+        unless @resource.catalog.resource(ref.to_s)
+          description = self.class.direction == :in ? "dependency" : "dependent"
+          fail ResourceError, "Could not find #{description} #{ref} for #{resource.ref}"
+        end
+      end
+    end
+
+    # Creates edges for all relationships.
+    # The `:in` relationships are specified by the event-receivers, and `:out`
+    # relationships are specified by the event generator.
+    # @todo references to "event-receivers" and "event generator" means in this context - are those just
+    #   the resources at the two ends of the relationship?
+    # This way 'source' and 'target' are consistent terms in both edges
+    # and events, i.e. an event targets edges whose source matches
+    # the event's source. The direction of the relationship determines
+    # which resource is applied first and which resource is considered
+    # to be the event generator.
+    # @return [Array<Puppet::Relationship>]
+    # @raise [???fail] when a reference can not be resolved
+    #
+    def to_edges
+      @value.collect do |reference|
+        reference.catalog = resource.catalog
+
+        # Either of the two retrieval attempts could have returned
+        # nil.
+        unless related_resource = reference.resolve
+          self.fail "Could not retrieve dependency '#{reference}' of #{@resource.ref}"
+        end
+
+        # Are we requiring them, or vice versa?  See the method docs
+        # for futher info on this.
+        if self.class.direction == :in
+          source = related_resource
+          target = @resource
+        else
+          source = @resource
+          target = related_resource
+        end
+
+        if method = self.class.callback
+          subargs = {
+            :event => self.class.events,
+            :callback => method
+          }
+          self.debug("subscribes to #{related_resource.ref}")
+        else
+          # If there's no callback, there's no point in even adding
+          # a label.
+          subargs = nil
+          self.debug("requires #{related_resource.ref}")
+        end
+
+        Puppet::Relationship.new(source, target, subargs)
+      end
+    end
+  end
+
+  # @todo document this, have no clue what this does... it retuns "RelationshipMetaparam.subclasses"
+  #
+  def self.relationship_params
+    RelationshipMetaparam.subclasses
+  end
+
+
+  # Note that the order in which the relationships params is defined
+  # matters.  The labelled params (notify and subcribe) must be later,
+  # so that if both params are used, those ones win.  It's a hackish
+  # solution, but it works.
+
+  newmetaparam(:require, :parent => RelationshipMetaparam, :attributes => {:direction => :in, :events => :NONE}) do
+    desc "One or more resources that this resource depends on, expressed as
+      [resource references](http://docs.puppetlabs.com/puppet/latest/reference/lang_datatypes.html#resource-references).
+      Multiple resources can be specified as an array of references. When this
+      attribute is present:
+
+      * The required resource(s) will be applied **before** this resource.
+
+      This is one of the four relationship metaparameters, along with
+      `before`, `notify`, and `subscribe`. For more context, including the
+      alternate chaining arrow (`->` and `~>`) syntax, see
+      [the language page on relationships](http://docs.puppetlabs.com/puppet/latest/reference/lang_relationships.html)."
+  end
+
+  newmetaparam(:subscribe, :parent => RelationshipMetaparam, :attributes => {:direction => :in, :events => :ALL_EVENTS, :callback => :refresh}) do
+    desc "One or more resources that this resource depends on, expressed as
+      [resource references](http://docs.puppetlabs.com/puppet/latest/reference/lang_datatypes.html#resource-references).
+      Multiple resources can be specified as an array of references. When this
+      attribute is present:
+
+      * The subscribed resource(s) will be applied _before_ this resource.
+      * If Puppet makes changes to any of the subscribed resources, it will cause
+        this resource to _refresh._ (Refresh behavior varies by resource
+        type: services will restart, mounts will unmount and re-mount, etc. Not
+        all types can refresh.)
+
+      This is one of the four relationship metaparameters, along with
+      `before`, `require`, and `notify`. For more context, including the
+      alternate chaining arrow (`->` and `~>`) syntax, see
+      [the language page on relationships](http://docs.puppetlabs.com/puppet/latest/reference/lang_relationships.html)."
+  end
+
+  newmetaparam(:before, :parent => RelationshipMetaparam, :attributes => {:direction => :out, :events => :NONE}) do
+    desc "One or more resources that depend on this resource, expressed as
+      [resource references](http://docs.puppetlabs.com/puppet/latest/reference/lang_datatypes.html#resource-references).
+      Multiple resources can be specified as an array of references. When this
+      attribute is present:
+
+      * This resource will be applied _before_ the dependent resource(s).
+
+      This is one of the four relationship metaparameters, along with
+      `require`, `notify`, and `subscribe`. For more context, including the
+      alternate chaining arrow (`->` and `~>`) syntax, see
+      [the language page on relationships](http://docs.puppetlabs.com/puppet/latest/reference/lang_relationships.html)."
+  end
+
+  newmetaparam(:notify, :parent => RelationshipMetaparam, :attributes => {:direction => :out, :events => :ALL_EVENTS, :callback => :refresh}) do
+    desc "One or more resources that depend on this resource, expressed as
+      [resource references](http://docs.puppetlabs.com/puppet/latest/reference/lang_datatypes.html#resource-references).
+      Multiple resources can be specified as an array of references. When this
+      attribute is present:
+
+      * This resource will be applied _before_ the notified resource(s).
+      * If Puppet makes changes to this resource, it will cause all of the
+        notified resources to _refresh._ (Refresh behavior varies by resource
+        type: services will restart, mounts will unmount and re-mount, etc. Not
+        all types can refresh.)
+
+      This is one of the four relationship metaparameters, along with
+      `before`, `require`, and `subscribe`. For more context, including the
+      alternate chaining arrow (`->` and `~>`) syntax, see
+      [the language page on relationships](http://docs.puppetlabs.com/puppet/latest/reference/lang_relationships.html)."
+  end
+
+  newmetaparam(:stage) do
+    desc %{Which run stage this class should reside in.
+
+      **Note: This metaparameter can only be used on classes,** and only when
+      declaring them with the resource-like syntax. It cannot be used on normal
+      resources or on classes declared with `include`.
+
+      By default, all classes are declared in the `main` stage. To assign a class
+      to a different stage, you must:
+
+      * Declare the new stage as a [`stage` resource](http://docs.puppetlabs.com/references/latest/type.html#stage).
+      * Declare an order relationship between the new stage and the `main` stage.
+      * Use the resource-like syntax to declare the class, and set the `stage`
+        metaparameter to the name of the desired stage.
+
+      For example:
+
+          stage { 'pre':
+            before => Stage['main'],
+          }
+
+          class { 'apt-updates':
+            stage => 'pre',
+          }
+    }
+  end
+
+  ###############################
+  # All of the provider plumbing for the resource types.
+  require 'puppet/provider'
+  require 'puppet/util/provider_features'
+
+  # Add the feature handling module.
+  extend Puppet::Util::ProviderFeatures
+
+  # The provider that has been selected for the instance of the resource type.
+  # @return [Puppet::Provider,nil] the selected provider or nil, if none has been selected
+  #
+  attr_reader :provider
+
+  # the Type class attribute accessors
+  class << self
+    # The loader of providers to use when loading providers from disk.
+    # Although it looks like this attribute provides a way to operate with different loaders of
+    # providers that is not the case; the attribute is written when a new type is created,
+    # and should not be changed thereafter.
+    # @api private
+    #
+    attr_accessor :providerloader
+
+    # @todo Don't know if this is a name, or a reference to a Provider instance (now marked up as an instance
+    #   of Provider.
+    # @return [Puppet::Provider, nil] The default provider for this type, or nil if non is defines
+    #
+    attr_writer :defaultprovider
+  end
+
+  # The default provider, or the most suitable provider if no default provider was set.
+  # @note a warning will be issued if no default provider has been configured and a search for the most
+  #   suitable provider returns more than one equally suitable provider.
+  # @return [Puppet::Provider, nil] the default or most suitable provider, or nil if no provider was found
+  #
+  def self.defaultprovider
+    return @defaultprovider if @defaultprovider
+
+    suitable = suitableprovider
+
+    # Find which providers are a default for this system.
+    defaults = suitable.find_all { |provider| provider.default? }
+
+    # If we don't have any default we use suitable providers
+    defaults = suitable if defaults.empty?
+    max = defaults.collect { |provider| provider.specificity }.max
+    defaults = defaults.find_all { |provider| provider.specificity == max }
+
+    if defaults.length > 1
+      Puppet.warning(
+        "Found multiple default providers for #{self.name}: #{defaults.collect { |i| i.name.to_s }.join(", ")}; using #{defaults[0].name}"
+      )
+    end
+
+    @defaultprovider = defaults.shift unless defaults.empty?
+  end
+
+  # @return [Hash{??? => Puppet::Provider}] Returns a hash of WHAT EXACTLY for the given type
+  # @todo what goes into this hash?
+  def self.provider_hash_by_type(type)
+    @provider_hashes ||= {}
+    @provider_hashes[type] ||= {}
+  end
+
+  # @return [Hash{ ??? => Puppet::Provider}] Returns a hash of WHAT EXACTLY for this type.
+  # @see provider_hash_by_type method to get the same for some other type
+  def self.provider_hash
+    Puppet::Type.provider_hash_by_type(self.name)
+  end
+
+  # Returns the provider having the given name.
+  # This will load a provider if it is not already loaded. The returned provider is the first found provider
+  # having the given name, where "first found" semantics is defined by the {providerloader} in use.
+  #
+  # @param name [String] the name of the provider to get
+  # @return [Puppet::Provider, nil] the found provider, or nil if no provider of the given name was found
+  #
+  def self.provider(name)
+    name = name.intern
+
+    # If we don't have it yet, try loading it.
+    @providerloader.load(name) unless provider_hash.has_key?(name)
+    provider_hash[name]
+  end
+
+  # Returns a list of loaded providers by name.
+  # This method will not load/search for available providers.
+  # @return [Array<String>] list of loaded provider names
+  #
+  def self.providers
+    provider_hash.keys
+  end
+
+  # Returns true if the given name is a reference to a provider and if this is a suitable provider for
+  # this type.
+  # @todo How does the provider know if it is suitable for the type? Is it just suitable for the platform/
+  #   environment where this method is executing?
+  # @param name [String] the name of the provider for which validity is checked
+  # @return [Boolean] true if the given name references a provider that is suitable
+  #
+  def self.validprovider?(name)
+    name = name.intern
+
+    (provider_hash.has_key?(name) && provider_hash[name].suitable?)
+  end
+
+  # Creates a new provider of a type.
+  # This method must be called directly on the type that it's implementing.
+  # @todo Fix Confusing Explanations!
+  #   Is this a new provider of a Type (metatype), or a provider of an instance of Type (a resource), or
+  #   a Provider (the implementation of a Type's behavior). CONFUSED. It calls magically named methods like
+  #   "providify" ...
+  # @param name [String, Symbol] the name of the WHAT? provider? type?
+  # @param options [Hash{Symbol => Object}] a hash of options, used by this method, and passed on to {#genclass}, (see
+  #   it for additional options to pass).
+  # @option options [Puppet::Provider] :parent the parent provider (what is this?)
+  # @option options [Puppet::Type] :resource_type the resource type, defaults to this type if unspecified
+  # @return [Puppet::Provider] a provider ???
+  # @raise [Puppet::DevError] when the parent provider could not be found.
+  #
+  def self.provide(name, options = {}, &block)
+    name = name.intern
+
+    if unprovide(name)
+      Puppet.debug "Reloading #{name} #{self.name} provider"
+    end
+
+    parent = if pname = options[:parent]
+      options.delete(:parent)
+      if pname.is_a? Class
+        pname
+      else
+        if provider = self.provider(pname)
+          provider
+        else
+          raise Puppet::DevError,
+            "Could not find parent provider #{pname} of #{name}"
+        end
+      end
+    else
+      Puppet::Provider
+    end
+
+    options[:resource_type] ||= self
+
+    self.providify
+
+    provider = genclass(
+      name,
+      :parent     => parent,
+      :hash       => provider_hash,
+      :prefix     => "Provider",
+      :block      => block,
+      :include    => feature_module,
+      :extend     => feature_module,
+      :attributes => options
+    )
+
+    provider
+  end
+
+  # Ensures there is a `:provider` parameter defined.
+  # Should only be called if there are providers.
+  # @return [void]
+  def self.providify
+    return if @paramhash.has_key? :provider
+
+    newparam(:provider) do
+      # We're using a hacky way to get the name of our type, since there doesn't
+      # seem to be a correct way to introspect this at the time this code is run.
+      # We expect that the class in which this code is executed will be something
+      # like Puppet::Type::Ssh_authorized_key::ParameterProvider.
+      desc <<-EOT
+        The specific backend to use for this `#{self.to_s.split('::')[2].downcase}`
+        resource. You will seldom need to specify this --- Puppet will usually
+        discover the appropriate provider for your platform.
+      EOT
+
+      # This is so we can refer back to the type to get a list of
+      # providers for documentation.
+      class << self
+        # The reference to a parent type for the parameter `:provider` used to get a list of
+        # providers for documentation purposes.
+        #
+        attr_accessor :parenttype
+      end
+
+      # Provides the ability to add documentation to a provider.
+      #
+      def self.doc
+        # Since we're mixing @doc with text from other sources, we must normalize
+        # its indentation with scrub. But we don't need to manually scrub the
+        # provider's doc string, since markdown_definitionlist sanitizes its inputs.
+        scrub(@doc) + "Available providers are:\n\n" + parenttype.providers.sort { |a,b|
+          a.to_s <=> b.to_s
+        }.collect { |i|
+          markdown_definitionlist( i, scrub(parenttype().provider(i).doc) )
+        }.join
+      end
+
+      # For each resource, the provider param defaults to
+      # the type's default provider
+      defaultto {
+        prov = @resource.class.defaultprovider
+        prov.name if prov
+      }
+
+      validate do |provider_class|
+        provider_class = provider_class[0] if provider_class.is_a? Array
+        provider_class = provider_class.class.name if provider_class.is_a?(Puppet::Provider)
+
+        unless @resource.class.provider(provider_class)
+          raise ArgumentError, "Invalid #{@resource.class.name} provider '#{provider_class}'"
+        end
+      end
+
+      munge do |provider|
+        provider = provider[0] if provider.is_a? Array
+        provider = provider.intern if provider.is_a? String
+        @resource.provider = provider
+
+        if provider.is_a?(Puppet::Provider)
+          provider.class.name
+        else
+          provider
+        end
+      end
+    end.parenttype = self
+  end
+
+  # @todo this needs a better explanation
+  # Removes the implementation class of a given provider.
+  # @return [Object] returns what {Puppet::Util::ClassGen#rmclass} returns
+  def self.unprovide(name)
+    if @defaultprovider and @defaultprovider.name == name
+      @defaultprovider = nil
+    end
+
+    rmclass(name, :hash => provider_hash, :prefix => "Provider")
+  end
+
+  # Returns a list of suitable providers for the given type.
+  # A call to this method will load all providers if not already loaded and ask each if it is
+  # suitable - those that are are included in the result.
+  # @note This method also does some special processing which rejects a provider named `:fake` (for testing purposes).
+  # @return [Array<Puppet::Provider>] Returns an array of all suitable providers.
+  #
+  def self.suitableprovider
+    providerloader.loadall if provider_hash.empty?
+    provider_hash.find_all { |name, provider|
+      provider.suitable?
+    }.collect { |name, provider|
+      provider
+    }.reject { |p| p.name == :fake } # For testing
+  end
+
+  # @return [Boolean] Returns true if this is something else than a `:provider`, or if it
+  #   is a provider and it is suitable, or if there is a default provider. Otherwise, false is returned.
+  #
+  def suitable?
+    # If we don't use providers, then we consider it suitable.
+    return true unless self.class.paramclass(:provider)
+
+    # We have a provider and it is suitable.
+    return true if provider && provider.class.suitable?
+
+    # We're using the default provider and there is one.
+    if !provider and self.class.defaultprovider
+      self.provider = self.class.defaultprovider.name
+      return true
+    end
+
+    # We specified an unsuitable provider, or there isn't any suitable
+    # provider.
+    false
+  end
+
+  # Sets the provider to the given provider/name.
+  # @overload provider=(name)
+  #   Sets the provider to the result of resolving the name to an instance of Provider.
+  #   @param name [String] the name of the provider
+  # @overload provider=(provider)
+  #   Sets the provider to the given instances of Provider.
+  #   @param provider [Puppet::Provider] the provider to set
+  # @return [Puppet::Provider] the provider set
+  # @raise [ArgumentError] if the provider could not be found/resolved.
+  #
+  def provider=(name)
+    if name.is_a?(Puppet::Provider)
+      @provider = name
+      @provider.resource = self
+    elsif klass = self.class.provider(name)
+      @provider = klass.new(self)
+    else
+      raise ArgumentError, "Could not find #{name} provider of #{self.class.name}"
+    end
+  end
+
+  ###############################
+  # All of the relationship code.
+
+  # Adds a block producing a single name (or list of names) of the given resource type name to autorequire.
+  # Resources in the catalog that have the named type and a title that is included in the result will be linked
+  # to the calling resource as a requirement.
+  #
+  # @example Autorequire the files File['foo', 'bar']
+  #   autorequire( 'file', {|| ['foo', 'bar'] })
+  #
+  # @param name [String] the name of a type of which one or several resources should be autorequired e.g. "file"
+  # @yield [ ] a block returning list of names of given type to auto require
+  # @yieldreturn [String, Array<String>] one or several resource names for the named type
+  # @return [void]
+  # @dsl type
+  # @api public
+  #
+  def self.autorequire(name, &block)
+    @autorequires ||= {}
+    @autorequires[name] = block
+  end
+
+  # Provides iteration over added auto-requirements (see {autorequire}).
+  # @yieldparam type [String] the name of the type to autoriquire an instance of
+  # @yieldparam block [Proc] a block producing one or several dependencies to auto require (see {autorequire}).
+  # @yieldreturn [void]
+  # @return [void]
+  def self.eachautorequire
+    @autorequires ||= {}
+    @autorequires.each { |type, block|
+      yield(type, block)
+    }
+  end
+
+  # Adds dependencies to the catalog from added autorequirements.
+  # See {autorequire} for how to add an auto-requirement.
+  # @todo needs details - see the param rel_catalog, and type of this param
+  # @param rel_catalog [Puppet::Resource::Catalog, nil] the catalog to
+  #   add dependencies to. Defaults to the current catalog (set when the
+  #   type instance was added to a catalog)
+  # @raise [Puppet::DevError] if there is no catalog
+  #
+  def autorequire(rel_catalog = nil)
+    rel_catalog ||= catalog
+    raise(Puppet::DevError, "You cannot add relationships without a catalog") unless rel_catalog
+
+    reqs = []
+    self.class.eachautorequire { |type, block|
+      # Ignore any types we can't find, although that would be a bit odd.
+      next unless Puppet::Type.type(type)
+
+      # Retrieve the list of names from the block.
+      next unless list = self.instance_eval(&block)
+      list = [list] unless list.is_a?(Array)
+
+      # Collect the current prereqs
+      list.each { |dep|
+        # Support them passing objects directly, to save some effort.
+        unless dep.is_a? Puppet::Type
+          # Skip autorequires that we aren't managing
+          unless dep = rel_catalog.resource(type, dep)
+            next
+          end
+        end
+
+        reqs << Puppet::Relationship.new(dep, self)
+      }
+    }
+
+    reqs
+  end
+
+  # Builds the dependencies associated with this resource.
+  #
+  # @return [Array<Puppet::Relationship>] list of relationships to other resources
+  def builddepends
+    # Handle the requires
+    self.class.relationship_params.collect do |klass|
+      if param = @parameters[klass.name]
+        param.to_edges
+      end
+    end.flatten.reject { |r| r.nil? }
+  end
+
+  # Sets the initial list of tags to associate to this resource.
+  #
+  # @return [void] ???
+  def tags=(list)
+    tag(self.class.name)
+    tag(*list)
+  end
+
+  # @comment - these two comments were floating around here, and turned up as documentation
+  #  for the attribute "title", much to my surprise and amusement. Clearly these comments
+  #  are orphaned ... I think they can just be removed as what they say should be covered
+  #  by the now added yardoc. <irony>(Yo! to quote some of the other actual awsome specific comments applicable
+  #  to objects called from elsewhere, or not. ;-)</irony>
+  #
+  # @comment Types (which map to resources in the languages) are entirely composed of
+  #   attribute value pairs.  Generally, Puppet calls any of these things an
+  #   'attribute', but these attributes always take one of three specific
+  #   forms:  parameters, metaparams, or properties.
+
+  # @comment In naming methods, I have tried to consistently name the method so
+  #   that it is clear whether it operates on all attributes (thus has 'attr' in
+  #   the method name, or whether it operates on a specific type of attributes.
+
+  # The title attribute of WHAT ???
+  # @todo Figure out what this is the title attribute of (it appears on line 1926 currently).
+  # @return [String] the title
+  attr_writer :title
+
+  # The noop attribute of WHAT ??? does WHAT???
+  # @todo Figure out what this is the noop attribute of (it appears on line 1931 currently).
+  # @return [???] the noop WHAT ??? (mode? if so of what, or noop for an instance of the type, or for all
+  #   instances of a type, or for what???
+  #
+  attr_writer :noop
+
+  include Enumerable
+
+  # class methods dealing with Type management
+
+  public
+
+  # The Type class attribute accessors
+  class << self
+    # @return [String] the name of the resource type; e.g., "File"
+    #
+    attr_reader :name
+
+    # @return [Boolean] true if the type should send itself a refresh event on change.
+    #
+    attr_accessor :self_refresh
+    include Enumerable, Puppet::Util::ClassGen
+    include Puppet::MetaType::Manager
+
+    include Puppet::Util
+    include Puppet::Util::Logging
+  end
+
+  # Initializes all of the variables that must be initialized for each subclass.
+  # @todo Does the explanation make sense?
+  # @return [void]
+  def self.initvars
+    # all of the instances of this class
+    @objects = Hash.new
+    @aliases = Hash.new
+
+    @defaults = {}
+
+    @parameters ||= []
+
+    @validproperties = {}
+    @properties = []
+    @parameters = []
+    @paramhash = {}
+
+    @paramdoc = Hash.new { |hash,key|
+      key = key.intern if key.is_a?(String)
+      if hash.include?(key)
+        hash[key]
+      else
+        "Param Documentation for #{key} not found"
+      end
+    }
+
+    @doc ||= ""
+
+  end
+
+  # Returns the name of this type (if specified) or the parent type #to_s.
+  # The returned name is on the form "Puppet::Type::<name>", where the first letter of name is
+  # capitalized.
+  # @return [String] the fully qualified name Puppet::Type::<name> where the first letter of name is captialized
+  #
+  def self.to_s
+    if defined?(@name)
+      "Puppet::Type::#{@name.to_s.capitalize}"
+    else
+      super
+    end
+  end
+
+  # Creates a `validate` method that is used to validate a resource before it is operated on.
+  # The validation should raise exceptions if the validation finds errors. (It is not recommended to
+  # issue warnings as this typically just ends up in a logfile - you should fail if a validation fails).
+  # The easiest way to raise an appropriate exception is to call the method {Puppet::Util::Errors.fail} with
+  # the message as an argument.
+  #
+  # @yield [ ] a required block called with self set to the instance of a Type class representing a resource.
+  # @return [void]
+  # @dsl type
+  # @api public
+  #
+  def self.validate(&block)
+    define_method(:validate, &block)
+  end
+
+  # @return [String] The file from which this type originates from
+  attr_accessor :file
+
+  # @return [Integer] The line in {#file} from which this type originates from
+  attr_accessor :line
+
+  # @todo what does this mean "this resource" (sounds like this if for an instance of the type, not the meta Type),
+  #   but not sure if this is about the catalog where the meta Type is included)
+  # @return [??? TODO] The catalog that this resource is stored in.
+  attr_accessor :catalog
+
+  # @return [Boolean] Flag indicating if this type is exported
+  attr_accessor :exported
+
+  # @return [Boolean] Flag indicating if the type is virtual (it should not be).
+  attr_accessor :virtual
+
+  # Creates a log entry with the given message at the log level specified by the parameter `loglevel`
+  # @return [void]
+  #
+  def log(msg)
+
+    Puppet::Util::Log.create(
+
+      :level => @parameters[:loglevel].value,
+      :message => msg,
+
+      :source => self
+    )
+  end
+
+
+  # instance methods related to instance intrinsics
+  # e.g., initialize and name
+
+  public
+
+  # @return [Hash] hash of parameters originally defined
+  # @api private
+  attr_reader :original_parameters
+
+  # Creates an instance of Type from a hash or a {Puppet::Resource}.
+  # @todo Unclear if this is a new Type or a new instance of a given type (the initialization ends
+  #   with calling validate - which seems like validation of an instance of a given type, not a new
+  #   meta type.
+  #
+  # @todo Explain what the Hash and Resource are. There seems to be two different types of
+  #   resources; one that causes the title to be set to resource.title, and one that
+  #   causes the title to be resource.ref ("for components") - what is a component?
+  #
+  # @overload initialize(hash)
+  #   @param [Hash] hash
+  #   @raise [Puppet::ResourceError] when the type validation raises
+  #     Puppet::Error or ArgumentError
+  # @overload initialize(resource)
+  #   @param resource [Puppet:Resource]
+  #   @raise [Puppet::ResourceError] when the type validation raises
+  #     Puppet::Error or ArgumentError
+  #
+  def initialize(resource)
+    resource = self.class.hash2resource(resource) unless resource.is_a?(Puppet::Resource)
+
+    # The list of parameter/property instances.
+    @parameters = {}
+
+    # Set the title first, so any failures print correctly.
+    if resource.type.to_s.downcase.to_sym == self.class.name
+      self.title = resource.title
+    else
+      # This should only ever happen for components
+      self.title = resource.ref
+    end
+
+    [:file, :line, :catalog, :exported, :virtual].each do |getter|
+      setter = getter.to_s + "="
+      if val = resource.send(getter)
+        self.send(setter, val)
+      end
+    end
+
+    @tags = resource.tags
+
+    @original_parameters = resource.to_hash
+
+    set_name(@original_parameters)
+
+    set_default(:provider)
+
+    set_parameters(@original_parameters)
+
+    begin
+      self.validate if self.respond_to?(:validate)
+    rescue Puppet::Error, ArgumentError => detail
+      error = Puppet::ResourceError.new("Validation of #{ref} failed: #{detail}")
+      adderrorcontext(error, detail)
+      raise error
+    end
+  end
+
+  private
+
+  # Sets the name of the resource from a hash containing a mapping of `name_var` to value.
+  # Sets the value of the property/parameter appointed by the `name_var` (if it is defined). The value set is
+  # given by the corresponding entry in the given hash - e.g. if name_var appoints the name `:path` the value
+  # of `:path` is set to the value at the key `:path` in the given hash. As a side effect this key/value is then
+  # removed from the given hash.
+  #
+  # @note This method mutates the given hash by removing the entry with a key equal to the value
+  #   returned from name_var!
+  # @param hash [Hash] a hash of what
+  # @return [void]
+  def set_name(hash)
+    self[name_var] = hash.delete(name_var) if name_var
+  end
+
+  # Sets parameters from the given hash.
+  # Values are set in _attribute order_ i.e. higher priority attributes before others, otherwise in
+  # the order they were specified (as opposed to just setting them in the order they happen to appear in
+  # when iterating over the given hash).
+  #
+  # Attributes that are not included in the given hash are set to their default value.
+  #
+  # @todo Is this description accurate? Is "ensure" an example of such a higher priority attribute?
+  # @return [void]
+  # @raise [Puppet::DevError] when impossible to set the value due to some problem
+  # @raise [ArgumentError, TypeError, Puppet::Error] when faulty arguments have been passed
+  #
+  def set_parameters(hash)
+    # Use the order provided by allattrs, but add in any
+    # extra attributes from the resource so we get failures
+    # on invalid attributes.
+    no_values = []
+    (self.class.allattrs + hash.keys).uniq.each do |attr|
+      begin
+        # Set any defaults immediately.  This is mostly done so
+        # that the default provider is available for any other
+        # property validation.
+        if hash.has_key?(attr)
+          self[attr] = hash[attr]
+        else
+          no_values << attr
+        end
+      rescue ArgumentError, Puppet::Error, TypeError
+        raise
+      rescue => detail
+        error = Puppet::DevError.new( "Could not set #{attr} on #{self.class.name}: #{detail}")
+        error.set_backtrace(detail.backtrace)
+        raise error
+      end
+    end
+    no_values.each do |attr|
+      set_default(attr)
+    end
+  end
+
+  public
+
+  # Finishes any outstanding processing.
+  # This method should be called as a final step in setup,
+  # to allow the parameters that have associated auto-require needs to be processed.
+  #
+  # @todo what is the expected sequence here - who is responsible for calling this? When?
+  #   Is the returned type correct?
+  # @return [Array<Puppet::Parameter>] the validated list/set of attributes
+  #
+  def finish
+    # Call post_compile hook on every parameter that implements it. This includes all subclasses
+    # of parameter including, but not limited to, regular parameters, metaparameters, relationship
+    # parameters, and properties.
+    eachparameter do |parameter|
+      parameter.post_compile if parameter.respond_to? :post_compile
+    end
+
+    # Make sure all of our relationships are valid.  Again, must be done
+    # when the entire catalog is instantiated.
+    self.class.relationship_params.collect do |klass|
+      if param = @parameters[klass.name]
+        param.validate_relationship
+      end
+    end.flatten.reject { |r| r.nil? }
+  end
+
+  # @comment For now, leave the 'name' method functioning like it used to.  Once 'title'
+  #   works everywhere, I'll switch it.
+  # Returns the resource's name
+  # @todo There is a comment in source that this is not quite the same as ':title' and that a switch should
+  #   be made...
+  # @return [String] the name of a resource
+  def name
+    self[:name]
+  end
+
+  # Returns the parent of this in the catalog.  In case of an erroneous catalog
+  # where multiple parents have been produced, the first found (non
+  # deterministic) parent is returned.
+  # @return [Puppet::Type, nil] the
+  #   containing resource or nil if there is no catalog or no containing
+  #   resource.
+  def parent
+    return nil unless catalog
+
+    @parent ||=
+      if parents = catalog.adjacent(self, :direction => :in)
+        parents.shift
+      else
+        nil
+      end
+  end
+
+  # Returns a reference to this as a string in "Type[name]" format.
+  # @return [String] a reference to this object on the form 'Type[name]'
+  #
+  def ref
+    # memoizing this is worthwhile ~ 3 percent of calls are the "first time
+    # around" in an average run of Puppet. --daniel 2012-07-17
+    @ref ||= "#{self.class.name.to_s.capitalize}[#{self.title}]"
+  end
+
+  # (see self_refresh)
+  # @todo check that meaningful yardoc is produced - this method delegates to "self.class.self_refresh"
+  # @return [Boolean] - ??? returns true when ... what?
+  #
+  def self_refresh?
+    self.class.self_refresh
+  end
+
+  # Marks the object as "being purged".
+  # This method is used by transactions to forbid deletion when there are dependencies.
+  # @todo what does this mean; "mark that we are purging" (purging what from where). How to use/when?
+  #   Is this internal API in transactions?
+  # @see purging?
+  def purging
+    @purging = true
+  end
+
+  # Returns whether this resource is being purged or not.
+  # This method is used by transactions to forbid deletion when there are dependencies.
+  # @return [Boolean] the current "purging" state
+  #
+  def purging?
+    if defined?(@purging)
+      @purging
+    else
+      false
+    end
+  end
+
+  # Returns the title of this object, or its name if title was not explicetly set.
+  # If the title is not already set, it will be computed by looking up the {#name_var} and using
+  # that value as the title.
+  # @todo it is somewhat confusing that if the name_var is a valid parameter, it is assumed to
+  #  be the name_var called :name, but if it is a property, it uses the name_var.
+  #  It is further confusing as Type in some respects supports multiple namevars.
+  #
+  # @return [String] Returns the title of this object, or its name if title was not explicetly set.
+  # @raise [??? devfail] if title is not set, and name_var can not be found.
+  def title
+    unless @title
+      if self.class.validparameter?(name_var)
+        @title = self[:name]
+      elsif self.class.validproperty?(name_var)
+        @title = self.should(name_var)
+      else
+        self.devfail "Could not find namevar #{name_var} for #{self.class.name}"
+      end
+    end
+
+    @title
+  end
+
+  # Produces a reference to this in reference format.
+  # @see #ref
+  #
+  def to_s
+    self.ref
+  end
+
+  # Convert this resource type instance to a Puppet::Resource.
+  # @return [Puppet::Resource] Returns a serializable representation of this resource
+  #
+  def to_resource
+    resource = self.retrieve_resource
+    resource.tag(*self.tags)
+
+    @parameters.each do |name, param|
+      # Avoid adding each instance name twice
+      next if param.class.isnamevar? and param.value == self.title
+
+      # We've already got property values
+      next if param.is_a?(Puppet::Property)
+      resource[name] = param.value
+    end
+
+    resource
+  end
+
+  # @return [Boolean] Returns whether the resource is virtual or not
+  def virtual?;  !!@virtual;  end
+  # @return [Boolean] Returns whether the resource is exported or not
+  def exported?; !!@exported; end
+
+  # @return [Boolean] Returns whether the resource is applicable to `:device`
+  # Returns true if a resource of this type can be evaluated on a 'network device' kind
+  # of hosts.
+  # @api private
+  def appliable_to_device?
+    self.class.can_apply_to(:device)
+  end
+
+  # @return [Boolean] Returns whether the resource is applicable to `:host`
+  # Returns true if a resource of this type can be evaluated on a regular generalized computer (ie not an appliance like a network device)
+  # @api private
+  def appliable_to_host?
+    self.class.can_apply_to(:host)
+  end
+end
+end
+
+require 'puppet/provider'
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/augeas.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/augeas.rb
new file mode 100644
index 0000000..57931b7
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/augeas.rb
@@ -0,0 +1,201 @@
+#
+#   Copyright 2011 Bryan Kearney <bkearney@redhat.com>
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+require 'puppet/parameter/boolean'
+
+Puppet::Type.newtype(:augeas) do
+  include Puppet::Util
+
+  feature :parse_commands, "Parse the command string"
+  feature :need_to_run?, "If the command should run"
+  feature :execute_changes, "Actually make the changes"
+
+  @doc = <<-'EOT'
+    Apply a change or an array of changes to the filesystem
+    using the augeas tool.
+
+    Requires:
+
+    - [Augeas](http://www.augeas.net)
+    - The ruby-augeas bindings
+
+    Sample usage with a string:
+
+        augeas{"test1" :
+          context => "/files/etc/sysconfig/firstboot",
+          changes => "set RUN_FIRSTBOOT YES",
+          onlyif  => "match other_value size > 0",
+        }
+
+    Sample usage with an array and custom lenses:
+
+        augeas{"jboss_conf":
+          context   => "/files",
+          changes   => [
+              "set etc/jbossas/jbossas.conf/JBOSS_IP $ipaddress",
+              "set etc/jbossas/jbossas.conf/JAVA_HOME /usr",
+            ],
+          load_path => "$/usr/share/jbossas/lenses",
+        }
+
+  EOT
+
+  newparam (:name) do
+    desc "The name of this task. Used for uniqueness."
+    isnamevar
+  end
+
+  newparam (:context) do
+    desc "Optional context path. This value is prepended to the paths of all
+      changes if the path is relative. If the `incl` parameter is set,
+      defaults to `/files + incl`; otherwise, defaults to the empty string."
+    defaultto ""
+    munge do |value|
+      if value.empty? and resource[:incl]
+        "/files" + resource[:incl]
+      else
+        value
+      end
+    end
+  end
+
+  newparam (:onlyif) do
+    desc "Optional augeas command and comparisons to control the execution of this type.
+      Supported onlyif syntax:
+
+      * `get <AUGEAS_PATH> <COMPARATOR> <STRING>`
+      * `match <MATCH_PATH> size <COMPARATOR> <INT>`
+      * `match <MATCH_PATH> include <STRING>`
+      * `match <MATCH_PATH> not_include <STRING>`
+      * `match <MATCH_PATH> == <AN_ARRAY>`
+      * `match <MATCH_PATH> != <AN_ARRAY>`
+
+      where:
+
+      * `AUGEAS_PATH` is a valid path scoped by the context
+      * `MATCH_PATH` is a valid match syntax scoped by the context
+      * `COMPARATOR` is one of `>, >=, !=, ==, <=,` or `<`
+      * `STRING` is a string
+      * `INT` is a number
+      * `AN_ARRAY` is in the form `['a string', 'another']`"
+    defaultto ""
+  end
+
+
+  newparam(:changes) do
+    desc "The changes which should be applied to the filesystem. This
+    can be a command or an array of commands. The following commands are supported:
+
+    * `set <PATH> <VALUE>` --- Sets the value `VALUE` at loction `PATH`
+    * `setm <PATH> <SUB> <VALUE>` --- Sets multiple nodes (matching `SUB` relative to `PATH`) to `VALUE`
+    * `rm <PATH>` --- Removes the node at location `PATH`
+    * `remove <PATH>` --- Synonym for `rm`
+    * `clear <PATH>` --- Sets the node at `PATH` to `NULL`, creating it if needed
+    * `clearm <PATH> <SUB>` --- Sets multiple nodes (matching `SUB` relative to `PATH`) to `NULL`
+    * `ins <LABEL> (before|after) <PATH>` --- Inserts an empty node `LABEL` either before or after `PATH`.
+    * `insert <LABEL> <WHERE> <PATH>` --- Synonym for `ins`
+    * `mv <PATH> <OTHER PATH>` --- Moves a node at `PATH` to the new location `OTHER PATH`
+    * `move <PATH> <OTHER PATH>` --- Synonym for `mv`
+    * `defvar <NAME> <PATH>` --- Sets Augeas variable `$NAME` to `PATH`
+    * `defnode <NAME> <PATH> <VALUE>` --- Sets Augeas variable `$NAME` to `PATH`, creating it with `VALUE` if needed
+
+    If the `context` parameter is set, that value is prepended to any relative `PATH`s."
+  end
+
+
+  newparam(:root) do
+    desc "A file system path; all files loaded by Augeas are loaded underneath `root`."
+    defaultto "/"
+  end
+
+  newparam(:load_path) do
+    desc "Optional colon-separated list or array of directories; these directories are searched for schema definitions. The agent's `$libdir/augeas/lenses` path will always be added to support pluginsync."
+    defaultto ""
+  end
+
+  newparam(:force) do
+    desc "Optional command to force the augeas type to execute even if it thinks changes
+    will not be made. This does not overide the `onlyif` parameter."
+
+    defaultto false
+  end
+
+  newparam(:type_check) do
+    desc "Whether augeas should perform typechecking. Defaults to false."
+    newvalues(:true, :false)
+
+    defaultto :false
+  end
+
+  newparam(:lens) do
+    desc "Use a specific lens, e.g. `Hosts.lns`. When this parameter is set, you
+      must also set the `incl` parameter to indicate which file to load.
+      The Augeas documentation includes [a list of available lenses](http://augeas.net/stock_lenses.html)."
+  end
+
+  newparam(:incl) do
+    desc "Load only a specific file, e.g. `/etc/hosts`. This can greatly speed
+      up the execution the resource. When this parameter is set, you must also
+      set the `lens` parameter to indicate which lens to use."
+  end
+
+  validate do
+    has_lens = !self[:lens].nil?
+    has_incl = !self[:incl].nil?
+    self.fail "You must specify both the lens and incl parameters, or neither." if has_lens != has_incl
+  end
+
+  newparam(:show_diff, :boolean => true, :parent => Puppet::Parameter::Boolean) do
+    desc "Whether to display differences when the file changes, defaulting to
+        true.  This parameter is useful for files that may contain passwords or
+        other secret data, which might otherwise be included in Puppet reports or
+        other insecure outputs.  If the global `show_diff` setting
+        is false, then no diffs will be shown even if this parameter is true."
+
+    defaultto :true
+  end
+
+  # This is the actual meat of the code. It forces
+  # augeas to be run and fails or not based on the augeas return
+  # code.
+  newproperty(:returns) do |property|
+    include Puppet::Util
+    desc "The expected return code from the augeas command. Should not be set."
+
+    defaultto 0
+
+    # Make output a bit prettier
+    def change_to_s(currentvalue, newvalue)
+      "executed successfully"
+    end
+
+    # if the onlyif resource is provided, then the value is parsed.
+    # a return value of 0 will stop exection because it matches the
+    # default value.
+    def retrieve
+      if @resource.provider.need_to_run?()
+        :need_to_run
+      else
+        0
+      end
+    end
+
+    # Actually execute the command.
+    def sync
+      @resource.provider.execute_changes
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/component.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/component.rb
new file mode 100644
index 0000000..255d1a9
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/component.rb
@@ -0,0 +1,77 @@
+
+require 'puppet'
+require 'puppet/type'
+require 'puppet/transaction'
+
+Puppet::Type.newtype(:component) do
+  include Enumerable
+
+  newparam(:name) do
+    desc "The name of the component.  Generally optional."
+    isnamevar
+  end
+
+  # Override how parameters are handled so that we support the extra
+  # parameters that are used with defined resource types.
+  def [](param)
+    return super if self.class.valid_parameter?(param)
+    @extra_parameters[param.to_sym]
+  end
+
+  # Override how parameters are handled so that we support the extra
+  # parameters that are used with defined resource types.
+  def []=(param, value)
+    return super if self.class.valid_parameter?(param)
+    @extra_parameters[param.to_sym] = value
+  end
+
+  # Initialize a new component
+  def initialize(*args)
+    @extra_parameters = {}
+    super
+  end
+
+  # Component paths are special because they function as containers.
+  def pathbuilder
+    if reference.type == "Class"
+      myname = reference.title
+    else
+      myname = reference.to_s
+    end
+    if p = self.parent
+      return [p.pathbuilder, myname]
+    else
+      return [myname]
+    end
+  end
+
+  def ref
+    reference.to_s
+  end
+
+  # We want our title to just be the whole reference, rather than @title.
+  def title
+    ref
+  end
+
+  def title=(str)
+    @reference = Puppet::Resource.new(str)
+  end
+
+  def refresh
+    catalog.adjacent(self).each do |child|
+      if child.respond_to?(:refresh)
+        child.refresh
+        child.log "triggering #{:refresh}"
+      end
+    end
+  end
+
+  def to_s
+    reference.to_s
+  end
+
+  private
+
+  attr_reader :reference
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/computer.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/computer.rb
new file mode 100644
index 0000000..5f42a6a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/computer.rb
@@ -0,0 +1,66 @@
+Puppet::Type.newtype(:computer) do
+
+  @doc = "Computer object management using DirectoryService
+    on OS X.
+
+    Note that these are distinctly different kinds of objects to 'hosts',
+    as they require a MAC address and can have all sorts of policy attached to
+    them.
+
+    This provider only manages Computer objects in the local directory service
+    domain, not in remote directories.
+
+    If you wish to manage `/etc/hosts` file on Mac OS X, then simply use the host
+    type as per other platforms.
+
+    This type primarily exists to create localhost Computer objects that MCX
+    policy can then be attached to.
+
+    **Autorequires:** If Puppet is managing the plist file representing a
+    Computer object (located at `/var/db/dslocal/nodes/Default/computers/{name}.plist`),
+    the Computer resource will autorequire it."
+
+  # ensurable
+
+  # We autorequire the computer object in case it is being managed at the
+  # file level by Puppet.
+
+  autorequire(:file) do
+    if self[:name]
+      "/var/db/dslocal/nodes/Default/computers/#{self[:name]}.plist"
+    else
+      nil
+    end
+  end
+
+  newproperty(:ensure, :parent => Puppet::Property::Ensure) do
+    desc "Control the existences of this computer record. Set this attribute to
+      `present` to ensure the computer record exists.  Set it to `absent`
+      to delete any computer records with this name"
+    newvalue(:present) do
+      provider.create
+    end
+
+    newvalue(:absent) do
+      provider.delete
+    end
+  end
+
+  newparam(:name) do
+    desc "The authoritative 'short' name of the computer record."
+    isnamevar
+  end
+
+  newparam(:realname) do
+    desc "The 'long' name of the computer record."
+  end
+
+  newproperty(:en_address) do
+    desc "The MAC address of the primary network interface. Must match en0."
+  end
+
+  newproperty(:ip_address) do
+    desc "The IP Address of the Computer object."
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/cron.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/cron.rb
new file mode 100644
index 0000000..8e53bf7
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/cron.rb
@@ -0,0 +1,492 @@
+require 'etc'
+require 'facter'
+require 'puppet/util/filetype'
+
+Puppet::Type.newtype(:cron) do
+  @doc = <<-'EOT'
+    Installs and manages cron jobs.  Every cron resource created by Puppet
+    requires a command and at least one periodic attribute (hour, minute,
+    month, monthday, weekday, or special).  While the name of the cron job is
+    not part of the actual job, the name is stored in a comment beginning with
+    `# Puppet Name: `. These comments are used to match crontab entries created
+    by Puppet with cron resources.
+
+    If an existing crontab entry happens to match the scheduling and command of a
+    cron resource that has never been synched, Puppet will defer to the existing
+    crontab entry and will not create a new entry tagged with the `# Puppet Name: `
+    comment.
+
+    Example:
+
+        cron { logrotate:
+          command => "/usr/sbin/logrotate",
+          user    => root,
+          hour    => 2,
+          minute  => 0
+        }
+
+    Note that all periodic attributes can be specified as an array of values:
+
+        cron { logrotate:
+          command => "/usr/sbin/logrotate",
+          user    => root,
+          hour    => [2, 4]
+        }
+
+    ...or using ranges or the step syntax `*/2` (although there's no guarantee
+    that your `cron` daemon supports these):
+
+        cron { logrotate:
+          command => "/usr/sbin/logrotate",
+          user    => root,
+          hour    => ['2-4'],
+          minute  => '*/10'
+        }
+
+    An important note: _the Cron type will not reset parameters that are
+    removed from a manifest_. For example, removing a `minute => 10` parameter
+    will not reset the minute component of the associated cronjob to `*`.
+    These changes must be expressed by setting the parameter to
+    `minute => absent` because Puppet only manages parameters that are out of
+    sync with manifest entries.
+
+    **Autorequires:** If Puppet is managing the user account specified by the
+    `user` property of a cron resource, then the cron resource will autorequire
+    that user.
+  EOT
+  ensurable
+
+  # A base class for all of the Cron parameters, since they all have
+  # similar argument checking going on.
+  class CronParam < Puppet::Property
+    class << self
+      attr_accessor :boundaries, :default
+    end
+
+    # We have to override the parent method, because we consume the entire
+    # "should" array
+    def insync?(is)
+      self.is_to_s(is) == self.should_to_s
+    end
+
+    # A method used to do parameter input handling.  Converts integers
+    # in string form to actual integers, and returns the value if it's
+    # an integer or false if it's just a normal string.
+    def numfix(num)
+      if num =~ /^\d+$/
+        return num.to_i
+      elsif num.is_a?(Integer)
+        return num
+      else
+        return false
+      end
+    end
+
+    # Verify that a number is within the specified limits.  Return the
+    # number if it is, or false if it is not.
+    def limitcheck(num, lower, upper)
+      (num >= lower and num <= upper) && num
+    end
+
+    # Verify that a value falls within the specified array.  Does case
+    # insensitive matching, and supports matching either the entire word
+    # or the first three letters of the word.
+    def alphacheck(value, ary)
+      tmp = value.downcase
+
+      # If they specified a shortened version of the name, then see
+      # if we can lengthen it (e.g., mon => monday).
+      if tmp.length == 3
+        ary.each_with_index { |name, index|
+          if tmp.upcase == name[0..2].upcase
+            return index
+          end
+        }
+      else
+        return ary.index(tmp) if ary.include?(tmp)
+      end
+
+      false
+    end
+
+    def should_to_s(newvalue = @should)
+      if newvalue
+        newvalue = [newvalue] unless newvalue.is_a?(Array)
+        if self.name == :command or newvalue[0].is_a? Symbol
+          newvalue[0]
+        else
+          newvalue.join(",")
+        end
+      else
+        nil
+      end
+    end
+
+    def is_to_s(currentvalue = @is)
+      if currentvalue
+        return currentvalue unless currentvalue.is_a?(Array)
+
+        if self.name == :command or currentvalue[0].is_a? Symbol
+          currentvalue[0]
+        else
+          currentvalue.join(",")
+        end
+      else
+        nil
+      end
+    end
+
+    def should
+      if @should and @should[0] == :absent
+        :absent
+      else
+        @should
+      end
+    end
+
+    def should=(ary)
+      super
+      @should.flatten!
+    end
+
+    # The method that does all of the actual parameter value
+    # checking; called by all of the +param<name>=+ methods.
+    # Requires the value, type, and bounds, and optionally supports
+    # a boolean of whether to do alpha checking, and if so requires
+    # the ary against which to do the checking.
+    munge do |value|
+      # Support 'absent' as a value, so that they can remove
+      # a value
+      if value == "absent" or value == :absent
+        return :absent
+      end
+
+      # Allow the */2 syntax
+      if value =~ /^\*\/[0-9]+$/
+        return value
+      end
+
+      # Allow ranges
+      if value =~ /^[0-9]+-[0-9]+$/
+        return value
+      end
+
+      # Allow ranges + */2
+      if value =~ /^[0-9]+-[0-9]+\/[0-9]+$/
+        return value
+      end
+
+      if value == "*"
+        return :absent
+      end
+
+      return value unless self.class.boundaries
+      lower, upper = self.class.boundaries
+      retval = nil
+      if num = numfix(value)
+        retval = limitcheck(num, lower, upper)
+      elsif respond_to?(:alpha)
+        # If it has an alpha method defined, then we check
+        # to see if our value is in that list and if so we turn
+        # it into a number
+        retval = alphacheck(value, alpha)
+      end
+
+      if retval
+        return retval.to_s
+      else
+        self.fail "#{value} is not a valid #{self.class.name}"
+      end
+    end
+  end
+
+  # Somewhat uniquely, this property does not actually change anything -- it
+  # just calls +@resource.sync+, which writes out the whole cron tab for
+  # the user in question.  There is no real way to change individual cron
+  # jobs without rewriting the entire cron file.
+  #
+  # Note that this means that managing many cron jobs for a given user
+  # could currently result in multiple write sessions for that user.
+  newproperty(:command, :parent => CronParam) do
+    desc "The command to execute in the cron job.  The environment
+      provided to the command varies by local system rules, and it is
+      best to always provide a fully qualified command.  The user's
+      profile is not sourced when the command is run, so if the
+      user's environment is desired it should be sourced manually.
+
+      All cron parameters support `absent` as a value; this will
+      remove any existing values for that field."
+
+    def retrieve
+      return_value = super
+      return_value = return_value[0] if return_value && return_value.is_a?(Array)
+
+      return_value
+    end
+
+    def should
+      if @should
+        if @should.is_a? Array
+          @should[0]
+        else
+          devfail "command is not an array"
+        end
+      else
+        nil
+      end
+    end
+
+    def munge(value)
+      value.strip
+    end
+  end
+
+  newproperty(:special) do
+    desc "A special value such as 'reboot' or 'annually'.
+       Only available on supported systems such as Vixie Cron.
+       Overrides more specific time of day/week settings.
+       Set to 'absent' to make puppet revert to a plain numeric schedule."
+
+    def specials
+      %w{reboot yearly annually monthly weekly daily midnight hourly absent} +
+        [ :absent ]
+    end
+
+    validate do |value|
+      raise ArgumentError, "Invalid special schedule #{value.inspect}" unless specials.include?(value)
+    end
+
+    def munge(value)
+      # Support value absent so that a schedule can be
+      # forced to change to numeric.
+      if value == "absent" or value == :absent
+        return :absent
+      end
+      value
+    end
+  end
+
+  newproperty(:minute, :parent => CronParam) do
+    self.boundaries = [0, 59]
+    desc "The minute at which to run the cron job.
+      Optional; if specified, must be between 0 and 59, inclusive."
+  end
+
+  newproperty(:hour, :parent => CronParam) do
+    self.boundaries = [0, 23]
+    desc "The hour at which to run the cron job. Optional;
+      if specified, must be between 0 and 23, inclusive."
+  end
+
+  newproperty(:weekday, :parent => CronParam) do
+    def alpha
+      %w{sunday monday tuesday wednesday thursday friday saturday}
+    end
+    self.boundaries = [0, 7]
+    desc "The weekday on which to run the command.
+      Optional; if specified, must be between 0 and 7, inclusive, with
+      0 (or 7) being Sunday, or must be the name of the day (e.g., Tuesday)."
+  end
+
+  newproperty(:month, :parent => CronParam) do
+    def alpha
+      # The ___placeholder accounts for the fact that month is unique among
+      # "nameable" crontab entries in that it does not use 0-based indexing.
+      # Padding the array with a placeholder introduces the appropriate shift
+      # in indices.
+      %w{___placeholder january february march april may june july
+        august september october november december}
+    end
+    self.boundaries = [1, 12]
+    desc "The month of the year.  Optional; if specified
+      must be between 1 and 12 or the month name (e.g., December)."
+  end
+
+  newproperty(:monthday, :parent => CronParam) do
+    self.boundaries = [1, 31]
+    desc "The day of the month on which to run the
+      command.  Optional; if specified, must be between 1 and 31."
+  end
+
+  newproperty(:environment) do
+    desc "Any environment settings associated with this cron job.  They
+      will be stored between the header and the job in the crontab.  There
+      can be no guarantees that other, earlier settings will not also
+      affect a given cron job.
+
+
+      Also, Puppet cannot automatically determine whether an existing,
+      unmanaged environment setting is associated with a given cron
+      job.  If you already have cron jobs with environment settings,
+      then Puppet will keep those settings in the same place in the file,
+      but will not associate them with a specific job.
+
+      Settings should be specified exactly as they should appear in
+      the crontab, e.g., `PATH=/bin:/usr/bin:/usr/sbin`."
+
+    validate do |value|
+      unless value =~ /^\s*(\w+)\s*=\s*(.*)\s*$/ or value == :absent or value == "absent"
+        raise ArgumentError, "Invalid environment setting #{value.inspect}"
+      end
+    end
+
+    def insync?(is)
+      if is.is_a? Array
+        return is.sort == @should.sort
+      else
+        return is == @should
+      end
+    end
+
+    def is_to_s(newvalue)
+      if newvalue
+        if newvalue.is_a?(Array)
+          newvalue.join(",")
+        else
+          newvalue
+        end
+      else
+        nil
+      end
+    end
+
+    def should
+      @should
+    end
+
+    def should_to_s(newvalue = @should)
+      if newvalue
+        newvalue.join(",")
+      else
+        nil
+      end
+    end
+  end
+
+  newparam(:name) do
+    desc "The symbolic name of the cron job.  This name
+      is used for human reference only and is generated automatically
+      for cron jobs found on the system.  This generally won't
+      matter, as Puppet will do its best to match existing cron jobs
+      against specified jobs (and Puppet adds a comment to cron jobs it adds),
+      but it is at least possible that converting from unmanaged jobs to
+      managed jobs might require manual intervention."
+
+    isnamevar
+  end
+
+  newproperty(:user) do
+    desc "The user who owns the cron job.  This user must
+      be allowed to run cron jobs, which is not currently checked by
+      Puppet.
+
+      This property defaults to the user running Puppet or `root`.
+
+      The default crontab provider executes the system `crontab` using
+      the user account specified by this property."
+
+    defaultto {
+      if not provider.is_a?(@resource.class.provider(:crontab))
+        struct = Etc.getpwuid(Process.uid)
+        struct.respond_to?(:name) && struct.name or 'root'
+      end
+    }
+  end
+
+  # Autorequire the owner of the crontab entry.
+  autorequire(:user) do
+    self[:user]
+  end
+
+  newproperty(:target) do
+    desc "The name of the crontab file in which the cron job should be stored.
+
+      This property defaults to the value of the `user` property if set, the
+      user running Puppet or `root`.
+
+      For the default crontab provider, this property is functionally
+      equivalent to the `user` property and should be avoided. In particular,
+      setting both `user` and `target` to different values will result in
+      undefined behavior."
+
+    defaultto {
+      if provider.is_a?(@resource.class.provider(:crontab))
+        if val = @resource.should(:user)
+          val
+        else
+          struct = Etc.getpwuid(Process.uid)
+          struct.respond_to?(:name) && struct.name or 'root'
+        end
+      elsif provider.class.ancestors.include?(Puppet::Provider::ParsedFile)
+        provider.class.default_target
+      else
+        nil
+      end
+    }
+  end
+
+  validate do
+    return true unless self[:special]
+    return true if self[:special] == :absent
+    # there is a special schedule in @should, so we don't want to see
+    # any numeric should values
+    [ :minute, :hour, :weekday, :monthday, :month ].each do |field|
+      next unless self[field]
+      next if self[field] == :absent
+      raise ArgumentError, "#{self.ref} cannot specify both a special schedule and a value for #{field}"
+    end
+  end
+
+  # We have to reorder things so that :provide is before :target
+
+  attr_accessor :uid
+
+  # Marks the resource as "being purged".
+  #
+  # @api public
+  #
+  # @note This overrides the Puppet::Type method in order to handle
+  #   an edge case that has so far been observed during testig only.
+  #   Without forcing the should-value for the user property to be
+  #   identical to the original cron file, purging from a fixture
+  #   will not work, because the user property defaults to the user
+  #   running the test. It is not clear whether this scenario can apply
+  #   during normal operation.
+  #
+  # @note Also, when not forcing the should-value for the target
+  #   property, unpurged file content (such as comments) can end up
+  #   being written to the default target (i.e. the current login name).
+  def purging
+    self[:target] = provider.target
+    self[:user] = provider.target
+    super
+  end
+
+  def value(name)
+    name = name.intern
+    ret = nil
+    if obj = @parameters[name]
+      ret = obj.should
+
+      ret ||= obj.retrieve
+
+      if ret == :absent
+        ret = nil
+      end
+    end
+
+    unless ret
+      case name
+      when :command
+      when :special
+        # nothing
+      else
+        #ret = (self.class.validproperty?(name).default || "*").to_s
+        ret = "*"
+      end
+    end
+
+    ret
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/exec.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/exec.rb
new file mode 100644
index 0000000..325219b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/exec.rb
@@ -0,0 +1,592 @@
+module Puppet
+  newtype(:exec) do
+    include Puppet::Util::Execution
+    require 'timeout'
+
+    @doc = "Executes external commands.
+
+      Any command in an `exec` resource **must** be able to run multiple times
+      without causing harm --- that is, it must be *idempotent*. There are three
+      main ways for an exec to be idempotent:
+
+      * The command itself is already idempotent. (For example, `apt-get update`.)
+      * The exec has an `onlyif`, `unless`, or `creates` attribute, which prevents
+        Puppet from running the command unless some condition is met.
+      * The exec has `refreshonly => true`, which only allows Puppet to run the
+        command when some other resource is changed. (See the notes on refreshing
+        below.)
+
+      A caution: There's a widespread tendency to use collections of execs to
+      manage resources that aren't covered by an existing resource type. This
+      works fine for simple tasks, but once your exec pile gets complex enough
+      that you really have to think to understand what's happening, you should
+      consider developing a custom resource type instead, as it will be much
+      more predictable and maintainable.
+
+      **Refresh:** `exec` resources can respond to refresh events (via
+      `notify`, `subscribe`, or the `~>` arrow). The refresh behavior of execs
+      is non-standard, and can be affected by the `refresh` and
+      `refreshonly` attributes:
+
+      * If `refreshonly` is set to true, the exec will _only_ run when it receives an
+        event. This is the most reliable way to use refresh with execs.
+      * If the exec already would have run and receives an event, it will run its
+        command **up to two times.** (If an `onlyif`, `unless`, or `creates` condition
+        is no longer met after the first run, the second run will not occur.)
+      * If the exec already would have run, has a `refresh` command, and receives an
+        event, it will run its normal command, then run its `refresh` command
+        (as long as any `onlyif`, `unless`, or `creates` conditions are still met
+        after the normal command finishes).
+      * If the exec would **not** have run (due to an `onlyif`, `unless`, or `creates`
+        attribute) and receives an event, it still will not run.
+      * If the exec has `noop => true`, would otherwise have run, and receives
+        an event from a non-noop resource, it will run once (or run its `refresh`
+        command instead, if it has one).
+
+      In short: If there's a possibility of your exec receiving refresh events,
+      it becomes doubly important to make sure the run conditions are restricted.
+
+      **Autorequires:** If Puppet is managing an exec's cwd or the executable
+      file used in an exec's command, the exec resource will autorequire those
+      files. If Puppet is managing the user that an exec should run as, the
+      exec resource will autorequire that user."
+
+    # Create a new check mechanism.  It's basically just a parameter that
+    # provides one extra 'check' method.
+    def self.newcheck(name, options = {}, &block)
+      @checks ||= {}
+
+      check = newparam(name, options, &block)
+      @checks[name] = check
+    end
+
+    def self.checks
+      @checks.keys
+    end
+
+    newproperty(:returns, :array_matching => :all, :event => :executed_command) do |property|
+      include Puppet::Util::Execution
+      munge do |value|
+        value.to_s
+      end
+
+      def event_name
+        :executed_command
+      end
+
+      defaultto "0"
+
+      attr_reader :output
+      desc "The expected exit code(s).  An error will be returned if the
+        executed command has some other exit code.  Defaults to 0. Can be
+        specified as an array of acceptable exit codes or a single value.
+
+        On POSIX systems, exit codes are always integers between 0 and 255.
+
+        On Windows, **most** exit codes should be integers between 0
+        and 2147483647.
+
+        Larger exit codes on Windows can behave inconsistently across different
+        tools. The Win32 APIs define exit codes as 32-bit unsigned integers, but
+        both the cmd.exe shell and the .NET runtime cast them to signed
+        integers. This means some tools will report negative numbers for exit
+        codes above 2147483647. (For example, cmd.exe reports 4294967295 as -1.)
+        Since Puppet uses the plain Win32 APIs, it will report the very large
+        number instead of the negative number, which might not be what you
+        expect if you got the exit code from a cmd.exe session.
+
+        Microsoft recommends against using negative/very large exit codes, and
+        you should avoid them when possible. To convert a negative exit code to
+        the positive one Puppet will use, add it to 4294967296."
+
+      # Make output a bit prettier
+      def change_to_s(currentvalue, newvalue)
+        "executed successfully"
+      end
+
+      # First verify that all of our checks pass.
+      def retrieve
+        # We need to return :notrun to trigger evaluation; when that isn't
+        # true, we *LIE* about what happened and return a "success" for the
+        # value, which causes us to be treated as in_sync?, which means we
+        # don't actually execute anything.  I think. --daniel 2011-03-10
+        if @resource.check_all_attributes
+          return :notrun
+        else
+          return self.should
+        end
+      end
+
+      # Actually execute the command.
+      def sync
+        event = :executed_command
+        tries = self.resource[:tries]
+        try_sleep = self.resource[:try_sleep]
+
+        begin
+          tries.times do |try|
+            # Only add debug messages for tries > 1 to reduce log spam.
+            debug("Exec try #{try+1}/#{tries}") if tries > 1
+            @output, @status = provider.run(self.resource[:command])
+            break if self.should.include?(@status.exitstatus.to_s)
+            if try_sleep > 0 and tries > 1
+              debug("Sleeping for #{try_sleep} seconds between tries")
+              sleep try_sleep
+            end
+          end
+        rescue Timeout::Error
+          self.fail Puppet::Error, "Command exceeded timeout", $!
+        end
+
+        if log = @resource[:logoutput]
+          case log
+          when :true
+            log = @resource[:loglevel]
+          when :on_failure
+            unless self.should.include?(@status.exitstatus.to_s)
+              log = @resource[:loglevel]
+            else
+              log = :false
+            end
+          end
+          unless log == :false
+            @output.split(/\n/).each { |line|
+              self.send(log, line)
+            }
+          end
+        end
+
+        unless self.should.include?(@status.exitstatus.to_s)
+          self.fail("#{self.resource[:command]} returned #{@status.exitstatus} instead of one of [#{self.should.join(",")}]")
+        end
+
+        event
+      end
+    end
+
+    newparam(:command) do
+      isnamevar
+      desc "The actual command to execute.  Must either be fully qualified
+        or a search path for the command must be provided.  If the command
+        succeeds, any output produced will be logged at the instance's
+        normal log level (usually `notice`), but if the command fails
+        (meaning its return code does not match the specified code) then
+        any output is logged at the `err` log level."
+
+      validate do |command|
+        raise ArgumentError, "Command must be a String, got value of class #{command.class}" unless command.is_a? String
+      end
+    end
+
+    newparam(:path) do
+      desc "The search path used for command execution.
+        Commands must be fully qualified if no path is specified.  Paths
+        can be specified as an array or as a '#{File::PATH_SEPARATOR}' separated list."
+
+      # Support both arrays and colon-separated fields.
+      def value=(*values)
+        @value = values.flatten.collect { |val|
+          val.split(File::PATH_SEPARATOR)
+        }.flatten
+      end
+    end
+
+    newparam(:user) do
+      desc "The user to run the command as.  Note that if you
+        use this then any error output is not currently captured.  This
+        is because of a bug within Ruby.  If you are using Puppet to
+        create this user, the exec will automatically require the user,
+        as long as it is specified by name.
+
+        Please note that the $HOME environment variable is not automatically set
+        when using this attribute."
+
+      validate do |user|
+        if Puppet.features.microsoft_windows?
+          self.fail "Unable to execute commands as other users on Windows"
+        elsif !Puppet.features.root? && resource.current_username() != user
+          self.fail "Only root can execute commands as other users"
+        end
+      end
+    end
+
+    newparam(:group) do
+      desc "The group to run the command as.  This seems to work quite
+        haphazardly on different platforms -- it is a platform issue
+        not a Ruby or Puppet one, since the same variety exists when
+        running commands as different users in the shell."
+      # Validation is handled by the SUIDManager class.
+    end
+
+    newparam(:cwd, :parent => Puppet::Parameter::Path) do
+      desc "The directory from which to run the command.  If
+        this directory does not exist, the command will fail."
+    end
+
+    newparam(:logoutput) do
+      desc "Whether to log command output in addition to logging the
+        exit code.  Defaults to `on_failure`, which only logs the output
+        when the command has an exit code that does not match any value
+        specified by the `returns` attribute. As with any resource type,
+        the log level can be controlled with the `loglevel` metaparameter."
+
+      defaultto :on_failure
+
+      newvalues(:true, :false, :on_failure)
+    end
+
+    newparam(:refresh) do
+      desc "How to refresh this command.  By default, the exec is just
+        called again when it receives an event from another resource,
+        but this parameter allows you to define a different command
+        for refreshing."
+
+      validate do |command|
+        provider.validatecmd(command)
+      end
+    end
+
+    newparam(:environment) do
+      desc "Any additional environment variables you want to set for a
+        command.  Note that if you use this to set PATH, it will override
+        the `path` attribute.  Multiple environment variables should be
+        specified as an array."
+
+      validate do |values|
+        values = [values] unless values.is_a? Array
+        values.each do |value|
+          unless value =~ /\w+=/
+            raise ArgumentError, "Invalid environment setting '#{value}'"
+          end
+        end
+      end
+    end
+
+    newparam(:umask, :required_feature => :umask) do
+      desc "Sets the umask to be used while executing this command"
+
+      munge do |value|
+        if value =~ /^0?[0-7]{1,4}$/
+          return value.to_i(8)
+        else
+          raise Puppet::Error, "The umask specification is invalid: #{value.inspect}"
+        end
+      end
+    end
+
+    newparam(:timeout) do
+      desc "The maximum time the command should take.  If the command takes
+        longer than the timeout, the command is considered to have failed
+        and will be stopped. The timeout is specified in seconds. The default
+        timeout is 300 seconds and you can set it to 0 to disable the timeout."
+
+      munge do |value|
+        value = value.shift if value.is_a?(Array)
+        begin
+          value = Float(value)
+        rescue ArgumentError
+          raise ArgumentError, "The timeout must be a number.", $!.backtrace
+        end
+        [value, 0.0].max
+      end
+
+      defaultto 300
+    end
+
+    newparam(:tries) do
+      desc "The number of times execution of the command should be tried.
+        Defaults to '1'. This many attempts will be made to execute
+        the command until an acceptable return code is returned.
+        Note that the timeout paramater applies to each try rather than
+        to the complete set of tries."
+
+      munge do |value|
+        if value.is_a?(String)
+          unless value =~ /^[\d]+$/
+            raise ArgumentError, "Tries must be an integer"
+          end
+          value = Integer(value)
+        end
+        raise ArgumentError, "Tries must be an integer >= 1" if value < 1
+        value
+      end
+
+      defaultto 1
+    end
+
+    newparam(:try_sleep) do
+      desc "The time to sleep in seconds between 'tries'."
+
+      munge do |value|
+        if value.is_a?(String)
+          unless value =~ /^[-\d.]+$/
+            raise ArgumentError, "try_sleep must be a number"
+          end
+          value = Float(value)
+        end
+        raise ArgumentError, "try_sleep cannot be a negative number" if value < 0
+        value
+      end
+
+      defaultto 0
+    end
+
+
+    newcheck(:refreshonly) do
+      desc <<-'EOT'
+        The command should only be run as a
+        refresh mechanism for when a dependent object is changed.  It only
+        makes sense to use this option when this command depends on some
+        other object; it is useful for triggering an action:
+
+            # Pull down the main aliases file
+            file { "/etc/aliases":
+              source => "puppet://server/module/aliases"
+            }
+
+            # Rebuild the database, but only when the file changes
+            exec { newaliases:
+              path        => ["/usr/bin", "/usr/sbin"],
+              subscribe   => File["/etc/aliases"],
+              refreshonly => true
+            }
+
+        Note that only `subscribe` and `notify` can trigger actions, not `require`,
+        so it only makes sense to use `refreshonly` with `subscribe` or `notify`.
+      EOT
+
+      newvalues(:true, :false)
+
+      # We always fail this test, because we're only supposed to run
+      # on refresh.
+      def check(value)
+        # We have to invert the values.
+        if value == :true
+          false
+        else
+          true
+        end
+      end
+    end
+
+    newcheck(:creates, :parent => Puppet::Parameter::Path) do
+      desc <<-'EOT'
+        A file to look for before running the command. The command will
+        only run if the file **doesn't exist.**
+
+        This parameter doesn't cause Puppet to create a file; it is only
+        useful if **the command itself** creates a file.
+
+            exec { "tar -xf /Volumes/nfs02/important.tar":
+              cwd     => "/var/tmp",
+              creates => "/var/tmp/myfile",
+              path    => ["/usr/bin", "/usr/sbin"]
+            }
+
+        In this example, `myfile` is assumed to be a file inside
+        `important.tar`. If it is ever deleted, the exec will bring it
+        back by re-extracting the tarball. If `important.tar` does **not**
+        actually contain `myfile`, the exec will keep running every time
+        Puppet runs.
+      EOT
+
+      accept_arrays
+
+      # If the file exists, return false (i.e., don't run the command),
+      # else return true
+      def check(value)
+        ! Puppet::FileSystem.exist?(value)
+      end
+    end
+
+    newcheck(:unless) do
+      desc <<-'EOT'
+        If this parameter is set, then this `exec` will run unless
+        the command has an exit code of 0.  For example:
+
+            exec { "/bin/echo root >> /usr/lib/cron/cron.allow":
+              path   => "/usr/bin:/usr/sbin:/bin",
+              unless => "grep root /usr/lib/cron/cron.allow 2>/dev/null"
+            }
+
+        This would add `root` to the cron.allow file (on Solaris) unless
+        `grep` determines it's already there.
+
+        Note that this command follows the same rules as the main command,
+        which is to say that it must be fully qualified if the path is not set.
+        It also uses the same provider as the main command, so any behavior
+        that differs by provider will match.
+      EOT
+
+      validate do |cmds|
+        cmds = [cmds] unless cmds.is_a? Array
+
+        cmds.each do |command|
+          provider.validatecmd(command)
+        end
+      end
+
+      # Return true if the command does not return 0.
+      def check(value)
+        begin
+          output, status = provider.run(value, true)
+        rescue Timeout::Error
+          err "Check #{value.inspect} exceeded timeout"
+          return false
+        end
+
+        output.split(/\n/).each { |line|
+          self.debug(line)
+        }
+
+        status.exitstatus != 0
+      end
+    end
+
+    newcheck(:onlyif) do
+      desc <<-'EOT'
+        If this parameter is set, then this `exec` will only run if
+        the command has an exit code of 0.  For example:
+
+            exec { "logrotate":
+              path   => "/usr/bin:/usr/sbin:/bin",
+              onlyif => "test `du /var/log/messages | cut -f1` -gt 100000"
+            }
+
+        This would run `logrotate` only if that test returned true.
+
+        Note that this command follows the same rules as the main command,
+        which is to say that it must be fully qualified if the path is not set.
+        It also uses the same provider as the main command, so any behavior
+        that differs by provider will match.
+
+        Also note that onlyif can take an array as its value, e.g.:
+
+            onlyif => ["test -f /tmp/file1", "test -f /tmp/file2"]
+
+        This will only run the exec if _all_ conditions in the array return true.
+      EOT
+
+      validate do |cmds|
+        cmds = [cmds] unless cmds.is_a? Array
+
+        cmds.each do |command|
+          provider.validatecmd(command)
+        end
+      end
+
+      # Return true if the command returns 0.
+      def check(value)
+        begin
+          output, status = provider.run(value, true)
+        rescue Timeout::Error
+          err "Check #{value.inspect} exceeded timeout"
+          return false
+        end
+
+        output.split(/\n/).each { |line|
+          self.debug(line)
+        }
+
+        status.exitstatus == 0
+      end
+    end
+
+    # Exec names are not isomorphic with the objects.
+    @isomorphic = false
+
+    validate do
+      provider.validatecmd(self[:command])
+    end
+
+    # FIXME exec should autorequire any exec that 'creates' our cwd
+    autorequire(:file) do
+      reqs = []
+
+      # Stick the cwd in there if we have it
+      reqs << self[:cwd] if self[:cwd]
+
+      file_regex = Puppet.features.microsoft_windows? ? %r{^([a-zA-Z]:[\\/]\S+)} : %r{^(/\S+)}
+
+      self[:command].scan(file_regex) { |str|
+        reqs << str
+      }
+
+      self[:command].scan(/^"([^"]+)"/) { |str|
+        reqs << str
+      }
+
+      [:onlyif, :unless].each { |param|
+        next unless tmp = self[param]
+
+        tmp = [tmp] unless tmp.is_a? Array
+
+        tmp.each do |line|
+          # And search the command line for files, adding any we
+          # find.  This will also catch the command itself if it's
+          # fully qualified.  It might not be a bad idea to add
+          # unqualified files, but, well, that's a bit more annoying
+          # to do.
+          reqs += line.scan(file_regex)
+        end
+      }
+
+      # For some reason, the += isn't causing a flattening
+      reqs.flatten!
+
+      reqs
+    end
+
+    autorequire(:user) do
+      # Autorequire users if they are specified by name
+      if user = self[:user] and user !~ /^\d+$/
+        user
+      end
+    end
+
+    def self.instances
+      []
+    end
+
+    # Verify that we pass all of the checks.  The argument determines whether
+    # we skip the :refreshonly check, which is necessary because we now check
+    # within refresh
+    def check_all_attributes(refreshing = false)
+      self.class.checks.each { |check|
+        next if refreshing and check == :refreshonly
+        if @parameters.include?(check)
+          val = @parameters[check].value
+          val = [val] unless val.is_a? Array
+          val.each do |value|
+            return false unless @parameters[check].check(value)
+          end
+        end
+      }
+
+      true
+    end
+
+    def output
+      if self.property(:returns).nil?
+        return nil
+      else
+        return self.property(:returns).output
+      end
+    end
+
+    # Run the command, or optionally run a separately-specified command.
+    def refresh
+      if self.check_all_attributes(true)
+        if cmd = self[:refresh]
+          provider.run(cmd)
+        else
+          self.property(:returns).sync
+        end
+      end
+    end
+
+    def current_username
+      Etc.getpwuid(Process.uid).name
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file.rb
new file mode 100644
index 0000000..33ba0dd
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file.rb
@@ -0,0 +1,933 @@
+require 'digest/md5'
+require 'cgi'
+require 'etc'
+require 'uri'
+require 'fileutils'
+require 'enumerator'
+require 'pathname'
+require 'puppet/parameter/boolean'
+require 'puppet/util/diff'
+require 'puppet/util/checksums'
+require 'puppet/util/backups'
+require 'puppet/util/symbolic_file_mode'
+
+Puppet::Type.newtype(:file) do
+  include Puppet::Util::MethodHelper
+  include Puppet::Util::Checksums
+  include Puppet::Util::Backups
+  include Puppet::Util::SymbolicFileMode
+
+  @doc = "Manages files, including their content, ownership, and permissions.
+
+    The `file` type can manage normal files, directories, and symlinks; the
+    type should be specified in the `ensure` attribute.
+
+    File contents can be managed directly with the `content` attribute, or
+    downloaded from a remote source using the `source` attribute; the latter
+    can also be used to recursively serve directories (when the `recurse`
+    attribute is set to `true` or `local`). On Windows, note that file
+    contents are managed in binary mode; Puppet never automatically translates
+    line endings.
+
+    **Autorequires:** If Puppet is managing the user or group that owns a
+    file, the file resource will autorequire them. If Puppet is managing any
+    parent directories of a file, the file resource will autorequire them."
+
+  feature :manages_symlinks,
+    "The provider can manage symbolic links."
+
+  def self.title_patterns
+    [ [ /^(.*?)\/*\Z/m, [ [ :path ] ] ] ]
+  end
+
+  newparam(:path) do
+    desc <<-'EOT'
+      The path to the file to manage.  Must be fully qualified.
+
+      On Windows, the path should include the drive letter and should use `/` as
+      the separator character (rather than `\\`).
+    EOT
+    isnamevar
+
+    validate do |value|
+      unless Puppet::Util.absolute_path?(value)
+        fail Puppet::Error, "File paths must be fully qualified, not '#{value}'"
+      end
+    end
+
+    munge do |value|
+      if value.start_with?('//') and ::File.basename(value) == "/"
+        # This is a UNC path pointing to a share, so don't add a trailing slash
+        ::File.expand_path(value)
+      else
+        ::File.join(::File.split(::File.expand_path(value)))
+      end
+    end
+  end
+
+  newparam(:backup) do
+    desc <<-EOT
+      Whether (and how) file content should be backed up before being replaced.
+      This attribute works best as a resource default in the site manifest
+      (`File { backup => main }`), so it can affect all file resources.
+
+      * If set to `false`, file content won't be backed up.
+      * If set to a string beginning with `.` (e.g., `.puppet-bak`), Puppet will
+        use copy the file in the same directory with that value as the extension
+        of the backup. (A value of `true` is a synonym for `.puppet-bak`.)
+      * If set to any other string, Puppet will try to back up to a filebucket
+        with that title. See the `filebucket` resource type for more details.
+        (This is the preferred method for backup, since it can be centralized
+        and queried.)
+
+      Default value: `puppet`, which backs up to a filebucket of the same name.
+      (Puppet automatically creates a **local** filebucket named `puppet` if one
+      doesn't already exist.)
+
+      Backing up to a local filebucket isn't particularly useful. If you want
+      to make organized use of backups, you will generally want to use the
+      puppet master server's filebucket service. This requires declaring a
+      filebucket resource and a resource default for the `backup` attribute
+      in site.pp:
+
+          # /etc/puppet/manifests/site.pp
+          filebucket { 'main':
+            path   => false,                # This is required for remote filebuckets.
+            server => 'puppet.example.com', # Optional; defaults to the configured puppet master.
+          }
+
+          File { backup => main, }
+
+      If you are using multiple puppet master servers, you will want to
+      centralize the contents of the filebucket. Either configure your load
+      balancer to direct all filebucket traffic to a single master, or use
+      something like an out-of-band rsync task to synchronize the content on all
+      masters.
+    EOT
+
+    defaultto "puppet"
+
+    munge do |value|
+      # I don't really know how this is happening.
+      value = value.shift if value.is_a?(Array)
+
+      case value
+      when false, "false", :false
+        false
+      when true, "true", ".puppet-bak", :true
+        ".puppet-bak"
+      when String
+        value
+      else
+        self.fail "Invalid backup type #{value.inspect}"
+      end
+    end
+  end
+
+  newparam(:recurse) do
+    desc "Whether to recursively manage the _contents_ of a directory. This attribute
+      is only used when `ensure => directory` is set. The allowed values are:
+
+      * `false` --- The default behavior. The contents of the directory will not be
+        automatically managed.
+      * `remote` --- If the `source` attribute is set, Puppet will automatically
+        manage the contents of the source directory (or directories), ensuring
+        that equivalent files and directories exist on the target system and
+        that their contents match.
+
+        Using `remote` will disable the `purge` attribute, but results in faster
+        catalog application than `recurse => true`.
+
+        The `source` attribute is mandatory when `recurse => remote`.
+      * `true` --- If the `source` attribute is set, this behaves similarly to
+        `recurse => remote`, automatically managing files from the source directory.
+
+        This also enables the `purge` attribute, which can delete unmanaged
+        files from a directory. See the description of `purge` for more details.
+
+        The `source` attribute is not mandatory when using `recurse => true`, so you
+        can enable purging in directories where all files are managed individually.
+
+        (Note: `inf` is a deprecated synonym for `true`.)
+
+      By default, setting recurse to `remote` or `true` will manage _all_
+      subdirectories. You can use the `recurselimit` attribute to limit the
+      recursion depth.
+    "
+
+    newvalues(:true, :false, :inf, :remote)
+
+    validate { |arg| }
+    munge do |value|
+      newval = super(value)
+      case newval
+      when :true, :inf; true
+      when :false; false
+      when :remote; :remote
+      else
+        self.fail "Invalid recurse value #{value.inspect}"
+      end
+    end
+  end
+
+  newparam(:recurselimit) do
+    desc "How far Puppet should descend into subdirectories, when using
+      `ensure => directory` and either `recurse => true` or `recurse => remote`.
+      The recursion limit affects which files will be copied from the `source`
+      directory, as well as which files can be purged when `purge => true`.
+
+      Setting `recurselimit => 0` is the same as setting `recurse => false` ---
+      Puppet will manage the directory, but all of its contents will be treated
+      as unmanaged.
+
+      Setting `recurselimit => 1` will manage files and directories that are
+      directly inside the directory, but will not manage the contents of any
+      subdirectories.
+
+      Setting `recurselimit => 2` will manage the direct contents of the
+      directory, as well as the contents of the _first_ level of subdirectories.
+
+      And so on --- 3 will manage the contents of the second level of
+      subdirectories, etc."
+
+    newvalues(/^[0-9]+$/)
+
+    munge do |value|
+      newval = super(value)
+      case newval
+      when Integer, Fixnum, Bignum; value
+      when /^\d+$/; Integer(value)
+      else
+        self.fail "Invalid recurselimit value #{value.inspect}"
+      end
+    end
+  end
+
+  newparam(:replace, :boolean => true, :parent => Puppet::Parameter::Boolean) do
+    desc "Whether to replace a file or symlink that already exists on the local system but
+      whose content doesn't match what the `source` or `content` attribute
+      specifies.  Setting this to false allows file resources to initialize files
+      without overwriting future changes.  Note that this only affects content;
+      Puppet will still manage ownership and permissions. Defaults to `true`."
+    defaultto :true
+  end
+
+  newparam(:force, :boolean => true, :parent => Puppet::Parameter::Boolean) do
+    desc "Perform the file operation even if it will destroy one or more directories.
+      You must use `force` in order to:
+
+      * `purge` subdirectories
+      * Replace directories with files or links
+      * Remove a directory when `ensure => absent`"
+    defaultto false
+  end
+
+  newparam(:ignore) do
+    desc "A parameter which omits action on files matching
+      specified patterns during recursion.  Uses Ruby's builtin globbing
+      engine, so shell metacharacters are fully supported, e.g. `[a-z]*`.
+      Matches that would descend into the directory structure are ignored,
+      e.g., `*/*`."
+
+    validate do |value|
+      unless value.is_a?(Array) or value.is_a?(String) or value == false
+        self.devfail "Ignore must be a string or an Array"
+      end
+    end
+  end
+
+  newparam(:links) do
+    desc "How to handle links during file actions.  During file copying,
+      `follow` will copy the target file instead of the link, `manage`
+      will copy the link itself, and `ignore` will just pass it by.
+      When not copying, `manage` and `ignore` behave equivalently
+      (because you cannot really ignore links entirely during local
+      recursion), and `follow` will manage the file to which the link points."
+
+    newvalues(:follow, :manage)
+
+    defaultto :manage
+  end
+
+  newparam(:purge, :boolean => true, :parent => Puppet::Parameter::Boolean) do
+    desc "Whether unmanaged files should be purged. This option only makes
+      sense when `ensure => directory` and `recurse => true`.
+
+      * When recursively duplicating an entire directory with the `source`
+        attribute, `purge => true` will automatically purge any files
+        that are not in the source directory.
+      * When managing files in a directory as individual resources,
+        setting `purge => true` will purge any files that aren't being
+        specifically managed.
+
+      If you have a filebucket configured, the purged files will be uploaded,
+      but if you do not, this will destroy data.
+
+      Unless `force => true` is set, purging will **not** delete directories,
+      although it will delete the files they contain.
+
+      If `recurselimit` is set and you aren't using `force => true`, purging
+      will obey the recursion limit; files in any subdirectories deeper than the
+      limit will be treated as unmanaged and left alone."
+
+    defaultto :false
+  end
+
+  newparam(:sourceselect) do
+    desc "Whether to copy all valid sources, or just the first one.  This parameter
+      only affects recursive directory copies; by default, the first valid
+      source is the only one used, but if this parameter is set to `all`, then
+      all valid sources will have all of their contents copied to the local
+      system. If a given file exists in more than one source, the version from
+      the earliest source in the list will be used."
+
+    defaultto :first
+
+    newvalues(:first, :all)
+  end
+
+  newparam(:show_diff, :boolean => true, :parent => Puppet::Parameter::Boolean) do
+    desc "Whether to display differences when the file changes, defaulting to
+        true.  This parameter is useful for files that may contain passwords or
+        other secret data, which might otherwise be included in Puppet reports or
+        other insecure outputs.  If the global `show_diff` setting
+        is false, then no diffs will be shown even if this parameter is true."
+
+    defaultto :true
+  end
+
+  newparam(:validate_cmd) do
+    desc "A command for validating the file's syntax before replacing it. If
+      Puppet would need to rewrite a file due to new `source` or `content`, it
+      will check the new content's validity first. If validation fails, the file
+      resource will fail.
+
+      This command must have a fully qualified path, and should contain a
+      percent (`%`) token where it would expect an input file. It must exit `0`
+      if the syntax is correct, and non-zero otherwise. The command will be
+      run on the target system while applying the catalog, not on the puppet master.
+
+      Example:
+
+          file { '/etc/apache2/apache2.conf':
+            content      => 'example',
+            validate_cmd => '/usr/sbin/apache2 -t -f %',
+          }
+
+      This would replace apache2.conf only if the test returned true.
+
+      Note that if a validation command requires a `%` as part of its text,
+      you can specify a different placeholder token with the
+      `validate_replacement` attribute."
+  end
+
+  newparam(:validate_replacement) do
+    desc "The replacement string in a `validate_cmd` that will be replaced
+      with an input file name. Defaults to: `%`"
+
+    defaultto '%'
+  end
+
+  # Autorequire the nearest ancestor directory found in the catalog.
+  autorequire(:file) do
+    req = []
+    path = Pathname.new(self[:path])
+    if !path.root?
+      # Start at our parent, to avoid autorequiring ourself
+      parents = path.parent.enum_for(:ascend)
+      if found = parents.find { |p| catalog.resource(:file, p.to_s) }
+        req << found.to_s
+      end
+    end
+    # if the resource is a link, make sure the target is created first
+    req << self[:target] if self[:target]
+    req
+  end
+
+  # Autorequire the owner and group of the file.
+  {:user => :owner, :group => :group}.each do |type, property|
+    autorequire(type) do
+      if @parameters.include?(property)
+        # The user/group property automatically converts to IDs
+        next unless should = @parameters[property].shouldorig
+        val = should[0]
+        if val.is_a?(Integer) or val =~ /^\d+$/
+          nil
+        else
+          val
+        end
+      end
+    end
+  end
+
+  CREATORS = [:content, :source, :target]
+  SOURCE_ONLY_CHECKSUMS = [:none, :ctime, :mtime]
+
+  validate do
+    creator_count = 0
+    CREATORS.each do |param|
+      creator_count += 1 if self.should(param)
+    end
+    creator_count += 1 if @parameters.include?(:source)
+    self.fail "You cannot specify more than one of #{CREATORS.collect { |p| p.to_s}.join(", ")}" if creator_count > 1
+
+    self.fail "You cannot specify a remote recursion without a source" if !self[:source] and self[:recurse] == :remote
+
+    self.fail "You cannot specify source when using checksum 'none'" if self[:checksum] == :none && !self[:source].nil?
+
+    SOURCE_ONLY_CHECKSUMS.each do |checksum_type|
+      self.fail "You cannot specify content when using checksum '#{checksum_type}'" if self[:checksum] == checksum_type && !self[:content].nil?
+    end
+
+    self.warning "Possible error: recurselimit is set but not recurse, no recursion will happen" if !self[:recurse] and self[:recurselimit]
+
+    provider.validate if provider.respond_to?(:validate)
+  end
+
+  def self.[](path)
+    return nil unless path
+    super(path.gsub(/\/+/, '/').sub(/\/$/, ''))
+  end
+
+  def self.instances
+    return []
+  end
+
+  # Determine the user to write files as.
+  def asuser
+    if self.should(:owner) and ! self.should(:owner).is_a?(Symbol)
+      writeable = Puppet::Util::SUIDManager.asuser(self.should(:owner)) {
+        FileTest.writable?(::File.dirname(self[:path]))
+      }
+
+      # If the parent directory is writeable, then we execute
+      # as the user in question.  Otherwise we'll rely on
+      # the 'owner' property to do things.
+      asuser = self.should(:owner) if writeable
+    end
+
+    asuser
+  end
+
+  def bucket
+    return @bucket if @bucket
+
+    backup = self[:backup]
+    return nil unless backup
+    return nil if backup =~ /^\./
+
+    unless catalog or backup == "puppet"
+      fail "Can not find filebucket for backups without a catalog"
+    end
+
+    unless catalog and filebucket = catalog.resource(:filebucket, backup) or backup == "puppet"
+      fail "Could not find filebucket #{backup} specified in backup"
+    end
+
+    return default_bucket unless filebucket
+
+    @bucket = filebucket.bucket
+
+    @bucket
+  end
+
+  def default_bucket
+    Puppet::Type.type(:filebucket).mkdefaultbucket.bucket
+  end
+
+  # Does the file currently exist?  Just checks for whether
+  # we have a stat
+  def exist?
+    stat ? true : false
+  end
+
+  def present?(current_values)
+    super && current_values[:ensure] != :false
+  end
+
+  # We have to do some extra finishing, to retrieve our bucket if
+  # there is one.
+  def finish
+    # Look up our bucket, if there is one
+    bucket
+    super
+  end
+
+  # Create any children via recursion or whatever.
+  def eval_generate
+    return [] unless self.recurse?
+
+    recurse
+  end
+
+  def ancestors
+    ancestors = Pathname.new(self[:path]).enum_for(:ascend).map(&:to_s)
+    ancestors.delete(self[:path])
+    ancestors
+  end
+
+  def flush
+    # We want to make sure we retrieve metadata anew on each transaction.
+    @parameters.each do |name, param|
+      param.flush if param.respond_to?(:flush)
+    end
+    @stat = :needs_stat
+  end
+
+  def initialize(hash)
+    # Used for caching clients
+    @clients = {}
+
+    super
+
+    # If they've specified a source, we get our 'should' values
+    # from it.
+    unless self[:ensure]
+      if self[:target]
+        self[:ensure] = :link
+      elsif self[:content]
+        self[:ensure] = :file
+      end
+    end
+
+    @stat = :needs_stat
+  end
+
+  # Configure discovered resources to be purged.
+  def mark_children_for_purging(children)
+    children.each do |name, child|
+      next if child[:source]
+      child[:ensure] = :absent
+    end
+  end
+
+  # Create a new file or directory object as a child to the current
+  # object.
+  def newchild(path)
+    full_path = ::File.join(self[:path], path)
+
+    # Add some new values to our original arguments -- these are the ones
+    # set at initialization.  We specifically want to exclude any param
+    # values set by the :source property or any default values.
+    # LAK:NOTE This is kind of silly, because the whole point here is that
+    # the values set at initialization should live as long as the resource
+    # but values set by default or by :source should only live for the transaction
+    # or so.  Unfortunately, we don't have a straightforward way to manage
+    # the different lifetimes of this data, so we kludge it like this.
+    # The right-side hash wins in the merge.
+    options = @original_parameters.merge(:path => full_path).reject { |param, value| value.nil? }
+
+    # These should never be passed to our children.
+    [:parent, :ensure, :recurse, :recurselimit, :target, :alias, :source].each do |param|
+      options.delete(param) if options.include?(param)
+    end
+
+    self.class.new(options)
+  end
+
+  # Files handle paths specially, because they just lengthen their
+  # path names, rather than including the full parent's title each
+  # time.
+  def pathbuilder
+    # We specifically need to call the method here, so it looks
+    # up our parent in the catalog graph.
+    if parent = parent()
+      # We only need to behave specially when our parent is also
+      # a file
+      if parent.is_a?(self.class)
+        # Remove the parent file name
+        list = parent.pathbuilder
+        list.pop # remove the parent's path info
+        return list << self.ref
+      else
+        return super
+      end
+    else
+      return [self.ref]
+    end
+  end
+
+  # Recursively generate a list of file resources, which will
+  # be used to copy remote files, manage local files, and/or make links
+  # to map to another directory.
+  def recurse
+    children = (self[:recurse] == :remote) ? {} : recurse_local
+
+    if self[:target]
+      recurse_link(children)
+    elsif self[:source]
+      recurse_remote(children)
+    end
+
+    # If we're purging resources, then delete any resource that isn't on the
+    # remote system.
+    mark_children_for_purging(children) if self.purge?
+
+    # REVISIT: sort_by is more efficient?
+    result = children.values.sort { |a, b| a[:path] <=> b[:path] }
+    remove_less_specific_files(result)
+  end
+
+  # This is to fix bug #2296, where two files recurse over the same
+  # set of files.  It's a rare case, and when it does happen you're
+  # not likely to have many actual conflicts, which is good, because
+  # this is a pretty inefficient implementation.
+  def remove_less_specific_files(files)
+    # REVISIT: is this Windows safe?  AltSeparator?
+    mypath = self[:path].split(::File::Separator)
+    other_paths = catalog.vertices.
+      select  { |r| r.is_a?(self.class) and r[:path] != self[:path] }.
+      collect { |r| r[:path].split(::File::Separator) }.
+      select  { |p| p[0,mypath.length]  == mypath }
+
+    return files if other_paths.empty?
+
+    files.reject { |file|
+      path = file[:path].split(::File::Separator)
+      other_paths.any? { |p| path[0,p.length] == p }
+      }
+  end
+
+  # A simple method for determining whether we should be recursing.
+  def recurse?
+    self[:recurse] == true or self[:recurse] == :remote
+  end
+
+  # Recurse the target of the link.
+  def recurse_link(children)
+    perform_recursion(self[:target]).each do |meta|
+      if meta.relative_path == "."
+        self[:ensure] = :directory
+        next
+      end
+
+      children[meta.relative_path] ||= newchild(meta.relative_path)
+      if meta.ftype == "directory"
+        children[meta.relative_path][:ensure] = :directory
+      else
+        children[meta.relative_path][:ensure] = :link
+        children[meta.relative_path][:target] = meta.full_path
+      end
+    end
+    children
+  end
+
+  # Recurse the file itself, returning a Metadata instance for every found file.
+  def recurse_local
+    result = perform_recursion(self[:path])
+    return {} unless result
+    result.inject({}) do |hash, meta|
+      next hash if meta.relative_path == "."
+
+      hash[meta.relative_path] = newchild(meta.relative_path)
+      hash
+    end
+  end
+
+  # Recurse against our remote file.
+  def recurse_remote(children)
+    sourceselect = self[:sourceselect]
+
+    total = self[:source].collect do |source|
+      next unless result = perform_recursion(source)
+      return if top = result.find { |r| r.relative_path == "." } and top.ftype != "directory"
+      result.each { |data| data.source = "#{source}/#{data.relative_path}" }
+      break result if result and ! result.empty? and sourceselect == :first
+      result
+    end.flatten.compact
+
+    # This only happens if we have sourceselect == :all
+    unless sourceselect == :first
+      found = []
+      total.reject! do |data|
+        result = found.include?(data.relative_path)
+        found << data.relative_path unless found.include?(data.relative_path)
+        result
+      end
+    end
+
+    total.each do |meta|
+      if meta.relative_path == "."
+        parameter(:source).metadata = meta
+        next
+      end
+      children[meta.relative_path] ||= newchild(meta.relative_path)
+      children[meta.relative_path][:source] = meta.source
+      if meta.ftype == "file"
+        children[meta.relative_path][:checksum] = Puppet[:digest_algorithm].to_sym
+      end
+
+      children[meta.relative_path].parameter(:source).metadata = meta
+    end
+
+    children
+  end
+
+  def perform_recursion(path)
+    Puppet::FileServing::Metadata.indirection.search(
+      path,
+      :links => self[:links],
+      :recurse => (self[:recurse] == :remote ? true : self[:recurse]),
+      :recurselimit => self[:recurselimit],
+      :ignore => self[:ignore],
+      :checksum_type => (self[:source] || self[:content]) ? self[:checksum] : :none,
+      :environment => catalog.environment_instance
+    )
+  end
+
+  # Back up and remove the file or directory at `self[:path]`.
+  #
+  # @param  [Symbol] should The file type replacing the current content.
+  # @return [Boolean] True if the file was removed, else False
+  # @raises [fail???] If the current file isn't one of %w{file link directory} and can't be removed.
+  def remove_existing(should)
+    wanted_type = should.to_s
+    current_type = read_current_type
+
+    if current_type.nil?
+      return false
+    end
+
+    if can_backup?(current_type)
+      backup_existing
+    end
+
+    if wanted_type != "link" and current_type == wanted_type
+      return false
+    end
+
+    case current_type
+    when "directory"
+      return remove_directory(wanted_type)
+    when "link", "file"
+      return remove_file(current_type, wanted_type)
+    else
+      self.fail "Could not back up files of type #{current_type}"
+    end
+  end
+
+  def retrieve
+    if source = parameter(:source)
+      source.copy_source_values
+    end
+    super
+  end
+
+  # Set the checksum, from another property.  There are multiple
+  # properties that modify the contents of a file, and they need the
+  # ability to make sure that the checksum value is in sync.
+  def setchecksum(sum = nil)
+    if @parameters.include? :checksum
+      if sum
+        @parameters[:checksum].checksum = sum
+      else
+        # If they didn't pass in a sum, then tell checksum to
+        # figure it out.
+        currentvalue = @parameters[:checksum].retrieve
+        @parameters[:checksum].checksum = currentvalue
+      end
+    end
+  end
+
+  # Should this thing be a normal file?  This is a relatively complex
+  # way of determining whether we're trying to create a normal file,
+  # and it's here so that the logic isn't visible in the content property.
+  def should_be_file?
+    return true if self[:ensure] == :file
+
+    # I.e., it's set to something like "directory"
+    return false if e = self[:ensure] and e != :present
+
+    # The user doesn't really care, apparently
+    if self[:ensure] == :present
+      return true unless s = stat
+      return(s.ftype == "file" ? true : false)
+    end
+
+    # If we've gotten here, then :ensure isn't set
+    return true if self[:content]
+    return true if stat and stat.ftype == "file"
+    false
+  end
+
+  # Stat our file.  Depending on the value of the 'links' attribute, we
+  # use either 'stat' or 'lstat', and we expect the properties to use the
+  # resulting stat object accordingly (mostly by testing the 'ftype'
+  # value).
+  #
+  # We use the initial value :needs_stat to ensure we only stat the file once,
+  # but can also keep track of a failed stat (@stat == nil). This also allows
+  # us to re-stat on demand by setting @stat = :needs_stat.
+  def stat
+    return @stat unless @stat == :needs_stat
+
+    method = :stat
+
+    # Files are the only types that support links
+    if (self.class.name == :file and self[:links] != :follow) or self.class.name == :tidy
+      method = :lstat
+    end
+
+    @stat = begin
+      Puppet::FileSystem.send(method, self[:path])
+    rescue Errno::ENOENT => error
+      nil
+    rescue Errno::ENOTDIR => error
+      nil
+    rescue Errno::EACCES => error
+      warning "Could not stat; permission denied"
+      nil
+    end
+  end
+
+  def to_resource
+    resource = super
+    resource.delete(:target) if resource[:target] == :notlink
+    resource
+  end
+
+  # Write out the file.  Requires the property name for logging.
+  # Write will be done by the content property, along with checksum computation
+  def write(property)
+    remove_existing(:file)
+
+    mode = self.should(:mode) # might be nil
+    mode_int = mode ? symbolic_mode_to_int(mode, Puppet::Util::DEFAULT_POSIX_MODE) : nil
+
+    if write_temporary_file?
+      Puppet::Util.replace_file(self[:path], mode_int) do |file|
+        file.binmode
+        content_checksum = write_content(file)
+        file.flush
+        fail_if_checksum_is_wrong(file.path, content_checksum) if validate_checksum?
+        if self[:validate_cmd]
+          output = Puppet::Util::Execution.execute(self[:validate_cmd].gsub(self[:validate_replacement], file.path), :failonfail => true, :combine => true)
+          output.split(/\n/).each { |line|
+            self.debug(line)
+          }
+        end
+      end
+    else
+      umask = mode ? 000 : 022
+      Puppet::Util.withumask(umask) { ::File.open(self[:path], 'wb', mode_int ) { |f| write_content(f) } }
+    end
+
+    # make sure all of the modes are actually correct
+    property_fix
+  end
+
+  private
+
+  # @return [String] The type of the current file, cast to a string.
+  def read_current_type
+    stat_info = stat
+    if stat_info
+      stat_info.ftype.to_s
+    else
+      nil
+    end
+  end
+
+  # @return [Boolean] If the current file can be backed up and needs to be backed up.
+  def can_backup?(type)
+    if type == "directory" and not force?
+      # (#18110) Directories cannot be removed without :force, so it doesn't
+      # make sense to back them up.
+      false
+    else
+      true
+    end
+  end
+
+  # @return [Boolean] True if the directory was removed
+  # @api private
+  def remove_directory(wanted_type)
+    if force?
+      debug "Removing existing directory for replacement with #{wanted_type}"
+      FileUtils.rmtree(self[:path])
+      stat_needed
+      true
+    else
+      notice "Not removing directory; use 'force' to override"
+      false
+    end
+  end
+
+  # @return [Boolean] if the file was removed (which is always true currently)
+  # @api private
+  def remove_file(current_type, wanted_type)
+    debug "Removing existing #{current_type} for replacement with #{wanted_type}"
+    Puppet::FileSystem.unlink(self[:path])
+    stat_needed
+    true
+  end
+
+  def stat_needed
+    @stat = :needs_stat
+  end
+
+  # Back up the existing file at a given prior to it being removed
+  # @api private
+  # @raise [Puppet::Error] if the file backup failed
+  # @return [void]
+  def backup_existing
+    unless perform_backup
+      raise Puppet::Error, "Could not back up; will not replace"
+    end
+  end
+
+  # Should we validate the checksum of the file we're writing?
+  def validate_checksum?
+    self[:checksum] !~ /time/
+  end
+
+  # Make sure the file we wrote out is what we think it is.
+  def fail_if_checksum_is_wrong(path, content_checksum)
+    newsum = parameter(:checksum).sum_file(path)
+    return if [:absent, nil, content_checksum].include?(newsum)
+
+    self.fail "File written to disk did not match checksum; discarding changes (#{content_checksum} vs #{newsum})"
+  end
+
+  # write the current content. Note that if there is no content property
+  # simply opening the file with 'w' as done in write is enough to truncate
+  # or write an empty length file.
+  def write_content(file)
+    (content = property(:content)) && content.write(file)
+  end
+
+  def write_temporary_file?
+    # unfortunately we don't know the source file size before fetching it
+    # so let's assume the file won't be empty
+    (c = property(:content) and c.length) || @parameters[:source]
+  end
+
+  # There are some cases where all of the work does not get done on
+  # file creation/modification, so we have to do some extra checking.
+  def property_fix
+    properties.each do |thing|
+      next unless [:mode, :owner, :group, :seluser, :selrole, :seltype, :selrange].include?(thing.name)
+
+      # Make sure we get a new stat objct
+      @stat = :needs_stat
+      currentvalue = thing.retrieve
+      thing.sync unless thing.safe_insync?(currentvalue)
+    end
+  end
+end
+
+# We put all of the properties in separate files, because there are so many
+# of them.  The order these are loaded is important, because it determines
+# the order they are in the property lit.
+require 'puppet/type/file/checksum'
+require 'puppet/type/file/content'     # can create the file
+require 'puppet/type/file/source'      # can create the file
+require 'puppet/type/file/target'      # creates a different type of file
+require 'puppet/type/file/ensure'      # can create the file
+require 'puppet/type/file/owner'
+require 'puppet/type/file/group'
+require 'puppet/type/file/mode'
+require 'puppet/type/file/type'
+require 'puppet/type/file/selcontext'  # SELinux file context
+require 'puppet/type/file/ctime'
+require 'puppet/type/file/mtime'
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/checksum.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/checksum.rb
new file mode 100644
index 0000000..1c35b1b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/checksum.rb
@@ -0,0 +1,43 @@
+require 'puppet/util/checksums'
+
+# Specify which checksum algorithm to use when checksumming
+# files.
+Puppet::Type.type(:file).newparam(:checksum) do
+  include Puppet::Util::Checksums
+
+  desc "The checksum type to use when determining whether to replace a file's contents.
+
+    The default checksum type is md5."
+
+  newvalues "md5", "md5lite", "sha256", "sha256lite", "mtime", "ctime", "none"
+
+  defaultto do
+    Puppet[:digest_algorithm].to_sym
+  end
+
+  def sum(content)
+    type = digest_algorithm()
+    "{#{type}}" + send(type, content)
+  end
+
+  def sum_file(path)
+    type = digest_algorithm()
+    method = type.to_s + "_file"
+    "{#{type}}" + send(method, path).to_s
+  end
+
+  def sum_stream(&block)
+    type = digest_algorithm()
+    method = type.to_s + "_stream"
+    checksum = send(method, &block)
+    "{#{type}}#{checksum}"
+  end
+
+  private
+
+  # Return the appropriate digest algorithm with fallbacks in case puppet defaults have not
+  # been initialized.
+  def digest_algorithm
+    value || Puppet[:digest_algorithm].to_sym
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/content.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/content.rb
new file mode 100644
index 0000000..ab28746
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/content.rb
@@ -0,0 +1,241 @@
+require 'net/http'
+require 'uri'
+require 'tempfile'
+
+require 'puppet/util/checksums'
+require 'puppet/network/http'
+require 'puppet/network/http/compression'
+
+module Puppet
+  Puppet::Type.type(:file).newproperty(:content) do
+    include Puppet::Util::Diff
+    include Puppet::Util::Checksums
+    include Puppet::Network::HTTP::Compression.module
+
+    attr_reader :actual_content
+
+    desc <<-'EOT'
+      The desired contents of a file, as a string. This attribute is mutually
+      exclusive with `source` and `target`.
+
+      Newlines and tabs can be specified in double-quoted strings using
+      standard escaped syntax --- \n for a newline, and \t for a tab.
+
+      With very small files, you can construct content strings directly in
+      the manifest...
+
+          define resolve(nameserver1, nameserver2, domain, search) {
+              $str = "search $search
+                  domain $domain
+                  nameserver $nameserver1
+                  nameserver $nameserver2
+                  "
+
+              file { "/etc/resolv.conf":
+                content => "$str",
+              }
+          }
+
+      ...but for larger files, this attribute is more useful when combined with the
+      [template](http://docs.puppetlabs.com/references/latest/function.html#template)
+      or [file](http://docs.puppetlabs.com/references/latest/function.html#file)
+      function.
+    EOT
+
+    # Store a checksum as the value, rather than the actual content.
+    # Simplifies everything.
+    munge do |value|
+      if value == :absent
+        value
+      elsif checksum?(value)
+        # XXX This is potentially dangerous because it means users can't write a file whose
+        # entire contents are a plain checksum
+        value
+      else
+        @actual_content = value
+        resource.parameter(:checksum).sum(value)
+      end
+    end
+
+    # Checksums need to invert how changes are printed.
+    def change_to_s(currentvalue, newvalue)
+      # Our "new" checksum value is provided by the source.
+      if source = resource.parameter(:source) and tmp = source.checksum
+        newvalue = tmp
+      end
+      if currentvalue == :absent
+        return "defined content as '#{newvalue}'"
+      elsif newvalue == :absent
+        return "undefined content from '#{currentvalue}'"
+      else
+        return "content changed '#{currentvalue}' to '#{newvalue}'"
+      end
+    end
+
+    def checksum_type
+      if source = resource.parameter(:source)
+        result = source.checksum
+      else
+        result = resource[:checksum]
+      end
+      if result =~ /^\{(\w+)\}.+/
+        return $1.to_sym
+      else
+        return result
+      end
+    end
+
+    def length
+      (actual_content and actual_content.length) || 0
+    end
+
+    def content
+      self.should
+    end
+
+    # Override this method to provide diffs if asked for.
+    # Also, fix #872: when content is used, and replace is true, the file
+    # should be insync when it exists
+    def insync?(is)
+      if resource.should_be_file?
+        return false if is == :absent
+      else
+        if resource[:ensure] == :present and resource[:content] and s = resource.stat
+          resource.warning "Ensure set to :present but file type is #{s.ftype} so no content will be synced"
+        end
+        return true
+      end
+
+      return true if ! @resource.replace?
+
+      result = super
+
+      if ! result and Puppet[:show_diff] and resource.show_diff?
+        write_temporarily do |path|
+          send @resource[:loglevel], "\n" + diff(@resource[:path], path)
+        end
+      end
+      result
+    end
+
+    def retrieve
+      return :absent unless stat = @resource.stat
+      ftype = stat.ftype
+      # Don't even try to manage the content on directories or links
+      return nil if ["directory","link"].include?(ftype)
+
+      begin
+        resource.parameter(:checksum).sum_file(resource[:path])
+      rescue => detail
+        raise Puppet::Error, "Could not read #{ftype} #{@resource.title}: #{detail}", detail.backtrace
+      end
+    end
+
+    # Make sure we're also managing the checksum property.
+    def should=(value)
+      # treat the value as a bytestring, in Ruby versions that support it, regardless of the encoding
+      # in which it has been supplied
+      value = value.dup.force_encoding(Encoding::ASCII_8BIT) if value.respond_to?(:force_encoding)
+      @resource.newattr(:checksum) unless @resource.parameter(:checksum)
+      super
+    end
+
+    # Just write our content out to disk.
+    def sync
+      return_event = @resource.stat ? :file_changed : :file_created
+
+      # We're safe not testing for the 'source' if there's no 'should'
+      # because we wouldn't have gotten this far if there weren't at least
+      # one valid value somewhere.
+      @resource.write(:content)
+
+      return_event
+    end
+
+    def write_temporarily
+      tempfile = Tempfile.new("puppet-file")
+      tempfile.open
+
+      write(tempfile)
+
+      tempfile.close
+
+      yield tempfile.path
+
+      tempfile.delete
+    end
+
+    def write(file)
+      resource.parameter(:checksum).sum_stream { |sum|
+        each_chunk_from(actual_content || resource.parameter(:source)) { |chunk|
+          sum << chunk
+          file.print chunk
+        }
+      }
+    end
+
+    # the content is munged so if it's a checksum source_or_content is nil
+    # unless the checksum indirectly comes from source
+    def each_chunk_from(source_or_content)
+      if source_or_content.is_a?(String)
+        yield source_or_content
+      elsif content_is_really_a_checksum? && source_or_content.nil?
+        yield read_file_from_filebucket
+      elsif source_or_content.nil?
+        yield ''
+      elsif Puppet[:default_file_terminus] == :file_server
+        yield source_or_content.content
+      elsif source_or_content.local?
+        chunk_file_from_disk(source_or_content) { |chunk| yield chunk }
+      else
+        chunk_file_from_source(source_or_content) { |chunk| yield chunk }
+      end
+    end
+
+    private
+
+    def content_is_really_a_checksum?
+      checksum?(should)
+    end
+
+    def chunk_file_from_disk(source_or_content)
+      File.open(source_or_content.full_path, "rb") do |src|
+        while chunk = src.read(8192)
+          yield chunk
+        end
+      end
+    end
+
+    def get_from_source(source_or_content, &block)
+      source = source_or_content.metadata.source
+      request = Puppet::Indirector::Request.new(:file_content, :find, source, nil, :environment => resource.catalog.environment)
+
+      request.do_request(:fileserver) do |req|
+        connection = Puppet::Network::HttpPool.http_instance(req.server, req.port)
+        connection.request_get(Puppet::Network::HTTP::API::V1.indirection2uri(req), add_accept_encoding({"Accept" => "raw"}), &block)
+      end
+    end
+
+
+    def chunk_file_from_source(source_or_content)
+      get_from_source(source_or_content) do |response|
+        case response.code
+        when /^2/;  uncompress(response) { |uncompressor| response.read_body { |chunk| yield uncompressor.uncompress(chunk) } }
+        else
+          # Raise the http error if we didn't get a 'success' of some kind.
+          message = "Error #{response.code} on SERVER: #{(response.body||'').empty? ? response.message : uncompress_body(response)}"
+          raise Net::HTTPError.new(message, response)
+        end
+      end
+    end
+
+    def read_file_from_filebucket
+      raise "Could not get filebucket from file" unless dipper = resource.bucket
+      sum = should.sub(/\{\w+\}/, '')
+
+      dipper.getfile(sum)
+    rescue => detail
+      self.fail Puppet::Error, "Could not retrieve content for #{should} from filebucket: #{detail}", detail
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/ctime.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/ctime.rb
new file mode 100644
index 0000000..e9fbdaf
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/ctime.rb
@@ -0,0 +1,20 @@
+module Puppet
+  Puppet::Type.type(:file).newproperty(:ctime) do
+    desc %q{A read-only state to check the file ctime. On most modern \*nix-like
+      systems, this is the time of the most recent change to the owner, group,
+      permissions, or content of the file.}
+
+    def retrieve
+      current_value = :absent
+      if stat = @resource.stat
+        current_value = stat.ctime
+      end
+      current_value
+    end
+
+    validate do |val|
+      fail "ctime is read-only"
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/ensure.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/ensure.rb
new file mode 100644
index 0000000..77ecc57
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/ensure.rb
@@ -0,0 +1,189 @@
+
+module Puppet
+  Puppet::Type.type(:file).ensurable do
+    require 'etc'
+    require 'puppet/util/symbolic_file_mode'
+    include Puppet::Util::SymbolicFileMode
+
+    desc <<-EOT
+      Whether the file should exist, and if so what kind of file it should be.
+      Possible values are `present`, `absent`, `file`, `directory`, and `link`.
+
+      * `present` will accept any form of file existence, and will create a
+        normal file if the file is missing. (The file will have no content
+        unless the `content` or `source` attribute is used.)
+      * `absent` will make sure the file doesn't exist, deleting it
+        if necessary.
+      * `file` will make sure it's a normal file, and enables use of the
+        `content` or `source` attribute.
+      * `directory` will make sure it's a directory, and enables use of the
+        `source`, `recurse`, `recurselimit`, `ignore`, and `purge` attributes.
+      * `link` will make sure the file is a symlink, and **requires** that you
+        also set the `target` attribute. Symlinks are supported on all Posix
+        systems and on Windows Vista / 2008 and higher. On Windows, managing
+        symlinks requires puppet agent's user account to have the "Create
+        Symbolic Links" privilege; this can be configured in the "User Rights
+        Assignment" section in the Windows policy editor. By default, puppet
+        agent runs as the Administrator account, which does have this privilege.
+
+      Puppet avoids destroying directories unless the `force` attribute is set
+      to `true`. This means that if a file is currently a directory, setting
+      `ensure` to anything but `directory` or `present` will cause Puppet to
+      skip managing the resource and log either a notice or an error.
+
+      There is one other non-standard value for `ensure`. If you specify the
+      path to another file as the ensure value, it is equivalent to specifying
+      `link` and using that path as the `target`:
+
+          # Equivalent resources:
+
+          file { "/etc/inetd.conf":
+            ensure => "/etc/inet/inetd.conf",
+          }
+
+          file { "/etc/inetd.conf":
+            ensure => link,
+            target => "/etc/inet/inetd.conf",
+          }
+
+      However, we recommend using `link` and `target` explicitly, since this
+      behavior can be harder to read.
+    EOT
+
+    # Most 'ensure' properties have a default, but with files we, um, don't.
+    nodefault
+
+    newvalue(:absent) do
+      Puppet::FileSystem.unlink(@resource[:path])
+    end
+
+    aliasvalue(:false, :absent)
+
+    newvalue(:file, :event => :file_created) do
+      # Make sure we're not managing the content some other way
+      if property = @resource.property(:content)
+        property.sync
+      else
+        @resource.write(:ensure)
+        @resource.should(:mode)
+      end
+    end
+
+    #aliasvalue(:present, :file)
+    newvalue(:present, :event => :file_created) do
+      # Make a file if they want something, but this will match almost
+      # anything.
+      set_file
+    end
+
+    newvalue(:directory, :event => :directory_created) do
+      mode = @resource.should(:mode)
+      parent = File.dirname(@resource[:path])
+      unless Puppet::FileSystem.exist? parent
+        raise Puppet::Error,
+          "Cannot create #{@resource[:path]}; parent directory #{parent} does not exist"
+      end
+      if mode
+        Puppet::Util.withumask(000) do
+          Dir.mkdir(@resource[:path], symbolic_mode_to_int(mode, 0755, true))
+        end
+      else
+        Dir.mkdir(@resource[:path])
+      end
+      @resource.send(:property_fix)
+      return :directory_created
+    end
+
+
+    newvalue(:link, :event => :link_created, :required_features => :manages_symlinks) do
+      fail "Cannot create a symlink without a target" unless property = resource.property(:target)
+      property.retrieve
+      property.mklink
+    end
+
+    # Symlinks.
+    newvalue(/./) do
+      # This code never gets executed.  We need the regex to support
+      # specifying it, but the work is done in the 'symlink' code block.
+    end
+
+    munge do |value|
+      value = super(value)
+      value,resource[:target] = :link,value unless value.is_a? Symbol
+      resource[:links] = :manage if value == :link and resource[:links] != :follow
+      value
+    end
+
+    def change_to_s(currentvalue, newvalue)
+      return super unless newvalue.to_s == "file"
+
+      return super unless property = @resource.property(:content)
+
+      # We know that content is out of sync if we're here, because
+      # it's essentially equivalent to 'ensure' in the transaction.
+      if source = @resource.parameter(:source)
+        should = source.checksum
+      else
+        should = property.should
+      end
+      if should == :absent
+        is = property.retrieve
+      else
+        is = :absent
+      end
+
+      property.change_to_s(is, should)
+    end
+
+    # Check that we can actually create anything
+    def check
+      basedir = File.dirname(@resource[:path])
+
+      if ! Puppet::FileSystem.exist?(basedir)
+        raise Puppet::Error,
+          "Can not create #{@resource.title}; parent directory does not exist"
+      elsif ! FileTest.directory?(basedir)
+        raise Puppet::Error,
+          "Can not create #{@resource.title}; #{dirname} is not a directory"
+      end
+    end
+
+    # We have to treat :present specially, because it works with any
+    # type of file.
+    def insync?(currentvalue)
+      unless currentvalue == :absent or resource.replace?
+        return true
+      end
+
+      if self.should == :present
+        return !(currentvalue.nil? or currentvalue == :absent)
+      else
+        return super(currentvalue)
+      end
+    end
+
+    def retrieve
+      if stat = @resource.stat
+        return stat.ftype.intern
+      else
+        if self.should == :false
+          return :false
+        else
+          return :absent
+        end
+      end
+    end
+
+    def sync
+      @resource.remove_existing(self.should)
+      if self.should == :absent
+        return :file_removed
+      end
+
+      event = super
+
+      event
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/group.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/group.rb
new file mode 100644
index 0000000..a1ae665
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/group.rb
@@ -0,0 +1,41 @@
+require 'puppet/util/posix'
+
+module Puppet
+  # Manage file group ownership.
+  Puppet::Type.type(:file).newproperty(:group) do
+    desc <<-EOT
+      Which group should own the file.  Argument can be either a group
+      name or a group ID.
+
+      On Windows, a user (such as "Administrator") can be set as a file's group
+      and a group (such as "Administrators") can be set as a file's owner;
+      however, a file's owner and group shouldn't be the same. (If the owner
+      is also the group, files with modes like `0640` will cause log churn, as
+      they will always appear out of sync.)
+    EOT
+
+    validate do |group|
+      raise(Puppet::Error, "Invalid group name '#{group.inspect}'") unless group and group != ""
+    end
+
+    def insync?(current)
+      # We don't want to validate/munge groups until we actually start to
+      # evaluate this property, because they might be added during the catalog
+      # apply.
+      @should.map! do |val|
+        provider.name2gid(val) or raise "Could not find group #{val}"
+      end
+
+      @should.include?(current)
+    end
+
+    # We want to print names, not numbers
+    def is_to_s(currentvalue)
+      provider.gid2name(currentvalue) || currentvalue
+    end
+
+    def should_to_s(newvalue)
+      provider.gid2name(newvalue) || newvalue
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/mode.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/mode.rb
new file mode 100644
index 0000000..6f10494
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/mode.rb
@@ -0,0 +1,168 @@
+# Manage file modes.  This state should support different formats
+# for specification (e.g., u+rwx, or -0011), but for now only supports
+# specifying the full mode.
+
+
+module Puppet
+  Puppet::Type.type(:file).newproperty(:mode) do
+    require 'puppet/util/symbolic_file_mode'
+    include Puppet::Util::SymbolicFileMode
+
+    desc <<-'EOT'
+      The desired permissions mode for the file, in symbolic or numeric
+      notation. This value should be specified as a quoted string; do not use
+      un-quoted numbers to represent file modes.
+
+      The `file` type uses traditional Unix permission schemes and translates
+      them to equivalent permissions for systems which represent permissions
+      differently, including Windows. For detailed ACL controls on Windows,
+      you can leave `mode` unmanaged and use
+      [the puppetlabs/acl module.](https://forge.puppetlabs.com/puppetlabs/acl)
+
+      Numeric modes should use the standard four-digit octal notation of
+      `<setuid/setgid/sticky><owner><group><other>` (e.g. 0644). Each of the
+      "owner," "group," and "other" digits should be a sum of the
+      permissions for that class of users, where read = 4, write = 2, and
+      execute/search = 1. When setting numeric permissions for
+      directories, Puppet sets the search permission wherever the read
+      permission is set.
+
+      Symbolic modes should be represented as a string of comma-separated
+      permission clauses, in the form `<who><op><perm>`:
+
+      * "Who" should be u (user), g (group), o (other), and/or a (all)
+      * "Op" should be = (set exact permissions), + (add select permissions),
+        or - (remove select permissions)
+      * "Perm" should be one or more of:
+          * r (read)
+          * w (write)
+          * x (execute/search)
+          * t (sticky)
+          * s (setuid/setgid)
+          * X (execute/search if directory or if any one user can execute)
+          * u (user's current permissions)
+          * g (group's current permissions)
+          * o (other's current permissions)
+
+      Thus, mode `0664` could be represented symbolically as either `a=r,ug+w`
+      or `ug=rw,o=r`.  However, symbolic modes are more expressive than numeric
+      modes: a mode only affects the specified bits, so `mode => 'ug+w'` will
+      set the user and group write bits, without affecting any other bits.
+
+      See the manual page for GNU or BSD `chmod` for more details
+      on numeric and symbolic modes.
+
+      On Windows, permissions are translated as follows:
+
+      * Owner and group names are mapped to Windows SIDs
+      * The "other" class of users maps to the "Everyone" SID
+      * The read/write/execute permissions map to the `FILE_GENERIC_READ`,
+        `FILE_GENERIC_WRITE`, and `FILE_GENERIC_EXECUTE` access rights; a
+        file's owner always has the `FULL_CONTROL` right
+      * "Other" users can't have any permissions a file's group lacks,
+        and its group can't have any permissions its owner lacks; that is, 0644
+        is an acceptable mode, but 0464 is not.
+    EOT
+
+    validate do |value|
+      if !value.is_a?(String)
+        Puppet.deprecation_warning("Non-string values for the file mode property are deprecated. It must be a string, " \
+          "either a symbolic mode like 'o+w,a+r' or an octal representation like '0644' or '755'.")
+      end
+      unless value.nil? or valid_symbolic_mode?(value)
+        raise Puppet::Error, "The file mode specification is invalid: #{value.inspect}"
+      end
+    end
+
+    munge do |value|
+      return nil if value.nil?
+
+      unless valid_symbolic_mode?(value)
+        raise Puppet::Error, "The file mode specification is invalid: #{value.inspect}"
+      end
+
+      normalize_symbolic_mode(value)
+    end
+
+    def desired_mode_from_current(desired, current)
+      current = current.to_i(8) if current.is_a? String
+      is_a_directory = @resource.stat && @resource.stat.directory?
+      symbolic_mode_to_int(desired, current, is_a_directory)
+    end
+
+    # If we're a directory, we need to be executable for all cases
+    # that are readable.  This should probably be selectable, but eh.
+    def dirmask(value)
+      if FileTest.directory?(resource[:path]) and value =~ /^\d+$/ then
+        value = value.to_i(8)
+        value |= 0100 if value & 0400 != 0
+        value |= 010 if value & 040 != 0
+        value |= 01 if value & 04 != 0
+        value = value.to_s(8)
+      end
+
+      value
+    end
+
+    # If we're not following links and we're a link, then we just turn
+    # off mode management entirely.
+    def insync?(currentvalue)
+      if stat = @resource.stat and stat.ftype == "link" and @resource[:links] != :follow
+        self.debug "Not managing symlink mode"
+        return true
+      else
+        return super(currentvalue)
+      end
+    end
+
+    def property_matches?(current, desired)
+      return false unless current
+      current_bits = normalize_symbolic_mode(current)
+      desired_bits = desired_mode_from_current(desired, current).to_s(8)
+      current_bits == desired_bits
+    end
+
+    # Ideally, dirmask'ing could be done at munge time, but we don't know if 'ensure'
+    # will eventually be a directory or something else. And unfortunately, that logic
+    # depends on the ensure, source, and target properties. So rather than duplicate
+    # that logic, and get it wrong, we do dirmask during retrieve, after 'ensure' has
+    # been synced.
+    def retrieve
+      if @resource.stat
+        @should &&= @should.collect { |s| self.dirmask(s) }
+      end
+
+      super
+    end
+
+    # Finally, when we sync the mode out we need to transform it; since we
+    # don't have access to the calculated "desired" value here, or the
+    # "current" value, only the "should" value we need to retrieve again.
+    def sync
+      current = @resource.stat ? @resource.stat.mode : 0644
+      set(desired_mode_from_current(@should[0], current).to_s(8))
+    end
+
+    def change_to_s(old_value, desired)
+      return super if desired =~ /^\d+$/
+
+      old_bits = normalize_symbolic_mode(old_value)
+      new_bits = normalize_symbolic_mode(desired_mode_from_current(desired, old_bits))
+      super(old_bits, new_bits) + " (#{desired})"
+    end
+
+    def should_to_s(should_value)
+      should_value.rjust(4, "0")
+    end
+
+    def is_to_s(currentvalue)
+      if currentvalue == :absent
+        # This can occur during audits---if a file is transitioning from
+        # present to absent the mode will have a value of `:absent`.
+        super
+      else
+        currentvalue.rjust(4, "0")
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/mtime.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/mtime.rb
new file mode 100644
index 0000000..3d57a49
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/mtime.rb
@@ -0,0 +1,18 @@
+module Puppet
+  Puppet::Type.type(:file).newproperty(:mtime) do
+    desc %q{A read-only state to check the file mtime. On \*nix-like systems, this
+      is the time of the most recent change to the content of the file.}
+
+    def retrieve
+      current_value = :absent
+      if stat = @resource.stat
+        current_value = stat.mtime
+      end
+      current_value
+    end
+
+    validate do |val|
+      fail "mtime is read-only"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/owner.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/owner.rb
new file mode 100644
index 0000000..3b61b40
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/owner.rb
@@ -0,0 +1,44 @@
+module Puppet
+  Puppet::Type.type(:file).newproperty(:owner) do
+    include Puppet::Util::Warnings
+
+    desc <<-EOT
+      The user to whom the file should belong.  Argument can be a user name or a
+      user ID.
+
+      On Windows, a group (such as "Administrators") can be set as a file's owner
+      and a user (such as "Administrator") can be set as a file's group; however,
+      a file's owner and group shouldn't be the same. (If the owner is also
+      the group, files with modes like `0640` will cause log churn, as they
+      will always appear out of sync.)
+    EOT
+
+    def insync?(current)
+      # We don't want to validate/munge users until we actually start to
+      # evaluate this property, because they might be added during the catalog
+      # apply.
+      @should.map! do |val|
+        provider.name2uid(val) or raise "Could not find user #{val}"
+      end
+
+      return true if @should.include?(current)
+
+      unless Puppet.features.root?
+        warnonce "Cannot manage ownership unless running as root"
+        return true
+      end
+
+      false
+    end
+
+    # We want to print names, not numbers
+    def is_to_s(currentvalue)
+      provider.uid2name(currentvalue) || currentvalue
+    end
+
+    def should_to_s(newvalue)
+      provider.uid2name(newvalue) || newvalue
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/selcontext.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/selcontext.rb
new file mode 100644
index 0000000..580dbbf
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/selcontext.rb
@@ -0,0 +1,124 @@
+# Manage SELinux context of files.
+#
+# This code actually manages three pieces of data in the context.
+#
+# [root@delenn files]# ls -dZ /
+# drwxr-xr-x  root root system_u:object_r:root_t         /
+#
+# The context of '/' here is 'system_u:object_r:root_t'.  This is
+# three seperate fields:
+#
+# system_u is the user context
+# object_r is the role context
+# root_t is the type context
+#
+# All three of these fields are returned in a single string by the
+# output of the stat command, but set individually with the chcon
+# command.  This allows the user to specify a subset of the three
+# values while leaving the others alone.
+#
+# See http://www.nsa.gov/selinux/ for complete docs on SELinux.
+
+
+module Puppet
+  require 'puppet/util/selinux'
+
+  class SELFileContext < Puppet::Property
+    include Puppet::Util::SELinux
+
+    def retrieve
+      return :absent unless @resource.stat
+      context = self.get_selinux_current_context(@resource[:path])
+      parse_selinux_context(name, context)
+    end
+
+    def retrieve_default_context(property)
+      if @resource[:selinux_ignore_defaults] == :true
+        return nil
+      end
+
+      unless context = self.get_selinux_default_context(@resource[:path])
+        return nil
+      end
+
+      property_default = self.parse_selinux_context(property, context)
+      self.debug "Found #{property} default '#{property_default}' for #{@resource[:path]}" if not property_default.nil?
+      property_default
+    end
+
+    def insync?(value)
+      if not selinux_support?
+        debug("SELinux bindings not found. Ignoring parameter.")
+        true
+      elsif not selinux_label_support?(@resource[:path])
+        debug("SELinux not available for this filesystem. Ignoring parameter.")
+        true
+      else
+        super
+      end
+    end
+
+    def sync
+      self.set_selinux_context(@resource[:path], @should, name)
+      :file_changed
+    end
+  end
+
+  Puppet::Type.type(:file).newparam(:selinux_ignore_defaults) do
+    desc "If this is set then Puppet will not ask SELinux (via matchpathcon) to
+      supply defaults for the SELinux attributes (seluser, selrole,
+      seltype, and selrange). In general, you should leave this set at its
+      default and only set it to true when you need Puppet to not try to fix
+      SELinux labels automatically."
+    newvalues(:true, :false)
+
+    defaultto :false
+  end
+
+  Puppet::Type.type(:file).newproperty(:seluser, :parent => Puppet::SELFileContext) do
+    desc "What the SELinux user component of the context of the file should be.
+      Any valid SELinux user component is accepted.  For example `user_u`.
+      If not specified it defaults to the value returned by matchpathcon for
+      the file, if any exists.  Only valid on systems with SELinux support
+      enabled."
+
+    @event = :file_changed
+    defaultto { self.retrieve_default_context(:seluser) }
+  end
+
+  Puppet::Type.type(:file).newproperty(:selrole, :parent => Puppet::SELFileContext) do
+    desc "What the SELinux role component of the context of the file should be.
+      Any valid SELinux role component is accepted.  For example `role_r`.
+      If not specified it defaults to the value returned by matchpathcon for
+      the file, if any exists.  Only valid on systems with SELinux support
+      enabled."
+
+    @event = :file_changed
+    defaultto { self.retrieve_default_context(:selrole) }
+  end
+
+  Puppet::Type.type(:file).newproperty(:seltype, :parent => Puppet::SELFileContext) do
+    desc "What the SELinux type component of the context of the file should be.
+      Any valid SELinux type component is accepted.  For example `tmp_t`.
+      If not specified it defaults to the value returned by matchpathcon for
+      the file, if any exists.  Only valid on systems with SELinux support
+      enabled."
+
+    @event = :file_changed
+    defaultto { self.retrieve_default_context(:seltype) }
+  end
+
+  Puppet::Type.type(:file).newproperty(:selrange, :parent => Puppet::SELFileContext) do
+    desc "What the SELinux range component of the context of the file should be.
+      Any valid SELinux range component is accepted.  For example `s0` or
+      `SystemHigh`.  If not specified it defaults to the value returned by
+      matchpathcon for the file, if any exists.  Only valid on systems with
+      SELinux support enabled and that have support for MCS (Multi-Category
+      Security)."
+
+    @event = :file_changed
+    defaultto { self.retrieve_default_context(:selrange) }
+  end
+
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/source.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/source.rb
new file mode 100644
index 0000000..e630a45
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/source.rb
@@ -0,0 +1,259 @@
+require 'puppet/file_serving/content'
+require 'puppet/file_serving/metadata'
+
+module Puppet
+  # Copy files from a local or remote source.  This state *only* does any work
+  # when the remote file is an actual file; in that case, this state copies
+  # the file down.  If the remote file is a dir or a link or whatever, then
+  # this state, during retrieval, modifies the appropriate other states
+  # so that things get taken care of appropriately.
+  Puppet::Type.type(:file).newparam(:source) do
+    include Puppet::Util::Diff
+
+    attr_accessor :source, :local
+    desc <<-'EOT'
+      A source file, which will be copied into place on the local system.
+      Values can be URIs pointing to remote files, or fully qualified paths to
+      files available on the local system (including files on NFS shares or
+      Windows mapped drives). This attribute is mutually exclusive with
+      `content` and `target`.
+
+      The available URI schemes are *puppet* and *file*. *Puppet*
+      URIs will retrieve files from Puppet's built-in file server, and are
+      usually formatted as:
+
+      `puppet:///modules/name_of_module/filename`
+
+      This will fetch a file from a module on the puppet master (or from a
+      local module when using puppet apply). Given a `modulepath` of
+      `/etc/puppetlabs/puppet/modules`, the example above would resolve to
+      `/etc/puppetlabs/puppet/modules/name_of_module/files/filename`.
+
+      Unlike `content`, the `source` attribute can be used to recursively copy
+      directories if the `recurse` attribute is set to `true` or `remote`. If
+      a source directory contains symlinks, use the `links` attribute to
+      specify whether to recreate links or follow them.
+
+      Multiple `source` values can be specified as an array, and Puppet will
+      use the first source that exists. This can be used to serve different
+      files to different system types:
+
+          file { "/etc/nfs.conf":
+            source => [
+              "puppet:///modules/nfs/conf.$host",
+              "puppet:///modules/nfs/conf.$operatingsystem",
+              "puppet:///modules/nfs/conf"
+            ]
+          }
+
+      Alternately, when serving directories recursively, multiple sources can
+      be combined by setting the `sourceselect` attribute to `all`.
+    EOT
+
+    validate do |sources|
+      sources = [sources] unless sources.is_a?(Array)
+      sources.each do |source|
+        next if Puppet::Util.absolute_path?(source)
+
+        begin
+          uri = URI.parse(URI.escape(source))
+        rescue => detail
+          self.fail Puppet::Error, "Could not understand source #{source}: #{detail}", detail
+        end
+
+        self.fail "Cannot use relative URLs '#{source}'" unless uri.absolute?
+        self.fail "Cannot use opaque URLs '#{source}'" unless uri.hierarchical?
+        self.fail "Cannot use URLs of type '#{uri.scheme}' as source for fileserving" unless %w{file puppet}.include?(uri.scheme)
+      end
+    end
+
+    SEPARATOR_REGEX = [Regexp.escape(File::SEPARATOR.to_s), Regexp.escape(File::ALT_SEPARATOR.to_s)].join
+
+    munge do |sources|
+      sources = [sources] unless sources.is_a?(Array)
+      sources.map do |source|
+        source = source.sub(/[#{SEPARATOR_REGEX}]+$/, '')
+
+        if Puppet::Util.absolute_path?(source)
+          URI.unescape(Puppet::Util.path_to_uri(source).to_s)
+        else
+          source
+        end
+      end
+    end
+
+    def change_to_s(currentvalue, newvalue)
+      # newvalue = "{md5}#{@metadata.checksum}"
+      if resource.property(:ensure).retrieve == :absent
+        return "creating from source #{metadata.source} with contents #{metadata.checksum}"
+      else
+        return "replacing from source #{metadata.source} with contents #{metadata.checksum}"
+      end
+    end
+
+    def checksum
+      metadata && metadata.checksum
+    end
+
+    # Look up (if necessary) and return local content.
+    def content
+      return @content if @content
+      raise Puppet::DevError, "No source for content was stored with the metadata" unless metadata.source
+
+      unless tmp = Puppet::FileServing::Content.indirection.find(metadata.source, :environment => resource.catalog.environment, :links => resource[:links])
+        self.fail "Could not find any content at %s" % metadata.source
+      end
+      @content = tmp.content
+    end
+
+    # Copy the values from the source to the resource.  Yay.
+    def copy_source_values
+      devfail "Somehow got asked to copy source values without any metadata" unless metadata
+
+      # conditionally copy :checksum
+      if metadata.ftype != "directory" && !(metadata.ftype == "link" && metadata.links == :manage)
+        copy_source_value(:checksum)
+      end
+
+      # Take each of the stats and set them as states on the local file
+      # if a value has not already been provided.
+      [:owner, :mode, :group].each do |metadata_method|
+        next if metadata_method == :owner and !Puppet.features.root?
+        next if metadata_method == :group and !Puppet.features.root?
+
+        if Puppet.features.microsoft_windows?
+          # Warn on Windows if source permissions are being used and the file resource
+          # does not have mode owner and group all set (which would take precedence).
+          if [:use, :use_when_creating].include?(resource[:source_permissions]) &&
+            (resource[:owner] == nil || resource[:group] == nil || resource[:mode] == nil)
+
+            warning = "Copying %s from the source" <<
+                      " file on Windows is deprecated;" <<
+                      " use source_permissions => ignore."
+            Puppet.deprecation_warning(warning % 'owner/mode/group')
+            resource.debug(warning % metadata_method.to_s)
+          end
+          # But never try to copy remote owner/group on Windows
+          next if [:owner, :group].include?(metadata_method) && !local?
+        end
+
+        case resource[:source_permissions]
+        when :ignore
+          next
+        when :use_when_creating
+          next if Puppet::FileSystem.exist?(resource[:path])
+        end
+
+        copy_source_value(metadata_method)
+      end
+
+      if resource[:ensure] == :absent
+        # We know all we need to
+      elsif metadata.ftype != "link"
+        resource[:ensure] = metadata.ftype
+      elsif resource[:links] == :follow
+        resource[:ensure] = :present
+      else
+        resource[:ensure] = "link"
+        resource[:target] = metadata.destination
+      end
+    end
+
+    attr_writer :metadata
+
+    # Provide, and retrieve if necessary, the metadata for this file.  Fail
+    # if we can't find data about this host, and fail if there are any
+    # problems in our query.
+    def metadata
+      return @metadata if @metadata
+      return nil unless value
+      value.each do |source|
+        begin
+          options = {
+            :environment          => resource.catalog.environment_instance,
+            :links                => resource[:links],
+            :source_permissions   => resource[:source_permissions]
+          }
+
+          if data = Puppet::FileServing::Metadata.indirection.find(source, options)
+            @metadata = data
+            @metadata.source = source
+            break
+          end
+        rescue => detail
+          self.fail Puppet::Error, "Could not retrieve file metadata for #{source}: #{detail}", detail
+        end
+      end
+      self.fail "Could not retrieve information from environment #{resource.catalog.environment} source(s) #{value.join(", ")}" unless @metadata
+      @metadata
+    end
+
+    def local?
+      found? and scheme == "file"
+    end
+
+    def full_path
+      Puppet::Util.uri_to_path(uri) if found?
+    end
+
+    def server?
+       uri and uri.host
+    end
+
+    def server
+      (uri and uri.host) or Puppet.settings[:server]
+    end
+
+    def port
+      (uri and uri.port) or Puppet.settings[:masterport]
+    end
+
+    def uri
+      @uri ||= URI.parse(URI.escape(metadata.source))
+    end
+
+    private
+
+    def scheme
+      (uri and uri.scheme)
+    end
+
+    def found?
+      ! (metadata.nil? or metadata.ftype.nil?)
+    end
+
+    def copy_source_value(metadata_method)
+      param_name = (metadata_method == :checksum) ? :content : metadata_method
+      if resource[param_name].nil? or resource[param_name] == :absent
+        value = metadata.send(metadata_method)
+        # Force the mode value in file resources to be a string containing octal.
+        value = value.to_s(8) if param_name == :mode && value.is_a?(Numeric)
+        resource[param_name] = value
+      end
+    end
+  end
+
+  Puppet::Type.type(:file).newparam(:source_permissions) do
+    desc <<-'EOT'
+      Whether (and how) Puppet should copy owner, group, and mode permissions from
+      the `source` to `file` resources when the permissions are not explicitly
+      specified. (In all cases, explicit permissions will take precedence.)
+      Valid values are `use`, `use_when_creating`, and `ignore`:
+
+      * `use` (the default) will cause Puppet to apply the owner, group,
+        and mode from the `source` to any files it is managing.
+      * `use_when_creating` will only apply the owner, group, and mode from the
+        `source` when creating a file; existing files will not have their permissions
+        overwritten.
+      * `ignore` will never apply the owner, group, or mode from the `source` when
+        managing a file. When creating new files without explicit permissions,
+        the permissions they receive will depend on platform-specific behavior.
+        On POSIX, Puppet will use the umask of the user it is running as. On
+        Windows, Puppet will use the default DACL associated with the user it is
+        running as.
+    EOT
+
+    defaultto :use
+    newvalues(:use, :use_when_creating, :ignore)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/target.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/target.rb
new file mode 100644
index 0000000..12b21d1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/target.rb
@@ -0,0 +1,87 @@
+module Puppet
+  Puppet::Type.type(:file).newproperty(:target) do
+    desc "The target for creating a link.  Currently, symlinks are the
+      only type supported. This attribute is mutually exclusive with `source`
+      and `content`.
+
+      Symlink targets can be relative, as well as absolute:
+
+          # (Useful on Solaris)
+          file { \"/etc/inetd.conf\":
+            ensure => link,
+            target => \"inet/inetd.conf\",
+          }
+
+      Directories of symlinks can be served recursively by instead using the
+      `source` attribute, setting `ensure` to `directory`, and setting the
+      `links` attribute to `manage`."
+
+    newvalue(:notlink) do
+      # We do nothing if the value is absent
+      return :nochange
+    end
+
+    # Anything else, basically
+    newvalue(/./) do
+      @resource[:ensure] = :link if ! @resource.should(:ensure)
+
+      # Only call mklink if ensure didn't call us in the first place.
+      currentensure  = @resource.property(:ensure).retrieve
+      mklink if @resource.property(:ensure).safe_insync?(currentensure)
+    end
+
+    # Create our link.
+    def mklink
+      raise Puppet::Error, "Cannot symlink on this platform version" if !provider.feature?(:manages_symlinks)
+
+      target = self.should
+
+      # Clean up any existing objects.  The argument is just for logging,
+      # it doesn't determine what's removed.
+      @resource.remove_existing(target)
+
+      raise Puppet::Error, "Could not remove existing file" if Puppet::FileSystem.exist?(@resource[:path])
+
+      Dir.chdir(File.dirname(@resource[:path])) do
+        Puppet::Util::SUIDManager.asuser(@resource.asuser) do
+          mode = @resource.should(:mode)
+          if mode
+            Puppet::Util.withumask(000) do
+              Puppet::FileSystem.symlink(target, @resource[:path])
+            end
+          else
+            Puppet::FileSystem.symlink(target, @resource[:path])
+          end
+        end
+
+        @resource.send(:property_fix)
+
+        :link_created
+      end
+    end
+
+    def insync?(currentvalue)
+      if [:nochange, :notlink].include?(self.should) or @resource.recurse?
+        return true
+      elsif ! @resource.replace? and Puppet::FileSystem.exist?(@resource[:path])
+        return true
+      else
+        return super(currentvalue)
+      end
+    end
+
+
+    def retrieve
+      if stat = @resource.stat
+        if stat.ftype == "link"
+          return Puppet::FileSystem.readlink(@resource[:path])
+        else
+          return :notlink
+        end
+      else
+        return :absent
+      end
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/type.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/type.rb
new file mode 100644
index 0000000..38f3015
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/file/type.rb
@@ -0,0 +1,19 @@
+module Puppet
+  Puppet::Type.type(:file).newproperty(:type) do
+    require 'etc'
+    desc "A read-only state to check the file type."
+
+    def retrieve
+      current_value = :absent
+      if stat = @resource.stat
+        current_value = stat.ftype
+      end
+      current_value
+    end
+
+    validate do |val|
+      fail "type is read-only"
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/filebucket.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/filebucket.rb
new file mode 100644
index 0000000..cbb5514
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/filebucket.rb
@@ -0,0 +1,122 @@
+module Puppet
+  require 'puppet/file_bucket/dipper'
+
+  newtype(:filebucket) do
+    @doc = <<-EOT
+      A repository for storing and retrieving file content by MD5 checksum. Can
+      be local to each agent node, or centralized on a puppet master server. All
+      puppet masters provide a filebucket service that agent nodes can access
+      via HTTP, but you must declare a filebucket resource before any agents
+      will do so.
+
+      Filebuckets are used for the following features:
+
+      - **Content backups.** If the `file` type's `backup` attribute is set to
+        the name of a filebucket, Puppet will back up the _old_ content whenever
+        it rewrites a file; see the documentation for the `file` type for more
+        details. These backups can be used for manual recovery of content, but
+        are more commonly used to display changes and differences in a tool like
+        Puppet Dashboard.
+      - **Content distribution.** The optional static compiler populates the
+        puppet master's filebucket with the _desired_ content for each file,
+        then instructs the agent to retrieve the content for a specific
+        checksum. For more details,
+        [see the `static_compiler` section in the catalog indirection docs](http://docs.puppetlabs.com/references/latest/indirection.html#catalog).
+
+      To use a central filebucket for backups, you will usually want to declare
+      a filebucket resource and a resource default for the `backup` attribute
+      in site.pp:
+
+          # /etc/puppet/manifests/site.pp
+          filebucket { 'main':
+            path   => false,                # This is required for remote filebuckets.
+            server => 'puppet.example.com', # Optional; defaults to the configured puppet master.
+          }
+
+          File { backup => main, }
+
+      Puppet master servers automatically provide the filebucket service, so
+      this will work in a default configuration. If you have a heavily
+      restricted `auth.conf` file, you may need to allow access to the
+      `file_bucket_file` endpoint.
+    EOT
+
+    newparam(:name) do
+      desc "The name of the filebucket."
+      isnamevar
+    end
+
+    newparam(:server) do
+      desc "The server providing the remote filebucket service. Defaults to the
+        value of the `server` setting (that is, the currently configured
+        puppet master server).
+
+        This setting is _only_ consulted if the `path` attribute is set to `false`."
+      defaultto { Puppet[:server] }
+    end
+
+    newparam(:port) do
+      desc "The port on which the remote server is listening. Defaults to the
+        value of the `masterport` setting, which is usually %s." % Puppet[:masterport]
+
+      defaultto { Puppet[:masterport] }
+    end
+
+    newparam(:path) do
+      desc "The path to the _local_ filebucket; defaults to the value of the
+        `clientbucketdir` setting.  To use a remote filebucket, you _must_ set
+        this attribute to `false`."
+
+      defaultto { Puppet[:clientbucketdir] }
+
+      validate do |value|
+        if value.is_a? Array
+          raise ArgumentError, "You can only have one filebucket path"
+        end
+
+        if value.is_a? String and not Puppet::Util.absolute_path?(value)
+          raise ArgumentError, "Filebucket paths must be absolute"
+        end
+
+        true
+      end
+    end
+
+    # Create a default filebucket.
+    def self.mkdefaultbucket
+      new(:name => "puppet", :path => Puppet[:clientbucketdir])
+    end
+
+    def bucket
+      mkbucket unless defined?(@bucket)
+      @bucket
+    end
+
+    private
+
+    def mkbucket
+      # Default is a local filebucket, if no server is given.
+      # If the default path has been removed, too, then
+      # the puppetmaster is used as default server
+
+      type = "local"
+      args = {}
+      if self[:path]
+        args[:Path] = self[:path]
+      else
+        args[:Server] = self[:server]
+        args[:Port] = self[:port]
+      end
+
+      begin
+        @bucket = Puppet::FileBucket::Dipper.new(args)
+      rescue => detail
+        message = "Could not create #{type} filebucket: #{detail}"
+        self.log_exception(detail, message)
+        self.fail(message)
+      end
+
+      @bucket.name = self.name
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/group.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/group.rb
new file mode 100644
index 0000000..ad307cd
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/group.rb
@@ -0,0 +1,200 @@
+require 'etc'
+require 'facter'
+require 'puppet/property/keyvalue'
+require 'puppet/parameter/boolean'
+
+module Puppet
+  newtype(:group) do
+    @doc = "Manage groups. On most platforms this can only create groups.
+      Group membership must be managed on individual users.
+
+      On some platforms such as OS X, group membership is managed as an
+      attribute of the group, not the user record. Providers must have
+      the feature 'manages_members' to manage the 'members' property of
+      a group record."
+
+    feature :manages_members,
+      "For directories where membership is an attribute of groups not users."
+
+    feature :manages_aix_lam,
+      "The provider can manage AIX Loadable Authentication Module (LAM) system."
+
+    feature :system_groups,
+      "The provider allows you to create system groups with lower GIDs."
+
+    feature :libuser,
+      "Allows local groups to be managed on systems that also use some other
+       remote NSS method of managing accounts."
+
+    ensurable do
+      desc "Create or remove the group."
+
+      newvalue(:present) do
+        provider.create
+      end
+
+      newvalue(:absent) do
+        provider.delete
+      end
+    end
+
+    newproperty(:gid) do
+      desc "The group ID.  Must be specified numerically.  If no group ID is
+        specified when creating a new group, then one will be chosen
+        automatically according to local system standards. This will likely
+        result in the same group having different GIDs on different systems,
+        which is not recommended.
+
+        On Windows, this property is read-only and will return the group's security
+        identifier (SID)."
+
+      def retrieve
+        provider.gid
+      end
+
+      def sync
+        if self.should == :absent
+          raise Puppet::DevError, "GID cannot be deleted"
+        else
+          provider.gid = self.should
+        end
+      end
+
+      munge do |gid|
+        case gid
+        when String
+          if gid =~ /^[-0-9]+$/
+            gid = Integer(gid)
+          else
+            self.fail "Invalid GID #{gid}"
+          end
+        when Symbol
+          unless gid == :absent
+            self.devfail "Invalid GID #{gid}"
+          end
+        end
+
+        return gid
+      end
+    end
+
+    newproperty(:members, :array_matching => :all, :required_features => :manages_members) do
+      desc "The members of the group. For directory services where group
+      membership is stored in the group objects, not the users. Use
+      with auth_membership to determine whether the specified members
+      are inclusive or the minimum."
+
+      def change_to_s(currentvalue, newvalue)
+        currentvalue = currentvalue.join(",") if currentvalue != :absent
+        newvalue = newvalue.join(",")
+        super(currentvalue, newvalue)
+      end
+
+      def insync?(current)
+        if provider.respond_to?(:members_insync?)
+          return provider.members_insync?(current, @should)
+        end
+
+        super(current)
+      end
+
+      def is_to_s(currentvalue)
+        if provider.respond_to?(:members_to_s)
+          currentvalue = '' if currentvalue.nil?
+          currentvalue = currentvalue.is_a?(Array) ? currentvalue : currentvalue.split(',')
+
+          return provider.members_to_s(currentvalue)
+        end
+
+        super(currentvalue)
+      end
+      alias :should_to_s :is_to_s
+
+      validate do |value|
+        if provider.respond_to?(:member_valid?)
+          return provider.member_valid?(value)
+        end
+      end
+    end
+
+    newparam(:auth_membership, :boolean => true, :parent => Puppet::Parameter::Boolean) do
+      desc "Whether the provider is authoritative for group membership. This
+        must be set to true to allow setting the group to no members with
+        `members => [],`."
+      defaultto true
+    end
+
+    newparam(:name) do
+      desc "The group name. While naming limitations vary by operating system,
+        it is advisable to restrict names to the lowest common denominator,
+        which is a maximum of 8 characters beginning with a letter.
+
+        Note that Puppet considers group names to be case-sensitive, regardless
+        of the platform's own rules; be sure to always use the same case when
+        referring to a given group."
+      isnamevar
+    end
+
+    newparam(:allowdupe, :boolean => true, :parent => Puppet::Parameter::Boolean) do
+      desc "Whether to allow duplicate GIDs. Defaults to `false`."
+
+      defaultto false
+    end
+
+    newparam(:ia_load_module, :required_features => :manages_aix_lam) do
+      desc "The name of the I&A module to use to manage this user"
+    end
+
+    newproperty(:attributes, :parent => Puppet::Property::KeyValue, :required_features => :manages_aix_lam) do
+      desc "Specify group AIX attributes in an array of `key=value` pairs."
+
+      def membership
+        :attribute_membership
+      end
+
+      def delimiter
+        " "
+      end
+
+      validate do |value|
+        raise ArgumentError, "Attributes value pairs must be separated by an =" unless value.include?("=")
+      end
+    end
+
+    newparam(:attribute_membership) do
+      desc "Whether specified attribute value pairs should be treated as the only attributes
+        of the user or whether they should merely
+        be treated as the minimum list."
+
+      newvalues(:inclusive, :minimum)
+
+      defaultto :minimum
+    end
+
+    newparam(:system, :boolean => true, :parent => Puppet::Parameter::Boolean) do
+      desc "Whether the group is a system group with lower GID."
+
+      defaultto false
+    end
+
+    newparam(:forcelocal, :boolean => true,
+             :required_features => :libuser,
+             :parent => Puppet::Parameter::Boolean) do
+      desc "Forces the management of local accounts when accounts are also
+            being managed by some other NSS"
+      defaultto false
+    end
+
+    # This method has been exposed for puppet to manage users and groups of
+    # files in its settings and should not be considered available outside of
+    # puppet.
+    #
+    # (see Puppet::Settings#service_group_available?)
+    #
+    # @return [Boolean] if the group exists on the system
+    # @api private
+    def exists?
+      provider.exists?
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/host.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/host.rb
new file mode 100644
index 0000000..d63b37d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/host.rb
@@ -0,0 +1,86 @@
+require 'puppet/property/ordered_list'
+
+module Puppet
+  newtype(:host) do
+    ensurable
+
+    newproperty(:ip) do
+      desc "The host's IP address, IPv4 or IPv6."
+
+
+      def valid_v4?(addr)
+        if /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/ =~ addr
+          return $~.captures.all? {|i| i = i.to_i; i >= 0 and i <= 255 }
+        end
+        return false
+      end
+
+      def valid_v6?(addr)
+        # http://forums.dartware.com/viewtopic.php?t=452
+        # ...and, yes, it is this hard.  Doing it programatically is harder.
+        return true if addr =~ /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/
+
+        return false
+      end
+
+      validate do |value|
+        return true if valid_v4?(value) or valid_v6?(value)
+        raise Puppet::Error, "Invalid IP address #{value.inspect}"
+      end
+    end
+
+    # for now we use OrderedList to indicate that the order does matter.
+    newproperty(:host_aliases, :parent => Puppet::Property::OrderedList) do
+      desc "Any aliases the host might have.  Multiple values must be
+        specified as an array."
+
+      def delimiter
+        " "
+      end
+
+      def inclusive?
+        true
+      end
+
+      validate do |value|
+        raise Puppet::Error, "Host aliases cannot include whitespace" if value =~ /\s/
+        raise Puppet::Error, "Host alias cannot be an empty string. Use an empty array to delete all host_aliases " if value =~ /^\s*$/
+      end
+
+    end
+
+    newproperty(:comment) do
+      desc "A comment that will be attached to the line with a # character."
+    end
+
+    newproperty(:target) do
+      desc "The file in which to store service information.  Only used by
+        those providers that write to disk. On most systems this defaults to `/etc/hosts`."
+
+      defaultto { if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile)
+        @resource.class.defaultprovider.default_target
+        else
+          nil
+        end
+      }
+    end
+
+    newparam(:name) do
+      desc "The host name."
+
+      isnamevar
+
+      validate do |value|
+        value.split('.').each do |hostpart|
+          unless hostpart =~ /^([\d\w]+|[\d\w][\d\w\-]+[\d\w])$/
+            raise Puppet::Error, "Invalid host name"
+          end
+        end
+      end
+    end
+
+    @doc = "Installs and manages host entries.  For most systems, these
+      entries will just be in `/etc/hosts`, but some systems (notably OS X)
+      will have different solutions."
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/interface.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/interface.rb
new file mode 100644
index 0000000..7362695
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/interface.rb
@@ -0,0 +1,116 @@
+#
+# Manages an interface on a given router or switch
+#
+
+require 'puppet/util/network_device/ipcalc'
+
+Puppet::Type.newtype(:interface) do
+
+    @doc = "This represents a router or switch interface. It is possible to manage
+    interface mode (access or trunking, native vlan and encapsulation) and
+    switchport characteristics (speed, duplex)."
+
+    apply_to_device
+
+    ensurable do
+      defaultvalues
+
+      aliasvalue :shutdown, :absent
+      aliasvalue :no_shutdown, :present
+
+      defaultto { :no_shutdown }
+    end
+
+    newparam(:name) do
+      desc "The interface's name."
+    end
+
+    newparam(:device_url) do
+      desc "The URL at which the router or switch can be reached."
+    end
+
+    newproperty(:description) do
+      desc "Interface description."
+
+      defaultto { @resource[:name] }
+    end
+
+    newproperty(:speed) do
+      desc "Interface speed."
+      newvalues(:auto, /^\d+/)
+    end
+
+    newproperty(:duplex) do
+      desc "Interface duplex."
+      newvalues(:auto, :full, :half)
+    end
+
+    newproperty(:native_vlan) do
+      desc "Interface native vlan (for access mode only)."
+      newvalues(/^\d+/)
+    end
+
+    newproperty(:encapsulation) do
+      desc "Interface switchport encapsulation."
+      newvalues(:none, :dot1q, :isl )
+    end
+
+    newproperty(:mode) do
+      desc "Interface switchport mode."
+      newvalues(:access, :trunk)
+    end
+
+    newproperty(:allowed_trunk_vlans) do
+      desc "Allowed list of Vlans that this trunk can forward."
+      newvalues(:all, /./)
+    end
+
+    newproperty(:etherchannel) do
+      desc "Channel group this interface is part of."
+      newvalues(/^\d+/)
+    end
+
+    newproperty(:ipaddress, :array_matching => :all) do
+      include Puppet::Util::NetworkDevice::IPCalc
+
+      desc "IP Address of this interface. Note that it might not be possible to set
+      an interface IP address; it depends on the interface type and device type.
+
+      Valid format of ip addresses are:
+
+      * IPV4, like 127.0.0.1
+      * IPV4/prefixlength like 127.0.1.1/24
+      * IPV6/prefixlength like FE80::21A:2FFF:FE30:ECF0/128
+      * an optional suffix for IPV6 addresses from this list: `eui-64`, `link-local`
+
+      It is also possible to supply an array of values.
+      "
+
+      validate do |values|
+        values = [values] unless values.is_a?(Array)
+        values.each do |value|
+          self.fail "Invalid interface ip address" unless parse(value.gsub(/\s*(eui-64|link-local)\s*$/,''))
+        end
+      end
+
+      munge do |value|
+        option = value =~ /eui-64|link-local/i ? value.gsub(/^.*?\s*(eui-64|link-local)\s*$/,'\1') : nil
+        [parse(value.gsub(/\s*(eui-64|link-local)\s*$/,'')), option].flatten
+      end
+
+      def value_to_s(value)
+        value = [value] unless value.is_a?(Array)
+        value.map{ |v| "#{v[1].to_s}/#{v[0]} #{v[2]}"}.join(",")
+      end
+
+      def change_to_s(currentvalue, newvalue)
+        currentvalue = value_to_s(currentvalue) if currentvalue != :absent
+        newvalue = value_to_s(newvalue)
+        super(currentvalue, newvalue)
+      end
+    end
+
+  def present?(current_values)
+    super && current_values[:ensure] != :shutdown
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/k5login.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/k5login.rb
new file mode 100644
index 0000000..554d7c2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/k5login.rb
@@ -0,0 +1,88 @@
+# Plug-in type for handling k5login files
+require 'puppet/util'
+
+Puppet::Type.newtype(:k5login) do
+  @doc = "Manage the `.k5login` file for a user.  Specify the full path to
+    the `.k5login` file as the name, and an array of principals as the
+    `principals` attribute."
+
+  ensurable
+
+  # Principals that should exist in the file
+  newproperty(:principals, :array_matching => :all) do
+    desc "The principals present in the `.k5login` file. This should be specified as an array."
+  end
+
+  # The path/name of the k5login file
+  newparam(:path) do
+    isnamevar
+    desc "The path to the `.k5login` file to manage.  Must be fully qualified."
+
+    validate do |value|
+      unless absolute_path?(value)
+        raise Puppet::Error, "File paths must be fully qualified."
+      end
+    end
+  end
+
+  # To manage the mode of the file
+  newproperty(:mode) do
+    desc "The desired permissions mode of the `.k5login` file. Defaults to `644`."
+    defaultto { "644" }
+  end
+
+  provide(:k5login) do
+    desc "The k5login provider is the only provider for the k5login
+      type."
+
+    # Does this file exist?
+    def exists?
+      Puppet::FileSystem.exist?(@resource[:name])
+    end
+
+    # create the file
+    def create
+      write(@resource.should(:principals))
+      should_mode = @resource.should(:mode)
+      unless self.mode == should_mode
+        self.mode = should_mode
+      end
+    end
+
+    # remove the file
+    def destroy
+      Puppet::FileSystem.unlink(@resource[:name])
+    end
+
+    # Return the principals
+    def principals(dummy_argument=:work_arround_for_ruby_GC_bug)
+      if Puppet::FileSystem.exist?(@resource[:name])
+        File.readlines(@resource[:name]).collect { |line| line.chomp }
+      else
+        :absent
+      end
+    end
+
+    # Write the principals out to the k5login file
+    def principals=(value)
+      write(value)
+    end
+
+    # Return the mode as an octal string, not as an integer
+    def mode
+      "%o" % (Puppet::FileSystem.stat(@resource[:name]).mode & 007777)
+    end
+
+    # Set the file mode, converting from a string to an integer.
+    def mode=(value)
+      File.chmod(Integer("0#{value}"), @resource[:name])
+    end
+
+    private
+    def write(value)
+      Puppet::Util.replace_file(@resource[:name], 0644) do |f|
+        f.puts value
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/macauthorization.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/macauthorization.rb
new file mode 100644
index 0000000..9504542
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/macauthorization.rb
@@ -0,0 +1,167 @@
+Puppet::Type.newtype(:macauthorization) do
+
+  @doc = "Manage the Mac OS X authorization database. See the
+    [Apple developer site](http://developer.apple.com/documentation/Security/Conceptual/Security_Overview/Security_Services/chapter_4_section_5.html)
+    for more information.
+
+    Note that authorization store directives with hyphens in their names have
+    been renamed to use underscores, as Puppet does not react well to hyphens
+    in identifiers.
+
+    **Autorequires:** If Puppet is managing the `/etc/authorization` file, each
+    macauthorization resource will autorequire it."
+
+  ensurable
+
+  autorequire(:file) do
+    ["/etc/authorization"]
+  end
+
+  def munge_boolean(value)
+    case value
+    when true, "true", :true
+      :true
+    when false, "false", :false
+      :false
+    else
+      fail("munge_boolean only takes booleans")
+    end
+  end
+
+  def munge_integer(value)
+      Integer(value)
+  rescue ArgumentError
+      fail("munge_integer only takes integers")
+  end
+
+  newparam(:name) do
+    desc "The name of the right or rule to be managed.
+    Corresponds to `key` in Authorization Services. The key is the name
+    of a rule. A key uses the same naming conventions as a right. The
+    Security Server uses a rule's key to match the rule with a right.
+    Wildcard keys end with a '.'. The generic rule has an empty key value.
+    Any rights that do not match a specific rule use the generic rule."
+
+    isnamevar
+  end
+
+  newproperty(:auth_type) do
+    desc "Type --- this can be a `right` or a `rule`. The `comment` type has
+    not yet been implemented."
+
+    newvalue(:right)
+    newvalue(:rule)
+    # newvalue(:comment)  # not yet implemented.
+  end
+
+  newproperty(:allow_root, :boolean => true) do
+    desc "Corresponds to `allow-root` in the authorization store. Specifies
+    whether a right should be allowed automatically if the requesting process
+    is running with `uid == 0`.  AuthorizationServices defaults this attribute
+    to false if not specified."
+
+    newvalue(:true)
+    newvalue(:false)
+
+    munge do |value|
+      @resource.munge_boolean(value)
+    end
+  end
+
+  newproperty(:authenticate_user, :boolean => true) do
+    desc "Corresponds to `authenticate-user` in the authorization store."
+
+    newvalue(:true)
+    newvalue(:false)
+
+    munge do |value|
+      @resource.munge_boolean(value)
+    end
+  end
+
+  newproperty(:auth_class) do
+    desc "Corresponds to `class` in the authorization store; renamed due
+    to 'class' being a reserved word in Puppet."
+
+    newvalue(:user)
+    newvalue(:'evaluate-mechanisms')
+    newvalue(:allow)
+    newvalue(:deny)
+    newvalue(:rule)
+  end
+
+  newproperty(:comment) do
+    desc "The `comment` attribute for authorization resources."
+  end
+
+  newproperty(:group) do
+    desc "A group which the user must authenticate as a member of. This
+    must be a single group."
+  end
+
+  newproperty(:k_of_n) do
+    desc "How large a subset of rule mechanisms must succeed for successful
+    authentication. If there are 'n' mechanisms, then 'k' (the integer value
+    of this parameter) mechanisms must succeed. The most common setting for
+    this parameter is `1`. If `k-of-n` is not set, then every mechanism ---
+    that is, 'n-of-n' --- must succeed."
+
+    munge do |value|
+      @resource.munge_integer(value)
+    end
+  end
+
+  newproperty(:mechanisms, :array_matching => :all) do
+    desc "An array of suitable mechanisms."
+  end
+
+  newproperty(:rule, :array_matching => :all) do
+    desc "The rule(s) that this right refers to."
+  end
+
+  newproperty(:session_owner, :boolean => true) do
+    desc "Whether the session owner automatically matches this rule or right.
+    Corresponds to `session-owner` in the authorization store."
+
+    newvalue(:true)
+    newvalue(:false)
+
+    munge do |value|
+      @resource.munge_boolean(value)
+    end
+  end
+
+  newproperty(:shared, :boolean => true) do
+    desc "Whether the Security Server should mark the credentials used to gain
+    this right as shared. The Security Server may use any shared credentials
+    to authorize this right. For maximum security, set sharing to false so
+    credentials stored by the Security Server for one application may not be
+    used by another application."
+
+    newvalue(:true)
+    newvalue(:false)
+
+    munge do |value|
+      @resource.munge_boolean(value)
+    end
+  end
+
+  newproperty(:timeout) do
+    desc "The number of seconds in which the credential used by this rule will
+    expire. For maximum security where the user must authenticate every time,
+    set the timeout to 0. For minimum security, remove the timeout attribute
+    so the user authenticates only once per session."
+
+    munge do |value|
+      @resource.munge_integer(value)
+    end
+  end
+
+  newproperty(:tries) do
+    desc "The number of tries allowed."
+    munge do |value|
+      @resource.munge_integer(value)
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/mailalias.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/mailalias.rb
new file mode 100644
index 0000000..ce7ca79
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/mailalias.rb
@@ -0,0 +1,48 @@
+module Puppet
+  newtype(:mailalias) do
+    @doc = "Creates an email alias in the local alias database."
+
+    ensurable
+
+    newparam(:name, :namevar => true) do
+      desc "The alias name."
+    end
+
+    newproperty(:recipient, :array_matching => :all) do
+      desc "Where email should be sent.  Multiple values
+        should be specified as an array."
+
+      def is_to_s(value)
+        if value.include?(:absent)
+          super
+        else
+          value.join(",")
+        end
+      end
+
+      def should
+        @should
+      end
+
+      def should_to_s(value)
+        if value.include?(:absent)
+          super
+        else
+          value.join(",")
+        end
+      end
+    end
+
+    newproperty(:target) do
+      desc "The file in which to store the aliases.  Only used by
+        those providers that write to disk."
+
+      defaultto { if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile)
+          @resource.class.defaultprovider.default_target
+        else
+          nil
+        end
+      }
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/maillist.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/maillist.rb
new file mode 100644
index 0000000..4e0542c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/maillist.rb
@@ -0,0 +1,62 @@
+module Puppet
+  newtype(:maillist) do
+    @doc = "Manage email lists.  This resource type can only create
+      and remove lists; it cannot currently reconfigure them."
+
+    ensurable do
+      defaultvalues
+
+      newvalue(:purged) do
+        provider.purge
+      end
+
+      def change_to_s(current_value, newvalue)
+        return "Purged #{resource}" if newvalue == :purged
+        super
+      end
+
+      def insync?(is)
+        return true if is == :absent && should == :purged
+        super
+      end
+    end
+
+    newparam(:name, :namevar => true) do
+      desc "The name of the email list."
+    end
+
+    newparam(:description) do
+      desc "The description of the mailing list."
+    end
+
+    newparam(:password) do
+      desc "The admin password."
+    end
+
+    newparam(:webserver) do
+      desc "The name of the host providing web archives and the administrative interface."
+    end
+
+    newparam(:mailserver) do
+      desc "The name of the host handling email for the list."
+    end
+
+    newparam(:admin) do
+      desc "The email address of the administrator."
+    end
+
+    def generate
+      if provider.respond_to?(:aliases)
+        should = self.should(:ensure) || :present
+        if should == :purged
+          should = :absent
+        end
+        atype = Puppet::Type.type(:mailalias)
+
+        provider.aliases.
+          reject  { |name,recipient| catalog.resource(:mailalias, name) }.
+          collect { |name,recipient| atype.new(:name => name, :recipient => recipient, :ensure => should) }
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/mcx.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/mcx.rb
new file mode 100644
index 0000000..86bc953
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/mcx.rb
@@ -0,0 +1,98 @@
+Puppet::Type.newtype(:mcx) do
+
+  @doc = "MCX object management using DirectoryService on OS X.
+
+The default provider of this type merely manages the XML plist as
+reported by the `dscl -mcxexport` command.  This is similar to the
+content property of the file type in Puppet.
+
+The recommended method of using this type is to use Work Group Manager
+to manage users and groups on the local computer, record the resulting
+puppet manifest using the command `puppet resource mcx`, then deploy it
+to other machines.
+
+**Autorequires:** If Puppet is managing the user, group, or computer that these
+MCX settings refer to, the MCX resource will autorequire that user, group, or computer.
+"
+  feature :manages_content, \
+    "The provider can manage MCXSettings as a string.",
+    :methods => [:content, :content=]
+
+  ensurable do
+    desc "Create or remove the MCX setting."
+
+    newvalue(:present) do
+      provider.create
+    end
+
+    newvalue(:absent) do
+      provider.destroy
+    end
+
+  end
+
+  newparam(:name) do
+    desc "The name of the resource being managed.
+    The default naming convention follows Directory Service paths:
+
+        /Computers/localhost
+        /Groups/admin
+        /Users/localadmin
+
+    The `ds_type` and `ds_name` type parameters are not necessary if the
+    default naming convention is followed."
+    isnamevar
+  end
+
+  newparam(:ds_type) do
+
+    desc "The DirectoryService type this MCX setting attaches to."
+
+    newvalues(:user, :group, :computer, :computerlist)
+
+  end
+
+  newparam(:ds_name) do
+    desc "The name to attach the MCX Setting to. (For example, `localhost`
+    when `ds_type => computer`.) This setting is not required, as it can be
+    automatically discovered when the resource name is parseable.  (For
+    example, in `/Groups/admin`, `group` will be used as the dstype.)"
+  end
+
+  newproperty(:content, :required_features => :manages_content) do
+    desc "The XML Plist used as the value of MCXSettings in DirectoryService.
+    This is the standard output from the system command:
+
+        dscl localhost -mcxexport /Local/Default/<ds_type>/ds_name
+
+    Note that `ds_type` is capitalized and plural in the dscl command."
+  end
+
+  # JJM Yes, this is not DRY at all.  Because of the code blocks
+  # autorequire must be done this way.  I think.
+
+  def setup_autorequire(type)
+    # value returns a Symbol
+    ds_type = value(:ds_type)
+    ds_name = value(:ds_name)
+    if ds_type == type
+      rval = [ ds_name.to_s ]
+    else
+      rval = [ ]
+    end
+    rval
+  end
+
+  autorequire(:user) do
+    setup_autorequire(:user)
+  end
+
+  autorequire(:group) do
+    setup_autorequire(:group)
+  end
+
+  autorequire(:computer) do
+    setup_autorequire(:computer)
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/mount.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/mount.rb
new file mode 100644
index 0000000..6f9d126
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/mount.rb
@@ -0,0 +1,297 @@
+require 'puppet/property/boolean'
+
+module Puppet
+  # We want the mount to refresh when it changes.
+  newtype(:mount, :self_refresh => true) do
+    @doc = "Manages mounted filesystems, including putting mount
+      information into the mount table. The actual behavior depends
+      on the value of the 'ensure' parameter.
+
+      **Refresh:** `mount` resources can respond to refresh events (via
+      `notify`, `subscribe`, or the `~>` arrow). If a `mount` receives an event
+      from another resource **and** its `ensure` attribute is set to `mounted`,
+      Puppet will try to unmount then remount that filesystem.
+
+      **Autorequires:** If Puppet is managing any parents of a mount resource ---
+      that is, other mount points higher up in the filesystem --- the child
+      mount will autorequire them."
+
+    feature :refreshable, "The provider can remount the filesystem.",
+      :methods => [:remount]
+
+    # Use the normal parent class, because we actually want to
+    # call code when sync is called.
+    newproperty(:ensure) do
+      desc "Control what to do with this mount. Set this attribute to
+        `unmounted` to make sure the filesystem is in the filesystem table
+        but not mounted (if the filesystem is currently mounted, it will be
+        unmounted).  Set it to `absent` to unmount (if necessary) and remove
+        the filesystem from the fstab.  Set to `mounted` to add it to the
+        fstab and mount it. Set to `present` to add to fstab but not change
+        mount/unmount status."
+
+      #  IS        -> SHOULD     In Sync  Action
+      #  ghost     -> present    NO       create
+      #  absent    -> present    NO       create
+      # (mounted   -> present    YES)
+      # (unmounted -> present    YES)
+      newvalue(:defined) do
+        provider.create
+        return :mount_created
+      end
+
+      aliasvalue :present, :defined
+
+      #  IS        -> SHOULD     In Sync  Action
+      #  ghost     -> unmounted  NO       create, unmount
+      #  absent    -> unmounted  NO       create
+      #  mounted   -> unmounted  NO       unmount
+      newvalue(:unmounted) do
+        case self.retrieve
+        when :ghost   # (not in fstab but mounted)
+          provider.create
+          @resource.flush
+          provider.unmount
+          return :mount_unmounted
+        when nil, :absent  # (not in fstab and not mounted)
+          provider.create
+          return :mount_created
+        when :mounted # (in fstab and mounted)
+          provider.unmount
+          syncothers # I guess it's more likely that the mount was originally mounted with
+                     # the wrong attributes so I sync AFTER the umount
+          return :mount_unmounted
+        else
+          raise Puppet::Error, "Unexpected change from #{current_value} to unmounted}"
+        end
+      end
+
+      #  IS        -> SHOULD     In Sync  Action
+      #  ghost     -> absent     NO       unmount
+      #  mounted   -> absent     NO       provider.destroy AND unmount
+      #  unmounted -> absent     NO       provider.destroy
+      newvalue(:absent, :event => :mount_deleted) do
+        current_value = self.retrieve
+        provider.unmount if provider.mounted?
+        provider.destroy unless current_value == :ghost
+      end
+
+      #  IS        -> SHOULD     In Sync  Action
+      #  ghost     -> mounted    NO       provider.create
+      #  absent    -> mounted    NO       provider.create AND mount
+      #  unmounted -> mounted    NO       mount
+      newvalue(:mounted, :event => :mount_mounted) do
+        # Create the mount point if it does not already exist.
+        current_value = self.retrieve
+        currently_mounted = provider.mounted?
+        provider.create if [nil, :absent, :ghost].include?(current_value)
+
+        syncothers
+
+        # The fs can be already mounted if it was absent but mounted
+        provider.property_hash[:needs_mount] = true unless currently_mounted
+      end
+
+      # insync: mounted   -> present
+      #         unmounted -> present
+      def insync?(is)
+        if should == :defined and [:mounted,:unmounted].include?(is)
+          true
+        else
+          super
+        end
+      end
+
+      def syncothers
+        # We have to flush any changes to disk.
+        currentvalues = @resource.retrieve_resource
+
+        # Determine if there are any out-of-sync properties.
+        oos = @resource.send(:properties).find_all do |prop|
+          unless currentvalues.include?(prop)
+            raise Puppet::DevError, "Parent has property %s but it doesn't appear in the current values", [prop.name]
+          end
+          if prop.name == :ensure
+            false
+          else
+            ! prop.safe_insync?(currentvalues[prop])
+          end
+        end.each { |prop| prop.sync }.length
+        @resource.flush if oos > 0
+      end
+    end
+
+    newproperty(:device) do
+      desc "The device providing the mount.  This can be whatever
+        device is supporting by the mount, including network
+        devices or devices specified by UUID rather than device
+        path, depending on the operating system."
+
+      validate do |value|
+        raise Puppet::Error, "device must not contain whitespace: #{value}" if value =~ /\s/
+      end
+    end
+
+    # Solaris specifies two devices, not just one.
+    newproperty(:blockdevice) do
+      desc "The device to fsck.  This is property is only valid
+        on Solaris, and in most cases will default to the correct
+        value."
+
+      # Default to the device but with "dsk" replaced with "rdsk".
+      defaultto do
+        if Facter.value(:osfamily) == "Solaris"
+          if device = resource[:device] and device =~ %r{/dsk/}
+            device.sub(%r{/dsk/}, "/rdsk/")
+          elsif fstype = resource[:fstype] and fstype == 'nfs'
+            '-'
+          else
+            nil
+          end
+        else
+          nil
+        end
+      end
+
+      validate do |value|
+        raise Puppet::Error, "blockdevice must not contain whitespace: #{value}" if value =~ /\s/
+      end
+    end
+
+    newproperty(:fstype) do
+      desc "The mount type.  Valid values depend on the
+        operating system.  This is a required option."
+
+      validate do |value|
+        raise Puppet::Error, "fstype must not contain whitespace: #{value}" if value =~ /\s/
+      end
+    end
+
+    newproperty(:options) do
+      desc "Mount options for the mounts, comma-separated as they would appear
+      in the fstab on Linux. AIX options other than dev, nodename, or vfs may
+      be defined here. If specified, AIX options of account, boot, check, free,
+      mount, size, type, vol, log, and quota must be alphabetically sorted at
+      the end of the list."
+
+      validate do |value|
+        raise Puppet::Error, "option must not contain whitespace: #{value}" if value =~ /\s/
+      end
+    end
+
+    newproperty(:pass) do
+      desc "The pass in which the mount is checked."
+
+      defaultto {
+        if @resource.managed?
+          if Facter.value(:osfamily) == 'Solaris'
+            '-'
+          else
+            0
+          end
+        end
+      }
+    end
+
+    newproperty(:atboot, :parent => Puppet::Property::Boolean) do
+      desc "Whether to mount the mount at boot.  Not all platforms
+        support this."
+
+      def munge(value)
+        munged = super
+        if munged
+          :yes
+        else
+          :no
+        end
+      end
+    end
+
+    newproperty(:dump) do
+      desc "Whether to dump the mount.  Not all platform support this.
+        Valid values are `1` or `0` (or `2` on FreeBSD). Default is `0`."
+
+      if Facter.value(:operatingsystem) == "FreeBSD"
+        newvalue(%r{(0|1|2)})
+      else
+        newvalue(%r{(0|1)})
+      end
+
+      defaultto {
+        0 if @resource.managed?
+      }
+    end
+
+    newproperty(:target) do
+      desc "The file in which to store the mount table.  Only used by
+        those providers that write to disk."
+
+      defaultto { if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile)
+          @resource.class.defaultprovider.default_target
+        else
+          nil
+        end
+      }
+    end
+
+    newparam(:name) do
+      desc "The mount path for the mount."
+
+      isnamevar
+
+      validate do |value|
+        raise Puppet::Error, "name must not contain whitespace: #{value}" if value =~ /\s/
+      end
+
+      munge do |value|
+        value.gsub(/^(.+?)\/*$/, '\1')
+      end
+    end
+
+    newparam(:remounts) do
+      desc "Whether the mount can be remounted  `mount -o remount`.  If
+        this is false, then the filesystem will be unmounted and remounted
+        manually, which is prone to failure."
+
+      newvalues(:true, :false)
+      defaultto do
+        case Facter.value(:operatingsystem)
+        when "FreeBSD", "Darwin", "DragonFly", "OpenBSD"
+          false
+        when "AIX"
+          if Facter.value(:kernelmajversion) == "5300"
+            false
+          elsif resource[:device] and resource[:device].match(%r{^[^/]+:/})
+            false
+          else
+            true
+          end
+        else
+          true
+        end
+      end
+    end
+
+    def refresh
+      # Only remount if we're supposed to be mounted.
+      provider.remount if self.should(:fstype) != "swap" and provider.mounted?
+    end
+
+    def value(name)
+      name = name.intern
+      if property = @parameters[name]
+        return property.value
+      end
+    end
+
+    # Ensure that mounts higher up in the filesystem are mounted first
+    autorequire(:mount) do
+      dependencies = []
+      Pathname.new(@parameters[:name].value).ascend do |parent|
+        dependencies.unshift parent.to_s
+      end
+      dependencies[0..-2]
+    end
+
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_command.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_command.rb
new file mode 100644
index 0000000..0d0e11b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_command.rb
@@ -0,0 +1,3 @@
+require 'puppet/util/nagios_maker'
+
+Puppet::Util::NagiosMaker.create_nagios_type :command
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_contact.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_contact.rb
new file mode 100644
index 0000000..d5a1f3c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_contact.rb
@@ -0,0 +1,3 @@
+require 'puppet/util/nagios_maker'
+
+Puppet::Util::NagiosMaker.create_nagios_type :contact
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_contactgroup.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_contactgroup.rb
new file mode 100644
index 0000000..b8f14c0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_contactgroup.rb
@@ -0,0 +1,3 @@
+require 'puppet/util/nagios_maker'
+
+Puppet::Util::NagiosMaker.create_nagios_type :contactgroup
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_host.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_host.rb
new file mode 100644
index 0000000..f2e03f6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_host.rb
@@ -0,0 +1,3 @@
+require 'puppet/util/nagios_maker'
+
+Puppet::Util::NagiosMaker.create_nagios_type :host
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_hostdependency.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_hostdependency.rb
new file mode 100644
index 0000000..fea71a6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_hostdependency.rb
@@ -0,0 +1,3 @@
+require 'puppet/util/nagios_maker'
+
+Puppet::Util::NagiosMaker.create_nagios_type :hostdependency
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_hostescalation.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_hostescalation.rb
new file mode 100644
index 0000000..5d18af2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_hostescalation.rb
@@ -0,0 +1,3 @@
+require 'puppet/util/nagios_maker'
+
+Puppet::Util::NagiosMaker.create_nagios_type :hostescalation
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_hostextinfo.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_hostextinfo.rb
new file mode 100644
index 0000000..da8e08d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_hostextinfo.rb
@@ -0,0 +1,3 @@
+require 'puppet/util/nagios_maker'
+
+Puppet::Util::NagiosMaker.create_nagios_type :hostextinfo
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_hostgroup.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_hostgroup.rb
new file mode 100644
index 0000000..e1943be
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_hostgroup.rb
@@ -0,0 +1,3 @@
+require 'puppet/util/nagios_maker'
+
+Puppet::Util::NagiosMaker.create_nagios_type :hostgroup
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_service.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_service.rb
new file mode 100644
index 0000000..22b987f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_service.rb
@@ -0,0 +1,3 @@
+require 'puppet/util/nagios_maker'
+
+Puppet::Util::NagiosMaker.create_nagios_type :service
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_servicedependency.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_servicedependency.rb
new file mode 100644
index 0000000..0e3340c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_servicedependency.rb
@@ -0,0 +1,3 @@
+require 'puppet/util/nagios_maker'
+
+Puppet::Util::NagiosMaker.create_nagios_type :servicedependency
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_serviceescalation.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_serviceescalation.rb
new file mode 100644
index 0000000..cb2af15
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_serviceescalation.rb
@@ -0,0 +1,3 @@
+require 'puppet/util/nagios_maker'
+
+Puppet::Util::NagiosMaker.create_nagios_type :serviceescalation
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_serviceextinfo.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_serviceextinfo.rb
new file mode 100644
index 0000000..6bdc709
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_serviceextinfo.rb
@@ -0,0 +1,3 @@
+require 'puppet/util/nagios_maker'
+
+Puppet::Util::NagiosMaker.create_nagios_type :serviceextinfo
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_servicegroup.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_servicegroup.rb
new file mode 100644
index 0000000..fef6696
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_servicegroup.rb
@@ -0,0 +1,3 @@
+require 'puppet/util/nagios_maker'
+
+Puppet::Util::NagiosMaker.create_nagios_type :servicegroup
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_timeperiod.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_timeperiod.rb
new file mode 100644
index 0000000..25a06d3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/nagios_timeperiod.rb
@@ -0,0 +1,3 @@
+require 'puppet/util/nagios_maker'
+
+Puppet::Util::NagiosMaker.create_nagios_type :timeperiod
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/notify.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/notify.rb
new file mode 100644
index 0000000..606df84
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/notify.rb
@@ -0,0 +1,44 @@
+#
+# Simple module for logging messages on the client-side
+
+
+module Puppet
+  newtype(:notify) do
+    @doc = "Sends an arbitrary message to the agent run-time log."
+
+    newproperty(:message) do
+      desc "The message to be sent to the log."
+      def sync
+        case @resource["withpath"]
+        when :true
+          send(@resource[:loglevel], self.should)
+        else
+          Puppet.send(@resource[:loglevel], self.should)
+        end
+        return
+      end
+
+      def retrieve
+        :absent
+      end
+
+      def insync?(is)
+        false
+      end
+
+      defaultto { @resource[:name] }
+    end
+
+    newparam(:withpath) do
+      desc "Whether to show the full object path. Defaults to false."
+      defaultto :false
+
+      newvalues(:true, :false)
+    end
+
+    newparam(:name) do
+      desc "An arbitrary tag for your own reference; the name of the message."
+      isnamevar
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/package.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/package.rb
new file mode 100644
index 0000000..bf47f32
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/package.rb
@@ -0,0 +1,476 @@
+# Define the different packaging systems.  Each package system is implemented
+# in a module, which then gets used to individually extend each package object.
+# This allows packages to exist on the same machine using different packaging
+# systems.
+
+require 'puppet/parameter/package_options'
+require 'puppet/parameter/boolean'
+
+module Puppet
+  newtype(:package) do
+    @doc = "Manage packages.  There is a basic dichotomy in package
+      support right now:  Some package types (e.g., yum and apt) can
+      retrieve their own package files, while others (e.g., rpm and sun)
+      cannot.  For those package formats that cannot retrieve their own files,
+      you can use the `source` parameter to point to the correct file.
+
+      Puppet will automatically guess the packaging format that you are
+      using based on the platform you are on, but you can override it
+      using the `provider` parameter; each provider defines what it
+      requires in order to function, and you must meet those requirements
+      to use a given provider.
+
+      **Autorequires:** If Puppet is managing the files specified as a
+      package's `adminfile`, `responsefile`, or `source`, the package
+      resource will autorequire those files."
+
+    feature :installable, "The provider can install packages.",
+      :methods => [:install]
+    feature :uninstallable, "The provider can uninstall packages.",
+      :methods => [:uninstall]
+    feature :upgradeable, "The provider can upgrade to the latest version of a
+        package.  This feature is used by specifying `latest` as the
+        desired value for the package.",
+      :methods => [:update, :latest]
+    feature :purgeable, "The provider can purge packages.  This generally means
+        that all traces of the package are removed, including
+        existing configuration files.  This feature is thus destructive
+        and should be used with the utmost care.",
+      :methods => [:purge]
+    feature :versionable, "The provider is capable of interrogating the
+        package database for installed version(s), and can select
+        which out of a set of available versions of a package to
+        install if asked."
+    feature :holdable, "The provider is capable of placing packages on hold
+        such that they are not automatically upgraded as a result of
+        other package dependencies unless explicit action is taken by
+        a user or another package. Held is considered a superset of
+        installed.",
+      :methods => [:hold]
+    feature :install_options, "The provider accepts options to be
+      passed to the installer command."
+    feature :uninstall_options, "The provider accepts options to be
+      passed to the uninstaller command."
+    feature :package_settings, "The provider accepts package_settings to be
+      ensured for the given package. The meaning and format of these settings is
+      provider-specific.",
+      :methods => [:package_settings_insync?, :package_settings, :package_settings=]
+    feature :virtual_packages, "The provider accepts virtual package names for install and uninstall."
+
+    ensurable do
+      desc <<-EOT
+        What state the package should be in. On packaging systems that can
+        retrieve new packages on their own, you can choose which package to
+        retrieve by specifying a version number or `latest` as the ensure
+        value. On packaging systems that manage configuration files separately
+        from "normal" system files, you can uninstall config files by
+        specifying `purged` as the ensure value. This defaults to `installed`.
+      EOT
+
+      attr_accessor :latest
+
+      newvalue(:present, :event => :package_installed) do
+        provider.install
+      end
+
+      newvalue(:absent, :event => :package_removed) do
+        provider.uninstall
+      end
+
+      newvalue(:purged, :event => :package_purged, :required_features => :purgeable) do
+        provider.purge
+      end
+
+      newvalue(:held, :event => :package_held, :required_features => :holdable) do
+        provider.hold
+      end
+
+      # Alias the 'present' value.
+      aliasvalue(:installed, :present)
+
+      newvalue(:latest, :required_features => :upgradeable) do
+        # Because yum always exits with a 0 exit code, there's a retrieve
+        # in the "install" method.  So, check the current state now,
+        # to compare against later.
+        current = self.retrieve
+        begin
+          provider.update
+        rescue => detail
+          self.fail Puppet::Error, "Could not update: #{detail}", detail
+        end
+
+        if current == :absent
+          :package_installed
+        else
+          :package_changed
+        end
+      end
+
+      newvalue(/./, :required_features => :versionable) do
+        begin
+          provider.install
+        rescue => detail
+          self.fail Puppet::Error, "Could not update: #{detail}", detail
+        end
+
+        if self.retrieve == :absent
+          :package_installed
+        else
+          :package_changed
+        end
+      end
+
+      defaultto :installed
+
+      # Override the parent method, because we've got all kinds of
+      # funky definitions of 'in sync'.
+      def insync?(is)
+        @lateststamp ||= (Time.now.to_i - 1000)
+        # Iterate across all of the should values, and see how they
+        # turn out.
+
+        @should.each { |should|
+          case should
+          when :present
+            return true unless [:absent, :purged, :held].include?(is)
+          when :latest
+            # Short-circuit packages that are not present
+            return false if is == :absent or is == :purged
+
+            # Don't run 'latest' more than about every 5 minutes
+            if @latest and ((Time.now.to_i - @lateststamp) / 60) < 5
+              #self.debug "Skipping latest check"
+            else
+              begin
+                @latest = provider.latest
+                @lateststamp = Time.now.to_i
+              rescue => detail
+                error = Puppet::Error.new("Could not get latest version: #{detail}")
+                error.set_backtrace(detail.backtrace)
+                raise error
+              end
+            end
+
+            case
+              when is.is_a?(Array) && is.include?(@latest)
+                return true
+              when is == @latest
+                return true
+              when is == :present
+                # This will only happen on retarded packaging systems
+                # that can't query versions.
+                return true
+              else
+                self.debug "#{@resource.name} #{is.inspect} is installed, latest is #{@latest.inspect}"
+            end
+
+
+          when :absent
+            return true if is == :absent or is == :purged
+          when :purged
+            return true if is == :purged
+          # this handles version number matches and
+          # supports providers that can have multiple versions installed
+          when *Array(is)
+            return true
+          end
+        }
+
+        false
+      end
+
+      # This retrieves the current state. LAK: I think this method is unused.
+      def retrieve
+        provider.properties[:ensure]
+      end
+
+      # Provide a bit more information when logging upgrades.
+      def should_to_s(newvalue = @should)
+        if @latest
+          @latest.to_s
+        else
+          super(newvalue)
+        end
+      end
+    end
+
+    newparam(:name) do
+      desc "The package name.  This is the name that the packaging
+      system uses internally, which is sometimes (especially on Solaris)
+      a name that is basically useless to humans.  If you want to
+      abstract package installation, then you can use aliases to provide
+      a common name to packages:
+
+          # In the 'openssl' class
+          $ssl = $operatingsystem ? {
+            solaris => SMCossl,
+            default => openssl
+          }
+
+          # It is not an error to set an alias to the same value as the
+          # object name.
+          package { $ssl:
+            ensure => installed,
+            alias  => openssl
+          }
+
+          . etc. .
+
+          $ssh = $operatingsystem ? {
+            solaris => SMCossh,
+            default => openssh
+          }
+
+          # Use the alias to specify a dependency, rather than
+          # having another selector to figure it out again.
+          package { $ssh:
+            ensure  => installed,
+            alias   => openssh,
+            require => Package[openssl]
+          }
+
+      "
+      isnamevar
+
+      validate do |value|
+        if !value.is_a?(String)
+          raise ArgumentError, "Name must be a String not #{value.class}"
+        end
+      end
+    end
+
+    newproperty(:package_settings, :required_features=>:package_settings) do
+      desc "Settings that can change the contents or configuration of a package.
+
+        The formatting and effects of package_settings are provider-specific; any
+        provider that implements them must explain how to use them in its
+        documentation. (Our general expectation is that if a package is
+        installed but its settings are out of sync, the provider should
+        re-install that package with the desired settings.)
+
+        An example of how package_settings could be used is FreeBSD's port build
+        options --- a future version of the provider could accept a hash of options,
+        and would reinstall the port if the installed version lacked the correct
+        settings.
+
+            package { 'www/apache22':
+              package_settings => { 'SUEXEC' => false }
+            }
+
+        Again, check the documentation of your platform's package provider to see
+        the actual usage."
+
+      validate do |value|
+        if provider.respond_to?(:package_settings_validate)
+          provider.package_settings_validate(value)
+        else
+          super(value)
+        end
+      end
+
+      munge do |value|
+        if provider.respond_to?(:package_settings_munge)
+          provider.package_settings_munge(value)
+        else
+          super(value)
+        end
+      end
+
+      def insync?(is)
+        provider.package_settings_insync?(should, is)
+      end
+
+      def should_to_s(newvalue)
+        if provider.respond_to?(:package_settings_should_to_s)
+          provider.package_settings_should_to_s(should, newvalue)
+        else
+          super(newvalue)
+        end
+      end
+
+      def is_to_s(currentvalue)
+        if provider.respond_to?(:package_settings_is_to_s)
+          provider.package_settings_is_to_s(should, currentvalue)
+        else
+          super(currentvalue)
+        end
+      end
+
+      def change_to_s(currentvalue, newvalue)
+        if provider.respond_to?(:package_settings_change_to_s)
+          provider.package_settings_change_to_s(currentvalue, newvalue)
+        else
+          super(currentvalue,newvalue)
+        end
+      end
+    end
+
+    newparam(:source) do
+      desc "Where to find the package file. This is only used by providers that don't
+        automatically download packages from a central repository. (For example:
+        the `yum` and `apt` providers ignore this attribute, but the `rpm` and
+        `dpkg` providers require it.)
+
+        Different providers accept different values for `source`. Most providers
+        accept paths to local files stored on the target system. Some providers
+        may also accept URLs or network drive paths. Puppet will not
+        automatically retrieve source files for you, and usually just passes the
+        value of `source` to the package installation command.
+
+        You can use a `file` resource if you need to manually copy package files
+        to the target system."
+
+      validate do |value|
+        provider.validate_source(value)
+      end
+    end
+
+    newparam(:instance) do
+      desc "A read-only parameter set by the package."
+    end
+
+    newparam(:status) do
+      desc "A read-only parameter set by the package."
+    end
+
+    newparam(:adminfile) do
+      desc "A file containing package defaults for installing packages.
+
+        This attribute is only used on Solaris. Its value should be a path to a
+        local file stored on the target system. Solaris's package tools expect
+        either an absolute file path or a relative path to a file in
+        `/var/sadm/install/admin`.
+
+        The value of `adminfile` will be passed directly to the `pkgadd` or
+        `pkgrm` command with the `-a <ADMINFILE>` option."
+    end
+
+    newparam(:responsefile) do
+      desc "A file containing any necessary answers to questions asked by
+        the package.  This is currently used on Solaris and Debian.  The
+        value will be validated according to system rules, but it should
+        generally be a fully qualified path."
+    end
+
+    newparam(:configfiles) do
+      desc "Whether configfiles should be kept or replaced.  Most packages
+        types do not support this parameter. Defaults to `keep`."
+
+      defaultto :keep
+
+      newvalues(:keep, :replace)
+    end
+
+    newparam(:category) do
+      desc "A read-only parameter set by the package."
+    end
+    newparam(:platform) do
+      desc "A read-only parameter set by the package."
+    end
+    newparam(:root) do
+      desc "A read-only parameter set by the package."
+    end
+    newparam(:vendor) do
+      desc "A read-only parameter set by the package."
+    end
+    newparam(:description) do
+      desc "A read-only parameter set by the package."
+    end
+
+    newparam(:allowcdrom) do
+      desc "Tells apt to allow cdrom sources in the sources.list file.
+        Normally apt will bail if you try this."
+
+      newvalues(:true, :false)
+    end
+
+    newparam(:flavor) do
+      desc "OpenBSD supports 'flavors', which are further specifications for
+        which type of package you want."
+    end
+
+    newparam(:install_options, :parent => Puppet::Parameter::PackageOptions, :required_features => :install_options) do
+      desc <<-EOT
+        An array of additional options to pass when installing a package. These
+        options are package-specific, and should be documented by the software
+        vendor.  One commonly implemented option is `INSTALLDIR`:
+
+            package { 'mysql':
+              ensure          => installed,
+              source          => 'N:/packages/mysql-5.5.16-winx64.msi',
+              install_options => [ '/S', { 'INSTALLDIR' => 'C:\\mysql-5.5' } ],
+            }
+
+        Each option in the array can either be a string or a hash, where each
+        key and value pair are interpreted in a provider specific way.  Each
+        option will automatically be quoted when passed to the install command.
+
+        On Windows, this is the **only** place in Puppet where backslash
+        separators should be used.  Note that backslashes in double-quoted
+        strings _must_ be double-escaped and backslashes in single-quoted
+        strings _may_ be double-escaped.
+      EOT
+    end
+
+    newparam(:uninstall_options, :parent => Puppet::Parameter::PackageOptions, :required_features => :uninstall_options) do
+      desc <<-EOT
+        An array of additional options to pass when uninstalling a package. These
+        options are package-specific, and should be documented by the software
+        vendor.  For example:
+
+            package { 'VMware Tools':
+              ensure            => absent,
+              uninstall_options => [ { 'REMOVE' => 'Sync,VSS' } ],
+            }
+
+        Each option in the array can either be a string or a hash, where each
+        key and value pair are interpreted in a provider specific way.  Each
+        option will automatically be quoted when passed to the uninstall
+        command.
+
+        On Windows, this is the **only** place in Puppet where backslash
+        separators should be used.  Note that backslashes in double-quoted
+        strings _must_ be double-escaped and backslashes in single-quoted
+        strings _may_ be double-escaped.
+      EOT
+    end
+
+    newparam(:allow_virtual, :boolean => true, :parent => Puppet::Parameter::Boolean, :required_features => :virtual_packages) do
+      desc 'Specifies if virtual package names are allowed for install and uninstall.'
+
+      # In a future release, this should be defaulted to true
+      defaultto false
+    end
+
+    autorequire(:file) do
+      autos = []
+      [:responsefile, :adminfile].each { |param|
+        if val = self[param]
+          autos << val
+        end
+      }
+
+      if source = self[:source] and absolute_path?(source)
+        autos << source
+      end
+      autos
+    end
+
+    # This only exists for testing.
+    def clear
+      if obj = @parameters[:ensure]
+        obj.latest = nil
+      end
+    end
+
+    # The 'query' method returns a hash of info if the package
+    # exists and returns nil if it does not.
+    def exists?
+      @provider.get(:ensure) != :absent
+    end
+
+    def present?(current_values)
+      super && current_values[:ensure] != :purged
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/resources.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/resources.rb
new file mode 100644
index 0000000..7a4ffd8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/resources.rb
@@ -0,0 +1,187 @@
+require 'puppet'
+require 'puppet/parameter/boolean'
+
+Puppet::Type.newtype(:resources) do
+  @doc = "This is a metatype that can manage other resource types.  Any
+    metaparams specified here will be passed on to any generated resources,
+    so you can purge umanaged resources but set `noop` to true so the
+    purging is only logged and does not actually happen."
+
+
+  newparam(:name) do
+    desc "The name of the type to be managed."
+
+    validate do |name|
+      raise ArgumentError, "Could not find resource type '#{name}'" unless Puppet::Type.type(name)
+    end
+
+    munge { |v| v.to_s }
+  end
+
+  newparam(:purge, :boolean => true, :parent => Puppet::Parameter::Boolean) do
+    desc "Whether to purge unmanaged resources.  When set to `true`, this will
+      delete any resource that is not specified in your configuration and is not
+      autorequired by any managed resources. **Note:** The `ssh_authorized_key`
+      resource type can't be purged this way; instead, see the `purge_ssh_keys`
+      attribute of the `user` type."
+
+    defaultto :false
+
+    validate do |value|
+      if munge(value)
+        unless @resource.resource_type.respond_to?(:instances)
+          raise ArgumentError, "Purging resources of type #{@resource[:name]} is not supported, since they cannot be queried from the system"
+        end
+        raise ArgumentError, "Purging is only supported on types that accept 'ensure'" unless @resource.resource_type.validproperty?(:ensure)
+      end
+    end
+  end
+
+  newparam(:unless_system_user) do
+    desc "This keeps system users from being purged.  By default, it
+      does not purge users whose UIDs are less than the minimum UID for the system (typically 500 or 1000), but you can specify
+      a different UID as the inclusive limit."
+
+    newvalues(:true, :false, /^\d+$/)
+
+    munge do |value|
+      case value
+      when /^\d+/
+        Integer(value)
+      when :true, true
+        @resource.class.system_users_max_uid
+      when :false, false
+        false
+      when Integer; value
+      else
+        raise ArgumentError, "Invalid value #{value.inspect}"
+      end
+    end
+
+    defaultto {
+      if @resource[:name] == "user"
+        @resource.class.system_users_max_uid
+      else
+        nil
+      end
+    }
+  end
+
+  newparam(:unless_uid) do
+    desc 'This keeps specific uids or ranges of uids from being purged when purge is true.
+      Accepts integers, integer strings, and arrays of integers or integer strings.
+      To specify a range of uids, consider using the range() function from stdlib.'
+
+    munge do |value|
+      value = [value] unless value.is_a? Array
+      value.flatten.collect do |v|
+        case v
+          when Integer
+            v
+          when String
+            Integer(v)
+          else
+            raise ArgumentError, "Invalid value #{v.inspect}."
+        end
+      end
+    end
+  end
+
+  def check(resource)
+    @checkmethod ||= "#{self[:name]}_check"
+    @hascheck ||= respond_to?(@checkmethod)
+    if @hascheck
+      return send(@checkmethod, resource)
+    else
+      return true
+    end
+  end
+
+  def able_to_ensure_absent?(resource)
+      resource[:ensure] = :absent
+  rescue ArgumentError, Puppet::Error
+      err "The 'ensure' attribute on #{self[:name]} resources does not accept 'absent' as a value"
+      false
+  end
+
+  # Generate any new resources we need to manage.  This is pretty hackish
+  # right now, because it only supports purging.
+  def generate
+    return [] unless self.purge?
+    resource_type.instances.
+      reject { |r| catalog.resource_refs.include? r.ref }.
+      select { |r| check(r) }.
+      select { |r| r.class.validproperty?(:ensure) }.
+      select { |r| able_to_ensure_absent?(r) }.
+      each { |resource|
+        @parameters.each do |name, param|
+          resource[name] = param.value if param.metaparam?
+        end
+
+        # Mark that we're purging, so transactions can handle relationships
+        # correctly
+        resource.purging
+      }
+  end
+
+  def resource_type
+    unless defined?(@resource_type)
+      unless type = Puppet::Type.type(self[:name])
+        raise Puppet::DevError, "Could not find resource type"
+      end
+      @resource_type = type
+    end
+    @resource_type
+  end
+
+  def self.deprecate_params(title,params)
+    return unless params
+    if title == 'cron' and ! params.select { |param| param.name.intern == :purge and param.value == true }.empty?
+      Puppet.deprecation_warning("Change notice: purging cron entries will be more aggressive in future versions, take care when updating your agents. See http://links.puppetlabs.com/puppet-aggressive-cron-purge")
+    end
+  end
+
+  # Make sure we don't purge users with specific uids
+  def user_check(resource)
+    return true unless self[:name] == "user"
+    return true unless self[:unless_system_user]
+    resource[:audit] = :uid
+    current_values = resource.retrieve_resource
+    current_uid = current_values[resource.property(:uid)]
+    unless_uids = self[:unless_uid]
+
+    return false if system_users.include?(resource[:name])
+    return false if unless_uids && unless_uids.include?(current_uid)
+
+    current_uid > self[:unless_system_user]
+  end
+
+  def system_users
+    %w{root nobody bin noaccess daemon sys}
+  end
+
+  def self.system_users_max_uid
+    return @system_users_max_uid if @system_users_max_uid
+
+    # First try to read the minimum user id from login.defs
+    if Puppet::FileSystem.exist?('/etc/login.defs')
+      @system_users_max_uid = Puppet::FileSystem.each_line '/etc/login.defs' do |line|
+        break $1.to_i - 1 if line =~ /^\s*UID_MIN\s+(\d+)(\s*#.*)?$/
+      end
+    end
+
+    # Otherwise, use a sensible default based on the OS family
+    @system_users_max_uid ||= case Facter.value(:osfamily)
+      when 'OpenBSD', 'FreeBSD'
+        999
+      else
+        499
+    end
+
+    @system_users_max_uid
+  end
+
+  def self.reset_system_users_max_uid!
+    @system_users_max_uid = nil
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/router.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/router.rb
new file mode 100644
index 0000000..06be960
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/router.rb
@@ -0,0 +1,17 @@
+#
+# Manage a router abstraction
+
+
+module Puppet
+  newtype(:router) do
+    @doc = "Manages connected router."
+
+    newparam(:url) do
+      desc <<-EOT
+        An SSH or telnet URL at which to access the router, in the form
+        `ssh://user:pass:enable@host/` or `telnet://user:pass:enable@host/`.
+      EOT
+      isnamevar
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/schedule.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/schedule.rb
new file mode 100644
index 0000000..f7c9b82
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/schedule.rb
@@ -0,0 +1,469 @@
+module Puppet
+  newtype(:schedule) do
+    @doc = <<-'EOT'
+      Define schedules for Puppet. Resources can be limited to a schedule by using the
+      [`schedule`](http://docs.puppetlabs.com/references/latest/metaparameter.html#schedule)
+      metaparameter.
+
+      Currently, **schedules can only be used to stop a resource from being
+      applied;** they cannot cause a resource to be applied when it otherwise
+      wouldn't be, and they cannot accurately specify a time when a resource
+      should run.
+
+      Every time Puppet applies its configuration, it will apply the
+      set of resources whose schedule does not eliminate them from
+      running right then, but there is currently no system in place to
+      guarantee that a given resource runs at a given time.  If you
+      specify a very  restrictive schedule and Puppet happens to run at a
+      time within that schedule, then the resources will get applied;
+      otherwise, that work may never get done.
+
+      Thus, it is advisable to use wider scheduling (e.g., over a couple of
+      hours) combined with periods and repetitions.  For instance, if you
+      wanted to restrict certain resources to only running once, between
+      the hours of two and 4 AM, then you would use this schedule:
+
+          schedule { 'maint':
+            range  => "2 - 4",
+            period => daily,
+            repeat => 1,
+          }
+
+      With this schedule, the first time that Puppet runs between 2 and 4 AM,
+      all resources with this schedule will get applied, but they won't
+      get applied again between 2 and 4 because they will have already
+      run once that day, and they won't get applied outside that schedule
+      because they will be outside the scheduled range.
+
+      Puppet automatically creates a schedule for each of the valid periods
+      with the same name as that period (e.g., hourly and daily).
+      Additionally, a schedule named `puppet` is created and used as the
+      default, with the following attributes:
+
+          schedule { 'puppet':
+            period => hourly,
+            repeat => 2,
+          }
+
+      This will cause resources to be applied every 30 minutes by default.
+      EOT
+
+    apply_to_all
+
+    newparam(:name) do
+      desc <<-EOT
+        The name of the schedule.  This name is used when assigning the schedule
+        to a resource with the `schedule` metaparameter:
+
+            schedule { 'everyday':
+              period => daily,
+              range  => "2 - 4",
+            }
+
+            exec { "/usr/bin/apt-get update":
+              schedule => 'everyday',
+            }
+
+        EOT
+      isnamevar
+    end
+
+    newparam(:range) do
+      desc <<-EOT
+        The earliest and latest that a resource can be applied.  This is
+        always a hyphen-separated range within a 24 hour period, and hours
+        must be specified in numbers between 0 and 23, inclusive.  Minutes and
+        seconds can optionally be provided, using the normal colon as a
+        separator. For instance:
+
+            schedule { 'maintenance':
+              range => "1:30 - 4:30",
+            }
+
+        This is mostly useful for restricting certain resources to being
+        applied in maintenance windows or during off-peak hours. Multiple
+        ranges can be applied in array context. As a convenience when specifying
+        ranges, you may cross midnight (e.g.: range => "22:00 - 04:00").
+      EOT
+
+      # This is lame; properties all use arrays as values, but parameters don't.
+      # That's going to hurt eventually.
+      validate do |values|
+        values = [values] unless values.is_a?(Array)
+        values.each { |value|
+          unless  value.is_a?(String) and
+              value =~ /\d+(:\d+){0,2}\s*-\s*\d+(:\d+){0,2}/
+            self.fail "Invalid range value '#{value}'"
+          end
+        }
+      end
+
+      munge do |values|
+        values = [values] unless values.is_a?(Array)
+        ret = []
+
+        values.each { |value|
+          range = []
+          # Split each range value into a hour, minute, second triad
+          value.split(/\s*-\s*/).each { |val|
+            # Add the values as an array.
+            range << val.split(":").collect { |n| n.to_i }
+          }
+
+          self.fail "Invalid range #{value}" if range.length != 2
+
+          # Make sure the hours are valid
+          [range[0][0], range[1][0]].each do |n|
+            raise ArgumentError, "Invalid hour '#{n}'" if n < 0 or n > 23
+          end
+
+          [range[0][1], range[1][1]].each do |n|
+            raise ArgumentError, "Invalid minute '#{n}'" if n and (n < 0 or n > 59)
+          end
+          ret << range
+        }
+
+        # Now our array of arrays
+        ret
+      end
+
+      def match?(previous, now)
+        # The lowest-level array is of the hour, minute, second triad
+        # then it's an array of two of those, to present the limits
+        # then it's an array of those ranges
+        @value = [@value] unless @value[0][0].is_a?(Array)
+
+        @value.each do |value|
+          limits = value.collect do |range|
+            ary = [now.year, now.month, now.day, range[0]]
+            if range[1]
+              ary << range[1]
+            else
+              ary << 0
+            end
+
+            if range[2]
+              ary << range[2]
+            else
+              ary << 0
+            end
+
+            time = Time.local(*ary)
+
+            unless time.hour == range[0]
+              self.devfail(
+                "Incorrectly converted time: #{time}: #{time.hour} vs #{range[0]}"
+              )
+            end
+
+            time
+          end
+
+          unless limits[0] < limits[1]
+            self.info(
+            "Assuming upper limit should be that time the next day"
+            )
+
+            # Find midnight between the two days. Adding one second
+            # to the end of the day is easier than dealing with dates.
+            ary = limits[0].to_a
+            ary[0] = 59
+            ary[1] = 59
+            ary[2] = 23
+            midnight = Time.local(*ary)+1
+
+            # If it is currently between the range start and midnight
+            # we consider that a successful match.
+            if now.between?(limits[0], midnight)
+              # We have to check the weekday match here as it is special-cased
+              # to support day-spanning ranges.
+              if @resource[:weekday]
+                return false unless @resource[:weekday].has_key?(now.wday)
+              end
+              return true
+            end
+
+            # If we didn't match between the starting time and midnight
+            # we must now move our midnight back 24 hours and try
+            # between the new midnight (24 hours prior) and the
+            # ending time.
+            midnight -= 86400
+
+            # Now we compare the current time between midnight and the
+            # end time.
+            if now.between?(midnight, limits[1])
+              # This case is the reason weekday matching is special cased
+              # in the range parameter. If we match a range that has spanned
+              # past midnight we want to match against the weekday when the range
+              # started, not when it currently is.
+              if @resource[:weekday]
+                return false unless @resource[:weekday].has_key?((now - 86400).wday)
+              end
+              return true
+            end
+
+            # If neither of the above matched then we don't match the
+            # range schedule.
+            return false
+          end
+
+          # Check to see if a weekday parameter was specified and, if so,
+          # do we match it or not. If we fail we can stop here.
+          # This is required because spanning ranges forces us to check
+          # weekday within the range parameter.
+          if @resource[:weekday]
+            return false unless @resource[:weekday].has_key?(now.wday)
+          end
+
+          return true if now.between?(*limits)
+        end
+
+        # Else, return false, since our current time isn't between
+        # any valid times
+        false
+      end
+    end
+
+    newparam(:periodmatch) do
+      desc "Whether periods should be matched by number (e.g., the two times
+        are in the same hour) or by distance (e.g., the two times are
+        60 minutes apart)."
+
+      newvalues(:number, :distance)
+
+      defaultto :distance
+    end
+
+    newparam(:period) do
+      desc <<-EOT
+        The period of repetition for resources on this schedule. The default is
+        for resources to get applied every time Puppet runs.
+
+        Note that the period defines how often a given resource will get
+        applied but not when; if you would like to restrict the hours
+        that a given resource can be applied (e.g., only at night during
+        a maintenance window), then use the `range` attribute.
+
+        If the provided periods are not sufficient, you can provide a
+        value to the *repeat* attribute, which will cause Puppet to
+        schedule the affected resources evenly in the period the
+        specified number of times.  Take this schedule:
+
+            schedule { 'veryoften':
+              period => hourly,
+              repeat => 6,
+            }
+
+        This can cause Puppet to apply that resource up to every 10 minutes.
+
+        At the moment, Puppet cannot guarantee that level of repetition; that
+        is, the resource can applied _up to_ every 10 minutes, but internal
+        factors might prevent it from actually running that often (e.g. if a
+        Puppet run is still in progress when the next run is scheduled to start,
+        that next run will be suppressed).
+
+        See the `periodmatch` attribute for tuning whether to match
+        times by their distance apart or by their specific value.
+      EOT
+
+      newvalues(:hourly, :daily, :weekly, :monthly, :never)
+
+      ScheduleScales = {
+        :hourly => 3600,
+        :daily => 86400,
+        :weekly => 604800,
+        :monthly => 2592000
+      }
+      ScheduleMethods = {
+        :hourly => :hour,
+        :daily => :day,
+        :monthly => :month,
+        :weekly => proc do |prev, now|
+          # Run the resource if the previous day was after this weekday (e.g., prev is wed, current is tue)
+          # or if it's been more than a week since we ran
+          prev.wday > now.wday or (now - prev) > (24 * 3600 * 7)
+        end
+      }
+
+      def match?(previous, now)
+        return false if value == :never
+
+        value = self.value
+        case @resource[:periodmatch]
+        when :number
+          method = ScheduleMethods[value]
+          if method.is_a?(Proc)
+            return method.call(previous, now)
+          else
+            # We negate it, because if they're equal we don't run
+            return now.send(method) != previous.send(method)
+          end
+        when :distance
+          scale = ScheduleScales[value]
+
+          # If the number of seconds between the two times is greater
+          # than the unit of time, we match.  We divide the scale
+          # by the repeat, so that we'll repeat that often within
+          # the scale.
+          return (now.to_i - previous.to_i) >= (scale / @resource[:repeat])
+        end
+      end
+    end
+
+    newparam(:repeat) do
+      desc "How often a given resource may be applied in this schedule's `period`.
+        Defaults to 1; must be an integer."
+
+      defaultto 1
+
+      validate do |value|
+        unless value.is_a?(Integer) or value =~ /^\d+$/
+          raise Puppet::Error,
+            "Repeat must be a number"
+        end
+
+        # This implicitly assumes that 'periodmatch' is distance -- that
+        # is, if there's no value, we assume it's a valid value.
+        return unless @resource[:periodmatch]
+
+        if value != 1 and @resource[:periodmatch] != :distance
+          raise Puppet::Error,
+            "Repeat must be 1 unless periodmatch is 'distance', not '#{@resource[:periodmatch]}'"
+        end
+      end
+
+      munge do |value|
+        value = Integer(value) unless value.is_a?(Integer)
+
+        value
+      end
+
+      def match?(previous, now)
+        true
+      end
+    end
+
+    newparam(:weekday) do
+      desc <<-EOT
+        The days of the week in which the schedule should be valid.
+        You may specify the full day name (Tuesday), the three character
+        abbreviation (Tue), or a number corresponding to the day of the
+        week where 0 is Sunday, 1 is Monday, etc. Multiple days can be specified
+        as an array. If not specified, the day of the week will not be
+        considered in the schedule.
+
+        If you are also using a range match that spans across midnight
+        then this parameter will match the day that it was at the start
+        of the range, not necessarily the day that it is when it matches.
+        For example, consider this schedule:
+
+            schedule { 'maintenance_window':
+              range   => '22:00 - 04:00',
+              weekday => 'Saturday',
+            }
+
+        This will match at 11 PM on Saturday and 2 AM on Sunday, but not
+        at 2 AM on Saturday.
+      EOT
+
+      validate do |values|
+        values = [values] unless values.is_a?(Array)
+        values.each { |value|
+          unless value.is_a?(String) and
+              (value =~ /^[0-6]$/ or value =~ /^(Mon|Tues?|Wed(?:nes)?|Thu(?:rs)?|Fri|Sat(?:ur)?|Sun)(day)?$/i)
+            raise ArgumentError, "%s is not a valid day of the week" % value
+          end
+        }
+      end
+
+      weekdays = {
+        'sun' => 0,
+        'mon' => 1,
+        'tue' => 2,
+        'wed' => 3,
+        'thu' => 4,
+        'fri' => 5,
+        'sat' => 6,
+      }
+
+      munge do |values|
+        values = [values] unless values.is_a?(Array)
+        ret = {}
+
+        values.each { |value|
+           if value =~ /^[0-6]$/
+              index = value.to_i
+           else
+              index = weekdays[value[0,3].downcase]
+           end
+            ret[index] = true
+        }
+        ret
+      end
+
+      def match?(previous, now)
+        # Special case weekday matching with ranges to a no-op here.
+        # If the ranges span days then we can't simply match the current
+        # weekday, as we want to match the weekday as it was when the range
+        # started.  As a result, all of that logic is in range, not here.
+        return true if @resource[:range]
+
+        return true if value.has_key?(now.wday)
+        false
+      end
+    end
+
+    def self.instances
+      []
+    end
+
+    def self.mkdefaultschedules
+      result = []
+      unless Puppet[:default_schedules]
+        Puppet.debug "Not creating default schedules: default_schedules is false"
+        return result
+      end
+
+      Puppet.debug "Creating default schedules"
+
+            result << self.new(
+
+        :name => "puppet",
+        :period => :hourly,
+
+        :repeat => "2"
+      )
+
+      # And then one for every period
+      @parameters.find { |p| p.name == :period }.value_collection.values.each { |value|
+
+              result << self.new(
+          :name => value.to_s,
+          :period => value
+        )
+      }
+
+      result
+    end
+
+    def match?(previous = nil, now = nil)
+
+      # If we've got a value, then convert it to a Time instance
+      previous &&= Time.at(previous)
+
+      now ||= Time.now
+
+      # Pull them in order
+      self.class.allattrs.each { |param|
+        if @parameters.include?(param) and
+          @parameters[param].respond_to?(:match?)
+          return false unless @parameters[param].match?(previous, now)
+        end
+      }
+
+      # If we haven't returned false, then return true; in other words,
+      # any provided schedules need to all match
+      true
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/scheduled_task.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/scheduled_task.rb
new file mode 100644
index 0000000..97215a2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/scheduled_task.rb
@@ -0,0 +1,184 @@
+require 'puppet/util'
+
+Puppet::Type.newtype(:scheduled_task) do
+  include Puppet::Util
+
+  @doc = "Installs and manages Windows Scheduled Tasks.  All attributes
+    except `name`, `command`, and `trigger` are optional; see the description
+    of the `trigger` attribute for details on setting schedules."
+
+  ensurable
+
+  newproperty(:enabled) do
+    desc "Whether the triggers for this task should be enabled. This attribute
+      affects every trigger for the task; triggers cannot be enabled or
+      disabled individually."
+
+    newvalue(:true,  :event => :task_enabled)
+    newvalue(:false, :event => :task_disabled)
+
+    defaultto(:true)
+  end
+
+  newparam(:name) do
+    desc "The name assigned to the scheduled task.  This will uniquely
+      identify the task on the system."
+
+    isnamevar
+  end
+
+  newproperty(:command) do
+    desc "The full path to the application to run, without any arguments."
+
+    validate do |value|
+      raise Puppet::Error.new('Must be specified using an absolute path.') unless absolute_path?(value)
+    end
+    munge do |value|
+      # windows converts slashes to backslashes, so the *is* value
+      # has backslashes. Do the same for the *should* value, so that
+      # we are slash-insensitive. See #13009
+      File.expand_path(value).gsub(/\//, '\\')
+    end
+  end
+
+  newproperty(:working_dir) do
+    desc "The full path of the directory in which to start the command."
+
+    validate do |value|
+      raise Puppet::Error.new('Must be specified using an absolute path.') unless absolute_path?(value)
+    end
+  end
+
+  newproperty(:arguments) do
+    desc "Any arguments or flags that should be passed to the command. Multiple arguments
+      should be specified as a space-separated string."
+  end
+
+  newproperty(:user) do
+    desc "The user to run the scheduled task as.  Please note that not
+      all security configurations will allow running a scheduled task
+      as 'SYSTEM', and saving the scheduled task under these
+      conditions will fail with a reported error of 'The operation
+      completed successfully'.  It is recommended that you either
+      choose another user to run the scheduled task, or alter the
+      security policy to allow v1 scheduled tasks to run as the
+      'SYSTEM' account.  Defaults to 'SYSTEM'.
+
+      Please also note that Puppet must be running as a privileged user
+      in order to manage `scheduled_task` resources. Running as an
+      unprivileged user will result in 'access denied' errors."
+
+    defaultto :system
+
+    def insync?(current)
+      provider.user_insync?(current, @should)
+    end
+  end
+
+  newparam(:password) do
+    desc "The password for the user specified in the 'user' attribute.
+      This is only used if specifying a user other than 'SYSTEM'.
+      Since there is no way to retrieve the password used to set the
+      account information for a task, this parameter will not be used
+      to determine if a scheduled task is in sync or not."
+  end
+
+  newproperty(:trigger, :array_matching => :all) do
+    desc <<-'EOT'
+      One or more triggers defining when the task should run. A single trigger is
+      represented as a hash, and multiple triggers can be specified with an array of
+      hashes.
+
+      A trigger can contain the following keys:
+
+      * For all triggers:
+          * `schedule` **(Required)** --- What kind of trigger this is.
+            Valid values are `daily`, `weekly`, `monthly`, or `once`. Each kind
+            of trigger is configured with a different set of keys; see the
+            sections below. (`once` triggers only need a start time/date.)
+          * `start_time` **(Required)** --- The time of day when the trigger should
+            first become active. Several time formats will work, but we
+            suggest 24-hour time formatted as HH:MM.
+          * `start_date` ---  The date when the trigger should first become active.
+            Defaults to the current date. You should format dates as YYYY-MM-DD,
+            although other date formats may work. (Under the hood, this uses `Date.parse`.)
+          * `minutes_interval` --- The repeat interval in minutes.
+          * `minutes_duration` --- The duration in minutes, needs to be greater than the
+            minutes_interval.
+      * For `daily` triggers:
+          * `every` --- How often the task should run, as a number of days. Defaults
+            to 1. ("2" means every other day, "3" means every three days, etc.)
+      * For `weekly` triggers:
+          * `every` --- How often the task should run, as a number of weeks. Defaults
+            to 1. ("2" means every other week, "3" means every three weeks, etc.)
+          * `day_of_week` --- Which days of the week the task should run, as an array.
+            Defaults to all days. Each day must be one of `mon`, `tues`,
+            `wed`, `thurs`, `fri`, `sat`, `sun`, or `all`.
+      * For `monthly` (by date) triggers:
+          * `months` --- Which months the task should run, as an array. Defaults to
+            all months. Each month must be an integer between 1 and 12.
+          * `on` **(Required)** --- Which days of the month the task should run,
+            as an array. Each day must beeither an integer between 1 and 31,
+            or the special value `last,` which is always the last day of the month.
+      * For `monthly` (by weekday) triggers:
+          * `months` --- Which months the task should run, as an array. Defaults to
+            all months. Each month must be an integer between 1 and 12.
+          * `day_of_week` **(Required)** --- Which day of the week the task should
+            run, as an array with only one element. Each day must be one of `mon`,
+            `tues`, `wed`, `thurs`, `fri`, `sat`, `sun`, or `all`.
+          * `which_occurrence` **(Required)** --- The occurrence of the chosen weekday
+            when the task should run. Must be one of `first`, `second`, `third`,
+            `fourth`, `fifth`, or `last`.
+
+
+      Examples:
+
+          # Run at 8am on the 1st, 15th, and last day of the month in January, March,
+          # May, July, September, and November, starting after August 31st, 2011.
+          trigger => {
+            schedule   => monthly,
+            start_date => '2011-08-31',   # Defaults to current date
+            start_time => '08:00',        # Must be specified
+            months     => [1,3,5,7,9,11], # Defaults to all
+            on         => [1, 15, last],  # Must be specified
+          }
+
+          # Run at 8am on the first Monday of the month for January, March, and May,
+          # starting after August 31st, 2011.
+          trigger => {
+            schedule         => monthly,
+            start_date       => '2011-08-31', # Defaults to current date
+            start_time       => '08:00',      # Must be specified
+            months           => [1,3,5],      # Defaults to all
+            which_occurrence => first,        # Must be specified
+            day_of_week      => [mon],        # Must be specified
+          }
+
+          # Run daily repeating every 30 minutes between 9am and 5pm (480 minutes) starting after August 31st, 2011.
+          trigger => {
+            schedule         => daily,
+            start_date       => '2011-08-31', # Defaults to current date
+            start_time       => '8:00',       # Must be specified
+            minutes_interval => 30,
+            minutes_duration => 480,
+          }
+
+    EOT
+
+    validate do |value|
+      provider.validate_trigger(value)
+    end
+
+    def insync?(current)
+      provider.trigger_insync?(current, @should)
+    end
+
+    def should_to_s(new_value=@should)
+      self.class.format_value_for_display(new_value)
+    end
+
+    def is_to_s(current_value=@is)
+      self.class.format_value_for_display(current_value)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/selboolean.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/selboolean.rb
new file mode 100644
index 0000000..eb30742
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/selboolean.rb
@@ -0,0 +1,26 @@
+module Puppet
+  newtype(:selboolean) do
+    @doc = "Manages SELinux booleans on systems with SELinux support.  The supported booleans
+      are any of the ones found in `/selinux/booleans/`."
+
+    newparam(:name) do
+      desc "The name of the SELinux boolean to be managed."
+      isnamevar
+    end
+
+    newproperty(:value) do
+      desc "Whether the SELinux boolean should be enabled or disabled."
+      newvalue(:on)
+      newvalue(:off)
+    end
+
+    newparam(:persistent) do
+      desc "If set true, SELinux booleans will be written to disk and persist accross reboots.
+        The default is `false`."
+
+      defaultto :false
+      newvalues(:true, :false)
+    end
+
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/selmodule.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/selmodule.rb
new file mode 100644
index 0000000..23bf235
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/selmodule.rb
@@ -0,0 +1,59 @@
+#
+# Simple module for managing SELinux policy modules
+#
+
+Puppet::Type.newtype(:selmodule) do
+  @doc = "Manages loading and unloading of SELinux policy modules
+    on the system.  Requires SELinux support.  See man semodule(8)
+    for more information on SELinux policy modules.
+
+    **Autorequires:** If Puppet is managing the file containing this SELinux
+    policy module (which is either explicitly specified in the `selmodulepath`
+    attribute or will be found at {`selmoduledir`}/{`name`}.pp), the selmodule
+    resource will autorequire that file."
+
+  ensurable
+
+  newparam(:name) do
+    desc "The name of the SELinux policy to be managed.  You should not
+      include the customary trailing .pp extension."
+    isnamevar
+  end
+
+  newparam(:selmoduledir) do
+
+    desc "The directory to look for the compiled pp module file in.
+      Currently defaults to `/usr/share/selinux/targeted`.  If the
+      `selmodulepath` attribute is not specified, Puppet will expect to find
+      the module in `<selmoduledir>/<name>.pp`, where `name` is the value of the
+      `name` parameter."
+
+    defaultto "/usr/share/selinux/targeted"
+  end
+
+  newparam(:selmodulepath) do
+
+    desc "The full path to the compiled .pp policy module.  You only need to use
+      this if the module file is not in the `selmoduledir` directory."
+
+  end
+
+  newproperty(:syncversion) do
+
+    desc "If set to `true`, the policy will be reloaded if the
+    version found in the on-disk file differs from the loaded
+    version.  If set to `false` (the default) the only check
+    that will be made is if the policy is loaded at all or not."
+
+    newvalue(:true)
+    newvalue(:false)
+  end
+
+  autorequire(:file) do
+    if self[:selmodulepath]
+      [self[:selmodulepath]]
+    else
+      ["#{self[:selmoduledir]}/#{self[:name]}.pp"]
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/service.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/service.rb
new file mode 100644
index 0000000..dc54f1d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/service.rb
@@ -0,0 +1,234 @@
+# This is our main way of managing processes right now.
+#
+# a service is distinct from a process in that services
+# can only be managed through the interface of an init script
+# which is why they have a search path for initscripts and such
+
+
+module Puppet
+
+  newtype(:service) do
+    @doc = "Manage running services.  Service support unfortunately varies
+      widely by platform --- some platforms have very little if any concept of a
+      running service, and some have a very codified and powerful concept.
+      Puppet's service support is usually capable of doing the right thing, but
+      the more information you can provide, the better behaviour you will get.
+
+      Puppet 2.7 and newer expect init scripts to have a working status command.
+      If this isn't the case for any of your services' init scripts, you will
+      need to set `hasstatus` to false and possibly specify a custom status
+      command in the `status` attribute. As a last resort, Puppet will attempt to
+      search the process table by calling whatever command is listed in the `ps`
+      fact. The default search pattern is the name of the service, but you can
+      specify it with the `pattern` attribute.
+
+      **Refresh:** `service` resources can respond to refresh events (via
+      `notify`, `subscribe`, or the `~>` arrow). If a `service` receives an
+      event from another resource, Puppet will restart the service it manages.
+      The actual command used to restart the service depends on the platform and
+      can be configured:
+
+      * If you set `hasrestart` to true, Puppet will use the init script's restart command.
+      * You can provide an explicit command for restarting with the `restart` attribute.
+      * If you do neither, the service's stop and start commands will be used."
+
+    feature :refreshable, "The provider can restart the service.",
+      :methods => [:restart]
+
+    feature :enableable, "The provider can enable and disable the service",
+      :methods => [:disable, :enable, :enabled?]
+
+    feature :controllable, "The provider uses a control variable."
+
+    feature :flaggable, "The provider can pass flags to the service."
+
+    newproperty(:enable, :required_features => :enableable) do
+      desc "Whether a service should be enabled to start at boot.
+        This property behaves quite differently depending on the platform;
+        wherever possible, it relies on local tools to enable or disable
+        a given service."
+
+      newvalue(:true, :event => :service_enabled) do
+        provider.enable
+      end
+
+      newvalue(:false, :event => :service_disabled) do
+        provider.disable
+      end
+
+      newvalue(:manual, :event => :service_manual_start) do
+        provider.manual_start
+      end
+
+      def retrieve
+        provider.enabled?
+      end
+
+      validate do |value|
+        if value == :manual and !Puppet.features.microsoft_windows?
+          raise Puppet::Error.new("Setting enable to manual is only supported on Microsoft Windows.")
+        end
+      end
+    end
+
+    # Handle whether the service should actually be running right now.
+    newproperty(:ensure) do
+      desc "Whether a service should be running."
+
+      newvalue(:stopped, :event => :service_stopped) do
+        provider.stop
+      end
+
+      newvalue(:running, :event => :service_started, :invalidate_refreshes => true) do
+        provider.start
+      end
+
+      aliasvalue(:false, :stopped)
+      aliasvalue(:true, :running)
+
+      def retrieve
+        provider.status
+      end
+
+      def sync
+        event = super()
+
+        if property = @resource.property(:enable)
+          val = property.retrieve
+          property.sync unless property.safe_insync?(val)
+        end
+
+        event
+      end
+    end
+
+    newproperty(:flags, :required_features => :flaggable) do
+      desc "Specify a string of flags to pass to the startup script."
+    end
+
+    newparam(:binary) do
+      desc "The path to the daemon.  This is only used for
+        systems that do not support init scripts.  This binary will be
+        used to start the service if no `start` parameter is
+        provided."
+    end
+
+    newparam(:hasstatus) do
+      desc "Declare whether the service's init script has a functional status
+        command; defaults to `true`. This attribute's default value changed in
+        Puppet 2.7.0.
+
+        The init script's status command must return 0 if the service is
+        running and a nonzero value otherwise. Ideally, these exit codes
+        should conform to [the LSB's specification][lsb-exit-codes] for init
+        script status actions, but Puppet only considers the difference
+        between 0 and nonzero to be relevant.
+
+        If a service's init script does not support any kind of status command,
+        you should set `hasstatus` to false and either provide a specific
+        command using the `status` attribute or expect that Puppet will look for
+        the service name in the process table. Be aware that 'virtual' init
+        scripts (like 'network' under Red Hat systems) will respond poorly to
+        refresh events from other resources if you override the default behavior
+        without providing a status command."
+
+      newvalues(:true, :false)
+
+      defaultto :true
+    end
+    newparam(:name) do
+      desc <<-EOT
+        The name of the service to run.
+
+        This name is used to find the service; on platforms where services
+        have short system names and long display names, this should be the
+        short name. (To take an example from Windows, you would use "wuauserv"
+        rather than "Automatic Updates.")
+      EOT
+      isnamevar
+    end
+
+    newparam(:path) do
+      desc "The search path for finding init scripts.  Multiple values should
+        be separated by colons or provided as an array."
+
+      munge do |value|
+        value = [value] unless value.is_a?(Array)
+        value.flatten.collect { |p| p.split(File::PATH_SEPARATOR) }.flatten
+      end
+
+      defaultto { provider.class.defpath if provider.class.respond_to?(:defpath) }
+    end
+    newparam(:pattern) do
+      desc "The pattern to search for in the process table.
+        This is used for stopping services on platforms that do not
+        support init scripts, and is also used for determining service
+        status on those service whose init scripts do not include a status
+        command.
+
+        Defaults to the name of the service. The pattern can be a simple string
+        or any legal Ruby pattern, including regular expressions (which should
+        be quoted without enclosing slashes)."
+
+      defaultto { @resource[:binary] || @resource[:name] }
+    end
+    newparam(:restart) do
+      desc "Specify a *restart* command manually.  If left
+        unspecified, the service will be stopped and then started."
+    end
+    newparam(:start) do
+      desc "Specify a *start* command manually.  Most service subsystems
+        support a `start` command, so this will not need to be
+        specified."
+    end
+    newparam(:status) do
+      desc "Specify a *status* command manually.  This command must
+        return 0 if the service is running and a nonzero value otherwise.
+        Ideally, these exit codes should conform to [the LSB's
+        specification][lsb-exit-codes] for init script status actions, but
+        Puppet only considers the difference between 0 and nonzero to be
+        relevant.
+
+        If left unspecified, the status of the service will be determined
+        automatically, usually by looking for the service in the process
+        table.
+
+        [lsb-exit-codes]: http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html"
+    end
+
+    newparam(:stop) do
+      desc "Specify a *stop* command manually."
+    end
+
+    newparam(:control) do
+      desc "The control variable used to manage services (originally for HP-UX).
+        Defaults to the upcased service name plus `START` replacing dots with
+        underscores, for those providers that support the `controllable` feature."
+      defaultto { resource.name.gsub(".","_").upcase + "_START" if resource.provider.controllable? }
+    end
+
+    newparam :hasrestart do
+      desc "Specify that an init script has a `restart` command.  If this is
+        false and you do not specify a command in the `restart` attribute,
+        the init script's `stop` and `start` commands will be used.
+
+        Defaults to false."
+      newvalues(:true, :false)
+    end
+
+    newparam(:manifest) do
+      desc "Specify a command to config a service, or a path to a manifest to do so."
+    end
+
+    # Basically just a synonym for restarting.  Used to respond
+    # to events.
+    def refresh
+      # Only restart if we're actually running
+      if (@parameters[:ensure] || newattr(:ensure)).retrieve == :running
+        provider.restart
+      else
+        debug "Skipping restart; service is not running"
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/ssh_authorized_key.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/ssh_authorized_key.rb
new file mode 100644
index 0000000..8b40907
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/ssh_authorized_key.rb
@@ -0,0 +1,153 @@
+module Puppet
+  newtype(:ssh_authorized_key) do
+    @doc = "Manages SSH authorized keys. Currently only type 2 keys are supported.
+
+      In their native habitat, SSH keys usually appear as a single long line. This
+      resource type requires you to split that line into several attributes. Thus, a
+      key that appears in your `~/.ssh/id_rsa.pub` file like this...
+
+          ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAy5mtOAMHwA2ZAIfW6Ap70r+I4EclYHEec5xIN59ROUjss23Skb1OtjzYpVPaPH8mSdSmsN0JHaBLiRcu7stl4O8D8zA4mz/vw32yyQ/Kqaxw8l0K76k6t2hKOGqLTY4aFbFISV6GDh7MYLn8KU7cGp96J+caO5R5TqtsStytsUhSyqH+iIDh4e4+BrwTc6V4Y0hgFxaZV5d18mLA4EPYKeG5+zyBCVu+jueYwFqM55E0tHbfiaIN9IzdLV+7NEEfdLkp6w2baLKPqWUBmuvPF1Mn3FwaFLjVsMT3GQeMue6b3FtUdTDeyAYoTxrsRo/WnDkS6Pa3YhrFwjtUqXfdaQ== nick@magpie.puppetlabs.lan
+
+      ...would translate to the following resource:
+
+          ssh_authorized_key { 'nick@magpie.puppetlabs.lan':
+            user => 'nick',
+            type => 'ssh-rsa',
+            key  => 'AAAAB3NzaC1yc2EAAAABIwAAAQEAy5mtOAMHwA2ZAIfW6Ap70r+I4EclYHEec5xIN59ROUjss23Skb1OtjzYpVPaPH8mSdSmsN0JHaBLiRcu7stl4O8D8zA4mz/vw32yyQ/Kqaxw8l0K76k6t2hKOGqLTY4aFbFISV6GDh7MYLn8KU7cGp96J+caO5R5TqtsStytsUhSyqH+iIDh4e4+BrwTc6V4Y0hgFxaZV5d18mLA4EPYKeG5+zyBCVu+jueYwFqM55E0tHbfiaIN9IzdLV+7NEEfdLkp6w2baLKPqWUBmuvPF1Mn3FwaFLjVsMT3GQeMue6b3FtUdTDeyAYoTxrsRo/WnDkS6Pa3YhrFwjtUqXfdaQ==',
+          }
+
+      To ensure that only the currently approved keys are present, you can purge
+      unmanaged SSH keys on a per-user basis. Do this with the `user` resource
+      type's `purge_ssh_keys` attribute:
+
+          user { 'nick':
+            ensure         => present,
+            purge_ssh_keys => true,
+          }
+
+      This will remove any keys in `~/.ssh/authorized_keys` that aren't being
+      managed with `ssh_authorized_key` resources. See the documentation of the
+      `user` type for more details.
+
+      **Autorequires:** If Puppet is managing the user account in which this
+      SSH key should be installed, the `ssh_authorized_key` resource will autorequire
+      that user."
+
+    ensurable
+
+    newparam(:name) do
+      desc "The SSH key comment. This attribute is currently used as a
+        system-wide primary key and therefore has to be unique."
+
+      isnamevar
+
+    end
+
+    newproperty(:type) do
+      desc "The encryption type used."
+
+      newvalues :'ssh-dss', :'ssh-rsa', :'ecdsa-sha2-nistp256', :'ecdsa-sha2-nistp384', :'ecdsa-sha2-nistp521', :'ssh-ed25519'
+
+      aliasvalue(:dsa, :'ssh-dss')
+      aliasvalue(:ed25519, :'ssh-ed25519')
+      aliasvalue(:rsa, :'ssh-rsa')
+    end
+
+    newproperty(:key) do
+      desc "The public key itself; generally a long string of hex characters. The `key`
+        attribute may not contain whitespace.
+
+        Make sure to omit the following in this attribute (and specify them in
+        other attributes):
+
+        * Key headers (e.g. 'ssh-rsa') --- put these in the `type` attribute.
+        * Key identifiers / comments (e.g. 'joe@joescomputer.local') --- put these in
+          the `name` attribute/resource title."
+
+      validate do |value|
+        raise Puppet::Error, "Key must not contain whitespace: #{value}" if value =~ /\s/
+      end
+    end
+
+    newproperty(:user) do
+      desc "The user account in which the SSH key should be installed. The resource
+        will autorequire this user if it is being managed as a `user` resource."
+    end
+
+    newproperty(:target) do
+      desc "The absolute filename in which to store the SSH key. This
+        property is optional and should only be used in cases where keys
+        are stored in a non-standard location (i.e.` not in
+        `~user/.ssh/authorized_keys`)."
+
+      defaultto :absent
+
+      def should
+        return super if defined?(@should) and @should[0] != :absent
+
+        return nil unless user = resource[:user]
+
+        begin
+          return File.expand_path("~#{user}/.ssh/authorized_keys")
+        rescue
+          Puppet.debug "The required user is not yet present on the system"
+          return nil
+        end
+      end
+
+      def insync?(is)
+        is == should
+      end
+    end
+
+    newproperty(:options, :array_matching => :all) do
+      desc "Key options; see sshd(8) for possible values. Multiple values
+        should be specified as an array."
+
+      defaultto do :absent end
+
+      def is_to_s(value)
+        if value == :absent or value.include?(:absent)
+          super
+        else
+          value.join(",")
+        end
+      end
+
+      def should_to_s(value)
+        if value == :absent or value.include?(:absent)
+          super
+        else
+          value.join(",")
+        end
+      end
+
+      validate do |value|
+        unless value == :absent or value =~ /^[-a-z0-9A-Z_]+(?:=\".*?\")?$/
+          raise Puppet::Error, "Option #{value} is not valid. A single option must either be of the form 'option' or 'option=\"value\". Multiple options must be provided as an array"
+        end
+      end
+    end
+
+    autorequire(:user) do
+      should(:user) if should(:user)
+    end
+
+    validate do
+      # Go ahead if target attribute is defined
+      return if @parameters[:target].shouldorig[0] != :absent
+
+      # Go ahead if user attribute is defined
+      return if @parameters.include?(:user)
+
+      # If neither target nor user is defined, this is an error
+      raise Puppet::Error, "Attribute 'user' or 'target' is mandatory"
+    end
+
+    # regular expression suitable for use by a ParsedFile based provider
+    REGEX = /^(?:(.+) )?(ssh-dss|ssh-ed25519|ssh-rsa|ecdsa-sha2-nistp256|ecdsa-sha2-nistp384|ecdsa-sha2-nistp521) ([^ ]+) ?(.*)$/
+    def self.keyline_regex
+      REGEX
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/sshkey.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/sshkey.rb
new file mode 100644
index 0000000..2a3d5fe
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/sshkey.rb
@@ -0,0 +1,73 @@
+module Puppet
+  newtype(:sshkey) do
+    @doc = "Installs and manages ssh host keys.  At this point, this type
+      only knows how to install keys into `/etc/ssh/ssh_known_hosts`.  See
+      the `ssh_authorized_key` type to manage authorized keys."
+
+    ensurable
+
+    newproperty(:type) do
+      desc "The encryption type used.  Probably ssh-dss or ssh-rsa."
+
+      newvalues :'ssh-dss', :'ssh-ed25519', :'ssh-rsa', :'ecdsa-sha2-nistp256', :'ecdsa-sha2-nistp384', :'ecdsa-sha2-nistp521'
+
+      aliasvalue(:dsa, :'ssh-dss')
+      aliasvalue(:ed25519, :'ssh-ed25519')
+      aliasvalue(:rsa, :'ssh-rsa')
+    end
+
+    newproperty(:key) do
+      desc "The key itself; generally a long string of uuencoded characters."
+    end
+
+    # FIXME This should automagically check for aliases to the hosts, just
+    # to see if we can automatically glean any aliases.
+    newproperty(:host_aliases) do
+      desc 'Any aliases the host might have.  Multiple values must be
+        specified as an array.'
+
+      attr_accessor :meta
+
+      def insync?(is)
+        is == @should
+      end
+      # We actually want to return the whole array here, not just the first
+      # value.
+      def should
+        defined?(@should) ? @should : nil
+      end
+
+      validate do |value|
+        if value =~ /\s/
+          raise Puppet::Error, "Aliases cannot include whitespace"
+        end
+        if value =~ /,/
+          raise Puppet::Error, "Aliases must be provided as an array, not a comma-separated list"
+        end
+      end
+    end
+
+    newparam(:name) do
+      desc "The host name that the key is associated with."
+
+      isnamevar
+
+      validate do |value|
+        raise Puppet::Error, "Resourcename cannot include whitespaces" if value =~ /\s/
+        raise Puppet::Error, "No comma in resourcename allowed. If you want to specify aliases use the host_aliases property" if value.include?(',')
+      end
+    end
+
+    newproperty(:target) do
+      desc "The file in which to store the ssh key.  Only used by
+        the `parsed` provider."
+
+      defaultto { if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile)
+        @resource.class.defaultprovider.default_target
+        else
+          nil
+        end
+      }
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/stage.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/stage.rb
new file mode 100644
index 0000000..46b66ed
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/stage.rb
@@ -0,0 +1,27 @@
+Puppet::Type.newtype(:stage) do
+  desc "A resource type for creating new run stages.  Once a stage is available,
+    classes can be assigned to it by declaring them with the resource-like syntax
+    and using
+    [the `stage` metaparameter](http://docs.puppetlabs.com/references/latest/metaparameter.html#stage).
+
+    Note that new stages are not useful unless you also declare their order
+    in relation to the default `main` stage.
+
+    A complete run stage example:
+
+        stage { 'pre':
+          before => Stage['main'],
+        }
+
+        class { 'apt-updates':
+          stage => 'pre',
+        }
+
+    Individual resources cannot be assigned to run stages; you can only set stages
+    for classes."
+
+  newparam :name do
+    desc "The name of the stage. Use this as the value for the `stage` metaparameter
+      when assigning classes to this stage."
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/tidy.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/tidy.rb
new file mode 100644
index 0000000..aecb1e6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/tidy.rb
@@ -0,0 +1,324 @@
+require 'puppet/parameter/boolean'
+
+Puppet::Type.newtype(:tidy) do
+  require 'puppet/file_serving/fileset'
+  require 'puppet/file_bucket/dipper'
+
+  @doc = "Remove unwanted files based on specific criteria.  Multiple
+    criteria are OR'd together, so a file that is too large but is not
+    old enough will still get tidied.
+
+    If you don't specify either `age` or `size`, then all files will
+    be removed.
+
+    This resource type works by generating a file resource for every file
+    that should be deleted and then letting that resource perform the
+    actual deletion.
+    "
+
+  newparam(:path) do
+    desc "The path to the file or directory to manage.  Must be fully
+      qualified."
+    isnamevar
+  end
+
+  newparam(:recurse) do
+    desc "If target is a directory, recursively descend
+      into the directory looking for files to tidy."
+
+    newvalues(:true, :false, :inf, /^[0-9]+$/)
+
+    # Replace the validation so that we allow numbers in
+    # addition to string representations of them.
+    validate { |arg| }
+    munge do |value|
+      newval = super(value)
+      case newval
+      when :true, :inf; true
+      when :false; false
+      when Integer, Fixnum, Bignum; value
+      when /^\d+$/; Integer(value)
+      else
+        raise ArgumentError, "Invalid recurse value #{value.inspect}"
+      end
+    end
+  end
+
+  newparam(:matches) do
+    desc <<-'EOT'
+      One or more (shell type) file glob patterns, which restrict
+      the list of files to be tidied to those whose basenames match
+      at least one of the patterns specified. Multiple patterns can
+      be specified using an array.
+
+      Example:
+
+          tidy { "/tmp":
+            age     => "1w",
+            recurse => 1,
+            matches => [ "[0-9]pub*.tmp", "*.temp", "tmpfile?" ]
+          }
+
+      This removes files from `/tmp` if they are one week old or older,
+      are not in a subdirectory and match one of the shell globs given.
+
+      Note that the patterns are matched against the basename of each
+      file -- that is, your glob patterns should not have any '/'
+      characters in them, since you are only specifying against the last
+      bit of the file.
+
+      Finally, note that you must now specify a non-zero/non-false value
+      for recurse if matches is used, as matches only apply to files found
+      by recursion (there's no reason to use static patterns match against
+      a statically determined path).  Requiering explicit recursion clears
+      up a common source of confusion.
+    EOT
+
+    # Make sure we convert to an array.
+    munge do |value|
+      fail "Tidy can't use matches with recurse 0, false, or undef" if "#{@resource[:recurse]}" =~ /^(0|false|)$/
+      [value].flatten
+    end
+
+    # Does a given path match our glob patterns, if any?  Return true
+    # if no patterns have been provided.
+    def tidy?(path, stat)
+      basename = File.basename(path)
+      flags = File::FNM_DOTMATCH | File::FNM_PATHNAME
+      return(value.find {|pattern| File.fnmatch(pattern, basename, flags) } ? true : false)
+    end
+  end
+
+  newparam(:backup) do
+    desc "Whether tidied files should be backed up.  Any values are passed
+      directly to the file resources used for actual file deletion, so consult
+      the `file` type's backup documentation to determine valid values."
+  end
+
+  newparam(:age) do
+    desc "Tidy files whose age is equal to or greater than
+      the specified time.  You can choose seconds, minutes,
+      hours, days, or weeks by specifying the first letter of any
+      of those words (e.g., '1w').
+
+      Specifying 0 will remove all files."
+
+    AgeConvertors = {
+      :s => 1,
+      :m => 60,
+      :h => 60 * 60,
+      :d => 60 * 60 * 24,
+      :w => 60 * 60 * 24 * 7,
+    }
+
+    def convert(unit, multi)
+      if num = AgeConvertors[unit]
+        return num * multi
+      else
+        self.fail "Invalid age unit '#{unit}'"
+      end
+    end
+
+    def tidy?(path, stat)
+      # If the file's older than we allow, we should get rid of it.
+      (Time.now.to_i - stat.send(resource[:type]).to_i) > value
+    end
+
+    munge do |age|
+      unit = multi = nil
+      case age
+      when /^([0-9]+)(\w)\w*$/
+        multi = Integer($1)
+        unit = $2.downcase.intern
+      when /^([0-9]+)$/
+        multi = Integer($1)
+        unit = :d
+      else
+        self.fail "Invalid tidy age #{age}"
+      end
+
+      convert(unit, multi)
+    end
+  end
+
+  newparam(:size) do
+    desc "Tidy files whose size is equal to or greater than
+      the specified size.  Unqualified values are in kilobytes, but
+      *b*, *k*, *m*, *g*, and *t* can be appended to specify *bytes*,
+      *kilobytes*, *megabytes*, *gigabytes*, and *terabytes*, respectively.
+      Only the first character is significant, so the full word can also
+      be used."
+
+    def convert(unit, multi)
+      if num = { :b => 0, :k => 1, :m => 2, :g => 3, :t => 4 }[unit]
+        result = multi
+        num.times do result *= 1024 end
+        return result
+      else
+        self.fail "Invalid size unit '#{unit}'"
+      end
+    end
+
+    def tidy?(path, stat)
+      stat.size >= value
+    end
+
+    munge do |size|
+      case size
+      when /^([0-9]+)(\w)\w*$/
+        multi = Integer($1)
+        unit = $2.downcase.intern
+      when /^([0-9]+)$/
+        multi = Integer($1)
+        unit = :k
+      else
+        self.fail "Invalid tidy size #{age}"
+      end
+
+      convert(unit, multi)
+    end
+  end
+
+  newparam(:type) do
+    desc "Set the mechanism for determining age. Default: atime."
+
+    newvalues(:atime, :mtime, :ctime)
+
+    defaultto :atime
+  end
+
+  newparam(:rmdirs, :boolean => true, :parent => Puppet::Parameter::Boolean) do
+    desc "Tidy directories in addition to files; that is, remove
+      directories whose age is older than the specified criteria.
+      This will only remove empty directories, so all contained
+      files must also be tidied before a directory gets removed."
+  end
+
+  # Erase PFile's validate method
+  validate do
+  end
+
+  def self.instances
+    []
+  end
+
+  def depthfirst?
+    true
+  end
+
+  def initialize(hash)
+    super
+
+    # only allow backing up into filebuckets
+    self[:backup] = false unless self[:backup].is_a? Puppet::FileBucket::Dipper
+  end
+
+  # Make a file resource to remove a given file.
+  def mkfile(path)
+    # Force deletion, so directories actually get deleted.
+    Puppet::Type.type(:file).new :path => path, :backup => self[:backup], :ensure => :absent, :force => true
+  end
+
+  def retrieve
+    # Our ensure property knows how to retrieve everything for us.
+    if obj = @parameters[:ensure]
+      return obj.retrieve
+    else
+      return {}
+    end
+  end
+
+  # Hack things a bit so we only ever check the ensure property.
+  def properties
+    []
+  end
+
+  def generate
+    return [] unless stat(self[:path])
+
+    case self[:recurse]
+    when Integer, Fixnum, Bignum, /^\d+$/
+      parameter = { :recurse => true, :recurselimit => self[:recurse] }
+    when true, :true, :inf
+      parameter = { :recurse => true }
+    end
+
+    if parameter
+      files = Puppet::FileServing::Fileset.new(self[:path], parameter).files.collect do |f|
+        f == "." ? self[:path] : ::File.join(self[:path], f)
+      end
+    else
+      files = [self[:path]]
+    end
+    result = files.find_all { |path| tidy?(path) }.collect { |path| mkfile(path) }.each { |file| notice "Tidying #{file.ref}" }.sort { |a,b| b[:path] <=> a[:path] }
+
+    # No need to worry about relationships if we don't have rmdirs; there won't be
+    # any directories.
+    return result unless rmdirs?
+
+    # Now make sure that all directories require the files they contain, if all are available,
+    # so that a directory is emptied before we try to remove it.
+    files_by_name = result.inject({}) { |hash, file| hash[file[:path]] = file; hash }
+
+    files_by_name.keys.sort { |a,b| b <=> b }.each do |path|
+      dir = ::File.dirname(path)
+      next unless resource = files_by_name[dir]
+      if resource[:require]
+        resource[:require] << Puppet::Resource.new(:file, path)
+      else
+        resource[:require] = [Puppet::Resource.new(:file, path)]
+      end
+    end
+
+    result
+  end
+
+  # Does a given path match our glob patterns, if any?  Return true
+  # if no patterns have been provided.
+  def matches?(path)
+    return true unless self[:matches]
+
+    basename = File.basename(path)
+    flags = File::FNM_DOTMATCH | File::FNM_PATHNAME
+    if self[:matches].find {|pattern| File.fnmatch(pattern, basename, flags) }
+      return true
+    else
+      debug "No specified patterns match #{path}, not tidying"
+      return false
+    end
+  end
+
+  # Should we remove the specified file?
+  def tidy?(path)
+    return false unless stat = self.stat(path)
+
+    return false if stat.ftype == "directory" and ! rmdirs?
+
+    # The 'matches' parameter isn't OR'ed with the other tests --
+    # it's just used to reduce the list of files we can match.
+    return false if param = parameter(:matches) and ! param.tidy?(path, stat)
+
+    tested = false
+    [:age, :size].each do |name|
+      next unless param = parameter(name)
+      tested = true
+      return true if param.tidy?(path, stat)
+    end
+
+    # If they don't specify either, then the file should always be removed.
+    return true unless tested
+    false
+  end
+
+  def stat(path)
+    begin
+      Puppet::FileSystem.lstat(path)
+    rescue Errno::ENOENT => error
+      info "File does not exist"
+      return nil
+    rescue Errno::EACCES => error
+      warning "Could not stat; permission denied"
+      return nil
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/user.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/user.rb
new file mode 100644
index 0000000..0df5978
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/user.rb
@@ -0,0 +1,700 @@
+require 'etc'
+require 'facter'
+require 'puppet/parameter/boolean'
+require 'puppet/property/list'
+require 'puppet/property/ordered_list'
+require 'puppet/property/keyvalue'
+
+module Puppet
+  newtype(:user) do
+    @doc = "Manage users.  This type is mostly built to manage system
+      users, so it is lacking some features useful for managing normal
+      users.
+
+      This resource type uses the prescribed native tools for creating
+      groups and generally uses POSIX APIs for retrieving information
+      about them.  It does not directly modify `/etc/passwd` or anything.
+
+      **Autorequires:** If Puppet is managing the user's primary group (as
+      provided in the `gid` attribute), the user resource will autorequire
+      that group. If Puppet is managing any role accounts corresponding to the
+      user's roles, the user resource will autorequire those role accounts."
+
+    feature :allows_duplicates,
+      "The provider supports duplicate users with the same UID."
+
+    feature :manages_homedir,
+      "The provider can create and remove home directories."
+
+    feature :manages_passwords,
+      "The provider can modify user passwords, by accepting a password
+      hash."
+
+    feature :manages_password_age,
+      "The provider can set age requirements and restrictions for
+      passwords."
+
+    feature :manages_password_salt,
+      "The provider can set a password salt. This is for providers that
+       implement PBKDF2 passwords with salt properties."
+
+    feature :manages_solaris_rbac,
+      "The provider can manage roles and normal users"
+
+    feature :manages_expiry,
+      "The provider can manage the expiry date for a user."
+
+   feature :system_users,
+     "The provider allows you to create system users with lower UIDs."
+
+    feature :manages_aix_lam,
+      "The provider can manage AIX Loadable Authentication Module (LAM) system."
+
+    feature :libuser,
+      "Allows local users to be managed on systems that also use some other
+       remote NSS method of managing accounts."
+
+    feature :manages_shell,
+      "The provider allows for setting shell and validates if possible"
+
+    newproperty(:ensure, :parent => Puppet::Property::Ensure) do
+      newvalue(:present, :event => :user_created) do
+        provider.create
+      end
+
+      newvalue(:absent, :event => :user_removed) do
+        provider.delete
+      end
+
+      newvalue(:role, :event => :role_created, :required_features => :manages_solaris_rbac) do
+        provider.create_role
+      end
+
+      desc "The basic state that the object should be in."
+
+      # If they're talking about the thing at all, they generally want to
+      # say it should exist.
+      defaultto do
+        if @resource.managed?
+          :present
+        else
+          nil
+        end
+      end
+
+      def retrieve
+        if provider.exists?
+          if provider.respond_to?(:is_role?) and provider.is_role?
+            return :role
+          else
+            return :present
+          end
+        else
+          return :absent
+        end
+      end
+    end
+
+    newproperty(:home) do
+      desc "The home directory of the user.  The directory must be created
+        separately and is not currently checked for existence."
+    end
+
+    newproperty(:uid) do
+      desc "The user ID; must be specified numerically. If no user ID is
+        specified when creating a new user, then one will be chosen
+        automatically. This will likely result in the same user having
+        different UIDs on different systems, which is not recommended. This is
+        especially noteworthy when managing the same user on both Darwin and
+        other platforms, since Puppet does UID generation on Darwin, but
+        the underlying tools do so on other platforms.
+
+        On Windows, this property is read-only and will return the user's
+        security identifier (SID)."
+
+      munge do |value|
+        case value
+        when String
+          if value =~ /^[-0-9]+$/
+            value = Integer(value)
+          end
+        end
+
+        return value
+      end
+    end
+
+    newproperty(:gid) do
+      desc "The user's primary group.  Can be specified numerically or by name.
+
+        This attribute is not supported on Windows systems; use the `groups`
+        attribute instead. (On Windows, designating a primary group is only
+        meaningful for domain accounts, which Puppet does not currently manage.)"
+
+      munge do |value|
+        if value.is_a?(String) and value =~ /^[-0-9]+$/
+          Integer(value)
+        else
+          value
+        end
+      end
+
+      def insync?(is)
+        # We know the 'is' is a number, so we need to convert the 'should' to a number,
+        # too.
+        @should.each do |value|
+          return true if number = Puppet::Util.gid(value) and is == number
+        end
+
+        false
+      end
+
+      def sync
+        found = false
+        @should.each do |value|
+          if number = Puppet::Util.gid(value)
+            provider.gid = number
+            found = true
+            break
+          end
+        end
+
+        fail "Could not find group(s) #{@should.join(",")}" unless found
+
+        # Use the default event.
+      end
+    end
+
+    newproperty(:comment) do
+      desc "A description of the user.  Generally the user's full name."
+      if RUBY_VERSION < "2.1.0"
+        munge do |v|
+          v.respond_to?(:force_encoding) ? v.force_encoding(Encoding::ASCII_8BIT) : v
+        end
+      end
+    end
+
+    newproperty(:shell, :required_features => :manages_shell) do
+      desc "The user's login shell.  The shell must exist and be
+        executable.
+
+        This attribute cannot be managed on Windows systems."
+    end
+
+    newproperty(:password, :required_features => :manages_passwords) do
+      desc %q{The user's password, in whatever encrypted format the local
+        system requires.
+
+        * Most modern Unix-like systems use salted SHA1 password hashes. You can use
+          Puppet's built-in `sha1` function to generate a hash from a password.
+        * Mac OS X 10.5 and 10.6 also use salted SHA1 hashes.
+        * Mac OS X 10.7 (Lion) uses salted SHA512 hashes. The Puppet Labs [stdlib][]
+          module contains a `str2saltedsha512` function which can generate password
+          hashes for Lion.
+        * Mac OS X 10.8 and higher use salted SHA512 PBKDF2 hashes. When
+          managing passwords on these systems the salt and iterations properties
+          need to be specified as well as the password.
+        * Windows passwords can only be managed in cleartext, as there is no Windows API
+          for setting the password hash.
+
+        [stdlib]: https://github.com/puppetlabs/puppetlabs-stdlib/
+
+        Be sure to enclose any value that includes a dollar sign ($) in single
+        quotes (') to avoid accidental variable interpolation.}
+
+      validate do |value|
+        raise ArgumentError, "Passwords cannot include ':'" if value.is_a?(String) and value.include?(":")
+      end
+
+      def change_to_s(currentvalue, newvalue)
+        if currentvalue == :absent
+          return "created password"
+        else
+          return "changed password"
+        end
+      end
+
+      def is_to_s( currentvalue )
+        return '[old password hash redacted]'
+      end
+      def should_to_s( newvalue )
+        return '[new password hash redacted]'
+      end
+
+    end
+
+    newproperty(:password_min_age, :required_features => :manages_password_age) do
+      desc "The minimum number of days a password must be used before it may be changed."
+
+      munge do |value|
+        case value
+        when String
+          Integer(value)
+        else
+          value
+        end
+      end
+
+      validate do |value|
+        if value.to_s !~ /^-?\d+$/
+          raise ArgumentError, "Password minimum age must be provided as a number."
+        end
+      end
+    end
+
+    newproperty(:password_max_age, :required_features => :manages_password_age) do
+      desc "The maximum number of days a password may be used before it must be changed."
+
+      munge do |value|
+        case value
+        when String
+          Integer(value)
+        else
+          value
+        end
+      end
+
+      validate do |value|
+        if value.to_s !~ /^-?\d+$/
+          raise ArgumentError, "Password maximum age must be provided as a number."
+        end
+      end
+    end
+
+    newproperty(:groups, :parent => Puppet::Property::List) do
+      desc "The groups to which the user belongs.  The primary group should
+        not be listed, and groups should be identified by name rather than by
+        GID.  Multiple groups should be specified as an array."
+
+      validate do |value|
+        if value =~ /^\d+$/
+          raise ArgumentError, "Group names must be provided, not GID numbers."
+        end
+        raise ArgumentError, "Group names must be provided as an array, not a comma-separated list." if value.include?(",")
+        raise ArgumentError, "Group names must not be empty. If you want to specify \"no groups\" pass an empty array" if value.empty?
+      end
+    end
+
+    newparam(:name) do
+      desc "The user name. While naming limitations vary by operating system,
+        it is advisable to restrict names to the lowest common denominator,
+        which is a maximum of 8 characters beginning with a letter.
+
+        Note that Puppet considers user names to be case-sensitive, regardless
+        of the platform's own rules; be sure to always use the same case when
+        referring to a given user."
+      isnamevar
+    end
+
+    newparam(:membership) do
+      desc "Whether specified groups should be considered the **complete list**
+        (`inclusive`) or the **minimum list** (`minimum`) of groups to which
+        the user belongs. Defaults to `minimum`."
+
+      newvalues(:inclusive, :minimum)
+
+      defaultto :minimum
+    end
+
+    newparam(:system, :boolean => true, :parent => Puppet::Parameter::Boolean) do
+      desc "Whether the user is a system user, according to the OS's criteria;
+      on most platforms, a UID less than or equal to 500 indicates a system
+      user. This parameter is only used when the resource is created and will
+      not affect the UID when the user is present. Defaults to `false`."
+
+      defaultto false
+    end
+
+    newparam(:allowdupe, :boolean => true, :parent => Puppet::Parameter::Boolean) do
+      desc "Whether to allow duplicate UIDs. Defaults to `false`."
+
+      defaultto false
+    end
+
+    newparam(:managehome, :boolean => true, :parent => Puppet::Parameter::Boolean) do
+      desc "Whether to manage the home directory when managing the user.
+        This will create the home directory when `ensure => present`, and
+        delete the home directory when `ensure => absent`. Defaults to `false`."
+
+      defaultto false
+
+      validate do |val|
+        if munge(val)
+          raise ArgumentError, "User provider #{provider.class.name} can not manage home directories" if provider and not provider.class.manages_homedir?
+        end
+      end
+    end
+
+    newproperty(:expiry, :required_features => :manages_expiry) do
+      desc "The expiry date for this user. Must be provided in
+           a zero-padded YYYY-MM-DD format --- e.g. 2010-02-19.
+           If you want to make sure the user account does never
+           expire, you can pass the special value `absent`."
+
+      newvalues :absent
+      newvalues /^\d{4}-\d{2}-\d{2}$/
+
+      validate do |value|
+        if value.intern != :absent and value !~ /^\d{4}-\d{2}-\d{2}$/
+          raise ArgumentError, "Expiry dates must be YYYY-MM-DD or the string \"absent\""
+        end
+      end
+    end
+
+    # Autorequire the group, if it's around
+    autorequire(:group) do
+      autos = []
+
+      if obj = @parameters[:gid] and groups = obj.shouldorig
+        groups = groups.collect { |group|
+          if group =~ /^\d+$/
+            Integer(group)
+          else
+            group
+          end
+        }
+        groups.each { |group|
+          case group
+          when Integer
+            if resource = catalog.resources.find { |r| r.is_a?(Puppet::Type.type(:group)) and r.should(:gid) == group }
+              autos << resource
+            end
+          else
+            autos << group
+          end
+        }
+      end
+
+      if obj = @parameters[:groups] and groups = obj.should
+        autos += groups.split(",")
+      end
+
+      autos
+    end
+
+    # This method has been exposed for puppet to manage users and groups of
+    # files in its settings and should not be considered available outside of
+    # puppet.
+    #
+    # (see Puppet::Settings#service_user_available?)
+    #
+    # @return [Boolean] if the user exists on the system
+    # @api private
+    def exists?
+      provider.exists?
+    end
+
+    def retrieve
+      absent = false
+      properties.inject({}) { |prophash, property|
+        current_value = :absent
+
+        if absent
+          prophash[property] = :absent
+        else
+          current_value = property.retrieve
+          prophash[property] = current_value
+        end
+
+        if property.name == :ensure and current_value == :absent
+          absent = true
+        end
+        prophash
+      }
+    end
+
+    newproperty(:roles, :parent => Puppet::Property::List, :required_features => :manages_solaris_rbac) do
+      desc "The roles the user has.  Multiple roles should be
+        specified as an array."
+
+      def membership
+        :role_membership
+      end
+
+      validate do |value|
+        if value =~ /^\d+$/
+          raise ArgumentError, "Role names must be provided, not numbers"
+        end
+        raise ArgumentError, "Role names must be provided as an array, not a comma-separated list" if value.include?(",")
+      end
+    end
+
+    #autorequire the roles that the user has
+    autorequire(:user) do
+      reqs = []
+
+      if roles_property = @parameters[:roles] and roles = roles_property.should
+        reqs += roles.split(',')
+      end
+
+      reqs
+    end
+
+    newparam(:role_membership) do
+      desc "Whether specified roles should be considered the **complete list**
+        (`inclusive`) or the **minimum list** (`minimum`) of roles the user
+        has. Defaults to `minimum`."
+
+      newvalues(:inclusive, :minimum)
+
+      defaultto :minimum
+    end
+
+    newproperty(:auths, :parent => Puppet::Property::List, :required_features => :manages_solaris_rbac) do
+      desc "The auths the user has.  Multiple auths should be
+        specified as an array."
+
+      def membership
+        :auth_membership
+      end
+
+      validate do |value|
+        if value =~ /^\d+$/
+          raise ArgumentError, "Auth names must be provided, not numbers"
+        end
+        raise ArgumentError, "Auth names must be provided as an array, not a comma-separated list" if value.include?(",")
+      end
+    end
+
+    newparam(:auth_membership) do
+      desc "Whether specified auths should be considered the **complete list**
+        (`inclusive`) or the **minimum list** (`minimum`) of auths the user
+        has. Defaults to `minimum`."
+
+      newvalues(:inclusive, :minimum)
+
+      defaultto :minimum
+    end
+
+    newproperty(:profiles, :parent => Puppet::Property::OrderedList, :required_features => :manages_solaris_rbac) do
+      desc "The profiles the user has.  Multiple profiles should be
+        specified as an array."
+
+      def membership
+        :profile_membership
+      end
+
+      validate do |value|
+        if value =~ /^\d+$/
+          raise ArgumentError, "Profile names must be provided, not numbers"
+        end
+        raise ArgumentError, "Profile names must be provided as an array, not a comma-separated list" if value.include?(",")
+      end
+    end
+
+    newparam(:profile_membership) do
+      desc "Whether specified roles should be treated as the **complete list**
+        (`inclusive`) or the **minimum list** (`minimum`) of roles
+        of which the user is a member. Defaults to `minimum`."
+
+      newvalues(:inclusive, :minimum)
+
+      defaultto :minimum
+    end
+
+    newproperty(:keys, :parent => Puppet::Property::KeyValue, :required_features => :manages_solaris_rbac) do
+      desc "Specify user attributes in an array of key = value pairs."
+
+      def membership
+        :key_membership
+      end
+
+      validate do |value|
+        raise ArgumentError, "Key/value pairs must be separated by an =" unless value.include?("=")
+      end
+    end
+
+    newparam(:key_membership) do
+      desc "Whether specified key/value pairs should be considered the
+        **complete list** (`inclusive`) or the **minimum list** (`minimum`) of
+        the user's attributes. Defaults to `minimum`."
+
+      newvalues(:inclusive, :minimum)
+
+      defaultto :minimum
+    end
+
+    newproperty(:project, :required_features => :manages_solaris_rbac) do
+      desc "The name of the project associated with a user."
+    end
+
+    newparam(:ia_load_module, :required_features => :manages_aix_lam) do
+      desc "The name of the I&A module to use to manage this user."
+    end
+
+    newproperty(:attributes, :parent => Puppet::Property::KeyValue, :required_features => :manages_aix_lam) do
+      desc "Specify AIX attributes for the user in an array of attribute = value pairs."
+
+      def membership
+        :attribute_membership
+      end
+
+      def delimiter
+        " "
+      end
+
+      validate do |value|
+        raise ArgumentError, "Attributes value pairs must be separated by an =" unless value.include?("=")
+      end
+    end
+
+    newparam(:attribute_membership) do
+      desc "Whether specified attribute value pairs should be treated as the
+        **complete list** (`inclusive`) or the **minimum list** (`minimum`) of
+        attribute/value pairs for the user. Defaults to `minimum`."
+
+      newvalues(:inclusive, :minimum)
+
+      defaultto :minimum
+    end
+
+    newproperty(:salt, :required_features => :manages_password_salt) do
+      desc "This is the 32 byte salt used to generate the PBKDF2 password used in
+            OS X. This field is required for managing passwords on OS X >= 10.8."
+    end
+
+    newproperty(:iterations, :required_features => :manages_password_salt) do
+      desc "This is the number of iterations of a chained computation of the
+            password hash (http://en.wikipedia.org/wiki/PBKDF2).  This parameter
+            is used in OS X. This field is required for managing passwords on OS X >= 10.8."
+
+      munge do |value|
+        if value.is_a?(String) and value =~/^[-0-9]+$/
+          Integer(value)
+        else
+          value
+        end
+      end
+    end
+
+    newparam(:forcelocal, :boolean => true,
+            :required_features => :libuser,
+            :parent => Puppet::Parameter::Boolean) do
+      desc "Forces the management of local accounts when accounts are also
+            being managed by some other NSS"
+      defaultto false
+    end
+
+    def generate
+      return [] if self[:purge_ssh_keys].empty?
+      find_unmanaged_keys
+    end
+
+    newparam(:purge_ssh_keys) do
+      desc "Whether to purge authorized SSH keys for this user if they are not managed
+        with the `ssh_authorized_key` resource type. Allowed values are:
+
+        * `false` (default) --- don't purge SSH keys for this user.
+        * `true` --- look for keys in the `.ssh/authorized_keys` file in the user's
+          home directory. Purge any keys that aren't managed as `ssh_authorized_key`
+          resources.
+        * An array of file paths --- look for keys in all of the files listed. Purge
+          any keys that aren't managed as `ssh_authorized_key` resources. If any of
+          these paths starts with `~` or `%h`, that token will be replaced with
+          the user's home directory."
+
+      defaultto :false
+
+      # Use Symbols instead of booleans until PUP-1967 is resolved.
+      newvalues(:true, :false)
+
+      validate do |value|
+        if [ :true, :false ].include? value.to_s.intern
+          return
+        end
+        value = [ value ] if value.is_a?(String)
+        if value.is_a?(Array)
+          value.each do |entry|
+
+            raise ArgumentError, "Each entry for purge_ssh_keys must be a string, not a #{entry.class}" unless entry.is_a?(String)
+
+            valid_home = Puppet::Util.absolute_path?(entry) || entry =~ %r{^~/|^%h/}
+            raise ArgumentError, "Paths to keyfiles must be absolute, not #{entry}" unless valid_home
+          end
+          return
+        end
+        raise ArgumentError, "purge_ssh_keys must be true, false, or an array of file names, not #{value.inspect}"
+      end
+
+      munge do |value|
+        # Resolve string, boolean and symbol forms of true and false to a
+        # single representation.
+        test_sym = value.to_s.intern
+        value = test_sym if [:true, :false].include? test_sym
+
+        return [] if value == :false
+        home = resource[:home]
+        if value == :true and not home
+          raise ArgumentError, "purge_ssh_keys can only be true for users with a defined home directory"
+        end
+
+        return [ "#{home}/.ssh/authorized_keys" ] if value == :true
+        # value is an array - munge each value
+        [ value ].flatten.map do |entry|
+          if entry =~ /^~|^%h/ and not home
+            raise ArgumentError, "purge_ssh_keys value '#{value}' meta character ~ or %h only allowed for users with a defined home directory"
+          end
+          entry.gsub!(/^~\//, "#{home}/")
+          entry.gsub!(/^%h\//, "#{home}/")
+          entry
+        end
+      end
+    end
+
+    # Generate ssh_authorized_keys resources for purging. The key files are
+    # taken from the purge_ssh_keys parameter. The generated resources inherit
+    # all metaparameters from the parent user resource.
+    #
+    # @return [Array<Puppet::Type::Ssh_authorized_key] a list of resources
+    #   representing the found keys
+    # @see generate
+    # @api private
+    def find_unmanaged_keys
+      self[:purge_ssh_keys].
+        select { |f| File.readable?(f) }.
+        map { |f| unknown_keys_in_file(f) }.
+        flatten.each do |res|
+          res[:ensure] = :absent
+          res[:user] = self[:name]
+          @parameters.each do |name, param|
+            res[name] = param.value if param.metaparam?
+          end
+        end
+    end
+
+    # Parse an ssh authorized keys file superficially, extract the comments
+    # on the keys. These are considered names of possible ssh_authorized_keys
+    # resources. Keys that are managed by the present catalog are ignored.
+    #
+    # @see generate
+    # @api private
+    # @return [Array<Puppet::Type::Ssh_authorized_key] a list of resources
+    #   representing the found keys
+    def unknown_keys_in_file(keyfile)
+      names = []
+      name_index = 0
+      File.new(keyfile).each do |line|
+        next unless line =~ Puppet::Type.type(:ssh_authorized_key).keyline_regex
+        # the name is stored in the 4th capture of the regex
+        name = $4
+        if name.empty?
+          key = $3.delete("\n")
+          # If no comment is specified for this key, generate a unique internal
+          # name. This uses the same rules as
+          # provider/ssh_authorized_key/parsed (PUP-3357)
+          name = "#{keyfile}:unnamed-#{name_index += 1}"
+        end
+        names << name
+        Puppet.debug "#{self.ref} parsed for purging Ssh_authorized_key[#{name}]"
+      end
+
+      names.map { |keyname|
+        Puppet::Type.type(:ssh_authorized_key).new(
+          :name => keyname,
+          :target => keyfile)
+      }.reject { |res|
+        catalog.resource_refs.include? res.ref
+      }
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/vlan.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/vlan.rb
new file mode 100644
index 0000000..dc33ea2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/vlan.rb
@@ -0,0 +1,26 @@
+#
+# Manages a Vlan on a given router or switch
+#
+
+Puppet::Type.newtype(:vlan) do
+    @doc = "Manages a VLAN on a router or switch."
+
+    apply_to_device
+
+    ensurable
+
+    newparam(:name) do
+      desc "The numeric VLAN ID."
+      isnamevar
+
+      newvalues(/^\d+/)
+    end
+
+    newproperty(:description) do
+      desc "The VLAN's name."
+    end
+
+    newparam(:device_url) do
+      desc "The URL of the router or switch maintaining this VLAN."
+    end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/whit.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/whit.rb
new file mode 100644
index 0000000..0cdba7a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/whit.rb
@@ -0,0 +1,34 @@
+Puppet::Type.newtype(:whit) do
+  desc "Whits are internal artifacts of Puppet's current implementation, and
+    Puppet suppresses their appearance in all logs. We make no guarantee of
+    the whit's continued existence, and it should never be used in an actual
+    manifest. Use the `anchor` type from the puppetlabs-stdlib module if you
+    need arbitrary whit-like no-op resources."
+
+  newparam :name do
+    desc "The name of the whit, because it must have one."
+  end
+
+
+  # Hide the fact that we're a whit from logs.
+  #
+  # I hate you, milkman whit.  You are so painful, so often.
+  #
+  # In this case the memoized version means we generate a new string about 1.9
+  # percent of the time, and we allocate about 1.6MB less memory, and generate
+  # a whole lot less GC churn.
+  #
+  # That number probably goes up at least O(n) with the complexity of your
+  # catalog, and I suspect beyond that, because that is, like, 10,000 calls
+  # for 200 distinct objects.  Even with just linear, that is a constant
+  # factor of, like, 50n. --daniel 2012-07-17
+  def to_s
+    @to_s ||= name.sub(/^completed_|^admissible_/, "")
+  end
+  alias path to_s
+
+  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/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/yumrepo.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/yumrepo.rb
new file mode 100644
index 0000000..0287170
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/yumrepo.rb
@@ -0,0 +1,363 @@
+require 'uri'
+
+Puppet::Type.newtype(:yumrepo) do
+  @doc = "The client-side description of a yum repository. Repository
+    configurations are found by parsing `/etc/yum.conf` and
+    the files indicated by the `reposdir` option in that file
+    (see `yum.conf(5)` for details).
+
+    Most parameters are identical to the ones documented
+    in the `yum.conf(5)` man page.
+
+    Continuation lines that yum supports (for the `baseurl`, for example)
+    are not supported. This type does not attempt to read or verify the
+    exinstence of files listed in the `include` attribute."
+
+  # Ensure yumrepos can be removed too.
+  ensurable
+  # Doc string for properties that can be made 'absent'
+  ABSENT_DOC="Set this to `absent` to remove it from the file completely."
+  # False can be false/0/no and True can be true/1/yes in yum.
+  YUM_BOOLEAN=/^(True|False|0|1|No|Yes)$/i
+  YUM_BOOLEAN_DOC="Valid values are: False/0/No or True/1/Yes."
+
+  VALID_SCHEMES = %w[file http https ftp]
+
+  newparam(:name, :namevar => true) do
+    desc "The name of the repository.  This corresponds to the
+     `repositoryid` parameter in `yum.conf(5)`."
+  end
+
+  newparam(:target) do
+    desc "The filename to write the yum repository to."
+
+    defaultto :absent
+  end
+
+  newproperty(:descr) do
+    desc "A human-readable description of the repository.
+      This corresponds to the name parameter in `yum.conf(5)`.
+      #{ABSENT_DOC}"
+
+    newvalues(/.*/, :absent)
+  end
+
+  newproperty(:mirrorlist) do
+    desc "The URL that holds the list of mirrors for this repository.
+      #{ABSENT_DOC}"
+
+    newvalues(/.*/, :absent)
+    validate do |value|
+      next if value.to_s == 'absent'
+      parsed = URI.parse(value)
+
+      unless VALID_SCHEMES.include?(parsed.scheme)
+        raise "Must be a valid URL"
+      end
+    end
+  end
+
+  newproperty(:baseurl) do
+    desc "The URL for this repository. #{ABSENT_DOC}"
+
+    newvalues(/.*/, :absent)
+    validate do |value|
+      next if value.to_s == 'absent'
+
+      value.split(/\s+/).each do |uri|
+
+        parsed = URI.parse(uri)
+
+        unless VALID_SCHEMES.include?(parsed.scheme)
+          raise "Must be a valid URL"
+        end
+      end
+    end
+  end
+
+  newproperty(:enabled) do
+    desc "Whether this repository is enabled.
+    #{YUM_BOOLEAN_DOC}
+    #{ABSENT_DOC}"
+
+    newvalues(YUM_BOOLEAN, :absent)
+  end
+
+  newproperty(:gpgcheck) do
+    desc "Whether to check the GPG signature on packages installed
+      from this repository.
+      #{YUM_BOOLEAN_DOC}
+      #{ABSENT_DOC}"
+
+    newvalues(YUM_BOOLEAN, :absent)
+  end
+
+  newproperty(:repo_gpgcheck) do
+    desc "Whether to check the GPG signature on repodata.
+      #{YUM_BOOLEAN_DOC}
+      #{ABSENT_DOC}"
+
+    newvalues(YUM_BOOLEAN, :absent)
+  end
+
+  newproperty(:gpgkey) do
+    desc "The URL for the GPG key with which packages from this
+      repository are signed. #{ABSENT_DOC}"
+
+    newvalues(/.*/, :absent)
+    validate do |value|
+      next if value.to_s == 'absent'
+
+      value.split(/\s+/).each do |uri|
+
+        parsed = URI.parse(uri)
+
+        unless VALID_SCHEMES.include?(parsed.scheme)
+          raise "Must be a valid URL"
+        end
+      end
+    end
+  end
+
+  newproperty(:mirrorlist_expire) do
+    desc "Time (in seconds) after which the mirrorlist locally cached
+      will expire.\n#{ABSENT_DOC}"
+
+    newvalues(/^[0-9]+$/, :absent)
+  end
+
+  newproperty(:include) do
+    desc "The URL of a remote file containing additional yum configuration
+      settings. Puppet does not check for this file's existence or validity.
+      #{ABSENT_DOC}"
+
+    newvalues(/.*/, :absent)
+    validate do |value|
+      next if value.to_s == 'absent'
+      parsed = URI.parse(value)
+
+      unless VALID_SCHEMES.include?(parsed.scheme)
+        raise "Must be a valid URL"
+      end
+    end
+  end
+
+  newproperty(:exclude) do
+    desc "List of shell globs. Matching packages will never be
+      considered in updates or installs for this repo.
+      #{ABSENT_DOC}"
+
+    newvalues(/.*/, :absent)
+  end
+
+  newproperty(:gpgcakey) do
+    desc "The URL for the GPG CA key for this repository. #{ABSENT_DOC}"
+
+    newvalues(/.*/, :absent)
+    validate do |value|
+      next if value.to_s == 'absent'
+      parsed = URI.parse(value)
+
+      unless VALID_SCHEMES.include?(parsed.scheme)
+        raise "Must be a valid URL"
+      end
+    end
+  end
+
+  newproperty(:includepkgs) do
+    desc "List of shell globs. If this is set, only packages
+      matching one of the globs will be considered for
+      update or install from this repo. #{ABSENT_DOC}"
+
+    newvalues(/.*/, :absent)
+  end
+
+  newproperty(:enablegroups) do
+    desc "Whether yum will allow the use of package groups for this
+      repository.
+      #{YUM_BOOLEAN_DOC}
+      #{ABSENT_DOC}"
+
+    newvalues(YUM_BOOLEAN, :absent)
+  end
+
+  newproperty(:failovermethod) do
+    desc "The failover method for this repository; should be either
+      `roundrobin` or `priority`. #{ABSENT_DOC}"
+
+    newvalues(/^roundrobin|priority$/, :absent)
+  end
+
+  newproperty(:keepalive) do
+    desc "Whether HTTP/1.1 keepalive should be used with this repository.
+      #{YUM_BOOLEAN_DOC}
+      #{ABSENT_DOC}"
+
+    newvalues(YUM_BOOLEAN, :absent)
+  end
+
+  newproperty(:retries) do
+    desc "Set the number of times any attempt to retrieve a file should
+      retry before returning an error. Setting this to `0` makes yum
+     try forever.\n#{ABSENT_DOC}"
+
+    newvalues(/^[0-9]+$/, :absent)
+  end
+
+  newproperty(:http_caching) do
+    desc "What to cache from this repository. #{ABSENT_DOC}"
+
+    newvalues(/^(packages|all|none)$/, :absent)
+  end
+
+  newproperty(:timeout) do
+    desc "Number of seconds to wait for a connection before timing
+      out. #{ABSENT_DOC}"
+
+    newvalues(/^\d+$/, :absent)
+  end
+
+  newproperty(:metadata_expire) do
+    desc "Number of seconds after which the metadata will expire.
+      #{ABSENT_DOC}"
+
+    newvalues(/^([0-9]+[dhm]?|never)$/, :absent)
+  end
+
+  newproperty(:protect) do
+    desc "Enable or disable protection for this repository. Requires
+      that the `protectbase` plugin is installed and enabled.
+      #{YUM_BOOLEAN_DOC}
+      #{ABSENT_DOC}"
+
+    newvalues(YUM_BOOLEAN, :absent)
+  end
+
+  newproperty(:priority) do
+    desc "Priority of this repository from 1-99. Requires that
+      the `priorities` plugin is installed and enabled.
+      #{ABSENT_DOC}"
+
+    newvalues(/.*/, :absent)
+    validate do |value|
+      next if value.to_s == 'absent'
+      unless (1..99).include?(value.to_i)
+        fail("Must be within range 1-99")
+      end
+    end
+  end
+
+  newproperty(:throttle) do
+    desc "Enable bandwidth throttling for downloads. This option
+      can be expressed as a absolute data rate in bytes/sec or a
+      percentage `60%`. An SI prefix (k, M or G) may be appended
+      to the data rate values.\n#{ABSENT_DOC}"
+
+    newvalues(/^\d+[kMG%]?$/, :absent)
+  end
+
+  newproperty(:bandwidth) do
+    desc "Use to specify the maximum available network bandwidth
+      in bytes/second. Used with the `throttle` option. If `throttle`
+      is a percentage and `bandwidth` is `0` then bandwidth throttling
+      will be disabled. If `throttle` is expressed as a data rate then
+      this option is ignored.\n#{ABSENT_DOC}"
+
+    newvalues(/^\d+[kMG]?$/, :absent)
+  end
+
+  newproperty(:cost) do
+    desc "Cost of this repository. #{ABSENT_DOC}"
+
+    newvalues(/^\d+$/, :absent)
+  end
+
+  newproperty(:proxy) do
+    desc "URL of a proxy server that Yum should use when accessing this repository.
+      This attribute can also be set to `'_none_'`, which will make Yum bypass any
+      global proxy settings when accessing this repository.
+      #{ABSENT_DOC}"
+
+    newvalues(/.*/, :absent)
+    validate do |value|
+      next if value.to_s =~ /^(absent|_none_)$/
+      parsed = URI.parse(value)
+
+      unless VALID_SCHEMES.include?(parsed.scheme)
+        raise "Must be a valid URL"
+      end
+    end
+  end
+
+  newproperty(:proxy_username) do
+    desc "Username for this proxy. #{ABSENT_DOC}"
+
+    newvalues(/.*/, :absent)
+  end
+
+  newproperty(:proxy_password) do
+    desc "Password for this proxy. #{ABSENT_DOC}"
+
+    newvalues(/.*/, :absent)
+  end
+
+  newproperty(:s3_enabled) do
+    desc "Access the repo via S3.
+      #{YUM_BOOLEAN_DOC}
+      #{ABSENT_DOC}"
+
+    newvalues(YUM_BOOLEAN, :absent)
+  end
+
+  newproperty(:sslcacert) do
+    desc "Path to the directory containing the databases of the
+      certificate authorities yum should use to verify SSL certificates.
+      #{ABSENT_DOC}"
+
+    newvalues(/.*/, :absent)
+  end
+
+  newproperty(:sslverify) do
+    desc "Should yum verify SSL certificates/hosts at all.
+      #{YUM_BOOLEAN_DOC}
+      #{ABSENT_DOC}"
+
+    newvalues(YUM_BOOLEAN, :absent)
+  end
+
+  newproperty(:sslclientcert) do
+    desc "Path  to the SSL client certificate yum should use to connect
+      to repos/remote sites. #{ABSENT_DOC}"
+
+    newvalues(/.*/, :absent)
+  end
+
+  newproperty(:sslclientkey) do
+    desc "Path to the SSL client key yum should use to connect
+      to repos/remote sites. #{ABSENT_DOC}"
+
+    newvalues(/.*/, :absent)
+  end
+
+  newproperty(:metalink) do
+    desc "Metalink for mirrors. #{ABSENT_DOC}"
+
+    newvalues(/.*/, :absent)
+    validate do |value|
+      next if value.to_s == 'absent'
+      parsed = URI.parse(value)
+
+      unless VALID_SCHEMES.include?(parsed.scheme)
+        raise "Must be a valid URL"
+      end
+    end
+  end
+
+  newproperty(:skip_if_unavailable) do
+    desc "Should yum skip this repository if unable to reach it.
+      #{YUM_BOOLEAN_DOC}
+      #{ABSENT_DOC}"
+
+    newvalues(YUM_BOOLEAN, :absent)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/zfs.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/zfs.rb
new file mode 100644
index 0000000..f4faa38
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/zfs.rb
@@ -0,0 +1,150 @@
+module Puppet
+  newtype(:zfs) do
+    @doc = "Manage zfs. Create destroy and set properties on zfs instances.
+
+**Autorequires:** If Puppet is managing the zpool at the root of this zfs
+instance, the zfs resource will autorequire it. If Puppet is managing any
+parent zfs instances, the zfs resource will autorequire them."
+
+    ensurable
+
+    newparam(:name) do
+      desc "The full name for this filesystem (including the zpool)."
+    end
+
+    newproperty(:aclinherit) do
+      desc "The aclinherit property. Valid values are `discard`, `noallow`, `restricted`, `passthrough`, `passthrough-x`."
+    end
+
+    newproperty(:aclmode) do
+      desc "The aclmode property. Valid values are `discard`, `groupmask`, `passthrough`."
+    end
+
+    newproperty(:atime) do
+      desc "The atime property. Valid values are `on`, `off`."
+    end
+
+    newproperty(:canmount) do
+      desc "The canmount property. Valid values are `on`, `off`, `noauto`."
+    end
+
+    newproperty(:checksum) do
+      desc "The checksum property. Valid values are `on`, `off`, `fletcher2`, `fletcher4`, `sha256`."
+    end
+
+    newproperty(:compression) do
+      desc "The compression property. Valid values are `on`, `off`, `lzjb`, `gzip`, `gzip-[1-9]`, `zle`."
+    end
+
+    newproperty(:copies) do
+      desc "The copies property. Valid values are `1`, `2`, `3`."
+    end
+
+    newproperty(:dedup) do
+      desc "The dedup property. Valid values are `on`, `off`."
+    end
+
+    newproperty(:devices) do
+      desc "The devices property. Valid values are `on`, `off`."
+    end
+
+    newproperty(:exec) do
+      desc "The exec property. Valid values are `on`, `off`."
+    end
+
+    newproperty(:logbias) do
+      desc "The logbias property. Valid values are `latency`, `throughput`."
+    end
+
+    newproperty(:mountpoint) do
+      desc "The mountpoint property. Valid values are `<path>`, `legacy`, `none`."
+    end
+
+    newproperty(:nbmand) do
+      desc "The nbmand property. Valid values are `on`, `off`."
+    end
+
+    newproperty(:primarycache) do
+      desc "The primarycache property. Valid values are `all`, `none`, `metadata`."
+    end
+
+    newproperty(:quota) do
+      desc "The quota property. Valid values are `<size>`, `none`."
+    end
+
+    newproperty(:readonly) do
+      desc "The readonly property. Valid values are `on`, `off`."
+    end
+
+    newproperty(:recordsize) do
+      desc "The recordsize property. Valid values are powers of two between 512 and 128k."
+    end
+
+    newproperty(:refquota) do
+      desc "The refquota property. Valid values are `<size>`, `none`."
+    end
+
+    newproperty(:refreservation) do
+      desc "The refreservation property. Valid values are `<size>`, `none`."
+    end
+
+    newproperty(:reservation) do
+      desc "The reservation property. Valid values are `<size>`, `none`."
+    end
+
+    newproperty(:secondarycache) do
+      desc "The secondarycache property. Valid values are `all`, `none`, `metadata`."
+    end
+
+    newproperty(:setuid) do
+      desc "The setuid property. Valid values are `on`, `off`."
+    end
+
+    newproperty(:shareiscsi) do
+      desc "The shareiscsi property. Valid values are `on`, `off`, `type=<type>`."
+    end
+
+    newproperty(:sharenfs) do
+      desc "The sharenfs property. Valid values are `on`, `off`, share(1M) options"
+    end
+
+    newproperty(:sharesmb) do
+      desc "The sharesmb property. Valid values are `on`, `off`, sharemgr(1M) options"
+    end
+
+    newproperty(:snapdir) do
+      desc "The snapdir property. Valid values are `hidden`, `visible`."
+    end
+
+    newproperty(:version) do
+      desc "The version property. Valid values are `1`, `2`, `3`, `4`, `current`."
+    end
+
+    newproperty(:volsize) do
+      desc "The volsize property. Valid values are `<size>`"
+    end
+
+    newproperty(:vscan) do
+      desc "The vscan property. Valid values are `on`, `off`."
+    end
+
+    newproperty(:xattr) do
+      desc "The xattr property. Valid values are `on`, `off`."
+    end
+
+    newproperty(:zoned) do
+      desc "The zoned property. Valid values are `on`, `off`."
+    end
+
+    autorequire(:zpool) do
+      #strip the zpool off the zfs name and autorequire it
+      [@parameters[:name].value.split('/')[0]]
+    end
+
+    autorequire(:zfs) do
+      #slice and dice, we want all the zfs before this one
+      names = @parameters[:name].value.split('/')
+      names.slice(1..-2).inject([]) { |a,v| a << "#{a.last}/#{v}" }.collect { |fs| names[0] + fs }
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/zone.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/zone.rb
new file mode 100644
index 0000000..9094aaf
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/zone.rb
@@ -0,0 +1,382 @@
+require 'puppet/property/list'
+Puppet::Type.newtype(:zone) do
+  @doc = "Manages Solaris zones.
+
+**Autorequires:** If Puppet is managing the directory specified as the root of
+the zone's filesystem (with the `path` attribute), the zone resource will
+autorequire that directory."
+
+module Puppet::Zone
+  class StateMachine
+    # A silly little state machine.
+    def initialize
+      @state = {}
+      @sequence = []
+      @state_aliases = {}
+      @default = nil
+    end
+
+    # The order of calling insert_state is important
+    def insert_state(name, transitions)
+      @sequence << name
+      @state[name] = transitions
+    end
+
+    def alias_state(state, salias)
+      @state_aliases[state] = salias
+    end
+
+    def name(n)
+      @state_aliases[n.to_sym] || n.to_sym
+    end
+
+    def index(state)
+      @sequence.index(name(state))
+    end
+
+    # return all states between fs and ss excluding fs
+    def sequence(fs, ss)
+      fi = index(fs)
+      si= index(ss)
+      (if fi > si
+        then @sequence[si .. fi].map{|i| @state[i]}.reverse
+        else @sequence[fi .. si].map{|i| @state[i]}
+      end)[1..-1]
+    end
+
+    def cmp?(a,b)
+      index(a) < index(b)
+    end
+  end
+end
+
+  ensurable do
+    desc "The running state of the zone.  The valid states directly reflect
+      the states that `zoneadm` provides.  The states are linear,
+      in that a zone must be `configured`, then `installed`, and
+      only then can be `running`.  Note also that `halt` is currently
+      used to stop zones."
+
+    def self.fsm
+      return @fsm if @fsm
+      @fsm = Puppet::Zone::StateMachine.new
+    end
+
+    def self.alias_state(values)
+      values.each do |k,v|
+        fsm.alias_state(k,v)
+      end
+    end
+
+    def self.seqvalue(name, hash)
+      fsm.insert_state(name, hash)
+      self.newvalue name
+    end
+
+    # This is seq value because the order of declaration is important.
+    # i.e we go linearly from :absent -> :configured -> :installed -> :running
+    seqvalue :absent, :down => :destroy
+    seqvalue :configured, :up => :configure, :down => :uninstall
+    seqvalue :installed, :up => :install, :down => :stop
+    seqvalue :running, :up => :start
+
+    alias_state :incomplete => :installed, :ready => :installed, :shutting_down => :running
+
+    defaultto :running
+
+    def self.state_sequence(first, second)
+      fsm.sequence(first, second)
+    end
+
+    # Why override it? because property/ensure.rb has a default retrieve method
+    # that knows only about :present and :absent. That method just calls
+    # provider.exists? and returns :present if a result was returned.
+    def retrieve
+      provider.properties[:ensure]
+    end
+
+    def provider_sync_send(method)
+      warned = false
+      while provider.processing?
+        next if warned
+        info "Waiting for zone to finish processing"
+        warned = true
+        sleep 1
+      end
+      provider.send(method)
+      provider.flush()
+    end
+
+    def sync
+      method = nil
+      direction = up? ? :up : :down
+
+      # We need to get the state we're currently in and just call
+      # everything between it and us.
+      self.class.state_sequence(self.retrieve, self.should).each do |state|
+        method = state[direction]
+        raise Puppet::DevError, "Cannot move #{direction} from #{st[:name]}" unless method
+        provider_sync_send(method)
+      end
+
+      ("zone_#{self.should}").intern
+    end
+
+    # Are we moving up the property tree?
+    def up?
+      self.class.fsm.cmp?(self.retrieve, self.should)
+    end
+
+  end
+
+  newparam(:name) do
+    desc "The name of the zone."
+
+    isnamevar
+  end
+
+  newparam(:id) do
+    desc "The numerical ID of the zone.  This number is autogenerated
+      and cannot be changed."
+  end
+
+  newparam(:clone) do
+    desc "Instead of installing the zone, clone it from another zone.
+      If the zone root resides on a zfs file system, a snapshot will be
+      used to create the clone; if it resides on a ufs filesystem, a copy of the
+      zone will be used. The zone from which you clone must not be running."
+  end
+
+  newproperty(:ip, :parent => Puppet::Property::List) do
+    require 'ipaddr'
+
+    desc "The IP address of the zone.  IP addresses **must** be specified
+      with an interface, and may optionally be specified with a default router
+      (sometimes called a defrouter). The interface, IP address, and default
+      router should be separated by colons to form a complete IP address string.
+      For example: `bge0:192.168.178.200` would be a valid IP address string
+      without a default router, and `bge0:192.168.178.200:192.168.178.1` adds a
+      default router to it.
+
+      For zones with multiple interfaces, the value of this attribute should be
+      an array of IP address strings (each of which must include an interface
+      and may include a default router)."
+
+    # The default action of list should is to lst.join(' '). By specifying
+    # @should, we ensure the should remains an array. If we override should, we
+    # should also override insync?() -- property/list.rb
+    def should
+      @should
+    end
+
+    # overridden so that we match with self.should
+    def insync?(is)
+      is = [] if !is || is == :absent
+      is.sort == self.should.sort
+    end
+  end
+
+  newproperty(:iptype) do
+    desc "The IP stack type of the zone."
+    defaultto :shared
+    newvalue :shared
+    newvalue :exclusive
+  end
+
+  newproperty(:autoboot, :boolean => true) do
+    desc "Whether the zone should automatically boot."
+    defaultto true
+    newvalues(:true, :false)
+  end
+
+  newproperty(:path) do
+    desc "The root of the zone's filesystem.  Must be a fully qualified
+      file name.  If you include `%s` in the path, then it will be
+      replaced with the zone's name.  Currently, you cannot use
+      Puppet to move a zone. Consequently this is a readonly property."
+
+    validate do |value|
+      raise ArgumentError, "The zone base must be fully qualified" unless value =~ /^\//
+    end
+
+    munge do |value|
+      if value =~ /%s/
+        value % @resource[:name]
+      else
+        value
+      end
+    end
+  end
+
+  newproperty(:pool) do
+    desc "The resource pool for this zone."
+  end
+
+  newproperty(:shares) do
+    desc "Number of FSS CPU shares allocated to the zone."
+  end
+
+  newproperty(:dataset, :parent => Puppet::Property::List ) do
+    desc "The list of datasets delegated to the non-global zone from the
+      global zone.  All datasets must be zfs filesystem names which are
+      different from the mountpoint."
+
+    def should
+      @should
+    end
+
+    # overridden so that we match with self.should
+    def insync?(is)
+      is = [] if !is || is == :absent
+      is.sort == self.should.sort
+    end
+
+    validate do |value|
+      unless value !~ /^\//
+        raise ArgumentError, "Datasets must be the name of a zfs filesystem"
+      end
+    end
+  end
+
+  newproperty(:inherit, :parent => Puppet::Property::List) do
+    desc "The list of directories that the zone inherits from the global
+      zone.  All directories must be fully qualified."
+
+    def should
+      @should
+    end
+
+    # overridden so that we match with self.should
+    def insync?(is)
+      is = [] if !is || is == :absent
+      is.sort == self.should.sort
+    end
+
+    validate do |value|
+      unless value =~ /^\//
+        raise ArgumentError, "Inherited filesystems must be fully qualified"
+      end
+    end
+  end
+
+  # Specify the sysidcfg file.  This is pretty hackish, because it's
+  # only used to boot the zone the very first time.
+  newparam(:sysidcfg) do
+    desc %{The text to go into the `sysidcfg` file when the zone is first
+      booted.  The best way is to use a template:
+
+          # $confdir/modules/site/templates/sysidcfg.erb
+          system_locale=en_US
+          timezone=GMT
+          terminal=xterms
+          security_policy=NONE
+          root_password=<%= password %>
+          timeserver=localhost
+          name_service=DNS {domain_name=<%= domain %> name_server=<%= nameserver %>}
+          network_interface=primary {hostname=<%= realhostname %>
+            ip_address=<%= ip %>
+            netmask=<%= netmask %>
+            protocol_ipv6=no
+            default_route=<%= defaultroute %>}
+          nfs4_domain=dynamic
+
+      And then call that:
+
+          zone { myzone:
+            ip           => "bge0:192.168.0.23",
+            sysidcfg     => template("site/sysidcfg.erb"),
+            path         => "/opt/zones/myzone",
+            realhostname => "fully.qualified.domain.name"
+          }
+
+      The `sysidcfg` only matters on the first booting of the zone,
+      so Puppet only checks for it at that time.}
+  end
+
+  newparam(:create_args) do
+    desc "Arguments to the `zonecfg` create command.  This can be used to create branded zones."
+  end
+
+  newparam(:install_args) do
+    desc "Arguments to the `zoneadm` install command.  This can be used to create branded zones."
+  end
+
+  newparam(:realhostname) do
+    desc "The actual hostname of the zone."
+  end
+
+  # If Puppet is also managing the base dir or its parent dir, list them
+  # both as prerequisites.
+  autorequire(:file) do
+    if @parameters.include? :path
+      [@parameters[:path].value, ::File.dirname(@parameters[:path].value)]
+    else
+      nil
+    end
+  end
+
+  # If Puppet is also managing the zfs filesystem which is the zone dataset
+  # then list it as a prerequisite.  Zpool's get autorequired by the zfs
+  # type.  We just need to autorequire the dataset zfs itself as the zfs type
+  # will autorequire all of the zfs parents and zpool.
+  autorequire(:zfs) do
+    # Check if we have datasets in our zone configuration and autorequire each dataset
+    self[:dataset] if @parameters.include? :dataset
+  end
+
+  def validate_ip(ip, name)
+    IPAddr.new(ip) if ip
+  rescue ArgumentError
+    self.fail Puppet::Error, "'#{ip}' is an invalid #{name}", $!
+  end
+
+  def validate_exclusive(interface, address, router)
+    return if !interface.nil? and address.nil?
+    self.fail "only interface may be specified when using exclusive IP stack: #{interface}:#{address}"
+  end
+  def validate_shared(interface, address, router)
+    self.fail "ip must contain interface name and ip address separated by a \":\"" if interface.nil? or address.nil?
+    [address, router].each do |ip|
+      validate_ip(address, "IP address") unless ip.nil?
+    end
+  end
+
+  validate do
+    return unless self[:ip]
+    # self[:ip] reflects the type passed from proeprty:ip.should. If we
+    # override it and pass @should, then we get an array here back.
+    self[:ip].each do |ip|
+      interface, address, router = ip.split(':')
+      if self[:iptype] == :shared
+        validate_shared(interface, address, router)
+      else
+        validate_exclusive(interface, address, router)
+      end
+    end
+  end
+
+  def retrieve
+    provider.flush
+    hash = provider.properties
+    return setstatus(hash) unless hash.nil? or hash[:ensure] == :absent
+    # Return all properties as absent.
+    return Hash[properties.map{|p| [p, :absent]} ]
+  end
+
+  # Take the results of a listing and set everything appropriately.
+  def setstatus(hash)
+    prophash = {}
+    hash.each do |param, value|
+      next if param == :name
+      case self.class.attrtype(param)
+      when :property
+        # Only try to provide values for the properties we're managing
+        prop = self.property(param)
+        prophash[prop] = value if prop
+      else
+        self[param] = value
+      end
+    end
+    prophash
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/zpool.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/zpool.rb
new file mode 100644
index 0000000..043deec
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/type/zpool.rb
@@ -0,0 +1,91 @@
+module Puppet
+  class Property
+
+    class VDev < Property
+
+      def flatten_and_sort(array)
+        array = [array] unless array.is_a? Array
+        array.collect { |a| a.split(' ') }.flatten.sort
+      end
+
+      def insync?(is)
+        return @should == [:absent] if is == :absent
+
+        flatten_and_sort(is) == flatten_and_sort(@should)
+      end
+    end
+
+    class MultiVDev < VDev
+      def insync?(is)
+        return @should == [:absent] if is == :absent
+
+        return false unless is.length == @should.length
+
+        is.each_with_index { |list, i| return false unless flatten_and_sort(list) == flatten_and_sort(@should[i]) }
+
+        #if we made it this far we are in sync
+        true
+      end
+    end
+  end
+
+  newtype(:zpool) do
+    @doc = "Manage zpools. Create and delete zpools. The provider WILL NOT SYNC, only report differences.
+
+      Supports vdevs with mirrors, raidz, logs and spares."
+
+    ensurable
+
+    newproperty(:disk, :array_matching => :all, :parent => Puppet::Property::VDev) do
+      desc "The disk(s) for this pool. Can be an array or a space separated string."
+    end
+
+    newproperty(:mirror, :array_matching => :all, :parent => Puppet::Property::MultiVDev) do
+      desc "List of all the devices to mirror for this pool. Each mirror should be a
+      space separated string:
+
+          mirror => [\"disk1 disk2\", \"disk3 disk4\"],
+
+      "
+
+      validate do |value|
+        raise ArgumentError, "mirror names must be provided as string separated, not a comma-separated list" if value.include?(",")
+      end
+    end
+
+    newproperty(:raidz, :array_matching => :all, :parent => Puppet::Property::MultiVDev) do
+      desc "List of all the devices to raid for this pool. Should be an array of
+      space separated strings:
+
+          raidz => [\"disk1 disk2\", \"disk3 disk4\"],
+
+      "
+
+      validate do |value|
+        raise ArgumentError, "raid names must be provided as string separated, not a comma-separated list" if value.include?(",")
+      end
+    end
+
+    newproperty(:spare, :array_matching => :all, :parent => Puppet::Property::VDev) do
+      desc "Spare disk(s) for this pool."
+    end
+
+    newproperty(:log, :array_matching => :all, :parent => Puppet::Property::VDev) do
+      desc "Log disks for this pool. This type does not currently support mirroring of log disks."
+    end
+
+    newparam(:pool) do
+      desc "The name for this pool."
+      isnamevar
+    end
+
+    newparam(:raid_parity) do
+      desc "Determines parity when using the `raidz` parameter."
+    end
+
+    validate do
+      has_should = [:disk, :mirror, :raidz].select { |prop| self.should(prop) }
+      self.fail "You cannot specify #{has_should.join(" and ")} on this type (only one)" if has_should.length > 1
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util.rb
new file mode 100644
index 0000000..419b0c0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util.rb
@@ -0,0 +1,562 @@
+# A module to collect utility functions.
+
+require 'English'
+require 'puppet/error'
+require 'puppet/util/execution_stub'
+require 'uri'
+require 'pathname'
+require 'ostruct'
+require 'puppet/util/platform'
+require 'puppet/util/symbolic_file_mode'
+require 'puppet/file_system/uniquefile'
+require 'securerandom'
+
+module Puppet
+module Util
+  require 'puppet/util/monkey_patches'
+  require 'benchmark'
+
+  # These are all for backward compatibility -- these are methods that used
+  # to be in Puppet::Util but have been moved into external modules.
+  require 'puppet/util/posix'
+  extend Puppet::Util::POSIX
+
+  extend Puppet::Util::SymbolicFileMode
+
+  def self.activerecord_version
+    if (defined?(::ActiveRecord) and defined?(::ActiveRecord::VERSION) and defined?(::ActiveRecord::VERSION::MAJOR) and defined?(::ActiveRecord::VERSION::MINOR))
+      ([::ActiveRecord::VERSION::MAJOR, ::ActiveRecord::VERSION::MINOR].join('.').to_f)
+    else
+      0
+    end
+  end
+
+
+  # Run some code with a specific environment.  Resets the environment back to
+  # what it was at the end of the code.
+  def self.withenv(hash)
+    saved = ENV.to_hash
+    hash.each do |name, val|
+      ENV[name.to_s] = val
+    end
+
+    yield
+  ensure
+    ENV.clear
+    saved.each do |name, val|
+      ENV[name] = val
+    end
+  end
+
+
+  # Execute a given chunk of code with a new umask.
+  def self.withumask(mask)
+    cur = File.umask(mask)
+
+    begin
+      yield
+    ensure
+      File.umask(cur)
+    end
+  end
+
+
+  # Change the process to a different user
+  def self.chuser
+    if group = Puppet[:group]
+      begin
+        Puppet::Util::SUIDManager.change_group(group, true)
+      rescue => detail
+        Puppet.warning "could not change to group #{group.inspect}: #{detail}"
+        $stderr.puts "could not change to group #{group.inspect}"
+
+        # Don't exit on failed group changes, since it's
+        # not fatal
+        #exit(74)
+      end
+    end
+
+    if user = Puppet[:user]
+      begin
+        Puppet::Util::SUIDManager.change_user(user, true)
+      rescue => detail
+        $stderr.puts "Could not change to user #{user}: #{detail}"
+        exit(74)
+      end
+    end
+  end
+
+  # Create instance methods for each of the log levels.  This allows
+  # the messages to be a little richer.  Most classes will be calling this
+  # method.
+  def self.logmethods(klass, useself = true)
+    Puppet::Util::Log.eachlevel { |level|
+      klass.send(:define_method, level, proc { |args|
+        args = args.join(" ") if args.is_a?(Array)
+        if useself
+
+          Puppet::Util::Log.create(
+            :level => level,
+            :source => self,
+            :message => args
+          )
+        else
+
+          Puppet::Util::Log.create(
+            :level => level,
+            :message => args
+          )
+        end
+      })
+    }
+  end
+
+  # Proxy a bunch of methods to another object.
+  def self.classproxy(klass, objmethod, *methods)
+    classobj = class << klass; self; end
+    methods.each do |method|
+      classobj.send(:define_method, method) do |*args|
+        obj = self.send(objmethod)
+
+        obj.send(method, *args)
+      end
+    end
+  end
+
+  # Proxy a bunch of methods to another object.
+  def self.proxy(klass, objmethod, *methods)
+    methods.each do |method|
+      klass.send(:define_method, method) do |*args|
+        obj = self.send(objmethod)
+
+        obj.send(method, *args)
+      end
+    end
+  end
+
+  def benchmark(*args)
+    msg = args.pop
+    level = args.pop
+    object = nil
+
+    if args.empty?
+      if respond_to?(level)
+        object = self
+      else
+        object = Puppet
+      end
+    else
+      object = args.pop
+    end
+
+    raise Puppet::DevError, "Failed to provide level to :benchmark" unless level
+
+    unless level == :none or object.respond_to? level
+      raise Puppet::DevError, "Benchmarked object does not respond to #{level}"
+    end
+
+    # Only benchmark if our log level is high enough
+    if level != :none and Puppet::Util::Log.sendlevel?(level)
+      seconds = Benchmark.realtime {
+        yield
+      }
+      object.send(level, msg + (" in %0.2f seconds" % seconds))
+      return seconds
+    else
+      yield
+    end
+  end
+  module_function :benchmark
+
+  # Resolve a path for an executable to the absolute path. This tries to behave
+  # in the same manner as the unix `which` command and uses the `PATH`
+  # environment variable.
+  #
+  # @api public
+  # @param bin [String] the name of the executable to find.
+  # @return [String] the absolute path to the found executable.
+  def which(bin)
+    if absolute_path?(bin)
+      return bin if FileTest.file? bin and FileTest.executable? bin
+    else
+      ENV['PATH'].split(File::PATH_SEPARATOR).each do |dir|
+        begin
+          dest = File.expand_path(File.join(dir, bin))
+        rescue ArgumentError => e
+          # if the user's PATH contains a literal tilde (~) character and HOME is not set, we may get
+          # an ArgumentError here.  Let's check to see if that is the case; if not, re-raise whatever error
+          # was thrown.
+          if e.to_s =~ /HOME/ and (ENV['HOME'].nil? || ENV['HOME'] == "")
+            # if we get here they have a tilde in their PATH.  We'll issue a single warning about this and then
+            # ignore this path element and carry on with our lives.
+            Puppet::Util::Warnings.warnonce("PATH contains a ~ character, and HOME is not set; ignoring PATH element '#{dir}'.")
+          elsif e.to_s =~ /doesn't exist|can't find user/
+            # ...otherwise, we just skip the non-existent entry, and do nothing.
+            Puppet::Util::Warnings.warnonce("Couldn't expand PATH containing a ~ character; ignoring PATH element '#{dir}'.")
+          else
+            raise
+          end
+        else
+          if Puppet.features.microsoft_windows? && File.extname(dest).empty?
+            exts = ENV['PATHEXT']
+            exts = exts ? exts.split(File::PATH_SEPARATOR) : %w[.COM .EXE .BAT .CMD]
+            exts.each do |ext|
+              destext = File.expand_path(dest + ext)
+              return destext if FileTest.file? destext and FileTest.executable? destext
+            end
+          end
+          return dest if FileTest.file? dest and FileTest.executable? dest
+        end
+      end
+    end
+    nil
+  end
+  module_function :which
+
+  # 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 = '[\\\\/]'
+  label = '[^\\\\/]+'
+  AbsolutePathWindows = %r!^(?:(?:[A-Z]:#{slash})|(?:#{slash}#{slash}#{label}#{slash}#{label})|(?:#{slash}#{slash}\?#{slash}#{label}))!io
+  AbsolutePathPosix   = %r!^/!
+  def absolute_path?(path, platform=nil)
+    # Ruby only sets File::ALT_SEPARATOR on Windows and the Ruby standard
+    # library uses that to test what platform it's on.  Normally in Puppet we
+    # would use Puppet.features.microsoft_windows?, but this method needs to
+    # be called during the initialization of features so it can't depend on
+    # that.
+    platform ||= Puppet::Util::Platform.windows? ? :windows : :posix
+    regex = case platform
+            when :windows
+              AbsolutePathWindows
+            when :posix
+              AbsolutePathPosix
+            else
+              raise Puppet::DevError, "unknown platform #{platform} in absolute_path"
+            end
+
+    !! (path =~ regex)
+  end
+  module_function :absolute_path?
+
+  # Convert a path to a file URI
+  def path_to_uri(path)
+    return unless path
+
+    params = { :scheme => 'file' }
+
+    if Puppet.features.microsoft_windows?
+      path = path.gsub(/\\/, '/')
+
+      if unc = /^\/\/([^\/]+)(\/.+)/.match(path)
+        params[:host] = unc[1]
+        path = unc[2]
+      elsif path =~ /^[a-z]:\//i
+        path = '/' + path
+      end
+    end
+
+    params[:path] = URI.escape(path)
+
+    begin
+      URI::Generic.build(params)
+    rescue => detail
+      raise Puppet::Error, "Failed to convert '#{path}' to URI: #{detail}", detail.backtrace
+    end
+  end
+  module_function :path_to_uri
+
+  # Get the path component of a URI
+  def uri_to_path(uri)
+    return unless uri.is_a?(URI)
+
+    path = URI.unescape(uri.path)
+
+    if Puppet.features.microsoft_windows? and uri.scheme == 'file'
+      if uri.host
+        path = "//#{uri.host}" + path # UNC
+      else
+        path.sub!(/^\//, '')
+      end
+    end
+
+    path
+  end
+  module_function :uri_to_path
+
+  def safe_posix_fork(stdin=$stdin, stdout=$stdout, stderr=$stderr, &block)
+    child_pid = Kernel.fork do
+      $stdin.reopen(stdin)
+      $stdout.reopen(stdout)
+      $stderr.reopen(stderr)
+
+      begin
+        Dir.foreach('/proc/self/fd') do |f|
+          if f != '.' && f != '..' && f.to_i >= 3
+            IO::new(f.to_i).close rescue nil
+          end
+        end
+      rescue Errno::ENOENT # /proc/self/fd not found
+        3.upto(256){|fd| IO::new(fd).close rescue nil}
+      end
+
+      block.call if block
+    end
+    child_pid
+  end
+  module_function :safe_posix_fork
+
+  def memory
+    unless defined?(@pmap)
+      @pmap = which('pmap')
+    end
+    if @pmap
+      %x{#{@pmap} #{Process.pid}| grep total}.chomp.sub(/^\s*total\s+/, '').sub(/K$/, '').to_i
+    else
+      0
+    end
+  end
+
+  def symbolizehash(hash)
+    newhash = {}
+    hash.each do |name, val|
+      name = name.intern if name.respond_to? :intern
+      newhash[name] = val
+    end
+    newhash
+  end
+  module_function :symbolizehash
+
+  # Just benchmark, with no logging.
+  def thinmark
+    seconds = Benchmark.realtime {
+      yield
+    }
+
+    seconds
+  end
+
+  module_function :memory, :thinmark
+
+  # Because IO#binread is only available in 1.9
+  def binread(file)
+    Puppet.deprecation_warning("Puppet::Util.binread is deprecated. Read the file without this method as it will be removed in a future version.")
+    File.open(file, 'rb') { |f| f.read }
+  end
+  module_function :binread
+
+  # utility method to get the current call stack and format it to a human-readable string (which some IDEs/editors
+  # will recognize as links to the line numbers in the trace)
+  def self.pretty_backtrace(backtrace = caller(1))
+    backtrace.collect do |line|
+      _, path, rest = /^(.*):(\d+.*)$/.match(line).to_a
+      # If the path doesn't exist - like in one test, and like could happen in
+      # the world - we should just tolerate it and carry on. --daniel 2012-09-05
+      # Also, if we don't match, just include the whole line.
+      if path
+        path = Pathname(path).realpath rescue path
+        "#{path}:#{rest}"
+      else
+        line
+      end
+    end.join("\n")
+  end
+
+  # Replace a file, securely.  This takes a block, and passes it the file
+  # handle of a file open for writing.  Write the replacement content inside
+  # the block and it will safely replace the target file.
+  #
+  # This method will make no changes to the target file until the content is
+  # successfully written and the block returns without raising an error.
+  #
+  # As far as possible the state of the existing file, such as mode, is
+  # preserved.  This works hard to avoid loss of any metadata, but will result
+  # in an inode change for the file.
+  #
+  # Arguments: `filename`, `default_mode`
+  #
+  # The filename is the file we are going to replace.
+  #
+  # The default_mode is the mode to use when the target file doesn't already
+  # exist; if the file is present we copy the existing mode/owner/group values
+  # across. The default_mode can be expressed as an octal integer, a numeric string (ie '0664')
+  # or a symbolic file mode.
+
+  DEFAULT_POSIX_MODE = 0644
+  DEFAULT_WINDOWS_MODE = nil
+
+  def replace_file(file, default_mode, &block)
+    raise Puppet::DevError, "replace_file requires a block" unless block_given?
+
+    if default_mode
+      unless valid_symbolic_mode?(default_mode)
+        raise Puppet::DevError, "replace_file default_mode: #{default_mode} is invalid"
+      end
+
+      mode = symbolic_mode_to_int(normalize_symbolic_mode(default_mode))
+    else
+      if Puppet.features.microsoft_windows?
+        mode = DEFAULT_WINDOWS_MODE
+      else
+        mode = DEFAULT_POSIX_MODE
+      end
+    end
+
+    begin
+      file     = Puppet::FileSystem.pathname(file)
+      tempfile = Puppet::FileSystem::Uniquefile.new(Puppet::FileSystem.basename_string(file), Puppet::FileSystem.dir_string(file))
+
+      # Set properties of the temporary file before we write the content, because
+      # Tempfile doesn't promise to be safe from reading by other people, just
+      # that it avoids races around creating the file.
+      #
+      # Our Windows emulation is pretty limited, and so we have to carefully
+      # and specifically handle the platform, which has all sorts of magic.
+      # So, unlike Unix, we don't pre-prep security; we use the default "quite
+      # secure" tempfile permissions instead.  Magic happens later.
+      if !Puppet.features.microsoft_windows?
+        # Grab the current file mode, and fall back to the defaults.
+        effective_mode =
+        if Puppet::FileSystem.exist?(file)
+          stat = Puppet::FileSystem.lstat(file)
+          tempfile.chown(stat.uid, stat.gid)
+          stat.mode
+        else
+          mode
+        end
+
+        if effective_mode
+          # We only care about the bottom four slots, which make the real mode,
+          # and not the rest of the platform stat call fluff and stuff.
+          tempfile.chmod(effective_mode & 07777)
+        end
+      end
+
+      # OK, now allow the caller to write the content of the file.
+      yield tempfile
+
+      # Now, make sure the data (which includes the mode) is safe on disk.
+      tempfile.flush
+      begin
+        tempfile.fsync
+      rescue NotImplementedError
+        # fsync may not be implemented by Ruby on all platforms, but
+        # there is absolutely no recovery path if we detect that.  So, we just
+        # ignore the return code.
+        #
+        # However, don't be fooled: that is accepting that we are running in
+        # an unsafe fashion.  If you are porting to a new platform don't stub
+        # that out.
+      end
+
+      tempfile.close
+
+      if Puppet.features.microsoft_windows?
+        # Windows ReplaceFile needs a file to exist, so touch handles this
+        if !Puppet::FileSystem.exist?(file)
+          Puppet::FileSystem.touch(file)
+          if mode
+            Puppet::Util::Windows::Security.set_mode(mode, Puppet::FileSystem.path_string(file))
+          end
+        end
+        # Yes, the arguments are reversed compared to the rename in the rest
+        # of the world.
+        Puppet::Util::Windows::File.replace_file(FileSystem.path_string(file), tempfile.path)
+
+      else
+        File.rename(tempfile.path, Puppet::FileSystem.path_string(file))
+      end
+    ensure
+      # in case an error occurred before we renamed the temp file, make sure it
+      # gets deleted
+      if tempfile
+        tempfile.close!
+      end
+    end
+
+
+    # Ideally, we would now fsync the directory as well, but Ruby doesn't
+    # have support for that, and it doesn't matter /that/ much...
+
+    # Return something true, and possibly useful.
+    file
+  end
+  module_function :replace_file
+
+  # Executes a block of code, wrapped with some special exception handling.  Causes the ruby interpreter to
+  #  exit if the block throws an exception.
+  #
+  # @api public
+  # @param [String] message a message to log if the block fails
+  # @param [Integer] code the exit code that the ruby interpreter should return if the block fails
+  # @yield
+  def exit_on_fail(message, code = 1)
+    yield
+  # First, we need to check and see if we are catching a SystemExit error.  These will be raised
+  #  when we daemonize/fork, and they do not necessarily indicate a failure case.
+  rescue SystemExit => err
+    raise err
+
+  # Now we need to catch *any* other kind of exception, because we may be calling third-party
+  #  code (e.g. webrick), and we have no idea what they might throw.
+  rescue Exception => err
+    ## NOTE: when debugging spec failures, these two lines can be very useful
+    #puts err.inspect
+    #puts Puppet::Util.pretty_backtrace(err.backtrace)
+    Puppet.log_exception(err, "Could not #{message}: #{err}")
+    Puppet::Util::Log.force_flushqueue()
+    exit(code)
+  end
+  module_function :exit_on_fail
+
+  def deterministic_rand(seed,max)
+    if defined?(Random) == 'constant' && Random.class == Class
+      Random.new(seed).rand(max).to_s
+    else
+      srand(seed)
+      result = rand(max).to_s
+      srand()
+      result
+    end
+  end
+  module_function :deterministic_rand
+
+
+  #######################################################################################################
+  # Deprecated methods relating to process execution; these have been moved to Puppet::Util::Execution
+  #######################################################################################################
+
+  def execpipe(command, failonfail = true, &block)
+    Puppet.deprecation_warning("Puppet::Util.execpipe is deprecated; please use Puppet::Util::Execution.execpipe")
+    Puppet::Util::Execution.execpipe(command, failonfail, &block)
+  end
+  module_function :execpipe
+
+  def execfail(command, exception)
+    Puppet.deprecation_warning("Puppet::Util.execfail is deprecated; please use Puppet::Util::Execution.execfail")
+    Puppet::Util::Execution.execfail(command, exception)
+  end
+  module_function :execfail
+
+  def execute(*args)
+    Puppet.deprecation_warning("Puppet::Util.execute is deprecated; please use Puppet::Util::Execution.execute")
+
+    Puppet::Util::Execution.execute(*args)
+  end
+  module_function :execute
+
+end
+end
+
+
+require 'puppet/util/errors'
+require 'puppet/util/methodhelper'
+require 'puppet/util/metaid'
+require 'puppet/util/classgen'
+require 'puppet/util/docs'
+require 'puppet/util/execution'
+require 'puppet/util/logging'
+require 'puppet/util/package'
+require 'puppet/util/warnings'
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/autoload.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/autoload.rb
new file mode 100644
index 0000000..88f0852
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/autoload.rb
@@ -0,0 +1,231 @@
+require 'pathname'
+require 'puppet/util/rubygems'
+require 'puppet/util/warnings'
+require 'puppet/util/methodhelper'
+
+# Autoload paths, either based on names or all at once.
+class Puppet::Util::Autoload
+  include Puppet::Util::MethodHelper
+
+  @autoloaders = {}
+  @loaded = {}
+
+  class << self
+    attr_reader :autoloaders
+    attr_accessor :loaded
+    private :autoloaders, :loaded
+
+    def gem_source
+      @gem_source ||= Puppet::Util::RubyGems::Source.new
+    end
+
+    # Has a given path been loaded?  This is used for testing whether a
+    # changed file should be loaded or just ignored.  This is only
+    # used in network/client/master, when downloading plugins, to
+    # see if a given plugin is currently loaded and thus should be
+    # reloaded.
+    def loaded?(path)
+      path = cleanpath(path).chomp('.rb')
+      loaded.include?(path)
+    end
+
+    # Save the fact that a given path has been loaded.  This is so
+    # we can load downloaded plugins if they've already been loaded
+    # into memory.
+    def mark_loaded(name, file)
+      name = cleanpath(name).chomp('.rb')
+      ruby_file = name + ".rb"
+      $LOADED_FEATURES << ruby_file unless $LOADED_FEATURES.include?(ruby_file)
+      loaded[name] = [file, File.mtime(file)]
+    end
+
+    def changed?(name)
+      name = cleanpath(name).chomp('.rb')
+      return true unless loaded.include?(name)
+      file, old_mtime = loaded[name]
+      environment = Puppet.lookup(:current_environment)
+      return true unless file == get_file(name, environment)
+      begin
+        old_mtime.to_i != File.mtime(file).to_i
+      rescue Errno::ENOENT
+        true
+      end
+    end
+
+    # Load a single plugin by name.  We use 'load' here so we can reload a
+    # given plugin.
+    def load_file(name, env)
+      file = get_file(name.to_s, env)
+      return false unless file
+      begin
+        mark_loaded(name, file)
+        Kernel.load file, @wrap
+        return true
+      rescue SystemExit,NoMemoryError
+        raise
+      rescue Exception => detail
+        message = "Could not autoload #{name}: #{detail}"
+        Puppet.log_exception(detail, message)
+        raise Puppet::Error, message, detail.backtrace
+      end
+    end
+
+    def loadall(path, env = nil)
+      # Load every instance of everything we can find.
+      files_to_load(path, env).each do |file|
+        name = file.chomp(".rb")
+        load_file(name, env) unless loaded?(name)
+      end
+    end
+
+    def reload_changed
+      loaded.keys.each { |file| load_file(file, nil) if changed?(file) }
+    end
+
+    # Get the correct file to load for a given path
+    # returns nil if no file is found
+    def get_file(name, env)
+      name = name + '.rb' unless name =~ /\.rb$/
+      path = search_directories(env).find { |dir| Puppet::FileSystem.exist?(File.join(dir, name)) }
+      path and File.join(path, name)
+    end
+
+    def files_to_load(path, env = nil)
+      search_directories(env).map {|dir| files_in_dir(dir, path) }.flatten.uniq
+    end
+
+    def files_in_dir(dir, path)
+      dir = Pathname.new(File.expand_path(dir))
+      Dir.glob(File.join(dir, path, "*.rb")).collect do |file|
+        Pathname.new(file).relative_path_from(dir).to_s
+      end
+    end
+
+    def module_directories(env)
+      # We're using a per-thread cache of module directories so that we don't
+      # scan the filesystem each time we try to load something. This is reset
+      # at the beginning of compilation and at the end of an agent run.
+      $env_module_directories ||= {}
+
+
+      # This is a little bit of a hack.  Basically, the autoloader is being
+      # called indirectly during application bootstrapping when we do things
+      # such as check "features".  However, during bootstrapping, we haven't
+      # yet parsed all of the command line parameters nor the config files,
+      # and thus we don't yet know with certainty what the module path is.
+      # This should be irrelevant during bootstrapping, because anything that
+      # we are attempting to load during bootstrapping should be something
+      # that we ship with puppet, and thus the module path is irrelevant.
+      #
+      # In the long term, I think the way that we want to handle this is to
+      # have the autoloader ignore the module path in all cases where it is
+      # not specifically requested (e.g., by a constructor param or
+      # something)... because there are very few cases where we should
+      # actually be loading code from the module path.  However, until that
+      # happens, we at least need a way to prevent the autoloader from
+      # attempting to access the module path before it is initialized.  For
+      # now we are accomplishing that by calling the
+      # "app_defaults_initialized?" method on the main puppet Settings object.
+      # --cprice 2012-03-16
+      if Puppet.settings.app_defaults_initialized?
+        env ||= Puppet.lookup(:environments).get(Puppet[:environment])
+
+        if env
+          # if the app defaults have been initialized then it should be safe to access the module path setting.
+          $env_module_directories[env] ||= env.modulepath.collect do |dir|
+            Dir.entries(dir).reject { |f| f =~ /^\./ }.collect { |f| File.join(dir, f, "lib") }
+          end.flatten.find_all do |d|
+            FileTest.directory?(d)
+          end
+        else
+          []
+        end
+      else
+        # if we get here, the app defaults have not been initialized, so we basically use an empty module path.
+        []
+      end
+    end
+
+    def libdirs()
+      # See the comments in #module_directories above.  Basically, we need to be careful not to try to access the
+      # libdir before we know for sure that all of the settings have been initialized (e.g., during bootstrapping).
+      if (Puppet.settings.app_defaults_initialized?)
+        Puppet[:libdir].split(File::PATH_SEPARATOR)
+      else
+        []
+      end
+    end
+
+    def gem_directories
+      gem_source.directories
+    end
+
+    def search_directories(env)
+      [gem_directories, module_directories(env), libdirs(), $LOAD_PATH].flatten
+    end
+
+    # Normalize a path. This converts ALT_SEPARATOR to SEPARATOR on Windows
+    # and eliminates unnecessary parts of a path.
+    def cleanpath(path)
+      # There are two cases here because cleanpath does not handle absolute
+      # paths correctly on windows (c:\ and c:/ are treated as distinct) but
+      # we don't want to convert relative paths to absolute
+      if Puppet::Util.absolute_path?(path)
+        File.expand_path(path)
+      else
+        Pathname.new(path).cleanpath.to_s
+      end
+    end
+  end
+
+  # Send [] and []= to the @autoloaders hash
+  Puppet::Util.classproxy self, :autoloaders, "[]", "[]="
+
+  attr_accessor :object, :path, :objwarn, :wrap
+
+  def initialize(obj, path, options = {})
+    @path = path.to_s
+    raise ArgumentError, "Autoload paths cannot be fully qualified" if Puppet::Util.absolute_path?(@path)
+    @object = obj
+
+    self.class[obj] = self
+
+    set_options(options)
+
+    @wrap = true unless defined?(@wrap)
+  end
+
+  def load(name, env = nil)
+    self.class.load_file(expand(name), env)
+  end
+
+  # Load all instances from a path of Autoload.search_directories matching the
+  # relative path this Autoloader was initialized with.  For example, if we
+  # have created a Puppet::Util::Autoload for Puppet::Type::User with a path of
+  # 'puppet/provider/user', the search_directories path will be searched for
+  # all ruby files matching puppet/provider/user/*.rb and they will then be
+  # loaded from the first directory in the search path providing them.  So
+  # earlier entries in the search path may shadow later entries.
+  #
+  # This uses require, rather than load, so that already-loaded files don't get
+  # reloaded unnecessarily.
+  def loadall(env = nil)
+    self.class.loadall(@path, env)
+  end
+
+  def loaded?(name)
+    self.class.loaded?(expand(name))
+  end
+
+  def changed?(name)
+    self.class.changed?(expand(name))
+  end
+
+  def files_to_load
+    self.class.files_to_load(@path)
+  end
+
+  def expand(name)
+    ::File.join(@path, name.to_s)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/backups.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/backups.rb
new file mode 100644
index 0000000..249d278
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/backups.rb
@@ -0,0 +1,86 @@
+require 'find'
+require 'fileutils'
+module Puppet::Util::Backups
+
+  # Deal with backups.
+  def perform_backup(file = nil)
+    # if they specifically don't want a backup, then just say
+    # we're good
+    return true unless self[:backup]
+
+    # let the path be specified
+    file ||= self[:path]
+    return true unless Puppet::FileSystem.exist?(file)
+
+    return(self.bucket ? perform_backup_with_bucket(file) : perform_backup_with_backuplocal(file, self[:backup]))
+  end
+
+  private
+
+  def perform_backup_with_bucket(fileobj)
+    file = (fileobj.class == String) ? fileobj : fileobj.name
+    case Puppet::FileSystem.lstat(file).ftype
+    when "directory"
+      # we don't need to backup directories when recurse is on
+      return true if self[:recurse]
+      info "Recursively backing up to filebucket"
+      Find.find(self[:path]) { |f| backup_file_with_filebucket(f) if File.file?(f) }
+    when "file"; backup_file_with_filebucket(file)
+    when "link";
+    end
+    true
+  end
+
+  def perform_backup_with_backuplocal(fileobj, backup)
+    file = (fileobj.class == String) ? fileobj : fileobj.name
+    newfile = file + backup
+
+    remove_backup(newfile)
+
+    begin
+      bfile = file + backup
+
+      # N.B. cp_r works on both files and directories
+      FileUtils.cp_r(file, bfile, :preserve => true)
+      return true
+    rescue => detail
+      # since they said they want a backup, let's error out
+      # if we couldn't make one
+      self.fail Puppet::Error, "Could not back #{file} up: #{detail.message}", detail
+    end
+  end
+
+  def remove_backup(newfile)
+    if self.class.name == :file and self[:links] != :follow
+      method = :lstat
+    else
+      method = :stat
+    end
+
+    begin
+      stat = Puppet::FileSystem.send(method, newfile)
+    rescue Errno::ENOENT
+      return
+    end
+
+    if stat.ftype == "directory"
+      raise Puppet::Error, "Will not remove directory backup #{newfile}; use a filebucket"
+    end
+
+    info "Removing old backup of type #{stat.ftype}"
+
+    begin
+      Puppet::FileSystem.unlink(newfile)
+    rescue => detail
+      message = "Could not remove old backup: #{detail}"
+      self.log_exception(detail, message)
+      self.fail Puppet::Error, message, detail
+    end
+  end
+
+  def backup_file_with_filebucket(f)
+    sum = self.bucket.backup(f)
+    self.info "Filebucketed #{f} to #{self.bucket.name} with sum #{sum}"
+    return sum
+    end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/cacher.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/cacher.rb
new file mode 100644
index 0000000..24017de
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/cacher.rb
@@ -0,0 +1,74 @@
+module Puppet::Util::Cacher
+  # Our module has been extended in a class; we can only add the Instance methods,
+  # which become *class* methods in the class.
+  def self.extended(other)
+    class << other
+      extend ClassMethods
+      include InstanceMethods
+    end
+  end
+
+  # Our module has been included in a class, which means the class gets the class methods
+  # and all of its instances get the instance methods.
+  def self.included(other)
+    other.extend(ClassMethods)
+    other.send(:include, InstanceMethods)
+  end
+
+  # Methods that can get added to a class.
+  module ClassMethods
+    # Provide a means of defining an attribute whose value will be cached.
+    # Must provide a block capable of defining the value if it's flushed..
+    def cached_attr(name, ttl, &block)
+      init_method = "init_#{name}"
+      define_method(init_method, &block)
+
+      set_attr_ttl(name, ttl)
+
+      define_method(name) do
+        cached_value(name)
+      end
+
+      define_method(name.to_s + "=") do |value|
+        # Make sure the cache timestamp is set
+        value_cache[name] = value
+        set_expiration(name)
+      end
+    end
+
+    def attr_ttl(name)
+      @attr_ttls[name]
+    end
+
+    def set_attr_ttl(name, value)
+      @attr_ttls ||= {}
+      @attr_ttls[name] = Integer(value)
+    end
+  end
+
+  # Methods that get added to instances.
+  module InstanceMethods
+    private
+
+    def cached_value(name)
+      if value_cache[name].nil? or expired_by_ttl?(name)
+        value_cache[name] = send("init_#{name}")
+        set_expiration(name)
+      end
+      value_cache[name]
+    end
+
+    def expired_by_ttl?(name)
+      @attr_expirations[name] < Time.now
+    end
+
+    def set_expiration(name)
+      @attr_expirations ||= {}
+      @attr_expirations[name] = Time.now + self.class.attr_ttl(name)
+    end
+
+    def value_cache
+      @value_cache ||= {}
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/checksums.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/checksums.rb
new file mode 100644
index 0000000..06df9e4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/checksums.rb
@@ -0,0 +1,202 @@
+require 'digest/md5'
+require 'digest/sha1'
+
+# A stand-alone module for calculating checksums
+# in a generic way.
+module Puppet::Util::Checksums
+  # @deprecated
+  # In Puppet 4 we should switch this to `module_function` to make these methods
+  # private when this class is included.
+  extend self
+
+  # It's not a good idea to use some of these in some contexts: for example, I
+  # wouldn't try bucketing a file using the :none checksum type.
+  def known_checksum_types
+    [:sha256, :sha256lite, :md5, :md5lite, :sha1, :sha1lite,
+      :mtime, :ctime, :none]
+  end
+
+  class FakeChecksum
+    def <<(*args)
+      self
+    end
+  end
+
+  # Is the provided string a checksum?
+  def checksum?(string)
+    # 'sha256lite'.length == 10
+    string =~ /^\{(\w{3,10})\}\S+/
+  end
+
+  # Strip the checksum type from an existing checksum
+  def sumdata(checksum)
+    checksum =~ /^\{(\w+)\}(.+)/ ? $2 : nil
+  end
+
+  # Strip the checksum type from an existing checksum
+  def sumtype(checksum)
+    checksum =~ /^\{(\w+)\}/ ? $1 : nil
+  end
+
+  # Calculate a checksum using Digest::SHA256.
+  def sha256(content)
+    require 'digest/sha2'
+    Digest::SHA256.hexdigest(content)
+  end
+
+  def sha256lite(content)
+    sha256(content[0..511])
+  end
+
+  def sha256_file(filename, lite = false)
+    require 'digest/sha2'
+
+    digest = Digest::SHA256.new
+    checksum_file(digest, filename,  lite)
+  end
+
+  def sha256lite_file(filename)
+    sha256_file(filename, true)
+  end
+
+  def sha256_stream(&block)
+    require 'digest/sha2'
+    digest = Digest::SHA256.new
+    yield digest
+    digest.hexdigest
+  end
+
+  def sha256_hex_length
+    64
+  end
+
+  alias :sha256lite_stream :sha256_stream
+  alias :sha256lite_hex_length :sha256_hex_length
+
+  # Calculate a checksum using Digest::MD5.
+  def md5(content)
+    Digest::MD5.hexdigest(content)
+  end
+
+  # Calculate a checksum of the first 500 chars of the content using Digest::MD5.
+  def md5lite(content)
+    md5(content[0..511])
+  end
+
+  # Calculate a checksum of a file's content using Digest::MD5.
+  def md5_file(filename, lite = false)
+    digest = Digest::MD5.new
+    checksum_file(digest, filename,  lite)
+  end
+
+  # Calculate a checksum of the first 500 chars of a file's content using Digest::MD5.
+  def md5lite_file(filename)
+    md5_file(filename, true)
+  end
+
+  def md5_stream(&block)
+    digest = Digest::MD5.new
+    yield digest
+    digest.hexdigest
+  end
+
+  def md5_hex_length
+    32
+  end
+
+  alias :md5lite_stream :md5_stream
+  alias :md5lite_hex_length :md5_hex_length
+
+  # Return the :mtime timestamp of a file.
+  def mtime_file(filename)
+    Puppet::FileSystem.stat(filename).send(:mtime)
+  end
+
+  # by definition this doesn't exist
+  # but we still need to execute the block given
+  def mtime_stream
+    noop_digest = FakeChecksum.new
+    yield noop_digest
+    nil
+  end
+
+  def mtime(content)
+    ""
+  end
+
+  # Calculate a checksum using Digest::SHA1.
+  def sha1(content)
+    Digest::SHA1.hexdigest(content)
+  end
+
+  # Calculate a checksum of the first 500 chars of the content using Digest::SHA1.
+  def sha1lite(content)
+    sha1(content[0..511])
+  end
+
+  # Calculate a checksum of a file's content using Digest::SHA1.
+  def sha1_file(filename, lite = false)
+    digest = Digest::SHA1.new
+    checksum_file(digest, filename, lite)
+  end
+
+  # Calculate a checksum of the first 500 chars of a file's content using Digest::SHA1.
+  def sha1lite_file(filename)
+    sha1_file(filename, true)
+  end
+
+  def sha1_stream
+    digest = Digest::SHA1.new
+    yield digest
+    digest.hexdigest
+  end
+
+  def sha1_hex_length
+    40
+  end
+
+  alias :sha1lite_stream :sha1_stream
+  alias :sha1lite_hex_length :sha1_hex_length
+
+  # Return the :ctime of a file.
+  def ctime_file(filename)
+    Puppet::FileSystem.stat(filename).send(:ctime)
+  end
+
+  alias :ctime_stream :mtime_stream
+
+  def ctime(content)
+    ""
+  end
+
+  # Return a "no checksum"
+  def none_file(filename)
+    ""
+  end
+
+  def none_stream
+    noop_digest = FakeChecksum.new
+    yield noop_digest
+    ""
+  end
+
+  def none(content)
+    ""
+  end
+
+  private
+
+  # Perform an incremental checksum on a file.
+  def checksum_file(digest, filename, lite = false)
+    buffer = lite ? 512 : 4096
+    File.open(filename, 'rb') do |file|
+      while content = file.read(buffer)
+        digest << content
+        break if lite
+      end
+    end
+
+    digest.hexdigest
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/classgen.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/classgen.rb
new file mode 100644
index 0000000..78e8732
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/classgen.rb
@@ -0,0 +1,236 @@
+require 'puppet/util/methodhelper'
+
+module Puppet
+  class ConstantAlreadyDefined < Error; end
+  class SubclassAlreadyDefined < Error; end
+end
+
+# This is a utility module for generating classes.
+# @api public
+#
+module Puppet::Util::ClassGen
+  include Puppet::Util::MethodHelper
+  include Puppet::Util
+
+  # Create a new class.
+  # @param name [String] the name of the generated class
+  # @param options [Hash] a hash of options
+  # @option options [Array<Class>] :array if specified, the generated class is appended to this array
+  # @option options [Hash<{String => Object}>] :attributes a hash that is applied to the generated class
+  #   by calling setter methods corresponding to this hash's keys/value pairs. This is done before the given
+  #   block is evaluated.
+  # @option options [Proc] :block a block to evaluate in the context of the class (this block can be provided
+  #   this way, or as a normal yield block).
+  # @option options [String] :constant (name with first letter capitalized) what to set the constant that references
+  #   the generated class to.
+  # @option options [Hash] :hash a hash of existing classes that this class is appended to (name => class).
+  #   This hash must be specified if the `:overwrite` option is set to `true`.
+  # @option options [Boolean] :overwrite whether an overwrite of an existing class should be allowed (requires also
+  #   defining the `:hash` with existing classes as the test is based on the content of this hash).
+  # @option options [Class] :parent (self) the parent class of the generated class.
+  # @option options [String] ('') :prefix the constant prefix to prepend to the constant name referencing the
+  #   generated class.
+  # @return [Class] the generated class
+  #
+  def genclass(name, options = {}, &block)
+    genthing(name, Class, options, block)
+  end
+
+  # Creates a new module.
+  # @param name [String] the name of the generated module
+  # @param options [Hash] hash with options
+  # @option options [Array<Class>] :array if specified, the generated class is appended to this array
+  # @option options [Hash<{String => Object}>] :attributes a hash that is applied to the generated class
+  #   by calling setter methods corresponding to this hash's keys/value pairs. This is done before the given
+  #   block is evaluated.
+  # @option options [Proc] :block a block to evaluate in the context of the class (this block can be provided
+  #   this way, or as a normal yield block).
+  # @option options [String] :constant (name with first letter capitalized) what to set the constant that references
+  #   the generated class to.
+  # @option options [Hash] :hash a hash of existing classes that this class is appended to (name => class).
+  #   This hash must be specified if the `:overwrite` option is set to `true`.
+  # @option options [Boolean] :overwrite whether an overwrite of an existing class should be allowed (requires also
+  #   defining the `:hash` with existing classes as the test is based on the content of this hash).
+  #   the capitalized name is appended and the result is set as the constant.
+  # @option options [String] ('') :prefix the constant prefix to prepend to the constant name referencing the
+  #   generated class.
+  # @return [Module] the generated Module
+  def genmodule(name, options = {}, &block)
+    genthing(name, Module, options, block)
+  end
+
+  # Removes an existing class.
+  # @param name [String] the name of the class to remove
+  # @param options [Hash] options
+  # @option options [Hash] :hash a hash of existing classes from which the class to be removed is also removed
+  # @return [Boolean] whether the class was removed or not
+  #
+  def rmclass(name, options)
+    options = symbolize_options(options)
+    const = genconst_string(name, options)
+    retval = false
+    if is_constant_defined?(const)
+      remove_const(const)
+      retval = true
+    end
+
+    if hash = options[:hash] and hash.include? name
+      hash.delete(name)
+      retval = true
+    end
+
+    # Let them know whether we did actually delete a subclass.
+    retval
+  end
+
+  private
+
+  # Generates the constant to create or remove.
+  # @api private
+  def genconst_string(name, options)
+    unless const = options[:constant]
+      prefix = options[:prefix] || ""
+      const = prefix + name2const(name)
+    end
+
+    const
+  end
+
+  # This does the actual work of creating our class or module.  It's just a
+  # slightly abstract version of genclass.
+  # @api private
+  def genthing(name, type, options, block)
+    options = symbolize_options(options)
+
+    name = name.to_s.downcase.intern
+
+    if type == Module
+      #evalmethod = :module_eval
+      evalmethod = :class_eval
+      # Create the class, with the correct name.
+      klass = Module.new do
+        class << self
+          attr_reader :name
+        end
+        @name = name
+      end
+    else
+      options[:parent] ||= self
+      evalmethod = :class_eval
+      # Create the class, with the correct name.
+      klass = Class.new(options[:parent]) do
+        @name = name
+      end
+    end
+
+    # Create the constant as appropriation.
+    handleclassconst(klass, name, options)
+
+    # Initialize any necessary variables.
+    initclass(klass, options)
+
+    block ||= options[:block]
+
+    # Evaluate the passed block if there is one.  This should usually
+    # define all of the work.
+    klass.send(evalmethod, &block) if block
+
+    klass.postinit if klass.respond_to? :postinit
+
+    # Store the class in hashes or arrays or whatever.
+    storeclass(klass, name, options)
+
+    klass
+  end
+
+  # const_defined? in Ruby 1.9 behaves differently in terms
+  # of which class hierarchy it polls for nested namespaces
+  #
+  # See http://redmine.ruby-lang.org/issues/show/1915
+  # @api private
+  #
+  def is_constant_defined?(const)
+    if ::RUBY_VERSION =~ /^1\.8/
+      const_defined?(const)
+    else
+      const_defined?(const, false)
+    end
+  end
+
+  # Handle the setting and/or removing of the associated constant.
+  # @api private
+  #
+  def handleclassconst(klass, name, options)
+    const = genconst_string(name, options)
+
+    if is_constant_defined?(const)
+      if options[:overwrite]
+        Puppet.info "Redefining #{name} in #{self}"
+        remove_const(const)
+      else
+        raise Puppet::ConstantAlreadyDefined,
+          "Class #{const} is already defined in #{self}"
+      end
+    end
+    const_set(const, klass)
+
+    const
+  end
+
+  # Perform the initializations on the class.
+  # @api private
+  #
+  def initclass(klass, options)
+    klass.initvars if klass.respond_to? :initvars
+
+    if attrs = options[:attributes]
+      attrs.each do |param, value|
+        method = param.to_s + "="
+        klass.send(method, value) if klass.respond_to? method
+      end
+    end
+
+    [:include, :extend].each do |method|
+      if set = options[method]
+        set = [set] unless set.is_a?(Array)
+        set.each do |mod|
+          klass.send(method, mod)
+        end
+      end
+    end
+
+    klass.preinit if klass.respond_to? :preinit
+  end
+
+  # Convert our name to a constant.
+  # @api private
+  def name2const(name)
+    name.to_s.capitalize
+  end
+
+  # Store the class in the appropriate places.
+  # @api private
+  def storeclass(klass, klassname, options)
+    if hash = options[:hash]
+      if hash.include? klassname and ! options[:overwrite]
+        raise Puppet::SubclassAlreadyDefined,
+          "Already a generated class named #{klassname}"
+      end
+
+      hash[klassname] = klass
+    end
+
+    # If we were told to stick it in a hash, then do so
+    if array = options[:array]
+      if (klass.respond_to? :name and
+              array.find { |c| c.name == klassname } and
+              ! options[:overwrite])
+        raise Puppet::SubclassAlreadyDefined,
+          "Already a generated class named #{klassname}"
+      end
+
+      array << klass
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/colors.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/colors.rb
new file mode 100644
index 0000000..dee607a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/colors.rb
@@ -0,0 +1,217 @@
+require 'puppet/util/platform'
+
+module Puppet::Util::Colors
+  BLACK       = {:console => "\e[0;30m", :html => "color: #FFA0A0"     }
+  RED         = {:console => "\e[0;31m", :html => "color: #FFA0A0"     }
+  GREEN       = {:console => "\e[0;32m", :html => "color: #00CD00"     }
+  YELLOW      = {:console => "\e[0;33m", :html => "color: #FFFF60"     }
+  BLUE        = {:console => "\e[0;34m", :html => "color: #80A0FF"     }
+  MAGENTA     = {:console => "\e[0;35m", :html => "color: #FFA500"     }
+  CYAN        = {:console => "\e[0;36m", :html => "color: #40FFFF"     }
+  WHITE       = {:console => "\e[0;37m", :html => "color: #FFFFFF"     }
+  HBLACK      = {:console => "\e[1;30m", :html => "color: #FFA0A0"     }
+  HRED        = {:console => "\e[1;31m", :html => "color: #FFA0A0"     }
+  HGREEN      = {:console => "\e[1;32m", :html => "color: #00CD00"     }
+  HYELLOW     = {:console => "\e[1;33m", :html => "color: #FFFF60"     }
+  HBLUE       = {:console => "\e[1;34m", :html => "color: #80A0FF"     }
+  HMAGENTA    = {:console => "\e[1;35m", :html => "color: #FFA500"     }
+  HCYAN       = {:console => "\e[1;36m", :html => "color: #40FFFF"     }
+  HWHITE      = {:console => "\e[1;37m", :html => "color: #FFFFFF"     }
+  BG_RED      = {:console => "\e[0;41m", :html => "background: #FFA0A0"}
+  BG_GREEN    = {:console => "\e[0;42m", :html => "background: #00CD00"}
+  BG_YELLOW   = {:console => "\e[0;43m", :html => "background: #FFFF60"}
+  BG_BLUE     = {:console => "\e[0;44m", :html => "background: #80A0FF"}
+  BG_MAGENTA  = {:console => "\e[0;45m", :html => "background: #FFA500"}
+  BG_CYAN     = {:console => "\e[0;46m", :html => "background: #40FFFF"}
+  BG_WHITE    = {:console => "\e[0;47m", :html => "background: #FFFFFF"}
+  BG_HRED     = {:console => "\e[1;41m", :html => "background: #FFA0A0"}
+  BG_HGREEN   = {:console => "\e[1;42m", :html => "background: #00CD00"}
+  BG_HYELLOW  = {:console => "\e[1;43m", :html => "background: #FFFF60"}
+  BG_HBLUE    = {:console => "\e[1;44m", :html => "background: #80A0FF"}
+  BG_HMAGENTA = {:console => "\e[1;45m", :html => "background: #FFA500"}
+  BG_HCYAN    = {:console => "\e[1;46m", :html => "background: #40FFFF"}
+  BG_HWHITE   = {:console => "\e[1;47m", :html => "background: #FFFFFF"}
+  RESET       = {:console => "\e[0m",    :html => ""                   }
+
+  Colormap = {
+    :debug => WHITE,
+    :info => GREEN,
+    :notice => CYAN,
+    :warning => YELLOW,
+    :err => HMAGENTA,
+    :alert => RED,
+    :emerg => HRED,
+    :crit => HRED,
+
+    :black       => BLACK,
+    :red         => RED,
+    :green       => GREEN,
+    :yellow      => YELLOW,
+    :blue        => BLUE,
+    :magenta     => MAGENTA,
+    :cyan        => CYAN,
+    :white       => WHITE,
+    :hblack      => HBLACK,
+    :hred        => HRED,
+    :hgreen      => HGREEN,
+    :hyellow     => HYELLOW,
+    :hblue       => HBLUE,
+    :hmagenta    => HMAGENTA,
+    :hcyan       => HCYAN,
+    :hwhite      => HWHITE,
+    :bg_red      => BG_RED,
+    :bg_green    => BG_GREEN,
+    :bg_yellow   => BG_YELLOW,
+    :bg_blue     => BG_BLUE,
+    :bg_magenta  => BG_MAGENTA,
+    :bg_cyan     => BG_CYAN,
+    :bg_white    => BG_WHITE,
+    :bg_hred     => BG_HRED,
+    :bg_hgreen   => BG_HGREEN,
+    :bg_hyellow  => BG_HYELLOW,
+    :bg_hblue    => BG_HBLUE,
+    :bg_hmagenta => BG_HMAGENTA,
+    :bg_hcyan    => BG_HCYAN,
+    :bg_hwhite   => BG_HWHITE,
+    :reset       => { :console => "\e[m", :html => "" }
+  }
+
+  # We define console_has_color? at load time since it's checking the
+  # underlying platform which will not change, and we don't want to perform
+  # the check every time we use logging
+  if Puppet::Util::Platform.windows? && RUBY_VERSION =~ /^1\./
+    # We're on windows and using ruby less than v2
+    # so we need win32console for color to work
+    begin
+      require 'ffi'
+      require 'win32console'
+
+      # The win32console gem uses ANSI functions for writing to the console
+      # which doesn't work for unicode strings, e.g. module tool. Ruby 1.9
+      # does the same thing, but doesn't account for ANSI escape sequences
+      class WideConsole < Win32::Console
+        extend FFI::Library
+
+        # http://msdn.microsoft.com/en-us/library/windows/desktop/ms687401(v=vs.85).aspx
+        # BOOL WINAPI WriteConsole(
+        #   _In_        HANDLE hConsoleOutput,
+        #   _In_        const VOID *lpBuffer,
+        #   _In_        DWORD nNumberOfCharsToWrite,
+        #   _Out_       LPDWORD lpNumberOfCharsWritten,
+        #   _Reserved_  LPVOID lpReserved
+        # );
+        ffi_lib :kernel32
+        attach_function_private :WriteConsoleW,
+          [:handle, :lpcwstr, :dword, :lpdword, :lpvoid], :win32_bool
+
+        # typedef struct _COORD {
+        #   SHORT X;
+        #   SHORT Y;
+        # } COORD, *PCOORD;
+        class COORD < FFI::Struct
+          layout :X, :short,
+                 :Y, :short
+        end
+
+        # http://msdn.microsoft.com/en-us/library/windows/desktop/ms687410(v=vs.85).aspx
+        # BOOL WINAPI WriteConsoleOutputCharacter(
+        #   _In_   HANDLE hConsoleOutput,
+        #   _In_   LPCTSTR lpCharacter,
+        #   _In_   DWORD nLength,
+        #   _In_   COORD dwWriteCoord,
+        #   _Out_  LPDWORD lpNumberOfCharsWritten
+        # );
+        ffi_lib :kernel32
+        attach_function_private :WriteConsoleOutputCharacterW,
+          [:handle, :lpcwstr, :dword, COORD, :lpdword], :win32_bool
+
+        def initialize(t = nil)
+          super(t)
+        end
+
+        def WriteChar(str, col, row)
+          writeCoord = COORD.new()
+          writeCoord[:X] = row
+          writeCoord[:Y] = col
+
+          chars_written = 0
+          FFI::MemoryPointer.from_string_to_wide_string(str) do |msg_ptr|
+            FFI::MemoryPointer.new(:dword, 1) do |numberOfCharsWritten_ptr|
+              WriteConsoleOutputCharacterW(@handle, msg_ptr,
+                str.length, writeCoord, numberOfCharsWritten_ptr)
+              chars_written = numberOfCharsWritten_ptr.read_dword
+            end
+          end
+
+          chars_written
+        end
+
+        def Write(str)
+          result = false
+          FFI::MemoryPointer.from_string_to_wide_string(str) do |msg_ptr|
+            FFI::MemoryPointer.new(:dword, 1) do |numberOfCharsWritten_ptr|
+              result = WriteConsoleW(@handle, msg_ptr,
+                str.length, FFI::MemoryPointer.new(:dword, 1),
+                FFI::MemoryPointer::NULL) != FFI::WIN32_FALSE
+            end
+          end
+
+          result
+        end
+      end
+
+      # Override the win32console's IO class so we can supply
+      # our own Console class
+      class WideIO < Win32::Console::ANSI::IO
+        def initialize(fd_std = :stdout)
+          super(fd_std)
+
+          handle = FD_STD_MAP[fd_std][1]
+          @Out = WideConsole.new(handle)
+        end
+      end
+
+      $stdout = WideIO.new(:stdout)
+      $stderr = WideIO.new(:stderr)
+    rescue LoadError
+      def console_has_color?
+        false
+      end
+    else
+      def console_has_color?
+        true
+      end
+    end
+  else
+    # On a posix system we can just enable it
+    def console_has_color?
+      true
+    end
+  end
+
+  def colorize(color, str)
+    case Puppet[:color]
+    when true, :ansi, "ansi", "yes"
+      if console_has_color?
+        console_color(color, str)
+      else
+        str
+      end
+    when :html, "html"
+      html_color(color, str)
+    else
+      str
+    end
+  end
+
+  def console_color(color, str)
+    Colormap[color][:console] +
+    str.gsub(RESET[:console], Colormap[color][:console]) +
+    RESET[:console]
+  end
+
+  def html_color(color, str)
+    span = '<span style="%s">' % Colormap[color][:html]
+    "#{span}%s</span>" % str.gsub(/<span .*?<\/span>/, "</span>\\0#{span}")
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/command_line.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/command_line.rb
new file mode 100644
index 0000000..22fd353
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/command_line.rb
@@ -0,0 +1,199 @@
+# Bundler and rubygems maintain a set of directories from which to
+# load gems. If Bundler is loaded, let it determine what can be
+# loaded. If it's not loaded, then use rubygems. But do this before
+# loading any puppet code, so that our gem loading system is sane.
+if not defined? ::Bundler
+  begin
+    require 'rubygems'
+  rescue LoadError
+  end
+end
+
+require 'puppet'
+require 'puppet/util'
+require "puppet/util/plugins"
+require "puppet/util/rubygems"
+require "puppet/util/limits"
+require 'puppet/util/colors'
+
+module Puppet
+  module Util
+    # This is the main entry point for all puppet applications / faces; it
+    # is basically where the bootstrapping process / lifecycle of an app
+    # begins.
+    class CommandLine
+      include Puppet::Util::Limits
+
+      OPTION_OR_MANIFEST_FILE = /^-|\.pp$|\.rb$/
+
+      # @param zero [String] the name of the executable
+      # @param argv [Array<String>] the arguments passed on the command line
+      # @param stdin [IO] (unused)
+      def initialize(zero = $0, argv = ARGV, stdin = STDIN)
+        @command = File.basename(zero, '.rb')
+        @argv = argv
+        Puppet::Plugins.on_commandline_initialization(:command_line_object => self)
+      end
+
+      # @return [String] name of the subcommand is being executed
+      # @api public
+      def subcommand_name
+        return @command if @command != 'puppet'
+
+        if @argv.first =~ OPTION_OR_MANIFEST_FILE
+          nil
+        else
+          @argv.first
+        end
+      end
+
+      # @return [Array<String>] the command line arguments being passed to the subcommand
+      # @api public
+      def args
+        return @argv if @command != 'puppet'
+
+        if subcommand_name.nil?
+          @argv
+        else
+          @argv[1..-1]
+        end
+      end
+
+      # @api private
+      # @deprecated
+      def self.available_subcommands
+        Puppet.deprecation_warning('Puppet::Util::CommandLine.available_subcommands is deprecated; please use Puppet::Application.available_application_names instead.')
+        Puppet::Application.available_application_names
+      end
+
+      # available_subcommands was previously an instance method, not a class
+      # method, and we have an unknown number of user-implemented applications
+      # that depend on that behaviour.  Forwarding allows us to preserve a
+      # backward compatible API. --daniel 2011-04-11
+      # @api private
+      # @deprecated
+      def available_subcommands
+        Puppet.deprecation_warning('Puppet::Util::CommandLine#available_subcommands is deprecated; please use Puppet::Application.available_application_names instead.')
+        Puppet::Application.available_application_names
+      end
+
+      # Run the puppet subcommand. If the subcommand is determined to be an
+      # external executable, this method will never return and the current
+      # process will be replaced via {Kernel#exec}.
+      #
+      # @return [void]
+      def execute
+        Puppet::Util.exit_on_fail("initialize global default settings") do
+          Puppet.initialize_settings(args)
+        end
+
+        setpriority(Puppet[:priority])
+
+        find_subcommand.run
+      end
+
+      # @api private
+      def external_subcommand
+        Puppet::Util.which("puppet-#{subcommand_name}")
+      end
+
+      private
+
+      def find_subcommand
+        if subcommand_name.nil?
+          NilSubcommand.new(self)
+        elsif Puppet::Application.available_application_names.include?(subcommand_name)
+          ApplicationSubcommand.new(subcommand_name, self)
+        elsif path_to_subcommand = external_subcommand
+          ExternalSubcommand.new(path_to_subcommand, self)
+        else
+          UnknownSubcommand.new(subcommand_name, self)
+        end
+      end
+
+      # @api private
+      class ApplicationSubcommand
+        def initialize(subcommand_name, command_line)
+          @subcommand_name = subcommand_name
+          @command_line = command_line
+        end
+
+        def run
+          # For most applications, we want to be able to load code from the modulepath,
+          # such as apply, describe, resource, and faces.
+          # For agent, we only want to load pluginsync'ed code from libdir.
+          # For master, we shouldn't ever be loading per-enviroment code into the master's
+          # ruby process, but that requires fixing (#17210, #12173, #8750). So for now
+          # we try to restrict to only code that can be autoloaded from the node's
+          # environment.
+
+          # PUP-2114 - at this point in the bootstrapping process we do not
+          # have an appropriate application-wide current_environment set.
+          # If we cannot find the configured environment, which may not exist,
+          # we do not attempt to add plugin directories to the load path.
+          #
+          if @subcommand_name != 'master' and @subcommand_name != 'agent'
+            if configured_environment = Puppet.lookup(:environments).get(Puppet[:environment])
+              configured_environment.each_plugin_directory do |dir|
+                $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
+              end
+            end
+          end
+
+          app = Puppet::Application.find(@subcommand_name).new(@command_line)
+          Puppet::Plugins.on_application_initialization(:application_object => @command_line)
+
+          app.run
+        end
+      end
+
+      # @api private
+      class ExternalSubcommand
+        def initialize(path_to_subcommand, command_line)
+          @path_to_subcommand = path_to_subcommand
+          @command_line = command_line
+        end
+
+        def run
+          Kernel.exec(@path_to_subcommand, *@command_line.args)
+        end
+      end
+
+      # @api private
+      class NilSubcommand
+        include Puppet::Util::Colors
+
+        def initialize(command_line)
+          @command_line = command_line
+        end
+
+        def run
+          args = @command_line.args
+          if args.include? "--version" or args.include? "-V"
+            puts Puppet.version
+          elsif @command_line.subcommand_name.nil? && args.count > 0
+            # If the subcommand is truly nil and there is an arg, it's an option; print out the invalid option message
+            puts colorize(:hred, "Error: Could not parse application options: invalid option: #{args[0]}")
+            exit 1
+          else
+            puts "See 'puppet help' for help on available puppet subcommands"
+          end
+        end
+      end
+
+      # @api private
+      class UnknownSubcommand < NilSubcommand
+        def initialize(subcommand_name, command_line)
+          @subcommand_name = subcommand_name
+          super(command_line)
+        end
+
+        def run
+          puts colorize(:hred, "Error: Unknown Puppet subcommand '#{@subcommand_name}'")
+          super
+          exit 1
+        end
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/command_line/puppet_option_parser.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/command_line/puppet_option_parser.rb
new file mode 100644
index 0000000..60cf5c4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/command_line/puppet_option_parser.rb
@@ -0,0 +1,87 @@
+require 'puppet/util/command_line/trollop'
+
+module Puppet
+  module Util
+    class CommandLine
+      class PuppetOptionError < Puppet::Error
+      end
+
+      class TrollopCommandlineError < Puppet::Util::CommandLine::Trollop::CommandlineError; end
+
+      # This is a command line option parser.  It is intended to have an API that is very similar to
+      #  the ruby stdlib 'OptionParser' API, for ease of integration into our existing code... however,
+      #  However, we've removed the OptionParser-based implementation and are only maintaining the
+      #  it's implemented based on the third-party "trollop" library.  This was done because there
+      #  are places where the stdlib OptionParser is not flexible enough to meet our needs.
+
+      class PuppetOptionParser
+        def initialize(usage_msg = nil)
+          require "puppet/util/command_line/trollop"
+
+          @create_default_short_options = false
+
+          @parser = Trollop::Parser.new do
+            banner usage_msg
+          end
+
+        end
+
+        # This parameter, if set, will tell the underlying option parser not to throw an
+        #  exception if we pass it options that weren't explicitly registered.  We need this
+        #  capability because we need to be able to pass all of the command-line options before
+        #  we know which application/face they are going to be running, but the app/face
+        #  may specify additional command-line arguments that are valid for that app/face.
+        attr_reader :ignore_invalid_options
+
+        def ignore_invalid_options=(value)
+          @parser.ignore_invalid_options = value
+        end
+
+        def on(*args, &block)
+          # The 2nd element is an optional "short" representation.
+          if args.length == 3
+            long, desc, type = args
+          elsif args.length == 4
+            long, short, desc, type = args
+          else
+            raise ArgumentError, "this method only takes 3 or 4 arguments. Given: #{args.inspect}"
+          end
+
+          options = {
+              :long => long,
+              :short => short,
+              :required => false,
+              :callback => pass_only_last_value_on_to(block),
+              :multi => true,
+          }
+
+          case type
+            when :REQUIRED
+              options[:type] = :string
+            when :NONE
+              options[:type] = :flag
+            else
+              raise PuppetOptionError.new("Unsupported type: '#{type}'")
+          end
+
+          @parser.opt long.sub("^--", "").intern, desc, options
+        end
+
+        def parse(*args)
+          args = args[0] if args.size == 1 and Array === args[0]
+          args_copy = args.dup
+          begin
+            @parser.parse args_copy
+          rescue Puppet::Util::CommandLine::Trollop::CommandlineError => err
+            raise PuppetOptionError.new("Error parsing arguments", err)
+          end
+        end
+
+        def pass_only_last_value_on_to(block)
+          lambda { |values| block.call(values.is_a?(Array) ? values.last : values) }
+        end
+        private :pass_only_last_value_on_to
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/command_line/trollop.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/command_line/trollop.rb
new file mode 100644
index 0000000..25f21d9
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/command_line/trollop.rb
@@ -0,0 +1,824 @@
+## lib/trollop.rb -- trollop command-line processing library
+## Author::    William Morgan (mailto: wmorgan-trollop@masanjin.net)
+## Copyright:: Copyright 2007 William Morgan
+## License::   the same terms as ruby itself
+##
+## 2012-03: small changes made by cprice (chris@puppetlabs.com);
+##           patch submitted for upstream consideration:
+##           https://gitorious.org/trollop/mainline/merge_requests/9
+## 2012-08: namespace changes made by Jeff McCune (jeff@puppetlabs.com)
+##           moved Trollop into Puppet::Util::CommandLine to prevent monkey
+##           patching the upstream trollop library if also loaded.
+
+require 'date'
+
+module Puppet
+module Util
+class CommandLine
+module Trollop
+
+VERSION = "1.16.2"
+
+## Thrown by Parser in the event of a commandline error. Not needed if
+## you're using the Trollop::options entry.
+class CommandlineError < StandardError; end
+
+## Thrown by Parser if the user passes in '-h' or '--help'. Handled
+## automatically by Trollop#options.
+class HelpNeeded < StandardError; end
+
+## Thrown by Parser if the user passes in '-h' or '--version'. Handled
+## automatically by Trollop#options.
+class VersionNeeded < StandardError; end
+
+## Regex for floating point numbers
+FLOAT_RE = /^-?((\d+(\.\d+)?)|(\.\d+))([eE][-+]?[\d]+)?$/
+
+## Regex for parameters
+PARAM_RE = /^-(-|\.$|[^\d\.])/
+
+## The commandline parser. In typical usage, the methods in this class
+## will be handled internally by Trollop::options. In this case, only the
+## #opt, #banner and #version, #depends, and #conflicts methods will
+## typically be called.
+##
+## If you want to instantiate this class yourself (for more complicated
+## argument-parsing logic), call #parse to actually produce the output hash,
+## and consider calling it from within
+## Trollop::with_standard_exception_handling.
+class Parser
+
+  ## The set of values that indicate a flag option when passed as the
+  ## +:type+ parameter of #opt.
+  FLAG_TYPES = [:flag, :bool, :boolean]
+
+  ## The set of values that indicate a single-parameter (normal) option when
+  ## passed as the +:type+ parameter of #opt.
+  ##
+  ## A value of +io+ corresponds to a readable IO resource, including
+  ## a filename, URI, or the strings 'stdin' or '-'.
+  SINGLE_ARG_TYPES = [:int, :integer, :string, :double, :float, :io, :date]
+
+  ## The set of values that indicate a multiple-parameter option (i.e., that
+  ## takes multiple space-separated values on the commandline) when passed as
+  ## the +:type+ parameter of #opt.
+  MULTI_ARG_TYPES = [:ints, :integers, :strings, :doubles, :floats, :ios, :dates]
+
+  ## The complete set of legal values for the +:type+ parameter of #opt.
+  TYPES = FLAG_TYPES + SINGLE_ARG_TYPES + MULTI_ARG_TYPES
+
+  INVALID_SHORT_ARG_REGEX = /[\d-]/ #:nodoc:
+
+  ## The values from the commandline that were not interpreted by #parse.
+  attr_reader :leftovers
+
+  ## The complete configuration hashes for each option. (Mainly useful
+  ## for testing.)
+  attr_reader :specs
+
+  ## A flag that determines whether or not to attempt to automatically generate "short" options if they are not
+  ##  explicitly specified.
+  attr_accessor :create_default_short_options
+
+  ## A flag that determines whether or not to raise an error if the parser is passed one or more
+  ##  options that were not registered ahead of time.  If 'true', then the parser will simply
+  ##  ignore options that it does not recognize.
+  attr_accessor :ignore_invalid_options
+
+  ## A flag indicating whether or not the parser should attempt to handle "--help" and
+  ##  "--version" specially.  If 'false', it will treat them just like any other option.
+  attr_accessor :handle_help_and_version
+
+  ## Initializes the parser, and instance-evaluates any block given.
+  def initialize *a, &b
+    @version = nil
+    @leftovers = []
+    @specs = {}
+    @long = {}
+    @short = {}
+    @order = []
+    @constraints = []
+    @stop_words = []
+    @stop_on_unknown = false
+
+    #instance_eval(&b) if b # can't take arguments
+    cloaker(&b).bind(self).call(*a) if b
+  end
+
+  ## Define an option. +name+ is the option name, a unique identifier
+  ## for the option that you will use internally, which should be a
+  ## symbol or a string. +desc+ is a string description which will be
+  ## displayed in help messages.
+  ##
+  ## Takes the following optional arguments:
+  ##
+  ## [+:long+] Specify the long form of the argument, i.e. the form with two dashes. If unspecified, will be automatically derived based on the argument name by turning the +name+ option into a string, and replacing any _'s by -'s.
+  ## [+:short+] Specify the short form of the argument, i.e. the form with one dash. If unspecified, will be automatically derived from +name+.
+  ## [+:type+] Require that the argument take a parameter or parameters of type +type+. For a single parameter, the value can be a member of +SINGLE_ARG_TYPES+, or a corresponding Ruby class (e.g. +Integer+ for +:int+). For multiple-argument parameters, the value can be any member of +MULTI_ARG_TYPES+ constant. If unset, the default argument type is +:flag+, meaning that the argument does not take a parameter. The specification of +:type+ is not necessary if a +:default+ is given.
+  ## [+:default+] Set the default value for an argument. Without a default value, the hash returned by #parse (and thus Trollop::options) will have a +nil+ value for this key unless the argument is given on the commandline. The argument type is derived automatically from the class of the default value given, so specifying a +:type+ is not necessary if a +:default+ is given. (But see below for an important caveat when +:multi+: is specified too.) If the argument is a flag, and the default is set to +true+, then if it is specified on the commandline the value will be +false+.
+  ## [+:required+] If set to +true+, the argument must be provided on the commandline.
+  ## [+:multi+] If set to +true+, allows multiple occurrences of the option on the commandline. Otherwise, only a single instance of the option is allowed. (Note that this is different from taking multiple parameters. See below.)
+  ##
+  ## Note that there are two types of argument multiplicity: an argument
+  ## can take multiple values, e.g. "--arg 1 2 3". An argument can also
+  ## be allowed to occur multiple times, e.g. "--arg 1 --arg 2".
+  ##
+  ## Arguments that take multiple values should have a +:type+ parameter
+  ## drawn from +MULTI_ARG_TYPES+ (e.g. +:strings+), or a +:default:+
+  ## value of an array of the correct type (e.g. [String]). The
+  ## value of this argument will be an array of the parameters on the
+  ## commandline.
+  ##
+  ## Arguments that can occur multiple times should be marked with
+  ## +:multi+ => +true+. The value of this argument will also be an array.
+  ## In contrast with regular non-multi options, if not specified on
+  ## the commandline, the default value will be [], not nil.
+  ##
+  ## These two attributes can be combined (e.g. +:type+ => +:strings+,
+  ## +:multi+ => +true+), in which case the value of the argument will be
+  ## an array of arrays.
+  ##
+  ## There's one ambiguous case to be aware of: when +:multi+: is true and a
+  ## +:default+ is set to an array (of something), it's ambiguous whether this
+  ## is a multi-value argument as well as a multi-occurrence argument.
+  ## In thise case, Trollop assumes that it's not a multi-value argument.
+  ## If you want a multi-value, multi-occurrence argument with a default
+  ## value, you must specify +:type+ as well.
+
+  def opt name, desc="", opts={}
+    raise ArgumentError, "you already have an argument named '#{name}'" if @specs.member? name
+
+    ## fill in :type
+    opts[:type] = # normalize
+      case opts[:type]
+      when :boolean, :bool; :flag
+      when :integer; :int
+      when :integers; :ints
+      when :double; :float
+      when :doubles; :floats
+      when Class
+        case opts[:type].name
+        when 'TrueClass', 'FalseClass'; :flag
+        when 'String'; :string
+        when 'Integer'; :int
+        when 'Float'; :float
+        when 'IO'; :io
+        when 'Date'; :date
+        else
+          raise ArgumentError, "unsupported argument type '#{opts[:type].class.name}'"
+        end
+      when nil; nil
+      else
+        raise ArgumentError, "unsupported argument type '#{opts[:type]}'" unless TYPES.include?(opts[:type])
+        opts[:type]
+      end
+
+    ## for options with :multi => true, an array default doesn't imply
+    ## a multi-valued argument. for that you have to specify a :type
+    ## as well. (this is how we disambiguate an ambiguous situation;
+    ## see the docs for Parser#opt for details.)
+    disambiguated_default =
+      if opts[:multi] && opts[:default].is_a?(Array) && !opts[:type]
+        opts[:default].first
+      else
+        opts[:default]
+      end
+
+    type_from_default =
+      case disambiguated_default
+      when Integer; :int
+      when Numeric; :float
+      when TrueClass, FalseClass; :flag
+      when String; :string
+      when IO; :io
+      when Date; :date
+      when Array
+        if opts[:default].empty?
+          raise ArgumentError, "multiple argument type cannot be deduced from an empty array for '#{opts[:default][0].class.name}'"
+        end
+        case opts[:default][0]    # the first element determines the types
+        when Integer; :ints
+        when Numeric; :floats
+        when String; :strings
+        when IO; :ios
+        when Date; :dates
+        else
+          raise ArgumentError, "unsupported multiple argument type '#{opts[:default][0].class.name}'"
+        end
+      when nil; nil
+      else
+        raise ArgumentError, "unsupported argument type '#{opts[:default].class.name}'"
+      end
+
+    raise ArgumentError, ":type specification and default type don't match (default type is #{type_from_default})" if opts[:type] && type_from_default && opts[:type] != type_from_default
+
+    opts[:type] = opts[:type] || type_from_default || :flag
+
+    ## fill in :long
+    opts[:long] = opts[:long] ? opts[:long].to_s : name.to_s.gsub("_", "-")
+    opts[:long] =
+      case opts[:long]
+      when /^--([^-].*)$/
+        $1
+      when /^[^-]/
+        opts[:long]
+      else
+        raise ArgumentError, "invalid long option name #{opts[:long].inspect}"
+      end
+    raise ArgumentError, "long option name #{opts[:long].inspect} is already taken; please specify a (different) :long" if @long[opts[:long]]
+
+    ## fill in :short
+    opts[:short] = opts[:short].to_s if opts[:short] unless opts[:short] == :none
+    opts[:short] = case opts[:short]
+      when /^-(.)$/; $1
+      when nil, :none, /^.$/; opts[:short]
+      else raise ArgumentError, "invalid short option name '#{opts[:short].inspect}'"
+    end
+
+    if opts[:short]
+      raise ArgumentError, "short option name #{opts[:short].inspect} is already taken; please specify a (different) :short" if @short[opts[:short]]
+      raise ArgumentError, "a short option name can't be a number or a dash" if opts[:short] =~ INVALID_SHORT_ARG_REGEX
+    end
+
+    ## fill in :default for flags
+    opts[:default] = false if opts[:type] == :flag && opts[:default].nil?
+
+    ## autobox :default for :multi (multi-occurrence) arguments
+    opts[:default] = [opts[:default]] if opts[:default] && opts[:multi] && !opts[:default].is_a?(Array)
+
+    ## fill in :multi
+    opts[:multi] ||= false
+
+    opts[:desc] ||= desc
+    @long[opts[:long]] = name
+    @short[opts[:short]] = name if opts[:short] && opts[:short] != :none
+    @specs[name] = opts
+    @order << [:opt, name]
+  end
+
+  ## Sets the version string. If set, the user can request the version
+  ## on the commandline. Should probably be of the form "<program name>
+  ## <version number>".
+  def version s=nil; @version = s if s; @version end
+
+  ## Adds text to the help display. Can be interspersed with calls to
+  ## #opt to build a multi-section help page.
+  def banner s; @order << [:text, s] end
+  alias :text :banner
+
+  ## Marks two (or more!) options as requiring each other. Only handles
+  ## undirected (i.e., mutual) dependencies. Directed dependencies are
+  ## better modeled with Trollop::die.
+  def depends *syms
+    syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
+    @constraints << [:depends, syms]
+  end
+
+  ## Marks two (or more!) options as conflicting.
+  def conflicts *syms
+    syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
+    @constraints << [:conflicts, syms]
+  end
+
+  ## Defines a set of words which cause parsing to terminate when
+  ## encountered, such that any options to the left of the word are
+  ## parsed as usual, and options to the right of the word are left
+  ## intact.
+  ##
+  ## A typical use case would be for subcommand support, where these
+  ## would be set to the list of subcommands. A subsequent Trollop
+  ## invocation would then be used to parse subcommand options, after
+  ## shifting the subcommand off of ARGV.
+  def stop_on *words
+    @stop_words = [*words].flatten
+  end
+
+  ## Similar to #stop_on, but stops on any unknown word when encountered
+  ## (unless it is a parameter for an argument). This is useful for
+  ## cases where you don't know the set of subcommands ahead of time,
+  ## i.e., without first parsing the global options.
+  def stop_on_unknown
+    @stop_on_unknown = true
+  end
+
+  ## Parses the commandline. Typically called by Trollop::options,
+  ## but you can call it directly if you need more control.
+  ##
+  ## throws CommandlineError, HelpNeeded, and VersionNeeded exceptions.
+  def parse cmdline=ARGV
+    vals = {}
+    required = {}
+
+    if handle_help_and_version
+      opt :version, "Print version and exit" if @version unless @specs[:version] || @long["version"]
+      opt :help, "Show this message" unless @specs[:help] || @long["help"]
+    end
+
+    @specs.each do |sym, opts|
+      required[sym] = true if opts[:required]
+      vals[sym] = opts[:default]
+      vals[sym] = [] if opts[:multi] && !opts[:default] # multi arguments default to [], not nil
+    end
+
+    resolve_default_short_options if create_default_short_options
+
+    ## resolve symbols
+    given_args = {}
+    @leftovers = each_arg cmdline do |arg, params|
+      sym = case arg
+      when /^-([^-])$/
+        @short[$1]
+      when /^--no-([^-]\S*)$/
+        @long["[no-]#{$1}"]
+      when /^--([^-]\S*)$/
+        @long[$1] ? @long[$1] : @long["[no-]#{$1}"]
+      else
+        raise CommandlineError, "invalid argument syntax: '#{arg}'"
+      end
+
+      unless sym
+        next 0 if ignore_invalid_options
+        raise CommandlineError, "unknown argument '#{arg}'" unless sym
+      end
+
+      if given_args.include?(sym) && !@specs[sym][:multi]
+        raise CommandlineError, "option '#{arg}' specified multiple times"
+      end
+
+      given_args[sym] ||= {}
+
+      given_args[sym][:arg] = arg
+      given_args[sym][:params] ||= []
+
+      # The block returns the number of parameters taken.
+      num_params_taken = 0
+
+      unless params.nil?
+        if SINGLE_ARG_TYPES.include?(@specs[sym][:type])
+          given_args[sym][:params] << params[0, 1]  # take the first parameter
+          num_params_taken = 1
+        elsif MULTI_ARG_TYPES.include?(@specs[sym][:type])
+          given_args[sym][:params] << params        # take all the parameters
+          num_params_taken = params.size
+        end
+      end
+
+      num_params_taken
+    end
+
+    if handle_help_and_version
+      ## check for version and help args
+      raise VersionNeeded if given_args.include? :version
+      raise HelpNeeded if given_args.include? :help
+    end
+
+    ## check constraint satisfaction
+    @constraints.each do |type, syms|
+      constraint_sym = syms.find { |sym| given_args[sym] }
+      next unless constraint_sym
+
+      case type
+      when :depends
+        syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} requires --#{@specs[sym][:long]}" unless given_args.include? sym }
+      when :conflicts
+        syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} conflicts with --#{@specs[sym][:long]}" if given_args.include?(sym) && (sym != constraint_sym) }
+      end
+    end
+
+    required.each do |sym, val|
+      raise CommandlineError, "option --#{@specs[sym][:long]} must be specified" unless given_args.include? sym
+    end
+
+    ## parse parameters
+    given_args.each do |sym, given_data|
+      arg = given_data[:arg]
+      params = given_data[:params]
+
+      opts = @specs[sym]
+      raise CommandlineError, "option '#{arg}' needs a parameter" if params.empty? && opts[:type] != :flag
+
+      vals["#{sym}_given".intern] = true # mark argument as specified on the commandline
+
+      case opts[:type]
+      when :flag
+        if arg =~ /^--no-/ and sym.to_s =~ /^--\[no-\]/
+          vals[sym] = opts[:default]
+        else
+          vals[sym] = !opts[:default]
+        end
+      when :int, :ints
+        vals[sym] = params.map { |pg| pg.map { |p| parse_integer_parameter p, arg } }
+      when :float, :floats
+        vals[sym] = params.map { |pg| pg.map { |p| parse_float_parameter p, arg } }
+      when :string, :strings
+        vals[sym] = params.map { |pg| pg.map { |p| p.to_s } }
+      when :io, :ios
+        vals[sym] = params.map { |pg| pg.map { |p| parse_io_parameter p, arg } }
+      when :date, :dates
+        vals[sym] = params.map { |pg| pg.map { |p| parse_date_parameter p, arg } }
+      end
+
+      if SINGLE_ARG_TYPES.include?(opts[:type])
+        unless opts[:multi]       # single parameter
+          vals[sym] = vals[sym][0][0]
+        else                      # multiple options, each with a single parameter
+          vals[sym] = vals[sym].map { |p| p[0] }
+        end
+      elsif MULTI_ARG_TYPES.include?(opts[:type]) && !opts[:multi]
+        vals[sym] = vals[sym][0]  # single option, with multiple parameters
+      end
+      # else: multiple options, with multiple parameters
+
+      opts[:callback].call(vals[sym]) if opts.has_key?(:callback)
+    end
+
+    ## modify input in place with only those
+    ## arguments we didn't process
+    cmdline.clear
+    @leftovers.each { |l| cmdline << l }
+
+    ## allow openstruct-style accessors
+    class << vals
+      def method_missing(m, *args)
+        self[m] || self[m.to_s]
+      end
+    end
+    vals
+  end
+
+  def parse_date_parameter param, arg #:nodoc:
+    begin
+      begin
+        time = Chronic.parse(param)
+      rescue NameError
+        # chronic is not available
+      end
+      time ? Date.new(time.year, time.month, time.day) : Date.parse(param)
+    rescue ArgumentError
+      raise CommandlineError, "option '#{arg}' needs a date", $!.backtrace
+    end
+  end
+
+  ## Print the help message to +stream+.
+  def educate stream=$stdout
+    width # just calculate it now; otherwise we have to be careful not to
+          # call this unless the cursor's at the beginning of a line.
+
+    left = {}
+    @specs.each do |name, spec|
+      left[name] = "--#{spec[:long]}" +
+        (spec[:short] && spec[:short] != :none ? ", -#{spec[:short]}" : "") +
+        case spec[:type]
+        when :flag; ""
+        when :int; " <i>"
+        when :ints; " <i+>"
+        when :string; " <s>"
+        when :strings; " <s+>"
+        when :float; " <f>"
+        when :floats; " <f+>"
+        when :io; " <filename/uri>"
+        when :ios; " <filename/uri+>"
+        when :date; " <date>"
+        when :dates; " <date+>"
+        end
+    end
+
+    leftcol_width = left.values.map { |s| s.length }.max || 0
+    rightcol_start = leftcol_width + 6 # spaces
+
+    unless @order.size > 0 && @order.first.first == :text
+      stream.puts "#@version\n" if @version
+      stream.puts "Options:"
+    end
+
+    @order.each do |what, opt|
+      if what == :text
+        stream.puts wrap(opt)
+        next
+      end
+
+      spec = @specs[opt]
+      stream.printf "  %#{leftcol_width}s:   ", left[opt]
+      desc = spec[:desc] + begin
+        default_s = case spec[:default]
+        when $stdout; "<stdout>"
+        when $stdin; "<stdin>"
+        when $stderr; "<stderr>"
+        when Array
+          spec[:default].join(", ")
+        else
+          spec[:default].to_s
+        end
+
+        if spec[:default]
+          if spec[:desc] =~ /\.$/
+            " (Default: #{default_s})"
+          else
+            " (default: #{default_s})"
+          end
+        else
+          ""
+        end
+      end
+      stream.puts wrap(desc, :width => width - rightcol_start - 1, :prefix => rightcol_start)
+    end
+  end
+
+  def width #:nodoc:
+    @width ||= if $stdout.tty?
+      begin
+        require 'curses'
+        Curses::init_screen
+        x = Curses::cols
+        Curses::close_screen
+        x
+      rescue Exception
+        80
+      end
+    else
+      80
+    end
+  end
+
+  def wrap str, opts={} # :nodoc:
+    if str == ""
+      [""]
+    else
+      str.split("\n").map { |s| wrap_line s, opts }.flatten
+    end
+  end
+
+  ## The per-parser version of Trollop::die (see that for documentation).
+  def die arg, msg
+    if msg
+      $stderr.puts "Error: argument --#{@specs[arg][:long]} #{msg}."
+    else
+      $stderr.puts "Error: #{arg}."
+    end
+    $stderr.puts "Try --help for help."
+    exit(-1)
+  end
+
+private
+
+  ## yield successive arg, parameter pairs
+  def each_arg args
+    remains = []
+    i = 0
+
+    until i >= args.length
+      if @stop_words.member? args[i]
+        remains += args[i .. -1]
+        return remains
+      end
+      case args[i]
+      when /^--$/ # arg terminator
+        remains += args[(i + 1) .. -1]
+        return remains
+      when /^--(\S+?)=(.*)$/ # long argument with equals
+        yield "--#{$1}", [$2]
+        i += 1
+      when /^--(\S+)$/ # long argument
+        params = collect_argument_parameters(args, i + 1)
+        unless params.empty?
+          num_params_taken = yield args[i], params
+          unless num_params_taken
+            if @stop_on_unknown
+              remains += args[i + 1 .. -1]
+              return remains
+            else
+              remains += params
+            end
+          end
+          i += 1 + num_params_taken
+        else # long argument no parameter
+          yield args[i], nil
+          i += 1
+        end
+      when /^-(\S+)$/ # one or more short arguments
+        shortargs = $1.split(//)
+        shortargs.each_with_index do |a, j|
+          if j == (shortargs.length - 1)
+            params = collect_argument_parameters(args, i + 1)
+            unless params.empty?
+              num_params_taken = yield "-#{a}", params
+              unless num_params_taken
+                if @stop_on_unknown
+                  remains += args[i + 1 .. -1]
+                  return remains
+                else
+                  remains += params
+                end
+              end
+              i += 1 + num_params_taken
+            else # argument no parameter
+              yield "-#{a}", nil
+              i += 1
+            end
+          else
+            yield "-#{a}", nil
+          end
+        end
+      else
+        if @stop_on_unknown
+          remains += args[i .. -1]
+          return remains
+        else
+          remains << args[i]
+          i += 1
+        end
+      end
+    end
+
+    remains
+  end
+
+  def parse_integer_parameter param, arg
+    raise CommandlineError, "option '#{arg}' needs an integer" unless param =~ /^\d+$/
+    param.to_i
+  end
+
+  def parse_float_parameter param, arg
+    raise CommandlineError, "option '#{arg}' needs a floating-point number" unless param =~ FLOAT_RE
+    param.to_f
+  end
+
+  def parse_io_parameter param, arg
+    case param
+    when /^(stdin|-)$/i; $stdin
+    else
+      require 'open-uri'
+      begin
+        open param
+      rescue SystemCallError => e
+        raise CommandlineError, "file or url for option '#{arg}' cannot be opened: #{e.message}", e.backtrace
+      end
+    end
+  end
+
+  def collect_argument_parameters args, start_at
+    params = []
+    pos = start_at
+    while args[pos] && args[pos] !~ PARAM_RE && !@stop_words.member?(args[pos]) do
+      params << args[pos]
+      pos += 1
+    end
+    params
+  end
+
+  def resolve_default_short_options
+    @order.each do |type, name|
+      next unless type == :opt
+      opts = @specs[name]
+      next if opts[:short]
+
+      c = opts[:long].split(//).find { |d| d !~ INVALID_SHORT_ARG_REGEX && !@short.member?(d) }
+      if c # found a character to use
+        opts[:short] = c
+        @short[c] = name
+      end
+    end
+  end
+
+  def wrap_line str, opts={}
+    prefix = opts[:prefix] || 0
+    width = opts[:width] || (self.width - 1)
+    start = 0
+    ret = []
+    until start > str.length
+      nextt =
+        if start + width >= str.length
+          str.length
+        else
+          x = str.rindex(/\s/, start + width)
+          x = str.index(/\s/, start) if x && x < start
+          x || str.length
+        end
+      ret << (ret.empty? ? "" : " " * prefix) + str[start ... nextt]
+      start = nextt + 1
+    end
+    ret
+  end
+
+  ## instance_eval but with ability to handle block arguments
+  ## thanks to why: http://redhanded.hobix.com/inspect/aBlockCostume.html
+  def cloaker &b
+    (class << self; self; end).class_eval do
+      define_method :cloaker_, &b
+      meth = instance_method :cloaker_
+      remove_method :cloaker_
+      meth
+    end
+  end
+end
+
+## The easy, syntactic-sugary entry method into Trollop. Creates a Parser,
+## passes the block to it, then parses +args+ with it, handling any errors or
+## requests for help or version information appropriately (and then exiting).
+## Modifies +args+ in place. Returns a hash of option values.
+##
+## The block passed in should contain zero or more calls to +opt+
+## (Parser#opt), zero or more calls to +text+ (Parser#text), and
+## probably a call to +version+ (Parser#version).
+##
+## The returned block contains a value for every option specified with
+## +opt+.  The value will be the value given on the commandline, or the
+## default value if the option was not specified on the commandline. For
+## every option specified on the commandline, a key "<option
+## name>_given" will also be set in the hash.
+##
+## Example:
+##
+##   require 'trollop'
+##   opts = Trollop::options do
+##     opt :monkey, "Use monkey mode"                     # a flag --monkey, defaulting to false
+##     opt :goat, "Use goat mode", :default => true       # a flag --goat, defaulting to true
+##     opt :num_limbs, "Number of limbs", :default => 4   # an integer --num-limbs <i>, defaulting to 4
+##     opt :num_thumbs, "Number of thumbs", :type => :int # an integer --num-thumbs <i>, defaulting to nil
+##   end
+##
+##   ## if called with no arguments
+##   p opts # => { :monkey => false, :goat => true, :num_limbs => 4, :num_thumbs => nil }
+##
+##   ## if called with --monkey
+##   p opts # => {:monkey_given=>true, :monkey=>true, :goat=>true, :num_limbs=>4, :help=>false, :num_thumbs=>nil}
+##
+## See more examples at http://trollop.rubyforge.org.
+def options args=ARGV, *a, &b
+  @last_parser = Parser.new(*a, &b)
+  with_standard_exception_handling(@last_parser) { @last_parser.parse args }
+end
+
+## If Trollop::options doesn't do quite what you want, you can create a Parser
+## object and call Parser#parse on it. That method will throw CommandlineError,
+## HelpNeeded and VersionNeeded exceptions when necessary; if you want to
+## have these handled for you in the standard manner (e.g. show the help
+## and then exit upon an HelpNeeded exception), call your code from within
+## a block passed to this method.
+##
+## Note that this method will call System#exit after handling an exception!
+##
+## Usage example:
+##
+##   require 'trollop'
+##   p = Trollop::Parser.new do
+##     opt :monkey, "Use monkey mode"                     # a flag --monkey, defaulting to false
+##     opt :goat, "Use goat mode", :default => true       # a flag --goat, defaulting to true
+##   end
+##
+##   opts = Trollop::with_standard_exception_handling p do
+##     o = p.parse ARGV
+##     raise Trollop::HelpNeeded if ARGV.empty? # show help screen
+##     o
+##   end
+##
+## Requires passing in the parser object.
+
+def with_standard_exception_handling parser
+  begin
+    yield
+  rescue CommandlineError => e
+    $stderr.puts "Error: #{e.message}."
+    $stderr.puts "Try --help for help."
+    exit(-1)
+  rescue HelpNeeded
+    parser.educate
+    exit
+  rescue VersionNeeded
+    puts parser.version
+    exit
+  end
+end
+
+## Informs the user that their usage of 'arg' was wrong, as detailed by
+## 'msg', and dies. Example:
+##
+##   options do
+##     opt :volume, :default => 0.0
+##   end
+##
+##   die :volume, "too loud" if opts[:volume] > 10.0
+##   die :volume, "too soft" if opts[:volume] < 0.1
+##
+## In the one-argument case, simply print that message, a notice
+## about -h, and die. Example:
+##
+##   options do
+##     opt :whatever # ...
+##   end
+##
+##   Trollop::die "need at least one filename" if ARGV.empty?
+def die arg, msg=nil
+  if @last_parser
+    @last_parser.die arg, msg
+  else
+    raise ArgumentError, "Trollop::die can only be called after Trollop::options"
+  end
+end
+
+module_function :options, :die, :with_standard_exception_handling
+
+end # module
+end
+end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/constant_inflector.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/constant_inflector.rb
new file mode 100644
index 0000000..960f7c7
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/constant_inflector.rb
@@ -0,0 +1,24 @@
+# Created on 2008-02-12
+# Copyright Luke Kanies
+
+# NOTE: I think it might be worth considering moving these methods directly into Puppet::Util.
+
+# A common module for converting between constants and
+# file names.
+
+
+module Puppet
+  module Util
+    module ConstantInflector
+      def file2constant(file)
+        file.split("/").collect { |name| name.capitalize }.join("::").gsub(/_+(.)/) { |term| $1.capitalize }
+      end
+      module_function :file2constant
+
+      def constant2file(constant)
+        constant.to_s.gsub(/([a-z])([A-Z])/) { |term| $1 + "_#{$2}" }.gsub("::", "/").downcase
+      end
+      module_function :constant2file
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/diff.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/diff.rb
new file mode 100644
index 0000000..fd7f77f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/diff.rb
@@ -0,0 +1,79 @@
+require 'tempfile'
+
+# Provide a diff between two strings.
+module Puppet::Util::Diff
+  include Puppet::Util::Execution
+  require 'tempfile'
+
+  def diff(old, new)
+    return '' unless diff_cmd = Puppet[:diff] and diff_cmd != ""
+
+    command = [diff_cmd]
+    if args = Puppet[:diff_args] and args != ""
+      args.split(' ').each do|arg|
+        command << arg
+      end
+    end
+    command << old << new
+    Puppet::Util::Execution.execute(command, :failonfail => false, :combine => false)
+  end
+
+  module_function :diff
+
+  # return diff string of two input strings
+  # format defaults to unified
+  # context defaults to 3 lines
+  def lcs_diff(data_old, data_new, format=:unified, context_lines=3)
+    unless Puppet.features.diff?
+      Puppet.warning "Cannot provide diff without the diff/lcs Ruby library"
+      return ""
+    end
+    data_old = data_old.split(/\n/).map! { |e| e.chomp }
+    data_new = data_new.split(/\n/).map! { |e| e.chomp }
+
+    output = ""
+
+    diffs = ::Diff::LCS.diff(data_old, data_new)
+    return output if diffs.empty?
+
+    oldhunk = hunk = nil
+    file_length_difference = 0
+
+    diffs.each do |piece|
+      begin
+
+        hunk = ::Diff::LCS::Hunk.new(
+          data_old, data_new, piece,
+            context_lines,
+
+            file_length_difference)
+        file_length_difference = hunk.file_length_difference
+      next unless oldhunk
+      # Hunks may overlap, which is why we need to be careful when our
+      # diff includes lines of context. Otherwise, we might print
+      # redundant lines.
+      if (context_lines > 0) and hunk.overlaps?(oldhunk)
+        hunk.unshift(oldhunk)
+      else
+        output << oldhunk.diff(format)
+      end
+      ensure
+        oldhunk = hunk
+        output << "\n"
+      end
+    end
+
+    # Handle the last remaining hunk
+    output << oldhunk.diff(format) << "\n"
+  end
+
+  def string_file_diff(path, string)
+    tempfile = Tempfile.new("puppet-diffing")
+    tempfile.open
+    tempfile.print string
+    tempfile.close
+    notice "\n" + diff(path, tempfile.path)
+    tempfile.delete
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/docs.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/docs.rb
new file mode 100644
index 0000000..3f0a2fb
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/docs.rb
@@ -0,0 +1,128 @@
+# Some simple methods for helping manage automatic documentation generation.
+module Puppet::Util::Docs
+  # Specify the actual doc string.
+  def desc(str)
+    @doc = str
+  end
+
+  # Add a new autodoc block.  We have to define these as class methods,
+  # rather than just sticking them in a hash, because otherwise they're
+  # too difficult to do inheritance with.
+  def dochook(name, &block)
+    method = "dochook_#{name}"
+
+    meta_def method, &block
+  end
+
+  attr_writer :doc
+
+  # Generate the full doc string.
+  def doc
+    extra = methods.find_all { |m| m.to_s =~ /^dochook_.+/ }.sort.collect { |m|
+      self.send(m)
+    }.delete_if {|r| r.nil? }.collect {|r| "* #{r}"}.join("\n")
+
+    if @doc
+      scrub(@doc) + (extra.empty? ? '' : "\n\n#{extra}")
+    else
+      extra
+    end
+  end
+
+  # Build a table
+  def doctable(headers, data)
+    str = "\n\n"
+
+    lengths = []
+    # Figure out the longest field for all columns
+    data.each do |name, values|
+      [name, values].flatten.each_with_index do |value, i|
+        lengths[i] ||= 0
+        lengths[i] = value.to_s.length if value.to_s.length > lengths[i]
+      end
+    end
+
+    # The headers could also be longest
+    headers.each_with_index do |value, i|
+      lengths[i] = value.to_s.length if value.to_s.length > lengths[i]
+    end
+
+    # Add the header names
+    str += headers.zip(lengths).collect { |value, num| pad(value, num) }.join(" | ") + " |" + "\n"
+
+    # And the header row
+    str += lengths.collect { |num| "-" * num }.join(" | ") + " |" + "\n"
+
+    # Now each data row
+    data.sort { |a, b| a[0].to_s <=> b[0].to_s }.each do |name, rows|
+      str += [name, rows].flatten.zip(lengths).collect do |value, length|
+        pad(value, length)
+      end.join(" | ") + " |" + "\n"
+    end
+
+    str + "\n"
+  end
+
+  # There is nothing that would ever set this. It gets read in reference/type.rb, but will never have any value but nil.
+  attr_reader :nodoc
+  def nodoc?
+    nodoc
+  end
+
+  # Pad a field with spaces
+  def pad(value, length)
+    value.to_s + (" " * (length - value.to_s.length))
+  end
+
+  HEADER_LEVELS = [nil, "#", "##", "###", "####", "#####"]
+
+  def markdown_header(name, level)
+    "#{HEADER_LEVELS[level]} #{name}\n\n"
+  end
+
+  def markdown_definitionlist(term, definition)
+    lines = scrub(definition).split("\n")
+    str = "#{term}\n: #{lines.shift}\n"
+    lines.each do |line|
+      str << "  " if line =~ /\S/
+      str << "#{line}\n"
+    end
+    str << "\n"
+  end
+
+  # Strip indentation and trailing whitespace from embedded doc fragments.
+  #
+  # Multi-line doc fragments are sometimes indented in order to preserve the
+  # formatting of the code they're embedded in. Since indents are syntactic
+  # elements in Markdown, we need to make sure we remove any indent that was
+  # added solely to preserve surrounding code formatting, but LEAVE any indent
+  # that delineates a Markdown element (code blocks, multi-line bulleted list
+  # items). We can do this by removing the *least common indent* from each line.
+  #
+  # Least common indent is defined as follows:
+  #
+  # * Find the smallest amount of leading space on any line...
+  # * ...excluding the first line (which may have zero indent without affecting
+  #   the common indent)...
+  # * ...and excluding lines that consist solely of whitespace.
+  # * The least common indent may be a zero-length string, if the fragment is
+  #   not indented to match code.
+  # * If there are hard tabs for some dumb reason, we assume they're at least
+  #   consistent within this doc fragment.
+  #
+  # See tests in spec/unit/util/docs_spec.rb for examples.
+  def scrub(text)
+    # One-liners are easy! (One-liners may be buffered with extra newlines.)
+    return text.strip if text.strip !~ /\n/
+    excluding_first_line = text.partition("\n").last
+    indent = excluding_first_line.scan(/^[ \t]*(?=\S)/).min || '' # prevent nil
+    # Clean hanging indent, if any
+    if indent.length > 0
+      text = text.gsub(/^#{indent}/, '')
+    end
+    # Clean trailing space
+    text.lines.map{|line|line.rstrip}.join("\n").rstrip
+  end
+
+  module_function :scrub
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/errors.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/errors.rb
new file mode 100644
index 0000000..9be5ee0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/errors.rb
@@ -0,0 +1,108 @@
+# Some helper methods for throwing and populating errors.
+#
+# @api public
+module Puppet::Util::Errors
+  # Throw a Puppet::DevError with the specified message.  Used for unknown or
+  # internal application failures.
+  #
+  # @param msg [String] message used in raised error
+  # @raise [Puppet::DevError] always raised with the supplied message
+  def devfail(msg)
+    self.fail(Puppet::DevError, msg)
+  end
+
+  # Add line and file info to the supplied exception if info is available from
+  # this object, is appropriately populated and the supplied exception supports
+  # it.  When other is supplied, the backtrace will be copied to the error
+  # object and the 'original' will be dropped from the error.
+  #
+  # @param error [Exception] exception that is populated with info
+  # @param other [Exception] original exception, source of backtrace info
+  # @return [Exception] error parameter
+  def adderrorcontext(error, other = nil)
+    error.line ||= self.line if error.respond_to?(:line=) and self.respond_to?(:line) and self.line
+    error.file ||= self.file if error.respond_to?(:file=) and self.respond_to?(:file) and self.file
+    error.original ||= other if error.respond_to?(:original=)
+
+    error.set_backtrace(other.backtrace) if other and other.respond_to?(:backtrace)
+    # It is not meaningful to keep the wrapped exception since its backtrace has already
+    # been adopted by the error. (The instance variable is private for good reasons).
+    error.instance_variable_set(:@original, nil)
+    error
+  end
+
+  # Return a human-readable string of this object's file and line attributes,
+  # if set.
+  #
+  # @return [String] description of file and line
+  def error_context
+    if file and line
+      " at #{file}:#{line}"
+    elsif line
+      " at line #{line}"
+    elsif file
+      " in #{file}"
+    else
+      ""
+    end
+  end
+
+  # Wrap a call in such a way that we always throw the right exception and keep
+  # as much context as possible.
+  #
+  # @param options [Hash<Symbol,Object>] options used to create error
+  # @option options [Class] :type error type to raise, defaults to
+  #   Puppet::DevError
+  # @option options [String] :message message to use in error, default mentions
+  #   the name of this class
+  # @raise [Puppet::Error] re-raised with extra context if the block raises it
+  # @raise [Error] of type options[:type], when the block raises other
+  #   exceptions
+  def exceptwrap(options = {})
+    options[:type] ||= Puppet::DevError
+    begin
+      return yield
+    rescue Puppet::Error => detail
+      raise adderrorcontext(detail)
+    rescue => detail
+      message = options[:message] || "#{self.class} failed with error #{detail.class}: #{detail}"
+
+      error = options[:type].new(message)
+      # We can't use self.fail here because it always expects strings,
+      # not exceptions.
+      raise adderrorcontext(error, detail)
+    end
+
+    retval
+  end
+
+  # Throw an error, defaulting to a Puppet::Error.
+  #
+  # @overload fail(message, ..)
+  #   Throw a Puppet::Error with a message concatenated from the given
+  #   arguments.
+  #   @param [String] message error message(s)
+  # @overload fail(error_klass, message, ..)
+  #   Throw an exception of type error_klass with a message concatenated from
+  #   the given arguments.
+  #   @param [Class] type of error
+  #   @param [String] message error message(s)
+  # @overload fail(error_klass, message, ..)
+  #   Throw an exception of type error_klass with a message concatenated from
+  #   the given arguments.
+  #   @param [Class] type of error
+  #   @param [String] message error message(s)
+  #   @param [Exception] original exception, source of backtrace info
+  def fail(*args)
+    if args[0].is_a?(Class)
+      type = args.shift
+    else
+      type = Puppet::Error
+    end
+
+    other = args.count > 1 ? args.pop : nil
+    error = adderrorcontext(type.new(args.join(" ")), other)
+
+    raise error
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/execution.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/execution.rb
new file mode 100644
index 0000000..e7094e4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/execution.rb
@@ -0,0 +1,343 @@
+require 'timeout'
+require 'puppet/file_system/uniquefile'
+
+module Puppet
+  require 'rbconfig'
+
+  require 'puppet/error'
+  # A command failed to execute.
+  # @api public
+  class ExecutionFailure < Puppet::Error
+  end
+end
+
+# This module defines methods for execution of system commands. It is intented for inclusion
+# in classes that needs to execute system commands.
+# @api public
+module Puppet::Util::Execution
+
+  # This is the full output from a process. The object itself (a String) is the
+  # stdout of the process.
+  #
+  # @api public
+  class ProcessOutput < String
+    # @return [Integer] The exit status of the process
+    # @api public
+    attr_reader :exitstatus
+
+    # @api private
+    def initialize(value,exitstatus)
+      super(value)
+      @exitstatus = exitstatus
+    end
+  end
+
+  # The command can be a simple string, which is executed as-is, or an Array,
+  # which is treated as a set of command arguments to pass through.
+  #
+  # In either case, the command is passed directly to the shell, STDOUT and
+  # STDERR are connected together, and STDOUT will be streamed to the yielded
+  # pipe.
+  #
+  # @param command [String, Array<String>] the command to execute as one string,
+  #   or as parts in an array. The parts of the array are joined with one
+  #   separating space between each entry when converting to the command line
+  #   string to execute.
+  # @param failonfail [Boolean] (true) if the execution should fail with
+  #   Exception on failure or not.
+  # @yield [pipe] to a block executing a subprocess
+  # @yieldparam pipe [IO] the opened pipe
+  # @yieldreturn [String] the output to return
+  # @raise [Puppet::ExecutionFailure] if the executed chiled process did not
+  #   exit with status == 0 and `failonfail` is `true`.
+  # @return [String] a string with the output from the subprocess executed by
+  #   the given block
+  #
+  # @see Kernel#open for `mode` values
+  # @api public
+  def self.execpipe(command, failonfail = true)
+    # Paste together an array with spaces.  We used to paste directly
+    # together, no spaces, which made for odd invocations; the user had to
+    # include whitespace between arguments.
+    #
+    # Having two spaces is really not a big drama, since this passes to the
+    # shell anyhow, while no spaces makes for a small developer cost every
+    # time this is invoked. --daniel 2012-02-13
+    command_str = command.respond_to?(:join) ? command.join(' ') : command
+
+    if respond_to? :debug
+      debug "Executing '#{command_str}'"
+    else
+      Puppet.debug "Executing '#{command_str}'"
+    end
+
+    # force the run of the command with
+    # the user/system locale to "C" (via environment variables LANG and LC_*)
+    # it enables to have non localized output for some commands and therefore
+    # a predictable output
+    english_env = ENV.to_hash.merge( {'LANG' => 'C', 'LC_ALL' => 'C'} )
+    output = Puppet::Util.withenv(english_env) do
+      open("| #{command_str} 2>&1") do |pipe|
+        yield pipe
+      end
+    end
+
+    if failonfail && exitstatus != 0
+      raise Puppet::ExecutionFailure, output
+    end
+
+    output
+  end
+
+  def self.exitstatus
+    $CHILD_STATUS.exitstatus
+  end
+  private_class_method :exitstatus
+
+  # Wraps execution of {execute} with mapping of exception to given exception (and output as argument).
+  # @raise [exception] under same conditions as {execute}, but raises the given `exception` with the output as argument
+  # @return (see execute)
+  # @api public
+  def self.execfail(command, exception)
+    output = execute(command)
+    return output
+  rescue Puppet::ExecutionFailure
+    raise exception, output, exception.backtrace
+  end
+
+  # Default empty options for {execute}
+  NoOptionsSpecified = {}
+
+  # Executes the desired command, and return the status and output.
+  # def execute(command, options)
+  # @param command [Array<String>, String] the command to execute. If it is
+  #   an Array the first element should be the executable and the rest of the
+  #   elements should be the individual arguments to that executable.
+  # @param options [Hash] a Hash of options
+  # @option options [Boolean]  :failonfail if this value is set to true, then this method will raise an error if the
+  #   command is not executed successfully.
+  # @option options [Integer, String] :uid (nil) the user id of the user that the process should be run as
+  # @option options [Integer, String] :gid (nil) the group id of the group that the process should be run as
+  # @option options [Boolean] :combine sets whether or not to combine stdout/stderr in the output
+  # @option options [String] :stdinfile (nil) sets a file that can be used for stdin. Passing a string for stdin is not currently
+  #   supported.
+  # @option options [Boolean] :squelch (true) if true, ignore stdout / stderr completely.
+  # @option options [Boolean] :override_locale (true) by default (and if this option is set to true), we will temporarily override
+  #   the user/system locale to "C" (via environment variables LANG and LC_*) while we are executing the command.
+  #   This ensures that the output of the command will be formatted consistently, making it predictable for parsing.
+  #   Passing in a value of false for this option will allow the command to be executed using the user/system locale.
+  # @option options [Hash<{String => String}>] :custom_environment ({}) a hash of key/value pairs to set as environment variables for the duration
+  #   of the command.
+  # @return [Puppet::Util::Execution::ProcessOutput] output as specified by options
+  # @raise [Puppet::ExecutionFailure] if the executed chiled process did not exit with status == 0 and `failonfail` is
+  #   `true`.
+  # @note Unfortunately, the default behavior for failonfail and combine (since
+  #   0.22.4 and 0.24.7, respectively) depend on whether options are specified
+  #   or not. If specified, then failonfail and combine default to false (even
+  #   when the options specified are neither failonfail nor combine). If no
+  #   options are specified, then failonfail and combine default to true.
+  # @comment See commits efe9a833c and d32d7f30
+  # @api public
+  #
+  def self.execute(command, options = NoOptionsSpecified)
+    # specifying these here rather than in the method signature to allow callers to pass in a partial
+    # set of overrides without affecting the default values for options that they don't pass in
+    default_options = {
+        :failonfail => NoOptionsSpecified.equal?(options),
+        :uid => nil,
+        :gid => nil,
+        :combine => NoOptionsSpecified.equal?(options),
+        :stdinfile => nil,
+        :squelch => false,
+        :override_locale => true,
+        :custom_environment => {},
+    }
+
+    options = default_options.merge(options)
+
+    if command.is_a?(Array)
+      command = command.flatten.map(&:to_s)
+      str = command.join(" ")
+    elsif command.is_a?(String)
+      str = command
+    end
+
+    if respond_to? :debug
+      debug "Executing '#{str}'"
+    else
+      Puppet.debug "Executing '#{str}'"
+    end
+
+    null_file = Puppet.features.microsoft_windows? ? 'NUL' : '/dev/null'
+
+    begin
+      stdin = File.open(options[:stdinfile] || null_file, 'r')
+      stdout = options[:squelch] ? File.open(null_file, 'w') : Puppet::FileSystem::Uniquefile.new('puppet')
+      stderr = options[:combine] ? stdout : File.open(null_file, 'w')
+
+      exec_args = [command, options, stdin, stdout, stderr]
+
+      if execution_stub = Puppet::Util::ExecutionStub.current_value
+        return execution_stub.call(*exec_args)
+      elsif Puppet.features.posix?
+        child_pid = nil
+        begin
+          child_pid = execute_posix(*exec_args)
+          exit_status = Process.waitpid2(child_pid).last.exitstatus
+          child_pid = nil
+        rescue Timeout::Error => e
+          # NOTE: For Ruby 2.1+, an explicit Timeout::Error class has to be
+          # passed to Timeout.timeout in order for there to be something for
+          # this block to rescue.
+          unless child_pid.nil?
+            Process.kill(:TERM, child_pid)
+            # Spawn a thread to reap the process if it dies.
+            Thread.new { Process.waitpid(child_pid) }
+          end
+
+          raise e
+        end
+      elsif Puppet.features.microsoft_windows?
+        process_info = execute_windows(*exec_args)
+        begin
+          exit_status = Puppet::Util::Windows::Process.wait_process(process_info.process_handle)
+        ensure
+          FFI::WIN32.CloseHandle(process_info.process_handle)
+          FFI::WIN32.CloseHandle(process_info.thread_handle)
+        end
+      end
+
+      [stdin, stdout, stderr].each {|io| io.close rescue nil}
+
+      # read output in if required
+      unless options[:squelch]
+        output = wait_for_output(stdout)
+        Puppet.warning "Could not get output" unless output
+      end
+
+      if options[:failonfail] and exit_status != 0
+        raise Puppet::ExecutionFailure, "Execution of '#{str}' returned #{exit_status}: #{output.strip}"
+      end
+    ensure
+      if !options[:squelch] && stdout
+        # if we opened a temp file for stdout, we need to clean it up.
+        stdout.close!
+      end
+    end
+
+    Puppet::Util::Execution::ProcessOutput.new(output || '', exit_status)
+  end
+
+  # Returns the path to the ruby executable (available via Config object, even if
+  # it's not in the PATH... so this is slightly safer than just using Puppet::Util.which)
+  # @return [String] the path to the Ruby executable
+  # @api private
+  #
+  def self.ruby_path()
+    File.join(RbConfig::CONFIG['bindir'],
+              RbConfig::CONFIG['ruby_install_name'] + RbConfig::CONFIG['EXEEXT']).
+      sub(/.*\s.*/m, '"\&"')
+  end
+
+  # Because some modules provide their own version of this method.
+  class << self
+    alias util_execute execute
+  end
+
+
+  # This is private method.
+  # @comment see call to private_class_method after method definition
+  # @api private
+  #
+  def self.execute_posix(command, options, stdin, stdout, stderr)
+    child_pid = Puppet::Util.safe_posix_fork(stdin, stdout, stderr) do
+
+      # We can't just call Array(command), and rely on it returning
+      # things like ['foo'], when passed ['foo'], because
+      # Array(command) will call command.to_a internally, which when
+      # given a string can end up doing Very Bad Things(TM), such as
+      # turning "/tmp/foo;\r\n /bin/echo" into ["/tmp/foo;\r\n", " /bin/echo"]
+      command = [command].flatten
+      Process.setsid
+      begin
+        Puppet::Util::SUIDManager.change_privileges(options[:uid], options[:gid], true)
+
+        # if the caller has requested that we override locale environment variables,
+        if (options[:override_locale]) then
+          # loop over them and clear them
+          Puppet::Util::POSIX::LOCALE_ENV_VARS.each { |name| ENV.delete(name) }
+          # set LANG and LC_ALL to 'C' so that the command will have consistent, predictable output
+          # it's OK to manipulate these directly rather than, e.g., via "withenv", because we are in
+          # a forked process.
+          ENV['LANG'] = 'C'
+          ENV['LC_ALL'] = 'C'
+        end
+
+        # unset all of the user-related environment variables so that different methods of starting puppet
+        # (automatic start during boot, via 'service', via /etc/init.d, etc.) won't have unexpected side
+        # effects relating to user / home dir environment vars.
+        # it's OK to manipulate these directly rather than, e.g., via "withenv", because we are in
+        # a forked process.
+        Puppet::Util::POSIX::USER_ENV_VARS.each { |name| ENV.delete(name) }
+
+        options[:custom_environment] ||= {}
+        Puppet::Util.withenv(options[:custom_environment]) do
+          Kernel.exec(*command)
+        end
+      rescue => detail
+        Puppet.log_exception(detail, "Could not execute posix command: #{detail}")
+        exit!(1)
+      end
+    end
+    child_pid
+  end
+  private_class_method :execute_posix
+
+
+  # This is private method.
+  # @comment see call to private_class_method after method definition
+  # @api private
+  #
+  def self.execute_windows(command, options, stdin, stdout, stderr)
+    command = command.map do |part|
+      part.include?(' ') ? %Q["#{part.gsub(/"/, '\"')}"] : part
+    end.join(" ") if command.is_a?(Array)
+
+    options[:custom_environment] ||= {}
+    Puppet::Util.withenv(options[:custom_environment]) do
+      Puppet::Util::Windows::Process.execute(command, options, stdin, stdout, stderr)
+    end
+  end
+  private_class_method :execute_windows
+
+
+  # This is private method.
+  # @comment see call to private_class_method after method definition
+  # @api private
+  #
+  def self.wait_for_output(stdout)
+    # Make sure the file's actually been written.  This is basically a race
+    # condition, and is probably a horrible way to handle it, but, well, oh
+    # well.
+    # (If this method were treated as private / inaccessible from outside of this file, we shouldn't have to worry
+    #  about a race condition because all of the places that we call this from are preceded by a call to "waitpid2",
+    #  meaning that the processes responsible for writing the file have completed before we get here.)
+    2.times do |try|
+      if Puppet::FileSystem.exist?(stdout.path)
+        stdout.open
+        begin
+          return stdout.read
+        ensure
+          stdout.close
+          stdout.unlink
+        end
+      else
+        time_to_sleep = try / 2.0
+        Puppet.warning "Waiting for output; will sleep #{time_to_sleep} seconds"
+        sleep(time_to_sleep)
+      end
+    end
+    nil
+  end
+  private_class_method :wait_for_output
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/execution_stub.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/execution_stub.rb
new file mode 100644
index 0000000..cc19e58
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/execution_stub.rb
@@ -0,0 +1,26 @@
+module Puppet::Util
+  class ExecutionStub
+    class << self
+      # Set a stub block that Puppet::Util::Execution.execute() should invoke instead
+      # of actually executing commands on the target machine.  Intended
+      # for spec testing.
+      #
+      # The arguments passed to the block are |command, options|, where
+      # command is an array of strings and options is an options hash.
+      def set(&block)
+        @value = block
+      end
+
+      # Uninstall any execution stub, so that calls to
+      # Puppet::Util::Execution.execute() behave normally again.
+      def reset
+        @value = nil
+      end
+
+      # Retrieve the current execution stub, or nil if there is no stub.
+      def current_value
+        @value
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/feature.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/feature.rb
new file mode 100644
index 0000000..23d00ed
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/feature.rb
@@ -0,0 +1,97 @@
+require 'puppet'
+
+class Puppet::Util::Feature
+  attr_reader :path
+
+  # Create a new feature test.  You have to pass the feature name,
+  # and it must be unique.  You can either provide a block that
+  # will get executed immediately to determine if the feature
+  # is present, or you can pass an option to determine it.
+  # Currently, the only supported option is 'libs' (must be
+  # passed as a symbol), which will make sure that each lib loads
+  # successfully.
+  def add(name, options = {})
+    method = name.to_s + "?"
+    @results.delete(name)
+
+    if block_given?
+      begin
+        result = yield
+      rescue Exception => detail
+        warn "Failed to load feature test for #{name}: #{detail}"
+        result = false
+      end
+      @results[name] = result
+    end
+
+    meta_def(method) do
+      # we return a cached result if:
+      #  * if a block is given (and we just evaluated it above)
+      #  * if we already have a positive result
+      #  * if we've tested this feature before and it failed, but we're
+      #    configured to always cache
+      if block_given?     ||
+          @results[name]  ||
+          (@results.has_key?(name) and Puppet[:always_cache_features])
+        @results[name]
+      else
+        @results[name] = test(name, options)
+        @results[name]
+      end
+    end
+  end
+
+  # Create a new feature collection.
+  def initialize(path)
+    @path = path
+    @results = {}
+    @loader = Puppet::Util::Autoload.new(self, @path)
+  end
+
+  def load
+    @loader.loadall
+  end
+
+  def method_missing(method, *args)
+    return super unless method.to_s =~ /\?$/
+
+    feature = method.to_s.sub(/\?$/, '')
+    @loader.load(feature)
+
+    respond_to?(method) && self.send(method)
+  end
+
+  # Actually test whether the feature is present.  We only want to test when
+  # someone asks for the feature, so we don't unnecessarily load
+  # files.
+  def test(name, options)
+    return true unless ary = options[:libs]
+    ary = [ary] unless ary.is_a?(Array)
+
+    ary.each do |lib|
+      return false unless load_library(lib, name)
+    end
+
+    # We loaded all of the required libraries
+    true
+  end
+
+  private
+
+  def load_library(lib, name)
+    raise ArgumentError, "Libraries must be passed as strings not #{lib.class}" unless lib.is_a?(String)
+
+    @rubygems ||= Puppet::Util::RubyGems::Source.new
+    @rubygems.clear_paths
+
+    begin
+      require lib
+    rescue SystemExit,NoMemoryError
+      raise
+    rescue Exception
+      Puppet.debug "Failed to load library '#{lib}' for feature '#{name}'"
+      return false
+    end
+    true
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/file_watcher.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/file_watcher.rb
new file mode 100644
index 0000000..fda994d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/file_watcher.rb
@@ -0,0 +1,28 @@
+class Puppet::Util::FileWatcher
+  include Enumerable
+
+  def each(&blk)
+    @files.keys.each(&blk)
+  end
+
+  def initialize
+    @files = {}
+  end
+
+  def changed?
+    @files.values.any?(&:changed?)
+  end
+
+  def watch(filename)
+    return if watching?(filename)
+    @files[filename] = Puppet::Util::WatchedFile.new(filename)
+  end
+
+  def watching?(filename)
+    @files.has_key?(filename)
+  end
+
+  def clear
+    @files.clear
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/fileparsing.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/fileparsing.rb
new file mode 100644
index 0000000..e19bb36
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/fileparsing.rb
@@ -0,0 +1,376 @@
+# A mini-language for parsing files.  This is only used file the ParsedFile
+# provider, but it makes more sense to split it out so it's easy to maintain
+# in one place.
+#
+# You can use this module to create simple parser/generator classes.  For instance,
+# the following parser should go most of the way to parsing /etc/passwd:
+#
+#   class Parser
+#       include Puppet::Util::FileParsing
+#       record_line :user, :fields => %w{name password uid gid gecos home shell},
+#           :separator => ":"
+#   end
+#
+# You would use it like this:
+#
+#   parser = Parser.new
+#   lines = parser.parse(File.read("/etc/passwd"))
+#
+#   lines.each do |type, hash| # type will always be :user, since we only have one
+#       p hash
+#   end
+#
+# Each line in this case would be a hash, with each field set appropriately.
+# You could then call 'parser.to_line(hash)' on any of those hashes to generate
+# the text line again.
+
+require 'puppet/util/methodhelper'
+
+module Puppet::Util::FileParsing
+  include Puppet::Util
+  attr_writer :line_separator, :trailing_separator
+
+  class FileRecord
+    include Puppet::Util
+    include Puppet::Util::MethodHelper
+    attr_accessor :absent, :joiner, :rts, :separator, :rollup, :name, :match, :block_eval
+
+    attr_reader :fields, :optional, :type
+
+    INVALID_FIELDS = [:record_type, :target, :on_disk]
+
+    # Customize this so we can do a bit of validation.
+    def fields=(fields)
+      @fields = fields.collect do |field|
+        r = field.intern
+        raise ArgumentError.new("Cannot have fields named #{r}") if INVALID_FIELDS.include?(r)
+        r
+      end
+    end
+
+    def initialize(type, options = {}, &block)
+      @type = type.intern
+      raise ArgumentError, "Invalid record type #{@type}" unless [:record, :text].include?(@type)
+
+      set_options(options)
+
+      if self.type == :record
+        # Now set defaults.
+        self.absent ||= ""
+        self.separator ||= /\s+/
+        self.joiner ||= " "
+        self.optional ||= []
+        @rollup = true unless defined?(@rollup)
+      end
+
+      if block_given?
+        @block_eval ||= :process
+
+        # Allow the developer to specify that a block should be instance-eval'ed.
+        if @block_eval == :instance
+          instance_eval(&block)
+        else
+          meta_def(@block_eval, &block)
+        end
+      end
+    end
+
+    # Convert a record into a line by joining the fields together appropriately.
+    # This is pulled into a separate method so it can be called by the hooks.
+    def join(details)
+      joinchar = self.joiner
+
+      fields.collect { |field|
+        # If the field is marked absent, use the appropriate replacement
+        if details[field] == :absent or details[field] == [:absent] or details[field].nil?
+          if self.optional.include?(field)
+            self.absent
+          else
+            raise ArgumentError, "Field '#{field}' is required"
+          end
+        else
+          details[field].to_s
+        end
+      }.reject { |c| c.nil?}.join(joinchar)
+    end
+
+    # Customize this so we can do a bit of validation.
+    def optional=(optional)
+      @optional = optional.collect do |field|
+        field.intern
+      end
+    end
+
+    # Create a hook that modifies the hash resulting from parsing.
+    def post_parse=(block)
+      meta_def(:post_parse, &block)
+    end
+
+    # Create a hook that modifies the hash just prior to generation.
+    def pre_gen=(block)
+      meta_def(:pre_gen, &block)
+    end
+
+    # Are we a text type?
+    def text?
+      type == :text
+    end
+
+    def to_line=(block)
+      meta_def(:to_line, &block)
+    end
+  end
+
+  # Clear all existing record definitions.  Only used for testing.
+  def clear_records
+    @record_types.clear
+    @record_order.clear
+  end
+
+  def fields(type)
+    if record = record_type(type)
+      record.fields.dup
+    else
+      nil
+    end
+  end
+
+  # Try to match a specific text line.
+  def handle_text_line(line, record)
+    line =~ record.match ? {:record_type => record.name, :line => line} : nil
+  end
+
+  # Try to match a record.
+  #
+  # @param [String] line The line to be parsed
+  # @param [Puppet::Util::FileType] record The filetype to use for parsing
+  #
+  # @return [Hash<Symbol, Object>] The parsed elements of the line
+  def handle_record_line(line, record)
+    ret = nil
+    if record.respond_to?(:process)
+      if ret = record.send(:process, line.dup)
+        unless ret.is_a?(Hash)
+          raise Puppet::DevError,
+            "Process record type #{record.name} returned non-hash"
+        end
+      else
+        return nil
+      end
+    elsif regex = record.match
+      # In this case, we try to match the whole line and then use the
+      # match captures to get our fields.
+      if match = regex.match(line)
+        ret = {}
+        record.fields.zip(match.captures).each do |field, value|
+          if value == record.absent
+            ret[field] = :absent
+          else
+            ret[field] = value
+          end
+        end
+      else
+        nil
+      end
+    else
+      ret = {}
+      sep = record.separator
+
+      # String "helpfully" replaces ' ' with /\s+/ in splitting, so we
+      # have to work around it.
+      if sep == " "
+        sep = / /
+      end
+      line_fields = line.split(sep)
+      record.fields.each do |param|
+        value = line_fields.shift
+        if value and value != record.absent
+          ret[param] = value
+        else
+          ret[param] = :absent
+        end
+      end
+
+      if record.rollup and ! line_fields.empty?
+        last_field = record.fields[-1]
+        val = ([ret[last_field]] + line_fields).join(record.joiner)
+        ret[last_field] = val
+      end
+    end
+
+    if ret
+      ret[:record_type] = record.name
+      return ret
+    else
+      return nil
+    end
+  end
+
+  def line_separator
+    @line_separator ||= "\n"
+
+    @line_separator
+  end
+
+  # Split text into separate lines using the record separator.
+  def lines(text)
+    # Remove any trailing separators, and then split based on them
+    text.sub(/#{self.line_separator}\Q/,'').split(self.line_separator)
+  end
+
+  # Split a bunch of text into lines and then parse them individually.
+  def parse(text)
+    count = 1
+    lines(text).collect do |line|
+      count += 1
+      if val = parse_line(line)
+        val
+      else
+        error = Puppet::ResourceError.new("Could not parse line #{line.inspect}")
+        error.line = count
+        raise error
+      end
+    end
+  end
+
+  # Handle parsing a single line.
+  def parse_line(line)
+    raise Puppet::DevError, "No record types defined; cannot parse lines" unless records?
+
+    @record_order.each do |record|
+      # These are basically either text or record lines.
+      method = "handle_#{record.type}_line"
+      if respond_to?(method)
+        if result = send(method, line, record)
+          record.send(:post_parse, result) if record.respond_to?(:post_parse)
+          return result
+        end
+      else
+        raise Puppet::DevError,
+          "Somehow got invalid line type #{record.type}"
+      end
+    end
+
+    nil
+  end
+
+  # Define a new type of record.  These lines get split into hashes.  Valid
+  # options are:
+  # * <tt>:absent</tt>: What to use as value within a line, when a field is
+  #   absent.  Note that in the record object, the literal :absent symbol is
+  #   used, and not this value.  Defaults to "".
+  # * <tt>:fields</tt>: The list of fields, as an array.  By default, all
+  #   fields are considered required.
+  # * <tt>:joiner</tt>: How to join fields together.  Defaults to '\t'.
+  # * <tt>:optional</tt>: Which fields are optional.  If these are missing,
+  #   you'll just get the 'absent' value instead of an ArgumentError.
+  # * <tt>:rts</tt>: Whether to remove trailing whitespace.  Defaults to false.
+  #   If true, whitespace will be removed; if a regex, then whatever matches
+  #   the regex will be removed.
+  # * <tt>:separator</tt>: The record separator.  Defaults to /\s+/.
+  def record_line(name, options, &block)
+    raise ArgumentError, "Must include a list of fields" unless options.include?(:fields)
+
+    record = FileRecord.new(:record, options, &block)
+    record.name = name.intern
+
+    new_line_type(record)
+  end
+
+  # Are there any record types defined?
+  def records?
+    defined?(@record_types) and ! @record_types.empty?
+  end
+
+  # Define a new type of text record.
+  def text_line(name, options, &block)
+    raise ArgumentError, "You must provide a :match regex for text lines" unless options.include?(:match)
+
+    record = FileRecord.new(:text, options, &block)
+    record.name = name.intern
+
+    new_line_type(record)
+  end
+
+  # Generate a file from a bunch of hash records.
+  def to_file(records)
+    text = records.collect { |record| to_line(record) }.join(line_separator)
+
+    text += line_separator if trailing_separator
+
+    text
+  end
+
+  # Convert our parsed record into a text record.
+  def to_line(details)
+    unless record = record_type(details[:record_type])
+      raise ArgumentError, "Invalid record type #{details[:record_type].inspect}"
+    end
+
+    if record.respond_to?(:pre_gen)
+      details = details.dup
+      record.send(:pre_gen, details)
+    end
+
+    case record.type
+    when :text; return details[:line]
+    else
+      return record.to_line(details) if record.respond_to?(:to_line)
+
+      line = record.join(details)
+
+      if regex = record.rts
+        # If they say true, then use whitespace; else, use their regex.
+        if regex == true
+          regex = /\s+$/
+        end
+        return line.sub(regex,'')
+      else
+        return line
+      end
+    end
+  end
+
+  # Whether to add a trailing separator to the file.  Defaults to true
+  def trailing_separator
+    if defined?(@trailing_separator)
+      return @trailing_separator
+    else
+      return true
+    end
+  end
+
+  def valid_attr?(type, attr)
+    type = type.intern
+    if record = record_type(type) and record.fields.include?(attr.intern)
+      return true
+    else
+      if attr.intern == :ensure
+        return true
+      else
+        false
+      end
+    end
+  end
+
+  private
+
+  # Define a new type of record.
+  def new_line_type(record)
+    @record_types ||= {}
+    @record_order ||= []
+
+    raise ArgumentError, "Line type #{record.name} is already defined" if @record_types.include?(record.name)
+
+    @record_types[record.name] = record
+    @record_order << record
+
+    record
+  end
+
+  # Retrieve the record object.
+  def record_type(type)
+    @record_types[type.intern]
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/filetype.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/filetype.rb
new file mode 100644
index 0000000..08f763e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/filetype.rb
@@ -0,0 +1,303 @@
+# Basic classes for reading, writing, and emptying files.  Not much
+# to see here.
+
+require 'puppet/util/selinux'
+require 'tempfile'
+require 'fileutils'
+
+class Puppet::Util::FileType
+  attr_accessor :loaded, :path, :synced
+
+  class FileReadError < Puppet::Error; end
+
+  include Puppet::Util::SELinux
+
+  class << self
+    attr_accessor :name
+    include Puppet::Util::ClassGen
+  end
+
+  # Create a new filetype.
+  def self.newfiletype(name, &block)
+    @filetypes ||= {}
+
+    klass = genclass(
+      name,
+      :block => block,
+      :prefix => "FileType",
+      :hash => @filetypes
+    )
+
+    # Rename the read and write methods, so that we're sure they
+    # maintain the stats.
+    klass.class_eval do
+      # Rename the read method
+      define_method(:real_read, instance_method(:read))
+      define_method(:read) do
+        begin
+          val = real_read
+          @loaded = Time.now
+          if val
+            return val.gsub(/# HEADER.*\n/,'')
+          else
+            return ""
+          end
+        rescue Puppet::Error => detail
+          raise
+        rescue => detail
+          message = "#{self.class} could not read #{@path}: #{detail}"
+          Puppet.log_exception(detail, message)
+          raise Puppet::Error, message, detail.backtrace
+        end
+      end
+
+      # And then the write method
+      define_method(:real_write, instance_method(:write))
+      define_method(:write) do |text|
+        begin
+          val = real_write(text)
+          @synced = Time.now
+          return val
+        rescue Puppet::Error => detail
+          raise
+        rescue => detail
+          message = "#{self.class} could not write #{@path}: #{detail}"
+          Puppet.log_exception(detail, message)
+          raise Puppet::Error, message, detail.backtrace
+        end
+      end
+    end
+  end
+
+  def self.filetype(type)
+    @filetypes[type]
+  end
+
+  # Pick or create a filebucket to use.
+  def bucket
+    @bucket ||= Puppet::Type.type(:filebucket).mkdefaultbucket.bucket
+  end
+
+  def initialize(path, default_mode = nil)
+    raise ArgumentError.new("Path is nil") if path.nil?
+    @path = path
+    @default_mode = default_mode
+  end
+
+  # Arguments that will be passed to the execute method. Will set the uid
+  # to the target user if the target user and the current user are not
+  # the same
+  def cronargs
+    if uid = Puppet::Util.uid(@path) and uid == Puppet::Util::SUIDManager.uid
+      {:failonfail => true, :combine => true}
+    else
+      {:failonfail => true, :combine => true, :uid => @path}
+    end
+  end
+
+  # Operate on plain files.
+  newfiletype(:flat) do
+    # Back the file up before replacing it.
+    def backup
+      bucket.backup(@path) if Puppet::FileSystem.exist?(@path)
+    end
+
+    # Read the file.
+    def read
+      if Puppet::FileSystem.exist?(@path)
+        File.read(@path)
+      else
+        return nil
+      end
+    end
+
+    # Remove the file.
+    def remove
+      Puppet::FileSystem.unlink(@path) if Puppet::FileSystem.exist?(@path)
+    end
+
+    # Overwrite the file.
+    def write(text)
+      tf = Tempfile.new("puppet")
+      tf.print text; tf.flush
+      File.chmod(@default_mode, tf.path) if @default_mode
+      FileUtils.cp(tf.path, @path)
+      tf.close
+      # If SELinux is present, we need to ensure the file has its expected context
+      set_selinux_default_context(@path)
+    end
+  end
+
+  # Operate on plain files.
+  newfiletype(:ram) do
+    @@tabs = {}
+
+    def self.clear
+      @@tabs.clear
+    end
+
+    def initialize(path, default_mode = nil)
+      # default_mode is meaningless for this filetype,
+      # supported only for compatibility with :flat
+      super
+      @@tabs[@path] ||= ""
+    end
+
+    # Read the file.
+    def read
+      Puppet.info "Reading #{@path} from RAM"
+      @@tabs[@path]
+    end
+
+    # Remove the file.
+    def remove
+      Puppet.info "Removing #{@path} from RAM"
+      @@tabs[@path] = ""
+    end
+
+    # Overwrite the file.
+    def write(text)
+      Puppet.info "Writing #{@path} to RAM"
+      @@tabs[@path] = text
+    end
+  end
+
+  # Handle Linux-style cron tabs.
+  newfiletype(:crontab) do
+    def initialize(user)
+      self.path = user
+    end
+
+    def path=(user)
+      begin
+        @uid = Puppet::Util.uid(user)
+      rescue Puppet::Error => detail
+        raise FileReadError, "Could not retrieve user #{user}: #{detail}", detail.backtrace
+      end
+
+      # XXX We have to have the user name, not the uid, because some
+      # systems *cough*linux*cough* require it that way
+      @path = user
+    end
+
+    # Read a specific @path's cron tab.
+    def read
+      %x{#{cmdbase} -l 2>/dev/null}
+    end
+
+    # Remove a specific @path's cron tab.
+    def remove
+      if %w{Darwin FreeBSD DragonFly}.include?(Facter.value("operatingsystem"))
+        %x{/bin/echo yes | #{cmdbase} -r 2>/dev/null}
+      else
+        %x{#{cmdbase} -r 2>/dev/null}
+      end
+    end
+
+    # Overwrite a specific @path's cron tab; must be passed the @path name
+    # and the text with which to create the cron tab.
+    def write(text)
+      IO.popen("#{cmdbase()} -", "w") { |p|
+        p.print text
+      }
+    end
+
+    private
+
+    # Only add the -u flag when the @path is different.  Fedora apparently
+    # does not think I should be allowed to set the @path to my own user name
+    def cmdbase
+      if @uid == Puppet::Util::SUIDManager.uid || Facter.value(:operatingsystem) == "HP-UX"
+        return "crontab"
+      else
+        return "crontab -u #{@path}"
+      end
+    end
+  end
+
+  # SunOS has completely different cron commands; this class implements
+  # its versions.
+  newfiletype(:suntab) do
+    # Read a specific @path's cron tab.
+    def read
+      Puppet::Util::Execution.execute(%w{crontab -l}, cronargs)
+    rescue => detail
+      case detail.to_s
+      when /can't open your crontab/
+        return ""
+      when /you are not authorized to use cron/
+        raise FileReadError, "User #{@path} not authorized to use cron", detail.backtrace
+      else
+        raise FileReadError, "Could not read crontab for #{@path}: #{detail}", detail.backtrace
+      end
+    end
+
+    # Remove a specific @path's cron tab.
+    def remove
+      Puppet::Util::Execution.execute(%w{crontab -r}, cronargs)
+    rescue => detail
+      raise FileReadError, "Could not remove crontab for #{@path}: #{detail}", detail.backtrace
+    end
+
+    # Overwrite a specific @path's cron tab; must be passed the @path name
+    # and the text with which to create the cron tab.
+    def write(text)
+      output_file = Tempfile.new("puppet_suntab")
+      begin
+        output_file.print text
+        output_file.close
+        # We have to chown the stupid file to the user.
+        File.chown(Puppet::Util.uid(@path), nil, output_file.path)
+        Puppet::Util::Execution.execute(["crontab", output_file.path], cronargs)
+      rescue => detail
+        raise FileReadError, "Could not write crontab for #{@path}: #{detail}", detail.backtrace
+      ensure
+        output_file.close
+        output_file.unlink
+      end
+    end
+  end
+
+  #  Support for AIX crontab with output different than suntab's crontab command.
+  newfiletype(:aixtab) do
+    # Read a specific @path's cron tab.
+    def read
+      Puppet::Util::Execution.execute(%w{crontab -l}, cronargs)
+    rescue => detail
+      case detail.to_s
+      when /Cannot open a file in the .* directory/
+        return ""
+      when /You are not authorized to use the cron command/
+        raise FileReadError, "User #{@path} not authorized to use cron", detail.backtrace
+      else
+        raise FileReadError, "Could not read crontab for #{@path}: #{detail}", detail.backtrace
+      end
+    end
+
+    # Remove a specific @path's cron tab.
+    def remove
+      Puppet::Util::Execution.execute(%w{crontab -r}, cronargs)
+    rescue => detail
+      raise FileReadError, "Could not remove crontab for #{@path}: #{detail}", detail.backtrace
+    end
+
+    # Overwrite a specific @path's cron tab; must be passed the @path name
+    # and the text with which to create the cron tab.
+    def write(text)
+      output_file = Tempfile.new("puppet_aixtab")
+
+      begin
+        output_file.print text
+        output_file.close
+        # We have to chown the stupid file to the user.
+        File.chown(Puppet::Util.uid(@path), nil, output_file.path)
+        Puppet::Util::Execution.execute(["crontab", output_file.path], cronargs)
+      rescue => detail
+        raise FileReadError, "Could not write crontab for #{@path}: #{detail}", detail.backtrace
+      ensure
+        output_file.close
+        output_file.unlink
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/http_proxy.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/http_proxy.rb
new file mode 100644
index 0000000..3785d49
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/http_proxy.rb
@@ -0,0 +1,65 @@
+module Puppet::Util::HttpProxy
+
+  def self.http_proxy_env
+    # Returns a URI object if proxy is set, or nil
+    proxy_env = ENV["http_proxy"] || ENV["HTTP_PROXY"]
+    begin
+      return URI.parse(proxy_env) if proxy_env
+    rescue URI::InvalidURIError
+      return nil
+    end
+    return nil
+  end
+
+  def self.http_proxy_host
+    env = self.http_proxy_env
+
+    if env and env.host
+      return env.host
+    end
+
+    if Puppet.settings[:http_proxy_host] == 'none'
+      return nil
+    end
+
+    return Puppet.settings[:http_proxy_host]
+  end
+
+  def self.http_proxy_port
+    env = self.http_proxy_env
+
+    if env and env.port
+      return env.port
+    end
+
+    return Puppet.settings[:http_proxy_port]
+  end
+
+  def self.http_proxy_user
+    env = self.http_proxy_env
+
+    if env and env.user
+      return env.user
+    end
+
+    if Puppet.settings[:http_proxy_user] == 'none'
+      return nil
+    end
+
+    return Puppet.settings[:http_proxy_user]
+  end
+
+  def self.http_proxy_password
+    env = self.http_proxy_env
+
+    if env and env.password
+      return env.password
+    end
+
+    if Puppet.settings[:http_proxy_user] == 'none' or Puppet.settings[:http_proxy_password] == 'none'
+      return nil
+    end
+
+    return Puppet.settings[:http_proxy_password]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/inifile.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/inifile.rb
new file mode 100644
index 0000000..23ce18a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/inifile.rb
@@ -0,0 +1,341 @@
+# Module Puppet::IniConfig
+# A generic way to parse .ini style files and manipulate them in memory
+# One 'file' can be made up of several physical files. Changes to sections
+# on the file are tracked so that only the physical files in which
+# something has changed are written back to disk
+# Great care is taken to preserve comments and blank lines from the original
+# files
+#
+# The parsing tries to stay close to python's ConfigParser
+
+require 'puppet/util/filetype'
+require 'puppet/error'
+
+module Puppet::Util::IniConfig
+  # A section in a .ini file
+  class Section
+    attr_reader :name, :file, :entries
+    attr_writer :destroy
+
+    def initialize(name, file)
+      @name = name
+      @file = file
+      @dirty = false
+      @entries = []
+      @destroy = false
+    end
+
+    # Does this section need to be updated in/removed from the associated file?
+    #
+    # @note This section is dirty if a key has been modified _or_ if the
+    #   section has been modified so the associated file can be rewritten
+    #   without this section.
+    def dirty?
+      @dirty or @destroy
+    end
+
+    def mark_dirty
+      @dirty = true
+    end
+
+    # Should only be used internally
+    def mark_clean
+      @dirty = false
+    end
+
+    # Should the file be destroyed?
+    def destroy?
+      @destroy
+    end
+
+    # Add a line of text (e.g., a comment) Such lines
+    # will be written back out in exactly the same
+    # place they were read in
+    def add_line(line)
+      @entries << line
+    end
+
+    # Set the entry 'key=value'. If no entry with the
+    # given key exists, one is appended to teh end of the section
+    def []=(key, value)
+      entry = find_entry(key)
+      @dirty = true
+      if entry.nil?
+        @entries << [key, value]
+      else
+        entry[1] = value
+      end
+    end
+
+    # Return the value associated with KEY. If no such entry
+    # exists, return nil
+    def [](key)
+      entry = find_entry(key)
+      return(entry.nil? ? nil : entry[1])
+    end
+
+    # Format the section as text in the way it should be
+    # written to file
+    def format
+      if @destroy
+        text = ""
+      else
+        text = "[#{name}]\n"
+        @entries.each do |entry|
+          if entry.is_a?(Array)
+            key, value = entry
+            text << "#{key}=#{value}\n" unless value.nil?
+          else
+            text << entry
+          end
+        end
+      end
+      text
+    end
+
+    private
+    def find_entry(key)
+      @entries.each do |entry|
+        return entry if entry.is_a?(Array) && entry[0] == key
+      end
+      nil
+    end
+
+  end
+
+  class PhysicalFile
+
+    # @!attribute [r] filetype
+    #   @api private
+    #   @return [Puppet::Util::FileType::FileTypeFlat]
+    attr_reader :filetype
+
+    # @!attribute [r] contents
+    #   @api private
+    #   @return [Array<String, Puppet::Util::IniConfig::Section>]
+    attr_reader :contents
+
+    # @!attribute [rw] destroy_empty
+    #   Whether empty files should be removed if no sections are defined.
+    #   Defaults to false
+    attr_accessor :destroy_empty
+
+    # @!attribute [rw] file_collection
+    #   @return [Puppet::Util::IniConfig::FileCollection]
+    attr_accessor :file_collection
+
+    def initialize(file, options = {})
+      @file = file
+      @contents = []
+      @filetype = Puppet::Util::FileType.filetype(:flat).new(file)
+
+      @destroy_empty = options.fetch(:destroy_empty, false)
+    end
+
+    # Read and parse the on-disk file associated with this object
+    def read
+      text = @filetype.read
+      if text.nil?
+        raise IniParseError, "Cannot read nonexistent file #{@file.inspect}"
+      end
+      parse(text)
+    end
+
+    INI_COMMENT = Regexp.union(
+      /^\s*$/,
+      /^[#;]/,
+      /^\s*rem\s/i
+    )
+    INI_CONTINUATION = /^[ \t\r\n\f]/
+    INI_SECTION_NAME = /^\[([^\]]+)\]/
+    INI_PROPERTY     = /^\s*([^\s=]+)\s*\=(.*)$/
+
+    # @api private
+    def parse(text)
+      section = nil   # The name of the current section
+      optname = nil   # The name of the last option in section
+      line_num = 0
+
+      text.each_line do |l|
+        line_num += 1
+        if l.match(INI_COMMENT)
+          # Whitespace or comment
+          if section.nil?
+            @contents << l
+          else
+            section.add_line(l)
+          end
+        elsif l.match(INI_CONTINUATION) && section && optname
+          # continuation line
+          section[optname] += "\n#{l.chomp}"
+        elsif (match = l.match(INI_SECTION_NAME))
+          # section heading
+          section.mark_clean if section
+
+          section_name = match[1]
+
+          section = add_section(section_name)
+          optname = nil
+        elsif (match = l.match(INI_PROPERTY))
+          # We allow space around the keys, but not the values
+          # For the values, we don't know if space is significant
+          key = match[1]
+          val = match[2]
+
+          if section.nil?
+            raise IniParseError.new("Property with key #{key.inspect} outside of a section")
+          end
+
+          section[key] = val
+          optname = key
+        else
+          raise IniParseError.new("Can't parse line '#{l.chomp}'", @file, line_num)
+        end
+      end
+      section.mark_clean unless section.nil?
+    end
+
+    # @return [Array<Puppet::Util::IniConfig::Section>] All sections defined in
+    #   this file.
+    def sections
+      @contents.select { |entry| entry.is_a? Section }
+    end
+
+    # @return [Puppet::Util::IniConfig::Section, nil] The section with the
+    #   given name if it exists, else nil.
+    def get_section(name)
+      @contents.find { |entry| entry.is_a? Section and entry.name == name }
+    end
+
+    def format
+      text = ""
+
+      @contents.each do |content|
+        if content.is_a? Section
+          text << content.format
+        else
+          text << content
+        end
+      end
+
+      text
+    end
+
+    def store
+      if @destroy_empty and (sections.empty? or sections.all?(&:destroy?))
+        ::File.unlink(@file)
+      elsif sections.any?(&:dirty?)
+        text = self.format
+        @filetype.write(text)
+      end
+      sections.each(&:mark_clean)
+    end
+
+    # Create a new section and store it in the file contents
+    #
+    # @api private
+    # @param name [String] The name of the section to create
+    # @return [Puppet::Util::IniConfig::Section]
+    def add_section(name)
+      if section_exists?(name)
+        raise IniParseError.new("Section #{name.inspect} is already defined, cannot redefine", @file)
+      end
+
+      section = Section.new(name, @file)
+      @contents << section
+
+      section
+    end
+
+    private
+
+    def section_exists?(name)
+      if self.get_section(name)
+        true
+      elsif @file_collection and @file_collection.get_section(name)
+        true
+      else
+        false
+      end
+    end
+  end
+
+  class FileCollection
+
+    attr_reader :files
+
+    def initialize
+      @files = {}
+    end
+
+    # Read and parse a file and store it in the collection. If the file has
+    # already been read it will be destroyed and re-read.
+    def read(file)
+      new_physical_file(file).read
+    end
+
+    def store
+      @files.values.each do |file|
+        file.store
+      end
+    end
+
+    def each_section(&block)
+      @files.values.each do |file|
+        file.sections.each do |section|
+          yield section
+        end
+      end
+    end
+
+    def each_file(&block)
+      @files.keys.each do |path|
+        yield path
+      end
+    end
+
+    def get_section(name)
+      sect = nil
+      @files.values.each do |file|
+        if (current = file.get_section(name))
+          sect = current
+        end
+      end
+      sect
+    end
+    alias [] get_section
+
+    def include?(name)
+      !! get_section(name)
+    end
+
+    def add_section(name, file)
+      get_physical_file(file).add_section(name)
+    end
+
+    private
+
+    # Return a file if it's already been defined, create a new file if it hasn't
+    # been defined.
+    def get_physical_file(file)
+      if @files[file]
+        @files[file]
+      else
+        new_physical_file(file)
+      end
+    end
+
+    # Create a new physical file and set required attributes on that file.
+    def new_physical_file(file)
+      @files[file] = PhysicalFile.new(file)
+      @files[file].file_collection = self
+      @files[file]
+    end
+  end
+
+  File = FileCollection
+
+  class IniParseError < Puppet::Error
+    include Puppet::ExternalFileError
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/inline_docs.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/inline_docs.rb
new file mode 100644
index 0000000..62818c1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/inline_docs.rb
@@ -0,0 +1,26 @@
+module Puppet::Util::InlineDocs
+  def self.included(klass)
+    klass.send(:include, InstanceMethods)
+    klass.extend ClassMethods
+  end
+
+  module ClassMethods
+    attr_accessor :use_docs
+    def associates_doc
+      self.use_docs = true
+    end
+  end
+
+  module InstanceMethods
+    attr_writer :doc
+
+    def doc
+      @doc ||= ""
+    end
+
+    # don't fetch lexer comment by default
+    def use_docs
+      self.class.use_docs
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instance_loader.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instance_loader.rb
new file mode 100644
index 0000000..c6d6b71
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instance_loader.rb
@@ -0,0 +1,81 @@
+require 'puppet/util/autoload'
+require 'puppet/util'
+
+# A module that can easily autoload things for us.  Uses an instance
+# of Puppet::Util::Autoload
+module Puppet::Util::InstanceLoader
+  include Puppet::Util
+
+  # Are we instance-loading this type?
+  def instance_loading?(type)
+    defined?(@autoloaders) and @autoloaders.include?(type.intern)
+  end
+
+  # Define a new type of autoloading.
+  def instance_load(type, path, options = {})
+    @autoloaders ||= {}
+    @instances ||= {}
+    type = type.intern
+    @instances[type] = {}
+    @autoloaders[type] = Puppet::Util::Autoload.new(self, path, options)
+
+    # Now define our new simple methods
+    unless respond_to?(type)
+      meta_def(type) do |name|
+        loaded_instance(type, name)
+      end
+    end
+  end
+
+  # Return a list of the names of all instances
+  def loaded_instances(type)
+    @instances[type].keys
+  end
+
+  # Collect the docs for all of our instances.
+  def instance_docs(type)
+    docs = ""
+
+    # Load all instances.
+    instance_loader(type).loadall
+
+    # Use this method so they all get loaded
+    loaded_instances(type).sort { |a,b| a.to_s <=> b.to_s }.each do |name|
+      mod = self.loaded_instance(name)
+      docs << "#{name}\n#{"-" * name.to_s.length}\n"
+
+      docs << Puppet::Util::Docs.scrub(mod.doc) << "\n\n"
+    end
+
+    docs
+  end
+
+  # Return the instance hash for our type.
+  def instance_hash(type)
+    @instances[type.intern]
+  end
+
+  # Return the Autoload object for a given type.
+  def instance_loader(type)
+    @autoloaders[type.intern]
+  end
+
+  # Retrieve an alread-loaded instance, or attempt to load our instance.
+  def loaded_instance(type, name)
+    name = name.intern
+    return nil unless instances = instance_hash(type)
+    unless instances.include? name
+      if instance_loader(type).load(name)
+        unless instances.include? name
+          Puppet.warning(
+            "Loaded #{type} file for #{name} but #{type} was not defined"
+          )
+          return nil
+        end
+      else
+        return nil
+      end
+    end
+    instances[name]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instrumentation.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instrumentation.rb
new file mode 100644
index 0000000..94a75ac
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instrumentation.rb
@@ -0,0 +1,152 @@
+require 'puppet'
+require 'puppet/util/classgen'
+require 'puppet/util/instance_loader'
+
+class Puppet::Util::Instrumentation
+  extend Puppet::Util::ClassGen
+  extend Puppet::Util::InstanceLoader
+
+  # we're using a ruby lazy autoloader to prevent a loop when requiring listeners
+  # since this class sets up an indirection which is also used in Puppet::Indirector::Indirection
+  # which is used to setup indirections...
+  autoload :Listener, 'puppet/util/instrumentation/listener'
+  autoload :Data, 'puppet/util/instrumentation/data'
+
+  # Set up autoloading and retrieving of instrumentation listeners.
+  instance_load :listener, 'puppet/util/instrumentation/listeners'
+
+  class << self
+    attr_accessor :listeners, :listeners_of
+  end
+
+  # instrumentation layer
+
+  # Triggers an instrumentation
+  #
+  # Call this method around the instrumentation point
+  #   Puppet::Util::Instrumentation.instrument(:my_long_computation) do
+  #     ... a long computation
+  #   end
+  #
+  # This will send an event to all the listeners of "my_long_computation".
+  # Note: this method uses ruby yield directive to call the instrumented code.
+  # It is usually way slower than calling start and stop directly around the instrumented code.
+  # For high traffic code path, it is thus advisable to not use this method.
+  def self.instrument(label, data = {})
+    id = self.start(label, data)
+    yield
+  ensure
+    self.stop(label, id, data)
+  end
+
+  # Triggers a "start" instrumentation event
+  #
+  # Important note:
+  #  For proper use, the data hash instance used for start should also
+  #  be used when calling stop. The idea is to use the current scope
+  #  where start is called to retain a reference to 'data' so that it is possible
+  #  to send it back to stop.
+  #  This way listeners can match start and stop events more easily.
+  def self.start(label, data)
+    data[:started] = Time.now
+    publish(label, :start, data)
+    data[:id] = next_id
+  end
+
+  # Triggers a "stop" instrumentation event
+  def self.stop(label, id, data)
+    data[:finished] = Time.now
+    publish(label, :stop, data)
+  end
+
+  def self.publish(label, event, data)
+    each_listener(label) do |k,l|
+      l.notify(label, event, data)
+    end
+  end
+
+  def self.listeners
+    @listeners.values
+  end
+
+  def self.each_listener(label)
+    @listeners_of[label] ||= @listeners.select do |k,l|
+      l.listen_to?(label)
+    end.each do |l|
+      yield l
+    end
+  end
+
+  # Adds a new listener
+  #
+  # Usage:
+  #   Puppet::Util::Instrumentation.new_listener(:my_instrumentation, pattern) do
+  #
+  #     def notify(label, data)
+  #       ... do something for data...
+  #     end
+  #   end
+  #
+  # It is possible to use a "pattern". The listener will be notified only
+  # if the pattern match the label of the event.
+  # The pattern can be a symbol, a string or a regex.
+  # If no pattern is provided, then the listener will be called for every events
+  def self.new_listener(name, options = {}, &block)
+    Puppet.debug "new listener called #{name}"
+    name = name.intern
+    listener = genclass(name, :hash => instance_hash(:listener), :block => block)
+    listener.send(:define_method, :name) do
+      name
+    end
+    subscribe(listener.new, options[:label_pattern], options[:event])
+  end
+
+  def self.subscribe(listener, label_pattern, event)
+    raise "Listener #{listener.name} is already subscribed" if @listeners.include?(listener.name)
+    Puppet.debug "registering instrumentation listener #{listener.name}"
+    @listeners[listener.name] = Listener.new(listener, label_pattern, event)
+    listener.subscribed if listener.respond_to?(:subscribed)
+    rehash
+  end
+
+  def self.unsubscribe(listener)
+    Puppet.warning("#{listener.name} hasn't been registered but asked to be unregistered") unless @listeners.include?(listener.name)
+    Puppet.info "unregistering instrumentation listener #{listener.name}"
+    @listeners.delete(listener.name)
+    listener.unsubscribed if listener.respond_to?(:unsubscribed)
+    rehash
+  end
+
+  def self.init
+    # let's init our probe indirection
+    require 'puppet/util/instrumentation/indirection_probe'
+    @listeners ||= {}
+    @listeners_of ||= {}
+    instance_loader(:listener).loadall
+  end
+
+  def self.clear
+    @listeners = {}
+    @listeners_of = {}
+    @id = 0
+  end
+
+  def self.[](key)
+    @listeners[key.intern]
+  end
+
+  def self.[]=(key, value)
+    @listeners[key.intern] = value
+    rehash
+  end
+
+  private
+
+  def self.rehash
+    @listeners_of = {}
+  end
+
+  def self.next_id
+    @id = (@id || 0) + 1
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instrumentation/data.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instrumentation/data.rb
new file mode 100644
index 0000000..34d978c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instrumentation/data.rb
@@ -0,0 +1,46 @@
+require 'puppet/indirector'
+require 'puppet/util/instrumentation'
+
+# This is just a transport class to be used through the instrumentation_data
+# indirection. All the data resides in the real underlying listeners which this
+# class delegates to.
+class Puppet::Util::Instrumentation::Data
+  extend Puppet::Indirector
+
+  indirects :instrumentation_data, :terminus_class => :local
+
+  attr_reader :listener
+
+  def initialize(listener_name)
+    @listener = Puppet::Util::Instrumentation[listener_name]
+    raise "Listener #{listener_name} wasn't registered" unless @listener
+  end
+
+  def name
+    @listener.name
+  end
+
+  def to_data_hash
+    { :name => name }.merge(@listener.respond_to?(:data) ? @listener.data : {})
+  end
+
+  def to_pson_data_hash
+    {
+      'document_type' => "Puppet::Util::Instrumentation::Data",
+      'data' => to_data_hash,
+    }
+  end
+
+  def to_pson(*args)
+    to_pson_data_hash.to_pson(*args)
+  end
+
+  def self.from_data_hash(data)
+    data
+  end
+
+  def self.from_pson(data)
+    Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
+    data
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instrumentation/indirection_probe.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instrumentation/indirection_probe.rb
new file mode 100644
index 0000000..afaccd3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instrumentation/indirection_probe.rb
@@ -0,0 +1,41 @@
+require 'puppet/indirector'
+require 'puppet/util/instrumentation'
+
+# We need to use a class other than Probe for the indirector because
+# the Indirection class might declare some probes, and this would be a huge unbreakable
+# dependency cycle.
+class Puppet::Util::Instrumentation::IndirectionProbe
+  extend Puppet::Indirector
+
+  indirects :instrumentation_probe, :terminus_class => :local
+
+  attr_reader :probe_name
+
+  def initialize(probe_name)
+    @probe_name = probe_name
+  end
+
+  def to_data_hash
+    { :name => probe_name }
+  end
+
+  def to_pson_data_hash
+    {
+      :document_type => "Puppet::Util::Instrumentation::IndirectionProbe",
+      :data => to_data_hash,
+    }
+  end
+
+  def to_pson(*args)
+    to_pson_data_hash.to_pson(*args)
+  end
+
+  def self.from_data_hash(data)
+    self.new(data["name"])
+  end
+
+  def self.from_pson(data)
+    Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
+    self.from_data_hash(data)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instrumentation/instrumentable.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instrumentation/instrumentable.rb
new file mode 100644
index 0000000..01c75ff
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instrumentation/instrumentable.rb
@@ -0,0 +1,136 @@
+require 'puppet/util/instrumentation'
+
+# This is the central point of all declared probes.
+# Every class needed to declare probes should include this module
+# and declare the methods that are subject to instrumentation:
+#
+#   class MyClass
+#     extend Puppet::Util::Instrumentation::Instrumentable
+#
+#     probe :mymethod
+#
+#     def mymethod
+#       ... this is code to be instrumented ...
+#     end
+#   end
+module Puppet::Util::Instrumentation::Instrumentable
+  INSTRUMENTED_CLASSES = {}
+
+  attr_reader :probes
+
+  class Probe
+    attr_reader :klass, :method, :label, :data
+
+    def initialize(method, klass, options = {})
+      @method = method
+      @klass = klass
+
+      @label = options[:label] || method
+      @data = options[:data] || {}
+    end
+
+    def enable
+      raise "Probe already enabled" if enabled?
+
+      # We're forced to perform this copy because in the class_eval'uated
+      # block below @method would be evaluated in the class context. It's better
+      # to close on locally-scoped variables than to resort to complex namespacing
+      # to get access to the probe instance variables.
+      method = @method; label = @label; data = @data
+      klass.class_eval {
+        alias_method("instrumented_#{method}", method)
+        define_method(method) do |*args|
+          id = nil
+          instrumentation_data = nil
+          begin
+            instrumentation_label = label.respond_to?(:call) ? label.call(self, args) : label
+            instrumentation_data = data.respond_to?(:call) ? data.call(self, args) : data
+            id = Puppet::Util::Instrumentation.start(instrumentation_label, instrumentation_data)
+            send("instrumented_#{method}".to_sym, *args)
+          ensure
+            Puppet::Util::Instrumentation.stop(instrumentation_label, id, instrumentation_data || {})
+          end
+        end
+      }
+      @enabled = true
+    end
+
+    def disable
+      raise "Probe is not enabled" unless enabled?
+
+      # For the same reason as in #enable, we're forced to do a local
+      # copy
+      method = @method
+      klass.class_eval do
+        alias_method(method, "instrumented_#{method}")
+        remove_method("instrumented_#{method}".to_sym)
+      end
+      @enabled = false
+    end
+
+    def enabled?
+      !!@enabled
+    end
+  end
+
+  # Declares a new probe
+  #
+  # It is possible to pass several options that will be later on evaluated
+  # and sent to the instrumentation layer.
+  #
+  # label::
+  #   this can either be a static symbol/string or a block. If it's a block
+  #   this one will be evaluated on every call of the instrumented method and
+  #   should return a string or a symbol
+  #
+  # data::
+  #   this can be a hash or a block. If it's a block this one will be evaluated
+  #   on every call of the instrumented method and should return a hash.
+  #
+  #Example:
+  #
+  #   class MyClass
+  #     extend Instrumentable
+  #
+  #     probe :mymethod, :data => Proc.new { |args|  { :data => args[1] } }, :label => Proc.new { |args| args[0] }
+  #
+  #     def mymethod(name, options)
+  #     end
+  #
+  #   end
+  #
+  def probe(method, options = {})
+    (@probes ||= []) << Probe.new(method, self, options)
+    INSTRUMENTED_CLASSES[self] = @probes
+  end
+
+  def self.probes
+    @probes
+  end
+
+  def self.probe_names
+    probe_names = []
+    each_probe { |probe| probe_names << "#{probe.klass}.#{probe.method}" }
+    probe_names
+  end
+
+  def self.enable_probes
+    each_probe { |probe| probe.enable }
+  end
+
+  def self.disable_probes
+    each_probe { |probe| probe.disable }
+  end
+
+  def self.clear_probes
+    INSTRUMENTED_CLASSES.clear
+    nil # do not leak our probes to the exterior world
+  end
+
+  def self.each_probe
+    INSTRUMENTED_CLASSES.each_key do |klass|
+      klass.probes.each { |probe| yield probe }
+    end
+    nil # do not leak our probes to the exterior world
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instrumentation/listener.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instrumentation/listener.rb
new file mode 100644
index 0000000..cb25b29
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instrumentation/listener.rb
@@ -0,0 +1,72 @@
+require 'puppet/indirector'
+require 'puppet/util/instrumentation'
+require 'puppet/util/instrumentation/data'
+
+class Puppet::Util::Instrumentation::Listener
+  include Puppet::Util
+  include Puppet::Util::Warnings
+  extend Puppet::Indirector
+
+  indirects :instrumentation_listener, :terminus_class => :local
+
+  attr_reader :pattern, :listener
+  attr_accessor :enabled
+
+  def initialize(listener, pattern = nil, enabled = false)
+    @pattern = pattern.is_a?(Symbol) ? pattern.to_s : pattern
+    raise "Listener isn't a correct listener (it doesn't provide the notify method)" unless listener.respond_to?(:notify)
+    @listener = listener
+    @enabled = enabled
+  end
+
+  def notify(label, event, data)
+    listener.notify(label, event, data)
+  rescue => e
+    warnonce("Error during instrumentation notification: #{e}")
+  end
+
+  def listen_to?(label)
+    enabled? and (!@pattern || @pattern === label.to_s)
+  end
+
+  def enabled?
+    !!@enabled
+  end
+
+  def name
+    @listener.name.to_s
+  end
+
+  def data
+    { :data => @listener.data }
+  end
+
+  def to_data_hash
+    {
+      :name => name,
+      :pattern => pattern,
+      :enabled => enabled?
+    }
+  end
+
+  def to_pson_data_hash
+    {
+      :document_type => "Puppet::Util::Instrumentation::Listener",
+      :data => to_data_hash,
+    }
+  end
+
+  def to_pson(*args)
+    to_pson_data_hash.to_pson(*args)
+  end
+
+  def self.from_data_hash(data)
+    result = Puppet::Util::Instrumentation[data["name"]]
+    self.new(result.listener, result.pattern, data["enabled"])
+  end
+
+  def self.from_pson(data)
+    Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
+    self.from_data_hash(data)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instrumentation/listeners/log.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instrumentation/listeners/log.rb
new file mode 100644
index 0000000..72797d6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instrumentation/listeners/log.rb
@@ -0,0 +1,23 @@
+# This is an example instrumentation listener that stores the last
+# 20 instrumented probe run time.
+Puppet::Util::Instrumentation.new_listener(:log) do
+
+  SIZE = 20
+
+  attr_accessor :last_logs
+
+  def initialize
+    @last_logs = {}
+  end
+
+  def notify(label, event, data)
+    return if event == :start
+    log_line = "#{label} took #{data[:finished] - data[:started]}"
+    (@last_logs[label] ||= []) << log_line
+    @last_logs[label].shift if @last_logs[label].length > SIZE
+  end
+
+  def data
+    @last_logs.dup
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instrumentation/listeners/performance.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instrumentation/listeners/performance.rb
new file mode 100644
index 0000000..5bf3e2c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/instrumentation/listeners/performance.rb
@@ -0,0 +1,24 @@
+Puppet::Util::Instrumentation.new_listener(:performance) do
+
+  attr_reader :samples
+
+  def initialize
+    @samples = {}
+  end
+
+  def notify(label, event, data)
+    return if event == :start
+
+    duration = data[:finished] - data[:started]
+    @samples[label] ||= { :count => 0, :max => 0, :min => nil, :sum => 0, :average => 0 }
+    @samples[label][:count] += 1
+    @samples[label][:sum] += duration
+    @samples[label][:max] = [ @samples[label][:max], duration ].max
+    @samples[label][:min] = [ @samples[label][:min], duration ].reject { |val| val.nil? }.min
+    @samples[label][:average] = @samples[label][:sum] / @samples[label][:count]
+  end
+
+  def data
+    @samples.dup
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/json_lockfile.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/json_lockfile.rb
new file mode 100644
index 0000000..df67b17
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/json_lockfile.rb
@@ -0,0 +1,44 @@
+require 'puppet/util/lockfile'
+
+# This class provides a simple API for managing a lock file
+# whose contents are a serialized JSON object.  In addition
+# to querying the basic state (#locked?) of the lock, managing
+# the lock (#lock, #unlock), the contents can be retrieved at
+# any time while the lock is held (#lock_data).  This can be
+# used to store structured data (state messages, etc.) about
+# the lock.
+#
+# @see Puppet::Util::Lockfile
+class Puppet::Util::JsonLockfile < Puppet::Util::Lockfile
+  # Lock the lockfile.  You may optionally pass a data object, which will be
+  # retrievable for the duration of time during which the file is locked.
+  #
+  # @param [Hash] lock_data an optional Hash of data to associate with the lock.
+  #   This may be used to store pids, descriptive messages, etc.  The
+  #   data may be retrieved at any time while the lock is held by
+  #   calling the #lock_data method. <b>NOTE</b> that the JSON serialization
+  #   does NOT support Symbol objects--if you pass them in, they will be
+  #   serialized as Strings, so you should plan accordingly.
+  # @return [boolean] true if lock is successfully acquired, false otherwise.
+  def lock(lock_data = nil)
+    return false if locked?
+
+    super(lock_data.to_pson)
+  end
+
+  # Retrieve the (optional) lock data that was specified at the time the file
+  #  was locked.
+  # @return [Object] the data object.  Remember that the serialization does not
+  #  support Symbol objects, so if your data Object originally contained symbols,
+  #  they will be converted to Strings.
+  def lock_data
+    return nil unless file_locked?
+    file_contents = super
+    return nil if file_contents.nil? or file_contents.empty?
+    PSON.parse(file_contents)
+  rescue PSON::ParserError => e
+    Puppet.warning "Unable to read lockfile data from #{@file_path}: not in PSON"
+    nil
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/ldap.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/ldap.rb
new file mode 100644
index 0000000..71d6a17
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/ldap.rb
@@ -0,0 +1,2 @@
+module Puppet::Util::Ldap
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/ldap/connection.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/ldap/connection.rb
new file mode 100644
index 0000000..c511092
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/ldap/connection.rb
@@ -0,0 +1,71 @@
+require 'puppet/util/ldap'
+require 'puppet/util/methodhelper'
+
+class Puppet::Util::Ldap::Connection
+  include Puppet::Util::MethodHelper
+
+  attr_accessor :host, :port, :user, :password, :reset, :ssl
+
+  attr_reader :connection
+
+  # Return a default connection, using our default settings.
+  def self.instance
+    ssl = if Puppet[:ldaptls]
+      :tls
+        elsif Puppet[:ldapssl]
+          true
+        else
+          false
+        end
+
+    options = {}
+    options[:ssl] = ssl
+    if user = Puppet.settings[:ldapuser] and user != ""
+      options[:user] = user
+      if pass = Puppet.settings[:ldappassword] and pass != ""
+        options[:password] = pass
+      end
+    end
+
+    new(Puppet[:ldapserver], Puppet[:ldapport], options)
+  end
+
+  def close
+    connection.unbind if connection.bound?
+  end
+
+  def initialize(host, port, options = {})
+    raise Puppet::Error, "Could not set up LDAP Connection: Missing ruby/ldap libraries" unless Puppet.features.ldap?
+
+    @host, @port = host, port
+
+    set_options(options)
+  end
+
+  # Create a per-connection unique name.
+  def name
+    [host, port, user, password, ssl].collect { |p| p.to_s }.join("/")
+  end
+
+  # Should we reset the connection?
+  def reset?
+    reset
+  end
+
+  # Start our ldap connection.
+  def start
+      case ssl
+      when :tls
+        @connection = LDAP::SSLConn.new(host, port, true)
+      when true
+        @connection = LDAP::SSLConn.new(host, port)
+      else
+        @connection = LDAP::Conn.new(host, port)
+      end
+      @connection.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
+      @connection.set_option(LDAP::LDAP_OPT_REFERRALS, LDAP::LDAP_OPT_ON)
+      @connection.simple_bind(user, password)
+  rescue => detail
+      raise Puppet::Error, "Could not connect to LDAP: #{detail}", detail.backtrace
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/ldap/generator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/ldap/generator.rb
new file mode 100644
index 0000000..608d729
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/ldap/generator.rb
@@ -0,0 +1,42 @@
+require 'puppet/util/ldap'
+
+class Puppet::Util::Ldap::Generator
+  # Declare the attribute we'll use to generate the value.
+  def from(source)
+    @source = source
+    self
+  end
+
+  # Actually do the generation.
+  def generate(value = nil)
+    if value.nil?
+      @generator.call
+    else
+      @generator.call(value)
+    end
+  end
+
+  # Initialize our generator with the name of the parameter
+  # being generated.
+  def initialize(name)
+    @name = name
+  end
+
+  def name
+    @name.to_s
+  end
+
+  def source
+    if @source
+      @source.to_s
+    else
+      nil
+    end
+  end
+
+  # Provide the code that does the generation.
+  def with(&block)
+    @generator = block
+    self
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/ldap/manager.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/ldap/manager.rb
new file mode 100644
index 0000000..9df1849
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/ldap/manager.rb
@@ -0,0 +1,278 @@
+require 'puppet/util/ldap'
+require 'puppet/util/ldap/connection'
+require 'puppet/util/ldap/generator'
+
+# The configuration class for LDAP providers, plus
+# connection handling for actually interacting with ldap.
+class Puppet::Util::Ldap::Manager
+  attr_reader :objectclasses, :puppet2ldap, :location, :rdn
+
+  # A null-op that just returns the config.
+  def and
+    self
+  end
+
+  # Set the offset from the search base and return the config.
+  def at(location)
+    @location = location
+    self
+  end
+
+  # The basic search base.
+  def base
+    [location, Puppet[:ldapbase]].join(",")
+  end
+
+  # Convert the name to a dn, then pass the args along to
+  # our connection.
+  def create(name, attributes)
+    attributes = attributes.dup
+
+    # Add the objectclasses
+    attributes["objectClass"] = objectclasses.collect { |o| o.to_s }
+    attributes["objectClass"] << "top" unless attributes["objectClass"].include?("top")
+
+    attributes[rdn.to_s] = [name]
+
+    # Generate any new values we might need.
+    generate(attributes)
+
+    # And create our resource.
+    connect { |conn| conn.add dn(name), attributes }
+  end
+
+  # Open, yield, and close the connection.  Cannot be left
+  # open, at this point.
+  def connect
+    raise ArgumentError, "You must pass a block to #connect" unless block_given?
+
+    unless @connection
+      if Puppet[:ldaptls]
+        ssl = :tls
+      elsif Puppet[:ldapssl]
+        ssl = true
+      else
+        ssl = false
+      end
+      options = {:ssl => ssl}
+      if user = Puppet[:ldapuser] and user != ""
+        options[:user] = user
+      end
+      if password = Puppet[:ldappassword] and password != ""
+        options[:password] = password
+      end
+      @connection = Puppet::Util::Ldap::Connection.new(Puppet[:ldapserver], Puppet[:ldapport], options)
+    end
+    @connection.start
+    begin
+      yield @connection.connection
+    ensure
+      @connection.close
+    end
+    nil
+  end
+
+  # Convert the name to a dn, then pass the args along to
+  # our connection.
+  def delete(name)
+    connect { |connection| connection.delete dn(name) }
+  end
+
+  # Calculate the dn for a given resource.
+  def dn(name)
+    ["#{rdn}=#{name}", base].join(",")
+  end
+
+  # Convert an ldap-style entry hash to a provider-style hash.
+  def entry2provider(entry)
+    raise ArgumentError, "Could not get dn from ldap entry" unless entry["dn"]
+
+    # DN is always a single-entry array.  Strip off the bits before the
+    # first comma, then the bits after the remaining equal sign.  This is the
+    # name.
+    name = entry["dn"].dup.pop.split(",").shift.split("=").pop
+
+    result = {:name => name}
+
+    @ldap2puppet.each do |ldap, puppet|
+      result[puppet] = entry[ldap.to_s] || :absent
+    end
+
+    result
+  end
+
+  # Create our normal search filter.
+  def filter
+    return(objectclasses.length == 1 ? "objectclass=#{objectclasses[0]}" : "(&(objectclass=" + objectclasses.join(")(objectclass=") + "))")
+  end
+
+  # Find the associated entry for a resource.  Returns a hash, minus
+  # 'dn', or nil if the entry cannot be found.
+  def find(name)
+    connect do |conn|
+      begin
+        conn.search2(dn(name), 0, "objectclass=*") do |result|
+          # Convert to puppet-appropriate attributes
+          return entry2provider(result)
+        end
+      rescue
+        return nil
+      end
+    end
+  end
+
+  # Declare a new attribute generator.
+  def generates(parameter)
+    @generators << Puppet::Util::Ldap::Generator.new(parameter)
+    @generators[-1]
+  end
+
+  # Generate any extra values we need to make the ldap entry work.
+  def generate(values)
+    return unless @generators.length > 0
+
+    @generators.each do |generator|
+      # Don't override any values that might exist.
+      next if values[generator.name]
+
+      if generator.source
+        unless value = values[generator.source]
+          raise ArgumentError, "#{generator.source} must be defined to generate #{generator.name}"
+        end
+        result = generator.generate(value)
+      else
+        result = generator.generate
+      end
+
+      result = [result] unless result.is_a?(Array)
+      result = result.collect { |r| r.to_s }
+
+      values[generator.name] = result
+    end
+  end
+
+  def initialize
+    @rdn = :cn
+    @generators = []
+  end
+
+  # Specify what classes this provider models.
+  def manages(*classes)
+    @objectclasses = classes
+    self
+  end
+
+  # Specify the attribute map.  Assumes the keys are the puppet
+  # attributes, and the values are the ldap attributes, and creates a map
+  # for each direction.
+  def maps(attributes)
+    # The map with the puppet attributes as the keys
+    @puppet2ldap = attributes
+
+    # and the ldap attributes as the keys.
+    @ldap2puppet = attributes.inject({}) { |map, ary| map[ary[1]] = ary[0]; map }
+
+    self
+  end
+
+  # Return the ldap name for a puppet attribute.
+  def ldap_name(attribute)
+    @puppet2ldap[attribute].to_s
+  end
+
+  # Convert the name to a dn, then pass the args along to
+  # our connection.
+  def modify(name, mods)
+    connect { |connection| connection.modify dn(name), mods }
+  end
+
+  # Specify the rdn that we use to build up our dn.
+  def named_by(attribute)
+    @rdn = attribute
+    self
+  end
+
+  # Return the puppet name for an ldap attribute.
+  def puppet_name(attribute)
+    @ldap2puppet[attribute]
+  end
+
+  # Search for all entries at our base.  A potentially expensive search.
+  def search(sfilter = nil)
+    sfilter ||= filter
+
+    result = []
+    connect do |conn|
+      conn.search2(base, 1, sfilter) do |entry|
+        result << entry2provider(entry)
+      end
+    end
+    return(result.empty? ? nil : result)
+  end
+
+  # Update the ldap entry with the desired state.
+  def update(name, is, should)
+    if should[:ensure] == :absent
+      Puppet.info "Removing #{dn(name)} from ldap"
+      delete(name)
+      return
+    end
+
+    # We're creating a new entry
+    if is.empty? or is[:ensure] == :absent
+      Puppet.info "Creating #{dn(name)} in ldap"
+      # Remove any :absent params and :ensure, then convert the names to ldap names.
+      attrs = ldap_convert(should)
+      create(name, attrs)
+      return
+    end
+
+    # We're modifying an existing entry.  Yuck.
+
+    mods = []
+    # For each attribute we're deleting that is present, create a
+    # modify instance for deletion.
+    [is.keys, should.keys].flatten.uniq.each do |property|
+      # They're equal, so do nothing.
+      next if is[property] == should[property]
+
+      attributes = ldap_convert(should)
+
+      prop_name = ldap_name(property).to_s
+
+      # We're creating it.
+      if is[property] == :absent or is[property].nil?
+        mods << LDAP::Mod.new(LDAP::LDAP_MOD_ADD, prop_name, attributes[prop_name])
+        next
+      end
+
+      # We're deleting it
+      if should[property] == :absent or should[property].nil?
+        mods << LDAP::Mod.new(LDAP::LDAP_MOD_DELETE, prop_name, [])
+        next
+      end
+
+      # We're replacing an existing value
+      mods << LDAP::Mod.new(LDAP::LDAP_MOD_REPLACE, prop_name, attributes[prop_name])
+    end
+
+    modify(name, mods)
+  end
+
+  # Is this a complete ldap configuration?
+  def valid?
+    location and objectclasses and ! objectclasses.empty? and puppet2ldap
+  end
+
+  private
+
+  # Convert a hash of attributes to ldap-like forms.  This mostly means
+  # getting rid of :ensure and making sure everything's an array of strings.
+  def ldap_convert(attributes)
+    attributes.reject { |param, value| value == :absent or param == :ensure }.inject({}) do |result, ary|
+      value = (ary[1].is_a?(Array) ? ary[1] : [ary[1]]).collect { |v| v.to_s }
+      result[ldap_name(ary[0])] = value
+      result
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/libuser.conf b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/libuser.conf
new file mode 100644
index 0000000..4b1cb85
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/libuser.conf
@@ -0,0 +1,15 @@
+[import]
+login_defs = /etc/login.defs
+default_useradd = /etc/default/useradd
+
+[defaults]
+crypt_style = md5
+modules = files shadow
+create_modules = files shadow
+
+[userdefaults]
+LU_USERNAME = %n
+LU_GIDNUMBER = %u
+
+[groupdefaults]
+LU_GROUPNAME = %n
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/libuser.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/libuser.rb
new file mode 100644
index 0000000..e3940ca
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/libuser.rb
@@ -0,0 +1,12 @@
+module Puppet::Util::Libuser
+   def self.getconf
+     File.expand_path("../libuser.conf", __FILE__)
+   end
+
+   def self.getenv
+     newenv = {}
+     newenv['LIBUSER_CONF'] = getconf
+     newenv
+   end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/limits.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/limits.rb
new file mode 100644
index 0000000..e2f805b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/limits.rb
@@ -0,0 +1,12 @@
+require 'puppet/util'
+
+module Puppet::Util::Limits
+  # @api private
+  def setpriority(priority)
+    return unless priority
+
+    Process.setpriority(0, Process.pid, priority)
+  rescue Errno::EACCES, NotImplementedError
+    Puppet.warning("Failed to set process priority to '#{priority}'")
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/lockfile.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/lockfile.rb
new file mode 100644
index 0000000..21a1c2d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/lockfile.rb
@@ -0,0 +1,66 @@
+# This class provides a simple API for managing a lock file
+# whose contents are an (optional) String.  In addition
+# to querying the basic state (#locked?) of the lock, managing
+# the lock (#lock, #unlock), the contents can be retrieved at
+# any time while the lock is held (#lock_data).  This can be
+# used to store pids, messages, etc.
+#
+# @see Puppet::Util::JsonLockfile
+class Puppet::Util::Lockfile
+  attr_reader :file_path
+
+  def initialize(file_path)
+    @file_path = file_path
+  end
+
+  # Lock the lockfile.  You may optionally pass a data object, which will be
+  # retrievable for the duration of time during which the file is locked.
+  #
+  # @param [String] lock_data an optional String data object to associate
+  #   with the lock.  This may be used to store pids, descriptive messages,
+  #   etc.  The data may be retrieved at any time while the lock is held by
+  #   calling the #lock_data method.
+
+  # @return [boolean] true if lock is successfully acquired, false otherwise.
+  def lock(lock_data = nil)
+    begin
+      Puppet::FileSystem.exclusive_create(@file_path, nil) do |fd|
+        fd.print(lock_data)
+      end
+      true
+    rescue Errno::EEXIST
+      false
+    end
+  end
+
+  def unlock
+    if locked?
+      Puppet::FileSystem.unlink(@file_path)
+      true
+    else
+      false
+    end
+  end
+
+  def locked?
+    # delegate logic to a more explicit private method
+    file_locked?
+  end
+
+  # Retrieve the (optional) lock data that was specified at the time the file
+  #  was locked.
+  # @return [String] the data object.
+  def lock_data
+    return File.read(@file_path) if file_locked?
+  end
+
+  # Private, internal utility method for encapsulating the logic about
+  #  whether or not the file is locked.  This method can be called
+  #  by other methods in this class without as much risk of accidentally
+  #  being overridden by child classes.
+  # @return [boolean] true if the file is locked, false if it is not.
+  def file_locked?
+    Puppet::FileSystem.exist? @file_path
+  end
+  private :file_locked?
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/log.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/log.rb
new file mode 100644
index 0000000..c66bd47
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/log.rb
@@ -0,0 +1,385 @@
+require 'puppet/util/tagging'
+require 'puppet/util/classgen'
+require 'puppet/network/format_support'
+
+# Pass feedback to the user.  Log levels are modeled after syslog's, and it is
+# expected that that will be the most common log destination.  Supports
+# multiple destinations, one of which is a remote server.
+class Puppet::Util::Log
+  include Puppet::Util
+  extend Puppet::Util::ClassGen
+  include Puppet::Util::Tagging
+  include Puppet::Network::FormatSupport
+
+  @levels = [:debug,:info,:notice,:warning,:err,:alert,:emerg,:crit]
+  @loglevel = 2
+
+  @desttypes = {}
+
+  # Create a new destination type.
+  def self.newdesttype(name, options = {}, &block)
+
+    dest = genclass(
+      name,
+      :parent     => Puppet::Util::Log::Destination,
+      :prefix     => "Dest",
+      :block      => block,
+      :hash       => @desttypes,
+      :attributes => options
+    )
+    dest.match(dest.name)
+
+    dest
+  end
+
+  require 'puppet/util/log/destination'
+  require 'puppet/util/log/destinations'
+
+  @destinations = {}
+
+  @queued = []
+
+  class << self
+    include Puppet::Util
+    include Puppet::Util::ClassGen
+
+    attr_reader :desttypes
+  end
+
+  # Reset log to basics.  Basically just flushes and closes files and
+  # undefs other objects.
+  def Log.close(destination)
+    if @destinations.include?(destination)
+      @destinations[destination].flush if @destinations[destination].respond_to?(:flush)
+      @destinations[destination].close if @destinations[destination].respond_to?(:close)
+      @destinations.delete(destination)
+    end
+  end
+
+  def self.close_all
+    destinations.keys.each { |dest|
+      close(dest)
+    }
+    raise Puppet::DevError.new("Log.close_all failed to close #{@destinations.keys.inspect}") if !@destinations.empty?
+  end
+
+  # Flush any log destinations that support such operations.
+  def Log.flush
+    @destinations.each { |type, dest|
+      dest.flush if dest.respond_to?(:flush)
+    }
+  end
+
+  def Log.autoflush=(v)
+    @destinations.each do |type, dest|
+      dest.autoflush = v if dest.respond_to?(:autoflush=)
+    end
+  end
+
+  # Create a new log message.  The primary role of this method is to
+  # avoid creating log messages below the loglevel.
+  def Log.create(hash)
+    raise Puppet::DevError, "Logs require a level" unless hash.include?(:level)
+    raise Puppet::DevError, "Invalid log level #{hash[:level]}" unless @levels.index(hash[:level])
+    @levels.index(hash[:level]) >= @loglevel ? Puppet::Util::Log.new(hash) : nil
+  end
+
+  def Log.destinations
+    @destinations
+  end
+
+  # Yield each valid level in turn
+  def Log.eachlevel
+    @levels.each { |level| yield level }
+  end
+
+  # Return the current log level.
+  def Log.level
+    @levels[@loglevel]
+  end
+
+  # Set the current log level.
+  def Log.level=(level)
+    level = level.intern unless level.is_a?(Symbol)
+
+    raise Puppet::DevError, "Invalid loglevel #{level}" unless @levels.include?(level)
+
+    @loglevel = @levels.index(level)
+  end
+
+  def Log.levels
+    @levels.dup
+  end
+
+  # Create a new log destination.
+  def Log.newdestination(dest)
+    # Each destination can only occur once.
+    if @destinations.find { |name, obj| obj.name == dest }
+      return
+    end
+
+    name, type = @desttypes.find do |name, klass|
+      klass.match?(dest)
+    end
+
+    if type.respond_to?(:suitable?) and not type.suitable?(dest)
+      return
+    end
+
+    raise Puppet::DevError, "Unknown destination type #{dest}" unless type
+
+    begin
+      if type.instance_method(:initialize).arity == 1
+        @destinations[dest] = type.new(dest)
+      else
+        @destinations[dest] = type.new
+      end
+      flushqueue
+      @destinations[dest]
+    rescue => detail
+      Puppet.log_exception(detail)
+
+      # If this was our only destination, then add the console back in.
+      newdestination(:console) if @destinations.empty? and (dest != :console and dest != "console")
+    end
+  end
+
+  def Log.with_destination(destination, &block)
+    if @destinations.include?(destination)
+      yield
+    else
+      newdestination(destination)
+      begin
+        yield
+      ensure
+        close(destination)
+      end
+    end
+  end
+
+  # Route the actual message. FIXME There are lots of things this method
+  # should do, like caching and a bit more.  It's worth noting that there's
+  # a potential for a loop here, if the machine somehow gets the destination set as
+  # itself.
+  def Log.newmessage(msg)
+    return if @levels.index(msg.level) < @loglevel
+
+    queuemessage(msg) if @destinations.length == 0
+
+    @destinations.each do |name, dest|
+      dest.handle(msg)
+    end
+  end
+
+  def Log.queuemessage(msg)
+    @queued.push(msg)
+  end
+
+  def Log.flushqueue
+    return unless @destinations.size >= 1
+    @queued.each do |msg|
+      Log.newmessage(msg)
+    end
+    @queued.clear
+  end
+
+  # Flush the logging queue.  If there are no destinations available,
+  #  adds in a console logger before flushing the queue.
+  # This is mainly intended to be used as a last-resort attempt
+  #  to ensure that logging messages are not thrown away before
+  #  the program is about to exit--most likely in a horrific
+  #  error scenario.
+  # @return nil
+  def Log.force_flushqueue()
+    if (@destinations.empty? and !(@queued.empty?))
+      newdestination(:console)
+    end
+    flushqueue
+  end
+
+  def Log.sendlevel?(level)
+    @levels.index(level) >= @loglevel
+  end
+
+  # Reopen all of our logs.
+  def Log.reopen
+    Puppet.notice "Reopening log files"
+    types = @destinations.keys
+    @destinations.each { |type, dest|
+      dest.close if dest.respond_to?(:close)
+    }
+    @destinations.clear
+    # We need to make sure we always end up with some kind of destination
+    begin
+      types.each { |type|
+        Log.newdestination(type)
+      }
+    rescue => detail
+      if @destinations.empty?
+        Log.setup_default
+        Puppet.err detail.to_s
+      end
+    end
+  end
+
+  def self.setup_default
+    Log.newdestination(
+      (Puppet.features.syslog?   ? :syslog   :
+      (Puppet.features.eventlog? ? :eventlog : Puppet[:puppetdlog])))
+  end
+
+  # Is the passed level a valid log level?
+  def self.validlevel?(level)
+    @levels.include?(level)
+  end
+
+  def self.from_data_hash(data)
+    obj = allocate
+    obj.initialize_from_hash(data)
+    obj
+  end
+
+  def self.from_pson(data)
+    Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
+    self.from_data_hash(data)
+  end
+
+  attr_accessor :time, :remote, :file, :line, :pos, :source, :issue_code, :environment, :node, :backtrace
+  attr_reader :level, :message
+
+  def initialize(args)
+    self.level = args[:level]
+    self.message = args[:message]
+    self.source = args[:source] || "Puppet"
+
+    @time = Time.now
+
+    if tags = args[:tags]
+      tags.each { |t| self.tag(t) }
+    end
+
+    # Don't add these unless defined (preserve 3.x API as much as possible)
+    [:file, :line, :pos, :issue_code, :environment, :node, :backtrace].each do |attr|
+      next unless value = args[attr]
+      send(attr.to_s + '=', value)
+    end
+
+    Log.newmessage(self)
+  end
+
+  def initialize_from_hash(data)
+    @level = data['level'].intern
+    @message = data['message']
+    @source = data['source']
+    @tags = Puppet::Util::TagSet.new(data['tags'])
+    @time = data['time']
+    if @time.is_a? String
+      @time = Time.parse(@time)
+    end
+    # Don't add these unless defined (preserve 3.x API as much as possible)
+    %w(file line pos issue_code environment node backtrace).each do |name|
+      next unless value = data[name]
+      send(name + '=', value)
+    end
+  end
+
+  def to_hash
+    self.to_data_hash
+  end
+
+  def to_data_hash
+    {
+      'level' => @level,
+      'message' => to_s,
+      'source' => @source,
+      'tags' => @tags.to_a,
+      'time' => @time.iso8601(9),
+      'file' => @file,
+      'line' => @line,
+    }
+  end
+
+  def to_structured_hash
+    hash = {
+      'level' => @level,
+      'message' => @message,
+      'source' => @source,
+      'tags' => @tags.to_a,
+      'time' => @time.iso8601(9),
+    }
+    %w(file line pos issue_code environment node backtrace).each do |name|
+      attr_name = "@#{name}"
+      hash[name] = instance_variable_get(attr_name) if instance_variable_defined?(attr_name)
+    end
+    hash
+  end
+
+  def to_pson(*args)
+    to_data_hash.to_pson(*args)
+  end
+
+  def message=(msg)
+    raise ArgumentError, "Puppet::Util::Log requires a message" unless msg
+    @message = msg.to_s
+  end
+
+  def level=(level)
+    raise ArgumentError, "Puppet::Util::Log requires a log level" unless level
+    raise ArgumentError, "Puppet::Util::Log requires a symbol or string" unless level.respond_to? "to_sym"
+    @level = level.to_sym
+    raise ArgumentError, "Invalid log level #{@level}" unless self.class.validlevel?(@level)
+
+    # Tag myself with my log level
+    tag(level)
+  end
+
+  # If they pass a source in to us, we make sure it is a string, and
+  # we retrieve any tags we can.
+  def source=(source)
+    if defined?(Puppet::Type) && source.is_a?(Puppet::Type)
+      @source = source.path
+      source.tags.each { |t| tag(t) }
+      self.file = source.file
+      self.line = source.line
+    else
+      @source = source.to_s
+    end
+  end
+
+  def to_report
+    "#{time} #{source} (#{level}): #{to_s}"
+  end
+
+  def to_s
+    msg = message
+
+    # Issue based messages do not have details in the message. It
+    # must be appended here
+    unless issue_code.nil?
+      msg = "Could not parse for environment #{environment}: #{msg}" unless environment.nil?
+      if file && line && pos
+        msg = "#{msg} at #{file}:#{line}:#{pos}"
+      elsif file and line
+        msg = "#{msg}  at #{file}:#{line}"
+      elsif line && pos
+        msg = "#{msg}  at line #{line}:#{pos}"
+      elsif line
+        msg = "#{msg}  at line #{line}"
+      elsif file
+        msg = "#{msg}  in #{file}"
+      end
+      msg = "#{msg} on node #{node}" unless node.nil?
+      if @backtrace.is_a?(Array)
+        msg += "\n"
+        msg += @backtrace.join("\n")
+      end
+    end
+    msg
+  end
+
+end
+
+# This is for backward compatibility from when we changed the constant to Puppet::Util::Log
+# because the reports include the constant name.  Apparently the alias was created in
+# March 2007, should could probably be removed soon.
+Puppet::Log = Puppet::Util::Log
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/log/destination.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/log/destination.rb
new file mode 100644
index 0000000..11ebd7d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/log/destination.rb
@@ -0,0 +1,49 @@
+# A type of log destination.
+class Puppet::Util::Log::Destination
+  class << self
+    attr_accessor :name
+  end
+
+  def self.initvars
+    @matches = []
+  end
+
+  # Mark the things we're supposed to match.
+  def self.match(obj)
+    @matches ||= []
+    @matches << obj
+  end
+
+  # See whether we match a given thing.
+  def self.match?(obj)
+    # Convert single-word strings into symbols like :console and :syslog
+    if obj.is_a? String and obj =~ /^\w+$/
+      obj = obj.downcase.intern
+    end
+
+    @matches.each do |thing|
+      # Search for direct matches or class matches
+      return true if thing === obj or thing == obj.class.to_s
+    end
+    false
+  end
+
+  def name
+    if defined?(@name)
+      return @name
+    else
+      return self.class.name
+    end
+  end
+
+  # Set how to handle a message.
+  def self.sethandler(&block)
+    define_method(:handle, &block)
+  end
+
+  # Mark how to initialize our object.
+  def self.setinit(&block)
+    define_method(:initialize, &block)
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/log/destinations.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/log/destinations.rb
new file mode 100644
index 0000000..fb8b6aa
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/log/destinations.rb
@@ -0,0 +1,253 @@
+Puppet::Util::Log.newdesttype :syslog do
+  def self.suitable?(obj)
+    Puppet.features.syslog?
+  end
+
+  def close
+    Syslog.close
+  end
+
+  def initialize
+    Syslog.close if Syslog.opened?
+    name = "puppet-#{Puppet.run_mode.name}"
+
+    options = Syslog::LOG_PID | Syslog::LOG_NDELAY
+
+    # XXX This should really be configurable.
+    str = Puppet[:syslogfacility]
+    begin
+      facility = Syslog.const_get("LOG_#{str.upcase}")
+    rescue NameError
+      raise Puppet::Error, "Invalid syslog facility #{str}", $!.backtrace
+    end
+
+    @syslog = Syslog.open(name, options, facility)
+  end
+
+  def handle(msg)
+    # XXX Syslog currently has a bug that makes it so you
+    # cannot log a message with a '%' in it.  So, we get rid
+    # of them.
+    if msg.source == "Puppet"
+      msg.to_s.split("\n").each do |line|
+        @syslog.send(msg.level, line.gsub("%", '%%'))
+      end
+    else
+      msg.to_s.split("\n").each do |line|
+        @syslog.send(msg.level, "(%s) %s" % [msg.source.to_s.gsub("%", ""),
+            line.gsub("%", '%%')
+          ]
+        )
+      end
+    end
+  end
+end
+
+Puppet::Util::Log.newdesttype :file do
+  require 'fileutils'
+
+  def self.match?(obj)
+    Puppet::Util.absolute_path?(obj)
+  end
+
+  def close
+    if defined?(@file)
+      @file.close
+      @file = nil
+    end
+  end
+
+  def flush
+    @file.flush if defined?(@file)
+  end
+
+  attr_accessor :autoflush
+
+  def initialize(path)
+    @name = path
+    @json = path.end_with?('.json') ? 1 : 0
+
+    # first make sure the directory exists
+    # We can't just use 'Config.use' here, because they've
+    # specified a "special" destination.
+    unless Puppet::FileSystem.exist?(Puppet::FileSystem.dir(path))
+      FileUtils.mkdir_p(File.dirname(path), :mode => 0755)
+      Puppet.info "Creating log directory #{File.dirname(path)}"
+    end
+
+    # create the log file, if it doesn't already exist
+    need_array_start = false
+    if @json == 1
+      need_array_start = true
+      if File.exists?(path)
+        sz = File.size(path)
+        need_array_start = sz == 0
+
+        # Assume that entries have been written and that a comma
+        # is needed before next entry
+        @json = 2 if sz > 2
+      end
+    end
+
+    file = File.open(path,  File::WRONLY|File::CREAT|File::APPEND)
+    file.puts('[') if need_array_start
+
+    # Give ownership to the user and group puppet will run as
+    begin
+      FileUtils.chown(Puppet[:user], Puppet[:group], path) unless Puppet::Util::Platform.windows?
+    rescue ArgumentError, Errno::EPERM
+      Puppet.err "Unable to set ownership of log file"
+    end
+
+    @file = file
+
+    @autoflush = Puppet[:autoflush]
+  end
+
+  def handle(msg)
+    if @json > 0
+      @json > 1 ? @file.puts(',') : @json = 2
+      JSON.dump(msg.to_structured_hash, @file)
+    else
+      @file.puts("#{msg.time} #{msg.source} (#{msg.level}): #{msg}")
+    end
+
+    @file.flush if @autoflush
+  end
+end
+
+Puppet::Util::Log.newdesttype :logstash_event do
+  require 'time'
+
+  def format(msg)
+    # logstash_event format is documented at
+    # https://logstash.jira.com/browse/LOGSTASH-675
+
+    data = {}
+    data = msg.to_hash
+    data['version'] = 1
+    data['@timestamp'] = data['time']
+    data.delete('time')
+
+    data
+  end
+
+  def handle(msg)
+    message = format(msg)
+    $stdout.puts message.to_pson
+  end
+end
+
+Puppet::Util::Log.newdesttype :console do
+  require 'puppet/util/colors'
+  include Puppet::Util::Colors
+
+  def initialize
+    # Flush output immediately.
+    $stderr.sync = true
+    $stdout.sync = true
+  end
+
+  def handle(msg)
+    levels = {
+      :emerg   => { :name => 'Emergency', :color => :hred,  :stream => $stderr },
+      :alert   => { :name => 'Alert',     :color => :hred,  :stream => $stderr },
+      :crit    => { :name => 'Critical',  :color => :hred,  :stream => $stderr },
+      :err     => { :name => 'Error',     :color => :hred,  :stream => $stderr },
+      :warning => { :name => 'Warning',   :color => :hred,  :stream => $stderr },
+
+      :notice  => { :name => 'Notice',    :color => :reset, :stream => $stdout },
+      :info    => { :name => 'Info',      :color => :green, :stream => $stdout },
+      :debug   => { :name => 'Debug',     :color => :cyan,  :stream => $stdout },
+    }
+
+    str = msg.respond_to?(:multiline) ? msg.multiline : msg.to_s
+    str = msg.source == "Puppet" ? str : "#{msg.source}: #{str}"
+
+    level = levels[msg.level]
+    level[:stream].puts colorize(level[:color], "#{level[:name]}: #{str}")
+  end
+end
+
+# Log to a transaction report.
+Puppet::Util::Log.newdesttype :report do
+  attr_reader :report
+
+  match "Puppet::Transaction::Report"
+
+  def initialize(report)
+    @report = report
+  end
+
+  def handle(msg)
+    @report << msg
+  end
+end
+
+# Log to an array, just for testing.
+module Puppet::Test
+  class LogCollector
+    def initialize(logs)
+      @logs = logs
+    end
+
+    def <<(value)
+      @logs << value
+    end
+  end
+end
+
+Puppet::Util::Log.newdesttype :array do
+  match "Puppet::Test::LogCollector"
+
+  def initialize(messages)
+    @messages = messages
+  end
+
+  def handle(msg)
+    @messages << msg
+  end
+end
+
+Puppet::Util::Log.newdesttype :eventlog do
+  Puppet::Util::Log::DestEventlog::EVENTLOG_ERROR_TYPE       = 0x0001
+  Puppet::Util::Log::DestEventlog::EVENTLOG_WARNING_TYPE     = 0x0002
+  Puppet::Util::Log::DestEventlog::EVENTLOG_INFORMATION_TYPE = 0x0004
+
+  def self.suitable?(obj)
+    Puppet.features.eventlog?
+  end
+
+  def initialize
+    @eventlog = Win32::EventLog.open("Application")
+  end
+
+  def to_native(level)
+    case level
+    when :debug,:info,:notice
+      [self.class::EVENTLOG_INFORMATION_TYPE, 0x01]
+    when :warning
+      [self.class::EVENTLOG_WARNING_TYPE, 0x02]
+    when :err,:alert,:emerg,:crit
+      [self.class::EVENTLOG_ERROR_TYPE, 0x03]
+    end
+  end
+
+  def handle(msg)
+    native_type, native_id = to_native(msg.level)
+
+    @eventlog.report_event(
+      :source      => "Puppet",
+      :event_type  => native_type,
+      :event_id    => native_id,
+      :data        => (msg.source and msg.source != 'Puppet' ? "#{msg.source}: " : '') + msg.to_s
+    )
+  end
+
+  def close
+    if @eventlog
+      @eventlog.close
+      @eventlog = nil
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/log/rate_limited_logger.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/log/rate_limited_logger.rb
new file mode 100644
index 0000000..73ebc53
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/log/rate_limited_logger.rb
@@ -0,0 +1,40 @@
+require 'puppet/util/logging'
+
+# Logging utility class that limits the frequency of identical log messages
+class Puppet::Util::Log::RateLimitedLogger
+  include Puppet::Util::Logging
+
+  def initialize(interval)
+    raise ArgumentError, "Logging rate-limit interval must be an integer" unless interval.is_a?(Integer)
+    @interval = interval
+    @log_record = {}
+  end
+
+  # Override the logging entry point to rate-limit it
+  def send_log(level, message)
+    Puppet::Util::Log.create({:level => level, :message => message}) if should_log?(level, message)
+  end
+
+  private
+
+  def should_log?(level, message)
+    # Initialize separate records for different levels, and only when needed
+    record = (@log_record[level] ||= {})
+    last_log = record[message]
+
+    # Skip logging if the time interval since the last logging hasn't elapsed yet
+    return false if last_log and within_interval?(last_log)
+
+    # Purge stale entries; do this after the interval check to reduce passes through the cache
+    record.delete_if { |key, time| !within_interval?(time) }
+
+    # Reset the beginning of the interval to the current time
+    record[message] = Time.now
+
+    true
+  end
+
+  def within_interval?(time)
+    time + @interval > Time.now
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/logging.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/logging.rb
new file mode 100644
index 0000000..8ad25e4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/logging.rb
@@ -0,0 +1,217 @@
+# A module to make logging a bit easier.
+require 'puppet/util/log'
+require 'puppet/error'
+
+module Puppet::Util::Logging
+
+  def send_log(level, message)
+    Puppet::Util::Log.create({:level => level, :source => log_source, :message => message}.merge(log_metadata))
+  end
+
+  # Create a method for each log level.
+  Puppet::Util::Log.eachlevel do |level|
+    define_method(level) do |args|
+      args = args.join(" ") if args.is_a?(Array)
+      send_log(level, args)
+    end
+  end
+
+  # Log an exception via Puppet.err.  Will also log the backtrace if Puppet[:trace] is set.
+  # Parameters:
+  # [exception] an Exception to log
+  # [message] an optional String overriding the message to be logged; by default, we log Exception.message.
+  #    If you pass a String here, your string will be logged instead.  You may also pass nil if you don't
+  #    wish to log a message at all; in this case it is likely that you are only calling this method in order
+  #    to take advantage of the backtrace logging.
+  def log_exception(exception, message = :default, options = {})
+    trace = Puppet[:trace] || options[:trace]
+    if message == :default && exception.is_a?(Puppet::ParseErrorWithIssue)
+      # Retain all detailed info and keep plain message and stacktrace separate
+      backtrace = []
+      build_exception_trace(backtrace, exception, trace)
+      Puppet::Util::Log.create({
+          :level => :err,
+          :source => log_source,
+          :message => exception.basic_message,
+          :issue_code => exception.issue_code,
+          :backtrace => backtrace.empty? ? nil : backtrace,
+          :file => exception.file,
+          :line => exception.line,
+          :pos => exception.pos,
+          :environment => exception.environment,
+          :node => exception.node
+        }.merge(log_metadata))
+    else
+      err(format_exception(exception, message, trace))
+    end
+  end
+
+  def build_exception_trace(arr, exception, trace = true)
+    if trace and exception.backtrace
+      exception.backtrace.each do |line|
+        arr << line =~ /^(.+):(\d+.*)$/ ? ("#{Pathname($1).realpath}:#{$2}" rescue line) : line
+      end
+    end
+    if exception.respond_to?(:original)
+      original =  exception.original
+      unless original.nil?
+        arr << 'Wrapped exception:'
+        arr << original.message
+        build_exception_trace(arr, original, trace)
+      end
+    end
+  end
+  private :build_exception_trace
+
+  def format_exception(exception, message = :default, trace = true)
+    arr = []
+    case message
+    when :default
+      arr << exception.message
+    when nil
+      # don't log anything if they passed a nil; they are just calling for the optional backtrace logging
+    else
+      arr << message
+    end
+
+    if trace and exception.backtrace
+      arr << Puppet::Util.pretty_backtrace(exception.backtrace)
+    end
+    if exception.respond_to?(:original) and exception.original
+      arr << "Wrapped exception:"
+      arr << format_exception(exception.original, :default, trace)
+    end
+    arr.flatten.join("\n")
+  end
+
+  def log_and_raise(exception, message)
+    log_exception(exception, message)
+    raise exception, message + "\n" + exception.to_s, exception.backtrace
+  end
+
+  class DeprecationWarning < Exception; end
+
+  # Logs a warning indicating that the Ruby code path is deprecated.  Note that
+  # this method keeps track of the offending lines of code that triggered the
+  # deprecation warning, and will only log a warning once per offending line of
+  # code.  It will also stop logging deprecation warnings altogether after 100
+  # unique deprecation warnings have been logged.  Finally, if
+  # Puppet[:disable_warnings] includes 'deprecations', it will squelch all
+  # warning calls made via this method.
+  #
+  # @param message [String] The message to log (logs via warning)
+  # @param key [String] Optional key to mark the message as unique. If not
+  #   passed in, the originating call line will be used instead.
+  def deprecation_warning(message, key = nil)
+    issue_deprecation_warning(message, key, nil, nil, true)
+  end
+
+  # Logs a warning whose origin comes from Puppet source rather than somewhere
+  # internal within Puppet.  Otherwise the same as deprecation_warning()
+  #
+  # @param message [String] The message to log (logs via warning)
+  # @param options [Hash]
+  # @option options [String] :file File we are warning from
+  # @option options [Integer] :line Line number we are warning from
+  # @option options [String] :key (:file + :line) Alternative key used to mark
+  #   warning as unique
+  #
+  # Either :file and :line and/or :key must be passed.
+  def puppet_deprecation_warning(message, options = {})
+    key = options[:key]
+    file = options[:file]
+    line = options[:line]
+    raise(Puppet::DevError, "Need either :file and :line, or :key") if (key.nil?) && (file.nil? || line.nil?)
+
+    key ||= "#{file}:#{line}"
+    issue_deprecation_warning(message, key, file, line, false)
+  end
+
+  def get_deprecation_offender()
+    # we have to put this in its own method to simplify testing; we need to be able to mock the offender results in
+    # order to test this class, and our framework does not appear to enjoy it if you try to mock Kernel.caller
+    #
+    # let's find the offending line;  we need to jump back up the stack a few steps to find the method that called
+    #  the deprecated method
+    if Puppet[:trace]
+      caller()[2..-1]
+    else
+      [caller()[2]]
+    end
+  end
+
+  def clear_deprecation_warnings
+    $deprecation_warnings.clear if $deprecation_warnings
+  end
+
+  # TODO: determine whether there might be a potential use for adding a puppet configuration option that would
+  # enable this deprecation logging.
+
+  # utility method that can be called, e.g., from spec_helper config.after, when tracking down calls to deprecated
+  # code.
+  # Parameters:
+  # [deprecations_file] relative or absolute path of a file to log the deprecations to
+  # [pattern] (default nil) if specified, will only log deprecations whose message matches the provided pattern
+  def log_deprecations_to_file(deprecations_file, pattern = nil)
+    # this method may get called lots and lots of times (e.g., from spec_helper config.after) without the global
+    # list of deprecation warnings being cleared out.  We don't want to keep logging the same offenders over and over,
+    # so, we need to keep track of what we've logged.
+    #
+    # It'd be nice if we could just clear out the list of deprecation warnings, but then the very next spec might
+    # find the same offender, and we'd end up logging it again.
+    $logged_deprecation_warnings ||= {}
+
+    File.open(deprecations_file, "a") do |f|
+      if ($deprecation_warnings) then
+        $deprecation_warnings.each do |offender, message|
+          if (! $logged_deprecation_warnings.has_key?(offender)) then
+            $logged_deprecation_warnings[offender] = true
+            if ((pattern.nil?) || (message =~ pattern)) then
+              f.puts(message)
+              f.puts(offender)
+              f.puts()
+            end
+          end
+        end
+      end
+    end
+  end
+
+  private
+
+  def issue_deprecation_warning(message, key, file, line, use_caller)
+    return if Puppet[:disable_warnings].include?('deprecations')
+    $deprecation_warnings ||= {}
+    if $deprecation_warnings.length < 100 then
+      key ||= (offender = get_deprecation_offender)
+      if (! $deprecation_warnings.has_key?(key)) then
+        $deprecation_warnings[key] = message
+        call_trace = use_caller ?
+          (offender || get_deprecation_offender).join('; ') :
+          "#{file || 'unknown'}:#{line || 'unknown'}"
+        warning("#{message}\n   (at #{call_trace})")
+      end
+    end
+  end
+
+  def is_resource?
+    defined?(Puppet::Type) && is_a?(Puppet::Type)
+  end
+
+  def is_resource_parameter?
+    defined?(Puppet::Parameter) && is_a?(Puppet::Parameter)
+  end
+
+  def log_metadata
+    [:file, :line, :tags].inject({}) do |result, attr|
+      result[attr] = send(attr) if respond_to?(attr)
+      result
+    end
+  end
+
+  def log_source
+    # We need to guard the existence of the constants, since this module is used by the base Puppet module.
+    (is_resource? or is_resource_parameter?) and respond_to?(:path) and return path.to_s
+    to_s
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/metaid.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/metaid.rb
new file mode 100644
index 0000000..4092e4f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/metaid.rb
@@ -0,0 +1,21 @@
+class Object
+  # The hidden singleton lurks behind everyone
+  def singleton_class; class << self; self; end; end
+  def meta_eval(&blk); singleton_class.instance_eval(&blk); end
+
+  # Adds methods to a singleton_class
+  def meta_def(name, &blk)
+    meta_eval { define_method name, &blk }
+  end
+
+  # Remove singleton_class methods.
+  def meta_undef(name, &blk)
+    meta_eval { remove_method name }
+  end
+
+  # Defines an instance method within a class
+  def class_def(name, &blk)
+    class_eval { define_method name, &blk }
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/methodhelper.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/methodhelper.rb
new file mode 100644
index 0000000..2dd3afd
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/methodhelper.rb
@@ -0,0 +1,32 @@
+# Where we store helper methods related to, um, methods.
+module Puppet::Util::MethodHelper
+  def requiredopts(*names)
+    names.each do |name|
+      devfail("#{name} is a required option for #{self.class}") if self.send(name).nil?
+    end
+  end
+
+  # Iterate over a hash, treating each member as an attribute.
+  def set_options(options)
+    options.each do |param,value|
+      method = param.to_s + "="
+      if respond_to? method
+        self.send(method, value)
+      else
+        raise ArgumentError, "Invalid parameter #{param} to object class #{self.class}"
+      end
+    end
+  end
+
+  # Take a hash and convert all of the keys to symbols if possible.
+  def symbolize_options(options)
+    options.inject({}) do |hash, opts|
+      if opts[0].respond_to? :intern
+        hash[opts[0].intern] = opts[1]
+      else
+        hash[opts[0]] = opts[1]
+      end
+      hash
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/metric.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/metric.rb
new file mode 100644
index 0000000..4173fde
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/metric.rb
@@ -0,0 +1,210 @@
+# included so we can test object types
+require 'puppet'
+require 'puppet/network/format_support'
+
+# A class for handling metrics.  This is currently ridiculously hackish.
+class Puppet::Util::Metric
+  include Puppet::Network::FormatSupport
+
+  attr_accessor :type, :name, :value, :label
+  attr_writer :values
+
+  attr_writer :basedir
+
+  def self.from_data_hash(data)
+    metric = new(data['name'], data['label'])
+    metric.values = data['values']
+    metric
+  end
+
+  def self.from_pson(data)
+    Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
+    self.from_data_hash(data)
+  end
+
+  def to_data_hash
+    {
+      'name' => @name,
+      'label' => @label,
+      'values' => @values
+    }
+  end
+
+  def to_pson(*args)
+    to_data_hash.to_pson(*args)
+  end
+
+  # Return a specific value
+  def [](name)
+    if value = @values.find { |v| v[0] == name }
+      return value[2]
+    else
+      return 0
+    end
+  end
+
+  def basedir
+    if defined?(@basedir)
+      @basedir
+    else
+      Puppet[:rrddir]
+    end
+  end
+
+  def create(start = nil)
+    Puppet.settings.use(:main, :metrics)
+
+    start ||= Time.now.to_i - 5
+
+    args = []
+
+    if Puppet.features.rrd_legacy? && ! Puppet.features.rrd?
+      @rrd = RRDtool.new(self.path)
+    end
+
+    values.each { |value|
+      # the 7200 is the heartbeat -- this means that any data that isn't
+      # more frequently than every two hours gets thrown away
+      args.push "DS:#{value[0]}:GAUGE:7200:U:U"
+    }
+    args.push "RRA:AVERAGE:0.5:1:300"
+
+    begin
+      if Puppet.features.rrd_legacy? && ! Puppet.features.rrd?
+        @rrd.create( Puppet[:rrdinterval], start, args)
+      else
+        RRD.create( self.path, '-s', Puppet[:rrdinterval].to_s, '-b', start.to_i.to_s, *args)
+      end
+    rescue => detail
+      raise detail, "Could not create RRD file #{path}: #{detail}", detail.backtrace
+    end
+  end
+
+  def dump
+    if Puppet.features.rrd_legacy? && ! Puppet.features.rrd?
+      puts @rrd.info
+    else
+      puts RRD.info(self.path)
+    end
+  end
+
+  def graph(range = nil)
+    unless Puppet.features.rrd? || Puppet.features.rrd_legacy?
+      Puppet.warning "RRD library is missing; cannot graph metrics"
+      return
+    end
+
+    unit = 60 * 60 * 24
+    colorstack = %w{#00ff00 #ff0000 #0000ff #ffff00 #ff99ff #ff9966 #66ffff #990000 #099000 #000990 #f00990 #0f0f0f #555555 #333333 #ffffff}
+
+    {:daily => unit, :weekly => unit * 7, :monthly => unit * 30, :yearly => unit * 365}.each do |name, time|
+      file = self.path.sub(/\.rrd$/, "-#{name}.png")
+      args = [file]
+
+      args.push("--title",self.label)
+      args.push("--imgformat","PNG")
+      args.push("--interlace")
+      defs = []
+      lines = []
+      #p @values.collect { |s,l| s }
+      values.zip(colorstack).each { |value,color|
+        next if value.nil?
+        # this actually uses the data label
+        defs.push("DEF:#{value[0]}=#{self.path}:#{value[0]}:AVERAGE")
+        lines.push("LINE2:#{value[0]}#{color}:#{value[1]}")
+      }
+      args << defs
+      args << lines
+      args.flatten!
+      if range
+        if Puppet.features.rrd_legacy? && ! Puppet.features.rrd?
+          args.push("--start",range[0],"--end",range[1])
+        else
+          args.push("--start",range[0].to_i.to_s,"--end",range[1].to_i.to_s)
+        end
+      else
+        if Puppet.features.rrd_legacy? && ! Puppet.features.rrd?
+          args.push("--start", Time.now.to_i - time, "--end", Time.now.to_i)
+        else
+          args.push("--start", (Time.now.to_i - time).to_s, "--end", Time.now.to_i.to_s)
+        end
+      end
+
+      begin
+        #Puppet.warning "args = #{args}"
+        if Puppet.features.rrd_legacy? && ! Puppet.features.rrd?
+          RRDtool.graph( args )
+        else
+          RRD.graph( *args )
+        end
+      rescue => detail
+        Puppet.err "Failed to graph #{self.name}: #{detail}"
+      end
+    end
+  end
+
+  def initialize(name,label = nil)
+    @name = name.to_s
+
+    @label = label || self.class.labelize(name)
+
+    @values = []
+  end
+
+  def path
+    File.join(self.basedir, @name + ".rrd")
+  end
+
+  def newvalue(name,value,label = nil)
+    raise ArgumentError.new("metric name #{name.inspect} is not a string") unless name.is_a? String
+    label ||= self.class.labelize(name)
+    @values.push [name,label,value]
+  end
+
+  def store(time)
+    unless Puppet.features.rrd? || Puppet.features.rrd_legacy?
+      Puppet.warning "RRD library is missing; cannot store metrics"
+      return
+    end
+    self.create(time - 5) unless Puppet::FileSystem.exist?(self.path)
+
+    if Puppet.features.rrd_legacy? && ! Puppet.features.rrd?
+      @rrd ||= RRDtool.new(self.path)
+    end
+
+    # XXX this is not terribly error-resistant
+    args = [time]
+    temps = []
+    values.each { |value|
+      #Puppet.warning "value[0]: #{value[0]}; value[1]: #{value[1]}; value[2]: #{value[2]}; "
+      args.push value[2]
+      temps.push value[0]
+    }
+    arg = args.join(":")
+    template = temps.join(":")
+    begin
+      if Puppet.features.rrd_legacy? && ! Puppet.features.rrd?
+        @rrd.update( template, [ arg ] )
+      else
+        RRD.update( self.path, '-t', template, arg )
+      end
+      #system("rrdtool updatev #{self.path} '#{arg}'")
+    rescue => detail
+      raise Puppet::Error, "Failed to update #{self.name}: #{detail}", detail.backtrace
+    end
+  end
+
+  def values
+    @values.sort { |a, b| a[1] <=> b[1] }
+  end
+
+  # Convert a name into a label.
+  def self.labelize(name)
+    name.to_s.capitalize.gsub("_", " ")
+  end
+end
+
+# This is necessary because we changed the class path in early 2007,
+# and reports directly yaml-dump these metrics, so both client and server
+# have to agree on the class name.
+Puppet::Metric = Puppet::Util::Metric
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/monkey_patches.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/monkey_patches.rb
new file mode 100644
index 0000000..901f94c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/monkey_patches.rb
@@ -0,0 +1,228 @@
+module Puppet::Util::MonkeyPatches
+end
+
+begin
+  Process.maxgroups = 1024
+rescue Exception
+  # Actually, I just want to ignore it, since various platforms - JRuby,
+  # Windows, and so forth - don't support it, but only because it isn't a
+  # meaningful or implementable concept there.
+end
+
+module RDoc
+  def self.caller(skip=nil)
+    in_gem_wrapper = false
+    Kernel.caller.reject { |call|
+      in_gem_wrapper ||= call =~ /#{Regexp.escape $0}:\d+:in `load'/
+    }
+  end
+end
+
+
+require "yaml"
+require "puppet/util/zaml.rb"
+
+class Symbol
+  def <=> (other)
+    self.to_s <=> other.to_s
+  end unless method_defined? '<=>'
+
+  def intern
+    self
+  end unless method_defined? 'intern'
+end
+
+[Object, Exception, Integer, Struct, Date, Time, Range, Regexp, Hash, Array, Float, String, FalseClass, TrueClass, Symbol, NilClass, Class].each { |cls|
+  cls.class_eval do
+    def to_yaml(ignored=nil)
+      ZAML.dump(self)
+    end
+  end
+}
+
+def YAML.dump(*args)
+  ZAML.dump(*args)
+end
+
+#
+# Workaround for bug in MRI 1.8.7, see
+#     http://redmine.ruby-lang.org/issues/show/2708
+# for details
+#
+if RUBY_VERSION == '1.8.7'
+  class NilClass
+    def closed?
+      true
+    end
+  end
+end
+
+class Object
+  # ActiveSupport 2.3.x mixes in a dangerous method
+  # that can cause rspec to fork bomb
+  # and other strange things like that.
+  def daemonize
+    raise NotImplementedError, "Kernel.daemonize is too dangerous, please don't try to use it."
+  end
+end
+
+class Symbol
+  # So, it turns out that one of the biggest memory allocation hot-spots in our
+  # code was using symbol-to-proc - because it allocated a new instance every
+  # time it was called, rather than caching (in Ruby 1.8.7 and earlier).
+  #
+  # In Ruby 1.9.3 and later Symbol#to_proc does implement a cache so we skip
+  # our monkey patch.
+  #
+  # Changing this means we can see XX memory reduction...
+  if RUBY_VERSION < "1.9.3"
+    if method_defined? :to_proc
+      alias __original_to_proc to_proc
+      def to_proc
+        @my_proc ||= __original_to_proc
+      end
+    else
+      def to_proc
+        @my_proc ||= Proc.new {|*args| args.shift.__send__(self, *args) }
+      end
+    end
+  end
+
+  # Defined in 1.9, absent in 1.8, and used for compatibility in various
+  # places, typically in third party gems.
+  def intern
+    return self
+  end unless method_defined? :intern
+end
+
+class String
+  unless method_defined? :lines
+    require 'puppet/util/monkey_patches/lines'
+    include Puppet::Util::MonkeyPatches::Lines
+  end
+end
+
+require 'fcntl'
+class IO
+  unless method_defined? :lines
+    require 'puppet/util/monkey_patches/lines'
+    include Puppet::Util::MonkeyPatches::Lines
+  end
+
+  def self.binread(name, length = nil, offset = 0)
+    Puppet.deprecation_warning("This is a monkey-patched implementation of IO.binread on ruby 1.8 and is deprecated. Read the file without this method as it will be removed in a future version.")
+    File.open(name, 'rb') do |f|
+      f.seek(offset) if offset > 0
+      f.read(length)
+    end
+  end unless singleton_methods.include?(:binread)
+
+  def self.binwrite(name, string, offset = nil)
+    # Determine if we should truncate or not.  Since the truncate method on a
+    # file handle isn't implemented on all platforms, safer to do this in what
+    # looks like the libc / POSIX flag - which is usually pretty robust.
+    # --daniel 2012-03-11
+    mode = Fcntl::O_CREAT | Fcntl::O_WRONLY | (offset.nil? ? Fcntl::O_TRUNC : 0)
+
+    # We have to duplicate the mode because Ruby on Windows is a bit precious,
+    # and doesn't actually carry over the mode.  It won't work to just use
+    # open, either, because that doesn't like our system modes and the default
+    # open bits don't do what we need, which is awesome. --daniel 2012-03-30
+    IO.open(IO::sysopen(name, mode), mode) do |f|
+      # ...seek to our desired offset, then write the bytes.  Don't try to
+      # seek past the start of the file, eh, because who knows what platform
+      # would legitimately blow up if we did that.
+      #
+      # Double-check the positioning, too, since destroying data isn't my idea
+      # of a good time. --daniel 2012-03-11
+      target = [0, offset.to_i].max
+      unless (landed = f.sysseek(target, IO::SEEK_SET)) == target
+        raise "unable to seek to target offset #{target} in #{name}: got to #{landed}"
+      end
+
+      f.syswrite(string)
+    end
+  end unless singleton_methods.include?(:binwrite)
+end
+
+class Float
+  INFINITY = (1.0/0.0) if defined?(Float::INFINITY).nil?
+end
+
+class Range
+  def intersection(other)
+    raise ArgumentError, 'value must be a Range' unless other.kind_of?(Range)
+    return unless other === self.first || self === other.first
+
+    start = [self.first, other.first].max
+    if self.exclude_end? && self.last <= other.last
+      start ... self.last
+    elsif other.exclude_end? && self.last >= other.last
+      start ... other.last
+    else
+      start .. [ self.last, other.last ].min
+    end
+  end unless method_defined? :intersection
+
+  alias_method :&, :intersection unless method_defined? :&
+end
+
+# (#19151) Reject all SSLv2 ciphers and handshakes
+require 'openssl'
+class OpenSSL::SSL::SSLContext
+  if DEFAULT_PARAMS[:options]
+    DEFAULT_PARAMS[:options] |= OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3
+  else
+    DEFAULT_PARAMS[:options] = OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3
+  end
+
+  if DEFAULT_PARAMS[:ciphers]
+    DEFAULT_PARAMS[:ciphers] << ':!SSLv2'
+  end
+
+  alias __original_initialize initialize
+  private :__original_initialize
+
+  def initialize(*args)
+    __original_initialize(*args)
+    params = {
+      :options => DEFAULT_PARAMS[:options],
+      :ciphers => DEFAULT_PARAMS[:ciphers],
+    }
+    set_params(params)
+  end
+end
+
+require 'puppet/util/platform'
+if Puppet::Util::Platform.windows?
+  require 'puppet/util/windows'
+  require 'openssl'
+
+  class OpenSSL::X509::Store
+    alias __original_set_default_paths set_default_paths
+    def set_default_paths
+      # This can be removed once openssl integrates with windows
+      # cert store, see http://rt.openssl.org/Ticket/Display.html?id=2158
+      Puppet::Util::Windows::RootCerts.instance.to_a.uniq.each do |x509|
+        begin
+          add_cert(x509)
+        rescue OpenSSL::X509::StoreError => e
+          warn "Failed to add #{x509.subject.to_s}"
+        end
+      end
+
+      __original_set_default_paths
+    end
+  end
+end
+
+# Older versions of SecureRandom (e.g. in 1.8.7) don't have the uuid method
+module SecureRandom
+  def self.uuid
+    # Copied from the 1.9.1 stdlib implementation of uuid
+    ary = self.random_bytes(16).unpack("NnnnnN")
+    ary[2] = (ary[2] & 0x0fff) | 0x4000
+    ary[3] = (ary[3] & 0x3fff) | 0x8000
+    "%08x-%04x-%04x-%04x-%04x%08x" % ary
+  end unless singleton_methods.include?(:uuid)
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/monkey_patches/lines.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/monkey_patches/lines.rb
new file mode 100644
index 0000000..e54e90d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/monkey_patches/lines.rb
@@ -0,0 +1,13 @@
+require 'puppet/util/monkey_patches'
+require 'enumerator'
+
+module Puppet::Util::MonkeyPatches::Lines
+  def lines(separator = $/)
+    if block_given?
+      self.each_line(separator) {|line| yield line }
+      return self
+    else
+      return enum_for(:each_line, separator)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/nagios_maker.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/nagios_maker.rb
new file mode 100644
index 0000000..61cf924
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/nagios_maker.rb
@@ -0,0 +1,85 @@
+require 'puppet/external/nagios'
+require 'puppet/external/nagios/base'
+require 'puppet/provider/naginator'
+
+module Puppet::Util::NagiosMaker
+  # Create a new nagios type, using all of the parameters
+  # from the parser.
+  def self.create_nagios_type(name)
+    name = name.to_sym
+    full_name = ("nagios_#{name}").to_sym
+
+    raise(Puppet::DevError, "No nagios type for #{name}") unless nagtype = Nagios::Base.type(name)
+
+    type = Puppet::Type.newtype(full_name) do
+
+      # Generate a file resource if necessary.
+      #
+      # @see Puppet::Type::File and its properties owner, group and mode.
+      def generate
+        return nil unless self[:owner] or self[:group] or self[:mode]
+        props = { :name => self[:target] }
+        [ :owner, :group, :mode ].each do |prop|
+          props[prop] = self[prop] if self[prop]
+        end
+        Puppet::Type.type(:file).new(props)
+      end
+
+    end
+
+    type.ensurable
+
+    type.newparam(nagtype.namevar, :namevar => true) do
+      desc "The name of this nagios_#{nagtype.name} resource."
+    end
+
+    [ :owner, :group, :mode].each do |fileprop|
+      type.newparam(fileprop) do
+        desc "The desired #{fileprop} of the config file for this nagios_#{nagtype.name} resource.
+ 
+          NOTE: If the target file is explicitly managed by a file resource in your manifest,
+          this parameter has no effect. If a parent directory of the target is managed by
+          a recursive file resource, this limitation does not apply (i.e., this parameter
+          takes precedence, and if purge is used, the target file is exempt)."
+      end
+    end
+
+    # We deduplicate the parameters because it makes sense to allow Naginator to have dupes.
+    nagtype.parameters.uniq.each do |param|
+      next if param == nagtype.namevar
+
+      # We can't turn these parameter names into constants, so at least for now they aren't
+      # supported.
+      next if param.to_s =~ /^[0-9]/
+
+      type.newproperty(param) do
+        desc "Nagios configuration file parameter."
+      end
+    end
+
+    type.newproperty(:target) do
+      desc 'The target.'
+
+      defaultto do
+        resource.class.defaultprovider.default_target
+      end
+    end
+
+    target = "/etc/nagios/#{full_name.to_s}.cfg"
+    provider = type.provide(:naginator, :parent => Puppet::Provider::Naginator, :default_target => target) {}
+    provider.nagios_type
+
+    type.desc "The Nagios type #{name.to_s}.  This resource type is autogenerated using the
+      model developed in Naginator, and all of the Nagios types are generated using the
+      same code and the same library.
+
+      This type generates Nagios configuration statements in Nagios-parseable configuration
+      files.  By default, the statements will be added to `#{target}`, but
+      you can send them to a different file by setting their `target` attribute.
+
+      You can purge Nagios resources using the `resources` type, but *only*
+      in the default file locations.  This is an architectural limitation.
+
+    "
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device.rb
new file mode 100644
index 0000000..60da036
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device.rb
@@ -0,0 +1,17 @@
+class Puppet::Util::NetworkDevice
+  class << self
+    attr_reader :current
+  end
+
+  def self.init(device)
+    require "puppet/util/network_device/#{device.provider}/device"
+    @current = Puppet::Util::NetworkDevice.const_get(device.provider.capitalize).const_get(:Device).new(device.url, device.options)
+  rescue => detail
+    raise detail, "Can't load #{device.provider} for #{device.name}: #{detail}", detail.backtrace
+  end
+
+  # Should only be used in tests
+  def self.teardown
+    @current = nil
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/base.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/base.rb
new file mode 100644
index 0000000..8f971ef
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/base.rb
@@ -0,0 +1,27 @@
+require 'puppet/util/autoload'
+require 'uri'
+require 'puppet/util/network_device/transport'
+require 'puppet/util/network_device/transport/base'
+
+class Puppet::Util::NetworkDevice::Base
+
+  attr_accessor :url, :transport
+
+  def initialize(url, options = {})
+    @url = URI.parse(url)
+
+    @autoloader = Puppet::Util::Autoload.new(
+      self,
+      "puppet/util/network_device/transport",
+      :wrap => false
+    )
+
+    if @autoloader.load(@url.scheme)
+      @transport = Puppet::Util::NetworkDevice::Transport.const_get(@url.scheme.capitalize).new(options[:debug])
+      @transport.host = @url.host
+      @transport.port = @url.port || case @url.scheme ; when "ssh" ; 22 ; when "telnet" ; 23 ; end
+      @transport.user = @url.user
+      @transport.password = @url.password
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/cisco.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/cisco.rb
new file mode 100644
index 0000000..8d18020
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/cisco.rb
@@ -0,0 +1,4 @@
+
+module Puppet::Util::NetworkDevice::Cisco
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/cisco/device.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/cisco/device.rb
new file mode 100644
index 0000000..1d41d6a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/cisco/device.rb
@@ -0,0 +1,267 @@
+require 'puppet'
+require 'puppet/util'
+require 'puppet/util/network_device/base'
+require 'puppet/util/network_device/ipcalc'
+require 'puppet/util/network_device/cisco/interface'
+require 'puppet/util/network_device/cisco/facts'
+require 'ipaddr'
+
+class Puppet::Util::NetworkDevice::Cisco::Device < Puppet::Util::NetworkDevice::Base
+
+  include Puppet::Util::NetworkDevice::IPCalc
+
+  attr_accessor :enable_password
+
+  def initialize(url, options = {})
+    super(url, options)
+    @enable_password = options[:enable_password] || parse_enable(@url.query)
+    transport.default_prompt = /[#>]\s?\z/n
+  end
+
+  def parse_enable(query)
+    if query
+      params = CGI.parse(query)
+      params['enable'].first unless params['enable'].empty?
+    end
+  end
+
+  def connect
+    transport.connect
+    login
+    transport.command("terminal length 0") do |out|
+      enable if out =~ />\s?\z/n
+    end
+    find_capabilities
+  end
+
+  def disconnect
+    transport.close
+  end
+
+  def command(cmd = nil)
+    connect
+    out = execute(cmd) if cmd
+    yield self if block_given?
+    disconnect
+    out
+  end
+
+  def execute(cmd)
+    transport.command(cmd)
+  end
+
+  def login
+    return if transport.handles_login?
+    if @url.user != ''
+      transport.command(@url.user, :prompt => /^Password:/)
+    else
+      transport.expect(/^Password:/)
+    end
+    transport.command(@url.password)
+  end
+
+  def enable
+    raise "Can't issue \"enable\" to enter privileged, no enable password set" unless enable_password
+    transport.command("enable", :prompt => /^Password:/)
+    transport.command(enable_password)
+  end
+
+  def support_vlan_brief?
+    !! @support_vlan_brief
+  end
+
+  def find_capabilities
+    out = execute("sh vlan brief")
+    lines = out.split("\n")
+    lines.shift; lines.pop
+
+    @support_vlan_brief = ! (lines.first =~ /^%/)
+  end
+
+  IF = {
+    :FastEthernet => %w{FastEthernet FastEth Fast FE Fa F},
+    :GigabitEthernet => %w{GigabitEthernet GigEthernet GigEth GE Gi G},
+    :TenGigabitEthernet => %w{TenGigabitEthernet TE Te},
+    :Ethernet => %w{Ethernet Eth E},
+    :Serial => %w{Serial Se S},
+    :PortChannel => %w{PortChannel Port-Channel Po},
+    :POS => %w{POS P},
+    :VLAN => %w{VLAN VL V},
+    :Loopback => %w{Loopback Loop Lo},
+    :ATM => %w{ATM AT A},
+    :Dialer => %w{Dialer Dial Di D},
+    :VirtualAccess => %w{Virtual-Access Virtual-A Virtual Virt}
+  }
+
+  def canonalize_ifname(interface)
+    IF.each do |k,ifnames|
+      if found = ifnames.find { |ifname| interface =~ /^#{ifname}\s*\d/i }
+        found = /^#{found}(.+)\Z/i.match(interface)
+        return "#{k.to_s}#{found[1]}".gsub(/\s+/,'')
+      end
+    end
+    interface
+  end
+
+  def facts
+    @facts ||= Puppet::Util::NetworkDevice::Cisco::Facts.new(transport)
+    facts = {}
+    command do |ng|
+      facts = @facts.retrieve
+    end
+    facts
+  end
+
+  def interface(name)
+    ifname = canonalize_ifname(name)
+    interface = parse_interface(ifname)
+    return { :ensure => :absent } if interface.empty?
+    interface.merge!(parse_trunking(ifname))
+    interface.merge!(parse_interface_config(ifname))
+  end
+
+  def new_interface(name)
+    Puppet::Util::NetworkDevice::Cisco::Interface.new(canonalize_ifname(name), transport)
+  end
+
+  def parse_interface(name)
+    resource = {}
+    out = execute("sh interface #{name}")
+    lines = out.split("\n")
+    lines.shift; lines.pop
+    lines.each do |l|
+      if l =~ /#{name} is (.+), line protocol is /
+        resource[:ensure] = ($1 == 'up' ? :present : :absent);
+      end
+      if l =~ /Auto Speed \(.+\),/ or l =~ /Auto Speed ,/ or l =~ /Auto-speed/
+        resource[:speed] = :auto
+      end
+      if l =~ /, (.+)Mb\/s/
+        resource[:speed] = $1
+      end
+      if l =~ /\s+Auto-duplex \((.{4})\),/
+        resource[:duplex] = :auto
+      end
+      if l =~ /\s+(.+)-duplex/
+        resource[:duplex] = $1 == "Auto" ? :auto : $1.downcase.to_sym
+      end
+      if l =~ /Description: (.+)/
+        resource[:description] = $1
+      end
+    end
+    resource
+  end
+
+  def parse_interface_config(name)
+    resource = Hash.new { |hash, key| hash[key] = Array.new ; }
+    out = execute("sh running-config interface #{name} | begin interface")
+    lines = out.split("\n")
+    lines.shift; lines.pop
+    lines.each do |l|
+      if l =~ /ip address (#{IP}) (#{IP})\s+secondary\s*$/
+        resource[:ipaddress] << [prefix_length(IPAddr.new($2)), IPAddr.new($1), 'secondary']
+      end
+      if l =~ /ip address (#{IP}) (#{IP})\s*$/
+        resource[:ipaddress] << [prefix_length(IPAddr.new($2)), IPAddr.new($1), nil]
+      end
+      if l =~ /ipv6 address (#{IP})\/(\d+) (eui-64|link-local)/
+        resource[:ipaddress] << [$2.to_i, IPAddr.new($1), $3]
+      end
+      if l =~ /channel-group\s+(\d+)/
+        resource[:etherchannel] = $1
+      end
+    end
+    resource
+  end
+
+  def parse_vlans
+    vlans = {}
+    out = execute(support_vlan_brief? ? "sh vlan brief" : "sh vlan-switch brief")
+    lines = out.split("\n")
+    lines.shift; lines.shift; lines.shift; lines.pop
+    vlan = nil
+    lines.each do |l|
+      case l
+            # vlan    name    status
+      when /^(\d+)\s+(\w+)\s+(\w+)\s+([a-zA-Z0-9,\/. ]+)\s*$/
+        vlan = { :name => $1, :description => $2, :status => $3, :interfaces => [] }
+        if $4.strip.length > 0
+          vlan[:interfaces] = $4.strip.split(/\s*,\s*/).map{ |ifn| canonalize_ifname(ifn) }
+        end
+        vlans[vlan[:name]] = vlan
+      when /^\s+([a-zA-Z0-9,\/. ]+)\s*$/
+        raise "invalid sh vlan summary output" unless vlan
+        if $1.strip.length > 0
+          vlan[:interfaces] += $1.strip.split(/\s*,\s*/).map{ |ifn| canonalize_ifname(ifn) }
+        end
+      else
+      end
+    end
+    vlans
+  end
+
+  def update_vlan(id, is = {}, should = {})
+    if should[:ensure] == :absent
+      Puppet.info "Removing #{id} from device vlan"
+      execute("conf t")
+      execute("no vlan #{id}")
+      execute("exit")
+      return
+    end
+
+    # We're creating or updating an entry
+    execute("conf t")
+    execute("vlan #{id}")
+    [is.keys, should.keys].flatten.uniq.each do |property|
+      Puppet.debug("trying property: #{property}: #{should[property]}")
+      next if property != :description
+      execute("name #{should[property]}")
+    end
+    execute("exit")
+    execute("exit")
+  end
+
+  def parse_trunking(interface)
+    trunking = {}
+    out = execute("sh interface #{interface} switchport")
+    lines = out.split("\n")
+    lines.shift; lines.pop
+    lines.each do |l|
+      case l
+      when /^Administrative mode:\s+(.*)$/i
+        case $1
+        when "trunk"
+          trunking[:mode] = :trunk
+        when "static access"
+          trunking[:mode] = :access
+        else
+          raise "Unknown switchport mode: #{$1} for #{interface}"
+        end
+      when /^Administrative Trunking Encapsulation:\s+(.*)$/
+        case $1
+        when "dot1q","isl"
+          trunking[:encapsulation] = $1.to_sym if trunking[:mode] == :trunk
+        else
+          raise "Unknown switchport encapsulation: #{$1} for #{interface}"
+        end
+      when /^Access Mode VLAN:\s+(.*) \(\(Inactive\)\)$/
+        # nothing
+      when /^Access Mode VLAN:\s+(.*) \(.*\)$/
+        trunking[:native_vlan] = $1 if trunking[:mode] == :access
+      when /^Trunking VLANs Enabled:\s+(.*)$/
+        next if trunking[:mode] == :access
+        vlans = $1
+        trunking[:allowed_trunk_vlans] = case vlans
+        when /all/i
+          :all
+        when /none/i
+          :none
+        else
+          vlans
+        end
+      end
+    end
+    trunking
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/cisco/facts.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/cisco/facts.rb
new file mode 100644
index 0000000..08943fa
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/cisco/facts.rb
@@ -0,0 +1,72 @@
+
+require 'puppet/util/network_device/cisco'
+require 'puppet/util/network_device/ipcalc'
+
+# this retrieves facts from a cisco device
+class Puppet::Util::NetworkDevice::Cisco::Facts
+
+  attr_reader :transport
+
+  def initialize(transport)
+    @transport = transport
+  end
+
+  def retrieve
+    facts = {}
+    facts.merge(parse_show_ver)
+  end
+
+  def parse_show_ver
+    facts = {}
+    out = @transport.command("sh ver")
+    lines = out.split("\n")
+    lines.shift; lines.pop
+    lines.each do |l|
+      case l
+      # cisco WS-C2924C-XL (PowerPC403GA) processor (revision 0x11) with 8192K/1024K bytes of memory.
+      # Cisco 1841 (revision 5.0) with 355328K/37888K bytes of memory.
+      # Cisco 877 (MPC8272) processor (revision 0x200) with 118784K/12288K bytes of memory.
+      # cisco WS-C2960G-48TC-L (PowerPC405) processor (revision C0) with 61440K/4088K bytes of memory.
+      # cisco WS-C2950T-24 (RC32300) processor (revision R0) with 19959K bytes of memory.
+      when /[cC]isco ([\w-]+) (?:\(([\w-]+)\) processor )?\(revision (.+)\) with (\d+[KMG])(?:\/(\d+[KMG]))? bytes of memory\./
+        facts[:hardwaremodel] = $1
+        facts[:processor] = $2 if $2
+        facts[:hardwarerevision] = $3
+        facts[:memorysize] = $4
+      # uptime
+      # Switch uptime is 1 year, 12 weeks, 6 days, 22 hours, 32 minutes
+      # c2950 uptime is 3 weeks, 1 day, 23 hours, 36 minutes
+      # c2960 uptime is 2 years, 27 weeks, 5 days, 21 hours, 30 minutes
+      # router uptime is 5 weeks, 1 day, 3 hours, 30 minutes
+      when /^\s*([\w-]+)\s+uptime is (.*?)$/
+        facts[:hostname] = $1
+        facts[:uptime] = $2
+        facts[:uptime_seconds] = uptime_to_seconds($2)
+        facts[:uptime_days] = facts[:uptime_seconds] / 86400
+      # "IOS (tm) C2900XL Software (C2900XL-C3H2S-M), Version 12.0(5)WC10, RELEASE SOFTWARE (fc1)"=> { :operatingsystem => "IOS", :operatingsystemrelease => "12.0(5)WC10", :operatingsystemmajrelease => "12.0", :operatingsystemfeature => "C3H2S"},
+      # "IOS (tm) C2950 Software (C2950-I6K2L2Q4-M), Version 12.1(22)EA8a, RELEASE SOFTWARE (fc1)"=> { :operatingsystem => "IOS", :operatingsystemrelease => "12.1(22)EA8a", :operatingsystemmajrelease => "12.1", :operatingsystemfeature => "I6K2L2Q4"},
+      # "Cisco IOS Software, C2960 Software (C2960-LANBASEK9-M), Version 12.2(44)SE, RELEASE SOFTWARE (fc1)"=>{ :operatingsystem => "IOS", :operatingsystemrelease => "12.2(44)SE", :operatingsystemmajrelease => "12.2", :operatingsystemfeature => "LANBASEK9"},
+      # "Cisco IOS Software, C870 Software (C870-ADVIPSERVICESK9-M), Version 12.4(11)XJ4, RELEASE SOFTWARE (fc2)"=>{ :operatingsystem => "IOS", :operatingsystemrelease => "12.4(11)XJ40", :operatingsystemmajrelease => "12.4XJ", :operatingsystemfeature => "ADVIPSERVICESK9"},
+      # "Cisco IOS Software, 1841 Software (C1841-ADVSECURITYK9-M), Version 12.4(24)T4, RELEASE SOFTWARE (fc2)" =>{ :operatingsystem => "IOS", :operatingsystemrelease => "12.4(24)T4", :operatingsystemmajrelease => "12.4T", :operatingsystemfeature => "ADVSECURITYK9"},
+      when /(?:Cisco )?(IOS)\s*(?:\(tm\) |Software, )?(?:\w+)\s+Software\s+\(\w+-(\w+)-\w+\), Version ([0-9.()A-Za-z]+),/
+        facts[:operatingsystem] = $1
+        facts[:operatingsystemrelease] = $3
+        facts[:operatingsystemmajrelease] = ios_major_version(facts[:operatingsystemrelease])
+        facts[:operatingsystemfeature] = $2
+      end
+    end
+    facts
+  end
+
+  def ios_major_version(version)
+    version.gsub(/^(\d+)\.(\d+)\(.+\)([A-Z]+)([\da-z]+)?/, '\1.\2\3')
+  end
+
+  def uptime_to_seconds(uptime)
+    captures = (uptime.match /^(?:(\d+) years?,)?\s*(?:(\d+) weeks?,)?\s*(?:(\d+) days?,)?\s*(?:(\d+) hours?,)?\s*(\d+) minutes?$/).captures
+    captures.zip([31536000, 604800, 86400, 3600, 60]).inject(0) do |total, (x,y)|
+      total + (x.nil? ? 0 : x.to_i * y)
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/cisco/interface.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/cisco/interface.rb
new file mode 100644
index 0000000..d184b9c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/cisco/interface.rb
@@ -0,0 +1,82 @@
+require 'puppet/util/network_device/cisco'
+require 'puppet/util/network_device/ipcalc'
+
+# this manages setting properties to an interface in a cisco switch or router
+class Puppet::Util::NetworkDevice::Cisco::Interface
+
+  include Puppet::Util::NetworkDevice::IPCalc
+  extend Puppet::Util::NetworkDevice::IPCalc
+
+  attr_reader :transport, :name
+
+  def initialize(name, transport)
+    @name = name
+    @transport = transport
+  end
+
+  COMMANDS = {
+    # property     => order, ios command/block/array
+    :description   => [1, "description %s"],
+    :speed         => [2, "speed %s"],
+    :duplex        => [3, "duplex %s"],
+    :native_vlan   => [4, "switchport access vlan %s"],
+    :encapsulation => [5, "switchport trunk encapsulation %s"],
+    :mode          => [6, "switchport mode %s"],
+    :allowed_trunk_vlans => [7, "switchport trunk allowed vlan %s"],
+    :etherchannel  => [8, ["channel-group %s", "port group %s"]],
+    :ipaddress     => [9,
+      lambda do |prefix,ip,option|
+        ip.ipv6? ? "ipv6 address #{ip.to_s}/#{prefix} #{option}" :
+                   "ip address #{ip.to_s} #{netmask(Socket::AF_INET,prefix)}"
+      end],
+      :ensure        => [10, lambda { |value| value == :present ? "no shutdown" : "shutdown" } ]
+  }
+
+  def update(is={}, should={})
+    Puppet.debug("Updating interface #{name}")
+    command("conf t")
+    command("interface #{name}")
+
+    # apply changes in a defined orders for cisco IOS devices
+    [is.keys, should.keys].flatten.uniq.sort {|a,b| COMMANDS[a][0] <=> COMMANDS[b][0] }.each do |property|
+      # They're equal, so do nothing.
+      next if is[property] == should[property]
+
+      # We're deleting it
+      if should[property] == :absent or should[property].nil?
+        execute(property, is[property], "no ")
+        next
+      end
+
+      # We're replacing an existing value or creating a new one
+      execute(property, should[property])
+    end
+
+    command("exit")
+    command("exit")
+  end
+
+  def execute(property, value, prefix='')
+    case COMMANDS[property][1]
+    when Array
+      COMMANDS[property][1].each do |command|
+        transport.command(prefix + command % value) do |out|
+          break unless out =~ /^%/
+        end
+      end
+    when String
+      command(prefix + COMMANDS[property][1] % value)
+    when Proc
+      value = [value] unless value.is_a?(Array)
+      value.each do |value|
+        command(prefix + COMMANDS[property][1].call(*value))
+      end
+    end
+  end
+
+  def command(command)
+    transport.command(command) do |out|
+      Puppet.err "Error while executing #{command}, device returned #{out}" if out =~ /^%/mo
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/config.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/config.rb
new file mode 100644
index 0000000..3c40b6a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/config.rb
@@ -0,0 +1,98 @@
+require 'ostruct'
+require 'puppet/util/watched_file'
+require 'puppet/util/network_device'
+
+class Puppet::Util::NetworkDevice::Config
+
+  def self.main
+    @main ||= self.new
+  end
+
+  def self.devices
+    main.devices || []
+  end
+
+  attr_reader :devices
+
+  def exists?
+    Puppet::FileSystem.exist?(@file.to_str)
+  end
+
+  def initialize
+    @file = Puppet::Util::WatchedFile.new(Puppet[:deviceconfig])
+
+    @devices = {}
+
+    read(true) # force reading at start
+  end
+
+  # Read the configuration file.
+  def read(force = false)
+    return unless exists?
+
+    parse if force or @file.changed?
+  end
+
+  private
+
+  def parse
+    begin
+      devices = {}
+      device = nil
+      File.open(@file) { |f|
+        count = 1
+        f.each { |line|
+          case line
+          when /^\s*#/ # skip comments
+            count += 1
+            next
+          when /^\s*$/  # skip blank lines
+            count += 1
+            next
+          when /^\[([\w.-]+)\]\s*$/ # [device.fqdn]
+            name = $1
+            name.chomp!
+            raise Puppet::Error, "Duplicate device found at line #{count}, already found at #{device.line}" if devices.include?(name)
+            device = OpenStruct.new
+            device.name = name
+            device.line = count
+            device.options = { :debug => false }
+            Puppet.debug "found device: #{device.name} at #{device.line}"
+            devices[name] = device
+          when /^\s*(type|url|debug)(\s+(.+))*$/
+            parse_directive(device, $1, $3, count)
+          else
+            raise Puppet::Error, "Invalid line #{count}: #{line}"
+          end
+          count += 1
+        }
+      }
+    rescue Errno::EACCES => detail
+      Puppet.err "Configuration error: Cannot read #{@file}; cannot serve"
+      #raise Puppet::Error, "Cannot read #{@config}"
+    rescue Errno::ENOENT => detail
+      Puppet.err "Configuration error: '#{@file}' does not exit; cannot serve"
+    end
+
+    @devices = devices
+  end
+
+  def parse_directive(device, var, value, count)
+    case var
+    when "type"
+      device.provider = value
+    when "url"
+      begin
+        URI.parse(value)
+      rescue URI::InvalidURIError
+        raise Puppet::Error, "#{value} is an invalid url"
+      end
+      device.url = value
+    when "debug"
+      device.options[:debug] = true
+    else
+      raise Puppet::Error, "Invalid argument '#{var}' at line #{count}"
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/ipcalc.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/ipcalc.rb
new file mode 100644
index 0000000..8ca5295
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/ipcalc.rb
@@ -0,0 +1,68 @@
+require 'puppet/util/network_device'
+
+module Puppet::Util::NetworkDevice::IPCalc
+
+  # This is a rip-off of authstore
+  Octet = '(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])'
+  IPv4 = "#{Octet}\.#{Octet}\.#{Octet}\.#{Octet}"
+  IPv6_full    = "_:_:_:_:_:_:_:_|_:_:_:_:_:_::_?|_:_:_:_:_::((_:)?_)?|_:_:_:_::((_:){0,2}_)?|_:_:_::((_:){0,3}_)?|_:_::((_:){0,4}_)?|_::((_:){0,5}_)?|::((_:){0,6}_)?"
+  IPv6_partial = "_:_:_:_:_:_:|_:_:_:_::(_:)?|_:_::(_:){0,2}|_::(_:){0,3}"
+  IP = "#{IPv4}|#{IPv6_full}".gsub(/_/,'([0-9a-fA-F]{1,4})').gsub(/\(/,'(?:')
+
+  def parse(value)
+    case value
+    when /^(#{IP})\/(\d+)$/  # 12.34.56.78/24, a001:b002::efff/120, c444:1000:2000::9:192.168.0.1/112
+      [$2.to_i,IPAddr.new($1)]
+    when /^(#{IP})$/           # 10.20.30.40,
+      value = IPAddr.new(value)
+      [bits(value.family),value]
+    end
+  end
+
+  def bits(family)
+    family == Socket::AF_INET6 ? 128 : 32
+  end
+
+  def fullmask(family)
+    (1 << bits(family)) - 1
+  end
+
+  def mask(family, length)
+    (1 << (bits(family) - length)) - 1
+  end
+
+  # returns ip address netmask from prefix length
+  def netmask(family, length)
+    IPAddr.new(fullmask(family) & ~mask(family, length) , family)
+  end
+
+  # returns an IOS wildmask
+  def wildmask(family, length)
+    IPAddr.new(mask(family, length) , family)
+  end
+
+  # returns ip address prefix length from netmask
+  def prefix_length(netmask)
+    mask_addr = netmask.to_i
+    return 0 if mask_addr == 0
+    length=32
+    if (netmask.ipv6?)
+      length=128
+    end
+
+    mask = mask_addr < 2**length ? length : 128
+
+    mask.times do
+        if ((mask_addr & 1) == 1)
+            break
+        end
+        mask_addr = mask_addr >> 1
+        mask = mask - 1
+    end
+    mask
+  end
+
+  def linklocal?(ip)
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/transport.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/transport.rb
new file mode 100644
index 0000000..6ecfa8e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/transport.rb
@@ -0,0 +1,5 @@
+require 'puppet/util/network_device'
+
+# stub
+module Puppet::Util::NetworkDevice::Transport
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/transport/base.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/transport/base.rb
new file mode 100644
index 0000000..4cee0dd
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/transport/base.rb
@@ -0,0 +1,26 @@
+
+require 'puppet/util/network_device'
+require 'puppet/util/network_device/transport'
+
+class Puppet::Util::NetworkDevice::Transport::Base
+  attr_accessor :user, :password, :host, :port
+  attr_accessor :default_prompt, :timeout
+
+  def initialize
+    @timeout = 10
+  end
+
+  def send(cmd)
+  end
+
+  def expect(prompt)
+  end
+
+  def command(cmd, options = {})
+    send(cmd)
+    expect(options[:prompt] || default_prompt) do |output|
+      yield output if block_given?
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/transport/ssh.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/transport/ssh.rb
new file mode 100644
index 0000000..1c20eb8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/transport/ssh.rb
@@ -0,0 +1,122 @@
+
+require 'puppet/util/network_device'
+require 'puppet/util/network_device/transport'
+require 'puppet/util/network_device/transport/base'
+
+# This is an adaptation/simplification of gem net-ssh-telnet, which aims to have
+# a sane interface to Net::SSH. Credits goes to net-ssh-telnet authors
+class Puppet::Util::NetworkDevice::Transport::Ssh < Puppet::Util::NetworkDevice::Transport::Base
+
+  attr_accessor :buf, :ssh, :channel
+
+  def initialize(verbose = false)
+    super()
+    @verbose = verbose
+    unless Puppet.features.ssh?
+      raise 'Connecting with ssh to a network device requires the \'net/ssh\' ruby library'
+    end
+  end
+
+  def handles_login?
+    true
+  end
+
+  def eof?
+    !! @eof
+  end
+
+  def connect(&block)
+    @output = []
+    @channel_data = ""
+
+    begin
+      Puppet.debug("connecting to #{host} as #{user}")
+      @ssh = Net::SSH.start(host, user, :port => port, :password => password, :timeout => timeout)
+    rescue TimeoutError
+      raise TimeoutError, "timed out while opening an ssh connection to the host", $!.backtrace
+    rescue Net::SSH::AuthenticationFailed
+      raise Puppet::Error, "SSH authentication failure connecting to #{host} as #{user}", $!.backtrace
+    rescue Net::SSH::Exception
+      raise Puppet::Error, "SSH connection failure to #{host}", $!.backtrace
+    end
+
+    @buf = ""
+    @eof = false
+    @channel = nil
+    @ssh.open_channel do |channel|
+      channel.request_pty { |ch,success| raise "failed to open pty" unless success }
+
+      channel.send_channel_request("shell") do |ch, success|
+        raise "failed to open ssh shell channel" unless success
+
+        ch.on_data { |ch,data| @buf << data }
+        ch.on_extended_data { |ch,type,data|  @buf << data if type == 1 }
+        ch.on_close { @eof = true }
+
+        @channel = ch
+        expect(default_prompt, &block)
+        # this is a little bit unorthodox, we're trying to escape
+        # the ssh loop there while still having the ssh connection up
+        # otherwise we wouldn't be able to return ssh stdout/stderr
+        # for a given call of command.
+        return
+      end
+
+    end
+    @ssh.loop
+
+  end
+
+  def close
+    @channel.close if @channel
+    @channel = nil
+    @ssh.close if @ssh
+  end
+
+  def expect(prompt)
+    line = ''
+    sock = @ssh.transport.socket
+
+    while not @eof
+      break if line =~ prompt and @buf == ''
+      break if sock.closed?
+
+      IO::select([sock], [sock], nil, nil)
+
+      process_ssh
+
+      # at this point we have accumulated some data in @buf
+      # or the channel has been closed
+      if @buf != ""
+        line += @buf.gsub(/\r\n/no, "\n")
+        @buf = ''
+        yield line if block_given?
+      elsif @eof
+        # channel has been closed
+        break if line =~ prompt
+        if line == ''
+          line = nil
+          yield nil if block_given?
+        end
+        break
+      end
+    end
+    Puppet.debug("ssh: expected #{line}") if @verbose
+    line
+  end
+
+  def send(line)
+    Puppet.debug("ssh: send #{line}") if @verbose
+    @channel.send_data(line + "\n")
+  end
+
+  def process_ssh
+    while @buf == "" and not eof?
+      begin
+        @channel.connection.process(0.1)
+      rescue IOError
+        @eof = true
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/transport/telnet.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/transport/telnet.rb
new file mode 100644
index 0000000..b25ce68
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/network_device/transport/telnet.rb
@@ -0,0 +1,44 @@
+require 'puppet/util/network_device'
+require 'puppet/util/network_device/transport'
+require 'puppet/util/network_device/transport/base'
+require 'net/telnet'
+
+class Puppet::Util::NetworkDevice::Transport::Telnet < Puppet::Util::NetworkDevice::Transport::Base
+    def initialize(verbose = false)
+      super()
+      @verbose = verbose
+    end
+
+    def handles_login?
+      false
+    end
+
+    def connect
+      @telnet = Net::Telnet::new("Host" => host, "Port" => port || 23,
+                                 "Timeout" => 10,
+                                 "Prompt" => default_prompt)
+    end
+
+    def close
+      @telnet.close if @telnet
+      @telnet = nil
+    end
+
+    def expect(prompt)
+      @telnet.waitfor(prompt) do |out|
+        yield out if block_given?
+      end
+    end
+
+    def command(cmd, options = {})
+      send(cmd)
+      expect(options[:prompt] || default_prompt) do |output|
+        yield output if block_given?
+      end
+    end
+
+    def send(line)
+      Puppet.debug("telnet: send #{line}") if @verbose
+      @telnet.puts(line)
+    end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/package.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/package.rb
new file mode 100644
index 0000000..5f1fc74
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/package.rb
@@ -0,0 +1,31 @@
+module Puppet::Util::Package
+  def versioncmp(version_a, version_b)
+    vre = /[-.]|\d+|[^-.\d]+/
+    ax = version_a.scan(vre)
+    bx = version_b.scan(vre)
+
+    while (ax.length>0 && bx.length>0)
+      a = ax.shift
+      b = bx.shift
+
+      if( a == b )                 then next
+      elsif (a == '-' && b == '-') then next
+      elsif (a == '-')             then return -1
+      elsif (b == '-')             then return 1
+      elsif (a == '.' && b == '.') then next
+      elsif (a == '.' )            then return -1
+      elsif (b == '.' )            then return 1
+      elsif (a =~ /^\d+$/ && b =~ /^\d+$/) then
+        if( a =~ /^0/ or b =~ /^0/ ) then
+          return a.to_s.upcase <=> b.to_s.upcase
+        end
+        return a.to_i <=> b.to_i
+      else
+        return a.upcase <=> b.upcase
+      end
+    end
+    version_a <=> version_b;
+  end
+
+  module_function :versioncmp
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/pidlock.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/pidlock.rb
new file mode 100644
index 0000000..3ebb4e0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/pidlock.rb
@@ -0,0 +1,62 @@
+require 'fileutils'
+require 'puppet/util/lockfile'
+
+class Puppet::Util::Pidlock
+
+  def initialize(lockfile)
+    @lockfile = Puppet::Util::Lockfile.new(lockfile)
+  end
+
+  def locked?
+    clear_if_stale
+    @lockfile.locked?
+  end
+
+  def mine?
+    Process.pid == lock_pid
+  end
+
+  def lock
+    return mine? if locked?
+
+    @lockfile.lock(Process.pid)
+  end
+
+  def unlock
+    if mine?
+      return @lockfile.unlock
+    else
+      false
+    end
+  end
+
+  def lock_pid
+    pid = @lockfile.lock_data
+    begin
+      Integer(pid)
+    rescue ArgumentError, TypeError
+      nil
+    end
+  end
+
+  def file_path
+    @lockfile.file_path
+  end
+
+  def clear_if_stale
+    return @lockfile.unlock if lock_pid.nil?
+
+    errors = [Errno::ESRCH]
+    # Win32::Process now throws SystemCallError. Since this could be
+    # defined anywhere, only add when on Windows.
+    errors << SystemCallError if Puppet::Util::Platform.windows?
+
+    begin
+      Process.kill(0, lock_pid)
+    rescue *errors
+      @lockfile.unlock
+    end
+  end
+  private :clear_if_stale
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/platform.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/platform.rb
new file mode 100644
index 0000000..8eb56c8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/platform.rb
@@ -0,0 +1,22 @@
+module Puppet
+  module Util
+    module Platform
+      def windows?
+        # Ruby only sets File::ALT_SEPARATOR on Windows and the Ruby standard
+        # library uses that to test what platform it's on. In some places we
+        # would use Puppet.features.microsoft_windows?, but this method can be
+        # used to determine the behavior of the underlying system without
+        # requiring features to be initialized and without side effect.
+        !!File::ALT_SEPARATOR
+      end
+      module_function :windows?
+
+      def default_paths
+        return [] if windows?
+
+        %w{/usr/sbin /sbin}
+      end
+      module_function :default_paths
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/plugins.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/plugins.rb
new file mode 100644
index 0000000..c39f6b1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/plugins.rb
@@ -0,0 +1,82 @@
+#
+# This system manages an extensible set of metadata about plugins which it
+#   collects by searching for files named "plugin_init.rb" in a series of
+#   directories.  Initially, these are simply the $LOAD_PATH.
+#
+# The contents of each file found is executed in the context of a Puppet::Plugins
+#    object (and thus scoped).  An example file might contain:
+#
+# -------------------------------------------------------
+#      @name = "Greet the CA"
+#
+#      @description = %q{
+#        This plugin causes a friendly greeting to print out on a master
+#        that is operating as the CA, after it has been set up but before
+#        it does anything.
+#      }
+#
+#      def after_application_setup(options)
+#        if options[:application_object].is_a?(Puppet::Application::Master) && Puppet::SSL::CertificateAuthority.ca?
+#          puts "Hey, this is the CA!"
+#        end
+#      end
+# -------------------------------------------------------
+#
+# Note that the instance variables are local to this Puppet::Plugin (and so may be used
+#   for maintaining state, etc.) but the plugin system does not provide any thread safety
+#   assurances, so they may not be adequate for some complex use cases.
+
+
+module Puppet
+  class Plugins
+    Paths  = [] # Where we might find plugin initialization code
+    Loaded = [] # Code we have found (one-to-one with paths once searched)
+    #
+    # Return all the Puppet::Plugins we know about, searching any new paths
+    #
+    def self.known
+      Paths[Loaded.length...Paths.length].each { |path|
+        file = File.join(path,'plugin_init.rb')
+        Loaded << (Puppet::FileSystem.exist?(file) && new(file))
+      }
+      Loaded.compact
+    end
+    #
+    # Add more places to look for plugins without adding duplicates or changing the
+    #   order of ones we've already found.
+    #
+    def self.look_in(*paths)
+      Paths.replace Paths | paths.flatten.collect { |path| File.expand_path(path) }
+    end
+    #
+    # Initially just look in $LOAD_PATH
+    #
+    look_in $LOAD_PATH
+    #
+    # Calling methods (hooks) on the class calls the method of the same name on
+    #   all plugins that use that hook, passing in the same arguments to each
+    #   and returning an array containing the results returned by each plugin as
+    #   an array of [plugin_name,result] pairs.
+    #
+    def self.method_missing(hook,*args,&block)
+      known.
+        select  { |p| p.respond_to? hook }.
+        collect { |p| [p.name,p.send(hook,*args,&block)] }
+    end
+    #
+    #
+    #
+    attr_reader :path,:name
+    def initialize(path)
+      @name = @path = path
+      class << self
+        private
+        def define_hooks
+          eval File.read(path),nil,path,1
+        end
+      end
+      define_hooks
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/posix.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/posix.rb
new file mode 100644
index 0000000..fa2c609
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/posix.rb
@@ -0,0 +1,137 @@
+# Utility methods for interacting with POSIX objects; mostly user and group
+module Puppet::Util::POSIX
+
+  # This is a list of environment variables that we will set when we want to override the POSIX locale
+  LOCALE_ENV_VARS = ['LANG', 'LC_ALL', 'LC_MESSAGES', 'LANGUAGE',
+                           'LC_COLLATE', 'LC_CTYPE', 'LC_MONETARY', 'LC_NUMERIC', 'LC_TIME']
+
+  # This is a list of user-related environment variables that we will unset when we want to provide a pristine
+  # environment for "exec" runs
+  USER_ENV_VARS = ['HOME', 'USER', 'LOGNAME']
+
+
+
+  # Retrieve a field from a POSIX Etc object.  The id can be either an integer
+  # or a name.  This only works for users and groups.  It's also broken on
+  # some platforms, unfortunately, which is why we fall back to the other
+  # method search_posix_field in the gid and uid methods if a sanity check
+  # fails
+  def get_posix_field(space, field, id)
+    raise Puppet::DevError, "Did not get id from caller" unless id
+
+    if id.is_a?(Integer)
+      if id > Puppet[:maximum_uid].to_i
+        Puppet.err "Tried to get #{field} field for silly id #{id}"
+        return nil
+      end
+      method = methodbyid(space)
+    else
+      method = methodbyname(space)
+    end
+
+    begin
+      return Etc.send(method, id).send(field)
+    rescue NoMethodError, ArgumentError
+      # ignore it; we couldn't find the object
+      return nil
+    end
+  end
+
+  # A degenerate method of retrieving name/id mappings.  The job of this method is
+  # to retrieve all objects of a certain type, search for a specific entry
+  # and then return a given field from that entry.
+  def search_posix_field(type, field, id)
+    idmethod = idfield(type)
+    integer = false
+    if id.is_a?(Integer)
+      integer = true
+      if id > Puppet[:maximum_uid].to_i
+        Puppet.err "Tried to get #{field} field for silly id #{id}"
+        return nil
+      end
+    end
+
+    Etc.send(type) do |object|
+      if integer and object.send(idmethod) == id
+        return object.send(field)
+      elsif object.name == id
+        return object.send(field)
+      end
+    end
+
+    # Apparently the group/passwd methods need to get reset; if we skip
+    # this call, then new users aren't found.
+    case type
+    when :passwd; Etc.send(:endpwent)
+    when :group; Etc.send(:endgrent)
+    end
+    nil
+  end
+
+  # Determine what the field name is for users and groups.
+  def idfield(space)
+    case space.intern
+    when :gr, :group; return :gid
+    when :pw, :user, :passwd; return :uid
+    else
+      raise ArgumentError.new("Can only handle users and groups")
+    end
+  end
+
+  # Determine what the method is to get users and groups by id
+  def methodbyid(space)
+    case space.intern
+    when :gr, :group; return :getgrgid
+    when :pw, :user, :passwd; return :getpwuid
+    else
+      raise ArgumentError.new("Can only handle users and groups")
+    end
+  end
+
+  # Determine what the method is to get users and groups by name
+  def methodbyname(space)
+    case space.intern
+    when :gr, :group; return :getgrnam
+    when :pw, :user, :passwd; return :getpwnam
+    else
+      raise ArgumentError.new("Can only handle users and groups")
+    end
+  end
+
+  # Get the GID
+  def gid(group)
+      get_posix_value(:group, :gid, group)
+  end
+
+  # Get the UID
+  def uid(user)
+      get_posix_value(:passwd, :uid, user)
+  end
+
+  private
+
+  # Get the specified id_field of a given field (user or group), 
+  # whether an ID name is provided
+  def get_posix_value(location, id_field, field)
+    begin
+      field = Integer(field)
+    rescue ArgumentError
+      # pass
+    end
+    if field.is_a?(Integer)
+      return nil unless name = get_posix_field(location, :name, field)
+      id = get_posix_field(location, id_field, name)
+      check_value = id
+    else
+      return nil unless id = get_posix_field(location, id_field, field)
+      name = get_posix_field(location, :name, id)
+      check_value = name
+    end
+    if check_value != field
+      return search_posix_field(location, id_field, field)
+    else
+      return id
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/profiler.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/profiler.rb
new file mode 100644
index 0000000..820231f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/profiler.rb
@@ -0,0 +1,53 @@
+require 'benchmark'
+
+# A simple profiling callback system.
+#
+# @api public
+module Puppet::Util::Profiler
+  require 'puppet/util/profiler/wall_clock'
+  require 'puppet/util/profiler/object_counts'
+  require 'puppet/util/profiler/around_profiler'
+
+  @profiler = Puppet::Util::Profiler::AroundProfiler.new
+
+  # Reset the profiling system to the original state
+  #
+  # @api private
+  def self.clear
+    @profiler.clear
+  end
+
+  # Retrieve the current list of profilers
+  #
+  # @api private
+  def self.current
+    @profiler.current
+  end
+
+  # @param profiler [#profile] A profiler for the current thread
+  # @api private
+  def self.add_profiler(profiler)
+    @profiler.add_profiler(profiler)
+  end
+
+  # @param profiler [#profile] A profiler to remove from the current thread
+  # @api private
+  def self.remove_profiler(profiler)
+    @profiler.remove_profiler(profiler)
+  end
+
+  # Profile a block of code and log the time it took to execute.
+  #
+  # This outputs logs entries to the Puppet masters logging destination
+  # providing the time it took, a message describing the profiled code
+  # and a leaf location marking where the profile method was called
+  # in the profiled hierachy.
+  #
+  # @param message [String] A description of the profiled event
+  # @param metric_id [Array] A list of strings making up the ID of a metric to profile
+  # @param block [Block] The segment of code to profile
+  # @api public
+  def self.profile(message, metric_id = nil, &block)
+    @profiler.profile(message, metric_id, &block)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/profiler/aggregate.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/profiler/aggregate.rb
new file mode 100644
index 0000000..e8a4ca5
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/profiler/aggregate.rb
@@ -0,0 +1,85 @@
+require 'puppet/util/profiler'
+require 'puppet/util/profiler/wall_clock'
+
+class Puppet::Util::Profiler::Aggregate < Puppet::Util::Profiler::WallClock
+  def initialize(logger, identifier)
+    super(logger, identifier)
+    @metrics_hash = Metric.new
+  end
+
+  def shutdown()
+    super
+    @logger.call("AGGREGATE PROFILING RESULTS:")
+    @logger.call("----------------------------")
+    print_metrics(@metrics_hash, "")
+    @logger.call("----------------------------")
+  end
+
+  def do_start(description, metric_id)
+    super(description, metric_id)
+  end
+
+  def do_finish(context, description, metric_id)
+    result = super(context, description, metric_id)
+    update_metric(@metrics_hash, metric_id, result[:time])
+    result
+  end
+
+  def update_metric(metrics_hash, metric_id, time)
+    first, *rest = *metric_id
+    if first
+      m = metrics_hash[first]
+      m.increment
+      m.add_time(time)
+      if rest.count > 0
+        update_metric(m, rest, time)
+      end
+    end
+  end
+
+  def values
+    @metrics_hash
+  end
+
+  def print_metrics(metrics_hash, prefix)
+    metrics_hash.sort_by {|k,v| v.time }.reverse.each do |k,v|
+      @logger.call("#{prefix}#{k}: #{v.time} ms (#{v.count} calls)")
+      print_metrics(metrics_hash[k], "#{prefix}#{k} -> ")
+    end
+  end
+
+  class Metric < Hash
+    def initialize
+      super
+      @count = 0
+      @time = 0
+    end
+    attr_reader :count, :time
+
+    def [](key)
+      if !has_key?(key)
+        self[key] = Metric.new
+      end
+      super(key)
+    end
+
+    def increment
+      @count += 1
+    end
+
+    def add_time(time)
+      @time += time
+    end
+  end
+
+  class Timer
+    def initialize
+      @start = Time.now
+    end
+
+    def stop
+      Time.now - @start
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/profiler/around_profiler.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/profiler/around_profiler.rb
new file mode 100644
index 0000000..0b408c6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/profiler/around_profiler.rb
@@ -0,0 +1,67 @@
+# A Profiler that can be used to wrap around blocks of code. It is configured
+# with other profilers and controls them to start before the block is executed
+# and finish after the block is executed.
+#
+# @api private
+class Puppet::Util::Profiler::AroundProfiler
+
+  def initialize
+    @profilers = []
+  end
+
+  # Reset the profiling system to the original state
+  #
+  # @api private
+  def clear
+    @profilers = []
+  end
+
+  # Retrieve the current list of profilers
+  #
+  # @api private
+  def current
+    @profilers
+  end
+
+  # @param profiler [#profile] A profiler for the current thread
+  # @api private
+  def add_profiler(profiler)
+    @profilers << profiler
+    profiler
+  end
+
+  # @param profiler [#profile] A profiler to remove from the current thread
+  # @api private
+  def remove_profiler(profiler)
+    @profilers.delete(profiler)
+  end
+
+  # Profile a block of code and log the time it took to execute.
+  #
+  # This outputs logs entries to the Puppet masters logging destination
+  # providing the time it took, a message describing the profiled code
+  # and a leaf location marking where the profile method was called
+  # in the profiled hierachy.
+  #
+  # @param message [String] A description of the profiled event
+  # @param metric_id [Array] A list of strings making up the ID of a metric to profile
+  # @param block [Block] The segment of code to profile
+  # @api private
+  def profile(message, metric_id = nil)
+    retval = nil
+    contexts = {}
+    @profilers.each do |profiler|
+      contexts[profiler] = profiler.start(message, metric_id)
+    end
+
+    begin
+      retval = yield
+    ensure
+      @profilers.each do |profiler|
+        profiler.finish(contexts[profiler], message, metric_id)
+      end
+    end
+
+    retval
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/profiler/logging.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/profiler/logging.rb
new file mode 100644
index 0000000..5d1fd10
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/profiler/logging.rb
@@ -0,0 +1,48 @@
+class Puppet::Util::Profiler::Logging
+  def initialize(logger, identifier)
+    @logger = logger
+    @identifier = identifier
+    @sequence = Sequence.new
+  end
+
+  def start(description, metric_id)
+    @sequence.next
+    @sequence.down
+    do_start(description, metric_id)
+  end
+
+  def finish(context, description, metric_id)
+    profile_explanation = do_finish(context, description, metric_id)[:msg]
+    @sequence.up
+    @logger.call("PROFILE [#{@identifier}] #{@sequence} #{description}: #{profile_explanation}")
+  end
+
+  def shutdown()
+    # nothing to do
+  end
+
+  class Sequence
+    INITIAL = 0
+    SEPARATOR = '.'
+
+    def initialize
+      @elements = [INITIAL]
+    end
+
+    def next
+      @elements[-1] += 1
+    end
+
+    def down
+      @elements << INITIAL
+    end
+
+    def up
+      @elements.pop
+    end
+
+    def to_s
+      @elements.join(SEPARATOR)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/profiler/object_counts.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/profiler/object_counts.rb
new file mode 100644
index 0000000..3f9e5de
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/profiler/object_counts.rb
@@ -0,0 +1,17 @@
+require 'puppet/util/profiler/logging'
+
+class Puppet::Util::Profiler::ObjectCounts < Puppet::Util::Profiler::Logging
+  def start
+    ObjectSpace.count_objects
+  end
+
+  def finish(before)
+    after = ObjectSpace.count_objects
+
+    diff = before.collect do |type, count|
+      [type, after[type] - count]
+    end
+
+    diff.sort.collect { |pair| pair.join(': ') }.join(', ')
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/profiler/wall_clock.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/profiler/wall_clock.rb
new file mode 100644
index 0000000..46ac095
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/profiler/wall_clock.rb
@@ -0,0 +1,35 @@
+require 'puppet/util/profiler/logging'
+
+# A profiler implementation that measures the number of seconds a segment of
+# code takes to execute and provides a callback with a string representation of
+# the profiling information.
+#
+# @api private
+class Puppet::Util::Profiler::WallClock < Puppet::Util::Profiler::Logging
+  def do_start(description, metric_id)
+    Timer.new
+  end
+
+  def do_finish(context, description, metric_id)
+    {:time => context.stop,
+     :msg => "took #{context} seconds"}
+  end
+
+  class Timer
+    FOUR_DECIMAL_DIGITS = '%0.4f'
+
+    def initialize
+      @start = Time.now
+    end
+
+    def stop
+      @time = Time.now - @start
+      @time
+    end
+
+    def to_s
+      format(FOUR_DECIMAL_DIGITS, @time)
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/provider_features.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/provider_features.rb
new file mode 100644
index 0000000..f8c0c0a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/provider_features.rb
@@ -0,0 +1,184 @@
+# Provides feature definitions.
+require 'puppet/util/methodhelper'
+require 'puppet/util/docs'
+require 'puppet/util'
+# This module models provider features and handles checking whether the features
+# are present.
+# @todo Unclear what is api and what is private in this module.
+#
+module Puppet::Util::ProviderFeatures
+  include Puppet::Util::Docs
+  # This class models provider features and handles checking whether the features
+  # are present.
+  # @todo Unclear what is api and what is private in this class
+  class ProviderFeature
+    include Puppet::Util
+    include Puppet::Util::MethodHelper
+    include Puppet::Util::Docs
+    attr_accessor :name, :docs, :methods
+
+    # Are all of the requirements met?
+    # Requirements are checked by checking if feature predicate methods have been generated - see {#methods_available?}.
+    # @param obj [Object, Class] the object or class to check if requirements are met
+    # @return [Boolean] whether all requirements for this feature are met or not.
+    def available?(obj)
+      if self.methods
+        return !!methods_available?(obj)
+      else
+        # In this case, the provider has to declare support for this
+        # feature, and that's been checked before we ever get to the
+        # method checks.
+        return false
+      end
+    end
+
+    def initialize(name, docs, hash)
+      self.name = name.intern
+      self.docs = docs
+      hash = symbolize_options(hash)
+      set_options(hash)
+    end
+
+    private
+
+    # Checks whether all feature predicate methods are available.
+    # @param obj [Object, Class] the object or class to check if feature predicates are available or not.
+    # @return [Boolean] Returns whether all of the required methods are available or not in the given object.
+    def methods_available?(obj)
+      methods.each do |m|
+        if obj.is_a?(Class)
+          return false unless obj.public_method_defined?(m)
+        else
+          return false unless obj.respond_to?(m)
+        end
+      end
+      true
+    end
+  end
+
+  # Defines one feature.
+  # At a minimum, a feature requires a name
+  # and docs, and at this point they should also specify a list of methods
+  # required to determine if the feature is present.
+  # @todo How methods that determine if the feature is present are specified.
+  def feature(name, docs, hash = {})
+    @features ||= {}
+    raise(Puppet::DevError, "Feature #{name} is already defined") if @features.include?(name)
+    begin
+      obj = ProviderFeature.new(name, docs, hash)
+      @features[obj.name] = obj
+    rescue ArgumentError => detail
+      error = ArgumentError.new(
+        "Could not create feature #{name}: #{detail}"
+      )
+      error.set_backtrace(detail.backtrace)
+      raise error
+    end
+  end
+
+  # @return [String] Returns a string with documentation covering all features.
+  def featuredocs
+    str = ""
+    @features ||= {}
+    return nil if @features.empty?
+    names = @features.keys.sort { |a,b| a.to_s <=> b.to_s }
+    names.each do |name|
+      doc = @features[name].docs.gsub(/\n\s+/, " ")
+      str << "- *#{name}*: #{doc}\n"
+    end
+
+    if providers.length > 0
+      headers = ["Provider", names].flatten
+      data = {}
+      providers.each do |provname|
+        data[provname] = []
+        prov = provider(provname)
+        names.each do |name|
+          if prov.feature?(name)
+            data[provname] << "*X*"
+          else
+            data[provname] << ""
+          end
+        end
+      end
+      str << doctable(headers, data)
+    end
+    str
+  end
+
+  # @return [Array<String>] Returns a list of features.
+  def features
+    @features ||= {}
+    @features.keys
+  end
+
+  # Generates a module that sets up the boolean predicate methods to test for given features.
+  #
+  def feature_module
+    unless defined?(@feature_module)
+      @features ||= {}
+      @feature_module = ::Module.new
+      const_set("FeatureModule", @feature_module)
+      features = @features
+      # Create a feature? method that can be passed a feature name and
+      # determine if the feature is present.
+      @feature_module.send(:define_method, :feature?) do |name|
+        method = name.to_s + "?"
+        return !!(respond_to?(method) and send(method))
+      end
+
+      # Create a method that will list all functional features.
+      @feature_module.send(:define_method, :features) do
+        return false unless defined?(features)
+        features.keys.find_all { |n| feature?(n) }.sort { |a,b|
+          a.to_s <=> b.to_s
+        }
+      end
+
+      # Create a method that will determine if a provided list of
+      # features are satisfied by the curred provider.
+      @feature_module.send(:define_method, :satisfies?) do |*needed|
+        ret = true
+        needed.flatten.each do |feature|
+          unless feature?(feature)
+            ret = false
+            break
+          end
+        end
+        ret
+      end
+
+      # Create a boolean method for each feature so you can test them
+      # individually as you might need.
+      @features.each do |name, feature|
+        method = name.to_s + "?"
+        @feature_module.send(:define_method, method) do
+          (is_a?(Class) ?  declared_feature?(name) : self.class.declared_feature?(name)) or feature.available?(self)
+        end
+      end
+
+      # Allow the provider to declare that it has a given feature.
+      @feature_module.send(:define_method, :has_features) do |*names|
+        @declared_features ||= []
+        names.each do |name|
+          @declared_features << name.intern
+        end
+      end
+      # Aaah, grammatical correctness
+      @feature_module.send(:alias_method, :has_feature, :has_features)
+    end
+    @feature_module
+  end
+
+  # @return [ProviderFeature] Returns a provider feature instance by name.
+  # @param name [String] the name of the feature to return
+  # @note Should only be used for testing.
+  # @api private
+  #
+  def provider_feature(name)
+    return nil unless defined?(@features)
+
+    @features[name]
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/pson.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/pson.rb
new file mode 100644
index 0000000..b796cb1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/pson.rb
@@ -0,0 +1,13 @@
+# A simple module to provide consistency between how we use PSON and how
+# ruby expects it to be used.  Basically, we don't want to require
+# that the sender specify a class.
+#  Ruby wants everyone to provide a 'type' field, and the PSON support
+# requires such a field to track the class down.  Because we use our URL to
+# figure out what class we're working on, we don't need that, and we don't want
+# our consumers and producers to need to know anything about our internals.
+module Puppet::Util::Pson
+  def pson_create(pson)
+    raise ArgumentError, "No data provided in pson data" unless pson['data']
+    from_data_hash(pson['data'])
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/queue.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/queue.rb
new file mode 100644
index 0000000..636bdcf
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/queue.rb
@@ -0,0 +1,96 @@
+
+require 'puppet/indirector'
+require 'puppet/util/instance_loader'
+
+# Implements a message queue client type plugin registry for use by the indirector facility.
+# Client modules for speaking a particular protocol (e.g. Stomp::Client for Stomp message
+# brokers, Memcached for Starling and Sparrow, etc.) register themselves with this module.
+#
+# Client classes are expected to live under the Puppet::Util::Queue namespace and corresponding
+# directory; the attempted use of a client via its typename (see below) will cause Puppet::Util::Queue
+# to attempt to load the corresponding plugin if it is not yet loaded.  The client class registers itself
+# with Puppet::Util::Queue and should use the same type name as the autloader expects for the plugin file.
+#   class Puppet::Util::Queue::SpecialMagicalClient < Messaging::SpecialMagic
+#       ...
+#       Puppet::Util::Queue.register_queue_type_class(self)
+#   end
+#
+# This module reduces the rightmost segment of the class name into a pretty symbol that will
+# serve as the queuing client's name.  Which means that the "SpecialMagicalClient" above will
+# be named <em>:special_magical_client</em> within the registry.
+#
+# Another class/module may mix-in this module, and may then make use of the registered clients.
+#   class Queue::Fue
+#       # mix it in at the class object level rather than instance level
+#       extend ::Puppet::Util::Queue
+#   end
+#
+# Queue::Fue instances can get a message queue client through the registry through the mixed-in method
+# +client+, which will return a class-wide singleton client instance, determined by +client_class+.
+#
+# The client plugins are expected to implement an interface similar to that of Stomp::Client:
+# * <tt>new</tt> should return a connected, ready-to-go client instance.  Note that no arguments are passed in.
+# * <tt>publish_message(queue, message)</tt> should publish the _message_ to the specified _queue_.
+# * <tt>subscribe(queue)</tt> _block_ subscribes to _queue_ and executes _block_ upon receiving a message.
+# * _queue_ names are simple names independent of the message broker or client library.  No "/queue/" prefixes like in Stomp::Client.
+module Puppet::Util::Queue
+  extend Puppet::Util::InstanceLoader
+  instance_load :queue_clients, 'puppet/util/queue'
+
+  # Adds a new class/queue-type pair to the registry.  The _type_ argument is optional; if not provided,
+  # _type_ defaults to a lowercased, underscored symbol programmatically derived from the rightmost
+  # namespace of <em>klass.name</em>.
+  #
+  #   # register with default name +:you+
+  #   register_queue_type(Foo::You)
+  #
+  #   # register with explicit queue type name +:myself+
+  #   register_queue_type(Foo::Me, :myself)
+  #
+  # If the type is already registered, an exception is thrown.  No checking is performed of _klass_,
+  # however; a given class could be registered any number of times, as long as the _type_ differs with
+  # each registration.
+  def self.register_queue_type(klass, type = nil)
+    type ||= queue_type_from_class(klass)
+    raise Puppet::Error, "Queue type #{type} is already registered" if instance_hash(:queue_clients).include?(type)
+    instance_hash(:queue_clients)[type] = klass
+  end
+
+  # Given a queue type symbol, returns the associated +Class+ object.  If the queue type is unknown
+  # (meaning it hasn't been registered with this module), an exception is thrown.
+  def self.queue_type_to_class(type)
+    c = loaded_instance :queue_clients, type
+    raise Puppet::Error, "Queue type #{type} is unknown." unless c
+    c
+  end
+
+  # Given a class object _klass_, returns the programmatic default queue type name symbol for _klass_.
+  # The algorithm is as shown in earlier examples; the last namespace segment of _klass.name_ is taken
+  # and converted from mixed case to underscore-separated lowercase, and interned.
+  #   queue_type_from_class(Foo) -> :foo
+  #   queue_type_from_class(Foo::Too) -> :too
+  #   queue_type_from_class(Foo::ForYouTwo) -> :for_you_too
+  #
+  # The implicit assumption here, consistent with Puppet's approach to plugins in general,
+  # is that all your client modules live in the same namespace, such that reduction to
+  # a flat namespace of symbols is reasonably safe.
+  def self.queue_type_from_class(klass)
+    # convert last segment of classname from studly caps to lower case with underscores, and symbolize
+    klass.name.split('::').pop.sub(/^[A-Z]/) {|c| c.downcase}.gsub(/[A-Z]/) {|c| '_' + c.downcase }.intern
+  end
+
+  # The class object for the client to be used, determined by queue configuration
+  # settings.
+  # Looks to the <tt>:queue_type</tt> configuration entry in the running application for
+  # the default queue type to use.
+  def client_class
+    Puppet::Util::Queue.queue_type_to_class(Puppet[:queue_type])
+  end
+
+  # Returns (instantiating as necessary) the singleton queue client instance, according to the
+  # client_class.  No arguments go to the client class constructor, meaning its up to the client class
+  # to know how to determine its queue message source (presumably through Puppet configuration data).
+  def client
+    @client ||= client_class.new
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/queue/stomp.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/queue/stomp.rb
new file mode 100644
index 0000000..4ed91e1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/queue/stomp.rb
@@ -0,0 +1,60 @@
+require 'puppet/util/queue'
+require 'stomp'
+require 'uri'
+
+# Implements the Ruby Stomp client as a queue type within the
+# Puppet::Indirector::Queue::Client registry, for use with the <tt>:queue</tt>
+# indirection terminus type.
+#
+# Looks to <tt>Puppet[:queue_source]</tt> for the sole argument to the
+# underlying Stomp::Client constructor; consequently, for this client to work,
+# <tt>Puppet[:queue_source]</tt> must use the Stomp::Client URL-like syntax
+# for identifying the Stomp message broker: <em>login:pass@host.port</em>
+class Puppet::Util::Queue::Stomp
+  attr_accessor :stomp_client
+
+  def initialize
+    begin
+      uri = URI.parse(Puppet[:queue_source])
+    rescue => detail
+      raise ArgumentError, "Could not create Stomp client instance - queue source #{Puppet[:queue_source]} is invalid: #{detail}", detail.backtrace
+    end
+    unless uri.scheme == "stomp"
+      raise ArgumentError, "Could not create Stomp client instance - queue source #{Puppet[:queue_source]} is not a Stomp URL: #{detail}"
+    end
+
+    begin
+      self.stomp_client = Stomp::Client.new(uri.user, uri.password, uri.host, uri.port, true)
+    rescue => detail
+      raise ArgumentError, "Could not create Stomp client instance with queue source #{Puppet[:queue_source]}: got internal Stomp client error #{detail}", detail.backtrace
+    end
+
+    # Identify the supported method for sending messages.
+    @method =
+      case
+      when stomp_client.respond_to?(:publish)
+        :publish
+      when stomp_client.respond_to?(:send)
+        :send
+      else
+        raise ArgumentError, "STOMP client does not respond to either publish or send"
+      end
+  end
+
+  def publish_message(target, msg)
+    stomp_client.__send__(@method, stompify_target(target), msg, :persistent => true)
+  end
+
+  def subscribe(target)
+    stomp_client.subscribe(stompify_target(target), :ack => :client) do |stomp_message|
+      yield(stomp_message.body)
+      stomp_client.acknowledge(stomp_message)
+    end
+  end
+
+  def stompify_target(target)
+    '/queue/' + target.to_s
+  end
+
+  Puppet::Util::Queue.register_queue_type(self, :stomp)
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rails/cache_accumulator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rails/cache_accumulator.rb
new file mode 100644
index 0000000..4b3717f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rails/cache_accumulator.rb
@@ -0,0 +1,65 @@
+require 'puppet/util'
+
+module Puppet::Util::CacheAccumulator
+  def self.included(klass)
+    klass.extend ClassMethods
+  end
+
+  class Base
+    attr_reader :klass, :attribute
+
+    def initialize(klass, attribute)
+      @klass = klass
+      @attribute = attribute
+      @find_or_create = "find_or_create_by_#{@attribute.to_s}".intern
+    end
+
+    def store
+      @store || reset
+    end
+
+    def reset
+      @store = {}
+    end
+
+    def find(*keys)
+      result = nil
+      if keys.length == 1
+        result = store[keys[0]] ||= @klass.send(@find_or_create, *keys)
+      else
+        found, missing = keys.partition {|k| store.include? k}
+        result = found.length
+        result += do_multi_find(missing) if missing.length > 0
+      end
+      result
+    end
+
+    def do_multi_find(keys)
+      result = 0
+      @klass.find(:all, :conditions => {@attribute => keys}).each do |obj|
+        store[obj.send(@attribute)] = obj
+        result += 1
+      end
+      result
+    end
+  end
+
+  module ClassMethods
+    def accumulates(*attributes)
+      attributes.each {|attrib| install_accumulator(attrib)}
+    end
+
+    def accumulators
+      @accumulators ||= {}
+    end
+
+    def install_accumulator(attribute)
+      self.accumulators[attribute] = Base.new(self, attribute)
+      module_eval %{
+        def self.accumulate_by_#{attribute.to_s}(*keys)
+          accumulators[:#{attribute.to_s}].find(*keys)
+        end
+      }
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rails/collection_merger.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rails/collection_merger.rb
new file mode 100644
index 0000000..f95d3d3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rails/collection_merger.rb
@@ -0,0 +1,17 @@
+module Puppet::Util::CollectionMerger
+  def ar_hash_merge(db_hash, mem_hash, args)
+    (db_hash.keys | mem_hash.keys).each do |key|
+      if (db_hash[key] && mem_hash[key])
+        # in both, update value
+        args[:modify].call(db_hash[key], mem_hash[key])
+      elsif (db_hash[key])
+        # in db, not memory, delete from database
+        args[:delete].call(db_hash[key])
+      else
+        # in mem, not in db, insert into the database
+        args[:create].call(key, mem_hash[key])
+      end
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rails/reference_serializer.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rails/reference_serializer.rb
new file mode 100644
index 0000000..9beeb00
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rails/reference_serializer.rb
@@ -0,0 +1,32 @@
+
+module Puppet::Util::ReferenceSerializer
+  def unserialize_value(val)
+    case val
+    when /^--- /
+      YAML.load(val)
+    when "true"
+      true
+    when "false"
+      false
+    else
+      val
+    end
+  end
+
+  def serialize_value(val)
+    case val
+    when Puppet::Resource
+      YAML.dump(val)
+    when true, false
+      # The database does this for us, but I prefer the
+      # methods be their exact inverses.
+      # Note that this means quoted booleans get returned
+      # as actual booleans, but there doesn't appear to be
+      # a way to fix that while keeping the ability to
+      # search for parameters set to true.
+      val.to_s
+    else
+      val
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc.rb
new file mode 100644
index 0000000..c2b9c15
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc.rb
@@ -0,0 +1,96 @@
+require 'puppet/util'
+module Puppet::Util::RDoc
+  module_function
+
+  # launch a rdoc documenation process
+  # with the files/dir passed in +files+
+  def rdoc(outputdir, files, charset = nil)
+    Puppet[:ignoreimport] = true
+
+    # then rdoc
+    require 'rdoc/rdoc'
+    require 'rdoc/options'
+
+    # load our parser
+    require 'puppet/util/rdoc/parser'
+
+    r = RDoc::RDoc.new
+
+    if Puppet.features.rdoc1?
+      RDoc::RDoc::GENERATORS["puppet"] = RDoc::RDoc::Generator.new(
+          "puppet/util/rdoc/generators/puppet_generator.rb",
+          :PuppetGenerator,
+          "puppet"
+        )
+    end
+
+    # specify our own format & where to output
+    options = [ "--fmt", "puppet",
+                "--quiet",
+                "--exclude", "/modules/[^/]*/spec/.*$",
+                "--exclude", "/modules/[^/]*/files/.*$",
+                "--exclude", "/modules/[^/]*/tests/.*$",
+                "--exclude", "/modules/[^/]*/templates/.*$",
+                "--op", outputdir ]
+
+    if !Puppet.features.rdoc1? || ::Options::OptionList.options.any? { |o| o[0] == "--force-update" } # Options is a root object in the rdoc1 namespace...
+      options << "--force-update"
+    end
+    options += [ "--charset", charset] if charset
+    # Rdoc root default is Dir.pwd, but the win32-dir gem monkey patchs Dir.pwd
+    # replacing Ruby's normal / with \.  When RDoc generates relative paths it
+    # uses relative_path_from that will generate errors when the slashes don't
+    # properly match.  This is a workaround for that issue.
+    if Puppet.features.microsoft_windows? && RDoc::VERSION !~ /^[0-3]\./
+      options += [ "--root", Dir.pwd.gsub(/\\/, '/')]
+    end
+    options += files
+
+    # launch the documentation process
+    r.document(options)
+  end
+
+  # launch an output to console manifest doc
+  def manifestdoc(files)
+    Puppet[:ignoreimport] = true
+    files.select { |f| FileTest.file?(f) }.each do |f|
+      parser = Puppet::Parser::Parser.new(Puppet.lookup(:current_environment))
+      parser.file = f
+      ast = parser.parse
+      output(f, ast)
+    end
+  end
+
+  # Ouputs to the console the documentation
+  # of a manifest
+  def output(file, ast)
+    astobj = []
+    ast.instantiate('').each do |resource_type|
+      astobj << resource_type if resource_type.file == file
+    end
+
+    astobj.sort! {|a,b| a.line <=> b.line }.each do |k|
+      output_astnode_doc(k)
+    end
+  end
+
+  def output_astnode_doc(ast)
+    puts ast.doc if !ast.doc.nil? and !ast.doc.empty?
+    if Puppet.settings[:document_all]
+      # scan each underlying resources to produce documentation
+      code = ast.code.children if ast.code.is_a?(Puppet::Parser::AST::ASTArray)
+      code ||= ast.code
+      output_resource_doc(code) unless code.nil?
+    end
+  end
+
+  def output_resource_doc(code)
+    code.sort { |a,b| a.line <=> b.line }.each do |stmt|
+      output_resource_doc(stmt.children) if stmt.is_a?(Puppet::Parser::AST::ASTArray)
+
+      if stmt.is_a?(Puppet::Parser::AST::Resource)
+        puts stmt.doc if !stmt.doc.nil? and !stmt.doc.empty?
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc/code_objects.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc/code_objects.rb
new file mode 100644
index 0000000..dd5cc2f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc/code_objects.rb
@@ -0,0 +1,334 @@
+require 'rdoc/code_objects'
+
+module RDoc
+
+  # This modules contains various class that are used to hold information
+  # about the various Puppet language structures we found while parsing.
+  #
+  # Those will be mapped to their html counterparts which are defined in
+  # PuppetGenerator.
+
+  # PuppetTopLevel is a top level (usually a .pp/.rb file)
+  module PuppetTopLevel
+    attr_accessor :module_name, :global
+  end
+
+  # Add top level comments to a class or module regardless of whether we are
+  # using rdoc1 or rdoc2+
+  # @api private
+  module AddClassModuleComment
+    def add_comment(comment, location = nil)
+      if PUPPET_RDOC_VERSION == 1
+        self.comment = comment
+      else
+        super
+      end
+    end
+  end
+
+  # PuppetModule holds a Puppet Module
+  # This is mapped to an HTMLPuppetModule
+  # it leverage the RDoc (ruby) module infrastructure
+  class PuppetModule < NormalModule
+    include AddClassModuleComment
+
+    attr_accessor :facts, :plugins
+
+    def initialize(name,superclass=nil)
+      @facts = []
+      @plugins = []
+      @nodes = {}
+      super(name,superclass)
+    end
+
+    def add_plugin(plugin)
+      if PUPPET_RDOC_VERSION == 1
+        add_to(@plugins, plugin)
+      else
+        add_plugin_rdoc2(plugin)
+      end
+    end
+
+    def add_plugin_rdoc2(plugin)
+      name = plugin.name
+      type = plugin.type
+      meth = AnyMethod.new("*args", name)
+      meth.params = "(*args)"
+      meth.visibility = :public
+      meth.document_self = true
+      meth.singleton = false
+      meth.comment = plugin.comment
+      if type == 'function'
+        @function_container ||= add_module(NormalModule, "__functions__")
+        @function_container.add_method(meth)
+      elsif type == 'type'
+        @type_container ||= add_module(NormalModule, "__types__")
+        @type_container.add_method(meth)
+      end
+    end
+
+    def add_fact(fact)
+      if PUPPET_RDOC_VERSION == 1
+        add_to(@facts, fact)
+      else
+        add_fact_rdoc2(fact)
+      end
+    end
+
+    def add_fact_rdoc2(fact)
+      @fact_container ||= add_module(NormalModule, "__facts__")
+      confine_str = fact.confine.empty? ? '' : fact.confine.to_s
+      const = Constant.new(fact.name, confine_str, fact.comment)
+      @fact_container.add_constant(const)
+    end
+
+    def add_node(name, superclass)
+      if PUPPET_RDOC_VERSION == 1
+        add_node_rdoc1(name, superclass)
+      else
+        add_node_rdoc2(name, superclass)
+      end
+    end
+
+    def add_node_rdoc1(name, superclass)
+      cls = @nodes[name]
+      unless cls
+        cls = PuppetNode.new(name, superclass)
+        @nodes[name] = cls if !@done_documenting
+        cls.parent = self
+        cls.section = @current_section
+      end
+      cls
+    end
+
+    # Adds a module called __nodes__ and adds nodes to it as classes
+    #
+    def add_node_rdoc2(name,superclass)
+      if cls = @nodes[name]
+        return cls
+      end
+      @node_container ||= add_module(NormalModule, "__nodes__")
+      cls = @node_container.add_class(PuppetNode, name, superclass)
+      @nodes[name] = cls if !@done_documenting
+      cls
+    end
+
+    def each_fact
+      @facts.each {|c| yield c}
+    end
+
+    def each_plugin
+      @plugins.each {|c| yield c}
+    end
+
+    def each_node
+      @nodes.each {|c| yield c}
+    end
+
+    def nodes
+      @nodes.values
+    end
+  end
+
+  # PuppetClass holds a puppet class
+  # It is mapped to a HTMLPuppetClass for display
+  # It leverages RDoc (ruby) Class
+  class PuppetClass < ClassModule
+    include AddClassModuleComment
+
+    attr_accessor :resource_list, :requires, :childs, :realizes
+
+    def initialize(name, superclass)
+      super(name,superclass)
+      @resource_list = []
+      @requires = []
+      @realizes = []
+      @childs = []
+    end
+
+    def aref_prefix
+      'puppet_class'
+    end
+
+    def add_resource(resource)
+      add_to(@resource_list, resource)
+    end
+
+    def is_module?
+      false
+    end
+
+    def superclass=(superclass)
+      @superclass = superclass
+    end
+
+    # we're (ab)using the RDoc require system here.
+    # we're adding a required Puppet class, overriding
+    # the RDoc add_require method which sees ruby required files.
+    def add_require(required)
+      add_to(@requires, required)
+    end
+
+    def add_realize(realized)
+      add_to(@realizes, realized)
+    end
+
+    def add_child(child)
+      @childs << child
+    end
+
+    # Look up the given symbol. RDoc only looks for class1::class2.method
+    # or class1::class2#method. Since our definitions are mapped to RDoc methods
+    # but are written class1::class2::define we need to perform the lookup by
+    # ourselves.
+    def find_symbol(symbol, method=nil)
+      result = super(symbol)
+      if not result and symbol =~ /::/
+        modules = symbol.split(/::/)
+        unless modules.empty?
+          module_name = modules.shift
+          result = find_module_named(module_name)
+          if result
+            last_name = ""
+            previous = nil
+            modules.each do |module_name|
+              previous = result
+              last_name = module_name
+              result = result.find_module_named(module_name)
+              break unless result
+            end
+            unless result
+              result = previous
+              method = last_name
+            end
+          end
+        end
+        if result && method
+          if !result.respond_to?(:find_local_symbol)
+            p result.name
+            p method
+            fail
+          end
+          result = result.find_local_symbol(method)
+        end
+      end
+      result
+    end
+
+  end
+
+  # PuppetNode holds a puppet node
+  # It is mapped to a HTMLPuppetNode for display
+  # A node is just a variation of a class
+  class PuppetNode < PuppetClass
+    include AddClassModuleComment
+
+    def initialize(name, superclass)
+      super(name,superclass)
+    end
+
+    def is_module?
+      false
+    end
+  end
+
+  # Plugin holds a native puppet plugin (function,type...)
+  # It is mapped to a HTMLPuppetPlugin for display
+  class Plugin < Context
+    attr_accessor :name, :type
+
+    def initialize(name, type)
+      super()
+      @name = name
+      @type = type
+      @comment = ""
+    end
+
+    def <=>(other)
+      @name <=> other.name
+    end
+
+    def full_name
+      @name
+    end
+
+    def http_url(prefix)
+      path = full_name.split("::")
+      File.join(prefix, *path) + ".html"
+    end
+
+    def is_fact?
+      false
+    end
+
+    def to_s
+      res = self.class.name + ": #{@name} (#{@type})\n"
+      res << @comment.to_s
+      res
+    end
+  end
+
+  # Fact holds a custom fact
+  # It is mapped to a HTMLPuppetPlugin for display
+  class Fact < Context
+    attr_accessor :name, :confine
+
+    def initialize(name, confine)
+      super()
+      @name = name
+      @confine = confine
+      @comment = ""
+    end
+
+    def <=>(other)
+      @name <=> other.name
+    end
+
+    def is_fact?
+      true
+    end
+
+    def full_name
+      @name
+    end
+
+    def to_s
+      res = self.class.name + ": #{@name}\n"
+      res << @comment.to_s
+      res
+    end
+  end
+
+  # PuppetResource holds a puppet resource
+  # It is mapped to a HTMLPuppetResource for display
+  # A resource is defined by its "normal" form Type[title]
+  class PuppetResource < CodeObject
+    attr_accessor :type, :title, :params
+
+    def initialize(type, title, comment, params)
+      super()
+      @type = type
+      @title = title
+      @comment = comment
+      @params = params
+    end
+
+    def <=>(other)
+      full_name <=> other.full_name
+    end
+
+    def full_name
+      @type + "[#{@title}]"
+    end
+
+    def name
+      full_name
+    end
+
+    def to_s
+      res = @type + "[#{@title}]\n"
+      res << @comment.to_s
+      res
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc/generators/puppet_generator.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc/generators/puppet_generator.rb
new file mode 100644
index 0000000..2ad15c2
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc/generators/puppet_generator.rb
@@ -0,0 +1,910 @@
+require 'rdoc/generators/html_generator'
+require 'puppet/util/rdoc/code_objects'
+require 'digest/md5'
+
+module Generators
+
+  # This module holds all the classes needed to generate the HTML documentation
+  # of a bunch of puppet manifests.
+  #
+  # It works by traversing all the code objects defined by the Puppet RDoc::Parser
+  # and produces HTML counterparts objects that in turns are used by RDoc template engine
+  # to produce the final HTML.
+  #
+  # It is also responsible of creating the whole directory hierarchy, and various index
+  # files.
+  #
+  # It is to be noted that the whole system is built on top of ruby RDoc. As such there
+  # is an implicit mapping of puppet entities to ruby entitites:
+  #
+  #         Puppet    =>    Ruby
+  #         ------------------------
+  #         Module          Module
+  #         Class           Class
+  #         Definition      Method
+  #         Resource
+  #         Node
+  #         Plugin
+  #         Fact
+
+  MODULE_DIR = "modules"
+  NODE_DIR = "nodes"
+  PLUGIN_DIR = "plugins"
+
+  # We're monkey patching RDoc markup to allow
+  # lowercase class1::class2::class3 crossref hyperlinking
+  module MarkUp
+    alias :old_markup :markup
+
+    def new_markup(str, remove_para=false)
+      first = @markup.nil?
+      res = old_markup(str, remove_para)
+      if first and not @markup.nil?
+        @markup.add_special(/\b([a-z]\w+(::\w+)*)/,:CROSSREF)
+        # we need to call it again, since we added a rule
+        res = old_markup(str, remove_para)
+      end
+      res
+    end
+    alias :markup :new_markup
+  end
+
+  # This is a specialized HTMLGenerator tailored to Puppet manifests
+  class PuppetGenerator < HTMLGenerator
+
+    def PuppetGenerator.for(options)
+      AllReferences::reset
+      HtmlMethod::reset
+
+      if options.all_one_file
+        PuppetGeneratorInOne.new(options)
+      else
+        PuppetGenerator.new(options)
+      end
+    end
+
+    def initialize(options) #:not-new:
+      @options    = options
+      load_html_template
+    end
+
+    # loads our own html template file
+    def load_html_template
+        require 'puppet/util/rdoc/generators/template/puppet/puppet'
+        extend RDoc::Page
+    rescue LoadError
+        $stderr.puts "Could not find Puppet template '#{template}'"
+        exit 99
+    end
+
+    def gen_method_index
+      # we don't generate an all define index
+      # as the presentation is per module/per class
+    end
+
+    # This is the central method, it generates the whole structures
+    # along with all the indices.
+    def generate_html
+      super
+      gen_into(@nodes)
+      gen_into(@plugins)
+    end
+
+    ##
+    # Generate:
+    #  the list of modules
+    #  the list of classes and definitions of a specific module
+    #  the list of all classes
+    #  the list of nodes
+    #  the list of resources
+    def build_indices
+      @allfiles = []
+      @nodes = []
+      @plugins = []
+
+      # contains all the seen modules
+      @modules = {}
+      @allclasses = {}
+
+      # remove unknown toplevels
+      # it can happen that RDoc triggers a different parser for some files (ie .c, .cc or .h)
+      # in this case RDoc generates a RDoc::TopLevel which we do not support in this generator
+      # So let's make sure we don't generate html for those.
+      @toplevels = @toplevels.select { |tl| tl.is_a? RDoc::PuppetTopLevel }
+
+      # build the modules, classes and per modules classes and define list
+      @toplevels.each do |toplevel|
+        next unless toplevel.document_self
+        file = HtmlFile.new(toplevel, @options, FILE_DIR)
+        classes = []
+        methods = []
+        modules = []
+        nodes = []
+
+        # find all classes of this toplevel
+        # store modules if we find one
+        toplevel.each_classmodule do |k|
+          generate_class_list(classes, modules, k, toplevel, CLASS_DIR)
+        end
+
+        # find all defines belonging to this toplevel
+        HtmlMethod.all_methods.each do |m|
+          # find parent module, check this method is not already
+          # defined.
+          if m.context.parent.toplevel === toplevel
+            methods << m
+          end
+        end
+
+        classes.each do |k|
+          @allclasses[k.index_name] = k if !@allclasses.has_key?(k.index_name)
+        end
+
+        # generate nodes and plugins found
+        classes.each do |k|
+          if k.context.is_module?
+            k.context.each_node do |name,node|
+              nodes << HTMLPuppetNode.new(node, toplevel, NODE_DIR, @options)
+              @nodes << nodes.last
+            end
+            k.context.each_plugin do |plugin|
+              @plugins << HTMLPuppetPlugin.new(plugin, toplevel, PLUGIN_DIR, @options)
+            end
+            k.context.each_fact do |fact|
+              @plugins << HTMLPuppetPlugin.new(fact, toplevel, PLUGIN_DIR, @options)
+            end
+          end
+        end
+
+        @files << file
+        @allfiles << { "file" => file, "modules" => modules, "classes" => classes, "methods" => methods, "nodes" => nodes }
+      end
+
+      # scan all classes to create the childs references
+      @allclasses.values.each do |klass|
+        if superklass = klass.context.superclass
+          if superklass = AllReferences[superklass] and (superklass.is_a?(HTMLPuppetClass) or superklass.is_a?(HTMLPuppetNode))
+            superklass.context.add_child(klass.context)
+          end
+        end
+      end
+
+      @classes = @allclasses.values
+    end
+
+    # produce a class/module list of HTMLPuppetModule/HTMLPuppetClass
+    # based on the code object traversal.
+    def generate_class_list(classes, modules, from, html_file, class_dir)
+      if from.is_module? and !@modules.has_key?(from.name)
+        k = HTMLPuppetModule.new(from, html_file, class_dir, @options)
+        classes << k
+        @modules[from.name] = k
+        modules << @modules[from.name]
+      elsif from.is_module?
+        modules << @modules[from.name]
+      elsif !from.is_module?
+        k = HTMLPuppetClass.new(from, html_file, class_dir, @options)
+        classes << k
+      end
+      from.each_classmodule do |mod|
+        generate_class_list(classes, modules, mod, html_file, class_dir)
+      end
+    end
+
+    # generate all the subdirectories, modules, classes and files
+    def gen_sub_directories
+        super
+        File.makedirs(MODULE_DIR)
+        File.makedirs(NODE_DIR)
+        File.makedirs(PLUGIN_DIR)
+    rescue
+        $stderr.puts $ERROR_INFO.message
+        exit 1
+    end
+
+    # generate the index of modules
+    def gen_file_index
+      gen_top_index(@modules.values, 'All Modules', RDoc::Page::TOP_INDEX, "fr_modules_index.html")
+    end
+
+    # generate a top index
+    def gen_top_index(collection, title, template, filename)
+      template = TemplatePage.new(RDoc::Page::FR_INDEX_BODY, template)
+      res = []
+      collection.sort.each do |f|
+        if f.document_self
+          res << { "classlist" => CGI.escapeHTML("#{MODULE_DIR}/fr_#{f.index_name}.html"), "module" => CGI.escapeHTML("#{CLASS_DIR}/#{f.index_name}.html"),"name" => CGI.escapeHTML(f.index_name) }
+        end
+      end
+
+      values = {
+        "entries"    => res,
+        'list_title' => CGI.escapeHTML(title),
+        'index_url'  => main_url,
+        'charset'    => @options.charset,
+        'style_url'  => style_url('', @options.css),
+      }
+
+      File.open(filename, "w") do |f|
+        template.write_html_on(f, values)
+      end
+    end
+
+    # generate the all classes index file and the combo index
+    def gen_class_index
+      gen_an_index(@classes, 'All Classes', RDoc::Page::CLASS_INDEX, "fr_class_index.html")
+      @allfiles.each do |file|
+        unless file['file'].context.file_relative_name =~ /\.rb$/
+
+          gen_composite_index(
+            file,
+              RDoc::Page::COMBO_INDEX,
+
+              "#{MODULE_DIR}/fr_#{file["file"].context.module_name}.html")
+        end
+      end
+    end
+
+    def gen_composite_index(collection, template, filename)\
+      return if Puppet::FileSystem.exist?(filename)
+
+      template = TemplatePage.new(RDoc::Page::FR_INDEX_BODY, template)
+      res1 = []
+      collection['classes'].sort.each do |f|
+        if f.document_self
+          res1 << { "href" => "../"+CGI.escapeHTML(f.path), "name" => CGI.escapeHTML(f.index_name) } unless f.context.is_module?
+        end
+      end
+
+      res2 = []
+      collection['methods'].sort.each do |f|
+        res2 << { "href" => "../#{f.path}", "name" => f.index_name.sub(/\(.*\)$/,'') } if f.document_self
+      end
+
+      module_name = []
+      res3 = []
+      res4 = []
+      collection['modules'].sort.each do |f|
+        module_name << { "href" => "../"+CGI.escapeHTML(f.path), "name" => CGI.escapeHTML(f.index_name) }
+        unless f.facts.nil?
+          f.facts.each do |fact|
+            res3 << {"href" => "../"+CGI.escapeHTML(AllReferences["PLUGIN(#{fact.name})"].path), "name" => CGI.escapeHTML(fact.name)}
+          end
+        end
+        unless f.plugins.nil?
+          f.plugins.each do |plugin|
+            res4 << {"href" => "../"+CGI.escapeHTML(AllReferences["PLUGIN(#{plugin.name})"].path), "name" => CGI.escapeHTML(plugin.name)}
+          end
+        end
+      end
+
+      res5 = []
+      collection['nodes'].sort.each do |f|
+        res5 << { "href" => "../"+CGI.escapeHTML(f.path), "name" => CGI.escapeHTML(f.name) } if f.document_self
+      end
+
+      values = {
+        "module" => module_name,
+        "classes"    => res1,
+        'classes_title' => CGI.escapeHTML("Classes"),
+        'defines_title' => CGI.escapeHTML("Defines"),
+        'facts_title' => CGI.escapeHTML("Custom Facts"),
+        'plugins_title' => CGI.escapeHTML("Plugins"),
+        'nodes_title' => CGI.escapeHTML("Nodes"),
+        'index_url'  => main_url,
+        'charset'    => @options.charset,
+        'style_url'  => style_url('', @options.css),
+      }
+
+      values["defines"] = res2 if res2.size>0
+      values["facts"] = res3 if res3.size>0
+      values["plugins"] = res4 if res4.size>0
+      values["nodes"] = res5 if res5.size>0
+
+      File.open(filename, "w") do |f|
+        template.write_html_on(f, values)
+      end
+    end
+
+    # returns the initial_page url
+    def main_url
+      main_page = @options.main_page
+      ref = nil
+      if main_page
+        ref = AllReferences[main_page]
+        if ref
+          ref = ref.path
+        else
+          $stderr.puts "Could not find main page #{main_page}"
+        end
+      end
+
+      unless ref
+        for file in @files
+          if file.document_self and file.context.global
+            ref = CGI.escapeHTML("#{CLASS_DIR}/#{file.context.module_name}.html")
+            break
+          end
+        end
+      end
+
+      unless ref
+        for file in @files
+          if file.document_self and !file.context.global
+            ref = CGI.escapeHTML("#{CLASS_DIR}/#{file.context.module_name}.html")
+            break
+          end
+        end
+      end
+
+      unless ref
+        $stderr.puts "Couldn't find anything to document"
+        $stderr.puts "Perhaps you've used :stopdoc: in all classes"
+        exit(1)
+      end
+
+      ref
+    end
+
+  end
+
+  # This module is used to generate a referenced full name list of ContextUser
+  module ReferencedListBuilder
+    def build_referenced_list(list)
+      res = []
+      list.each do |i|
+        ref = AllReferences[i.name] || @context.find_symbol(i.name)
+        ref = ref.viewer if ref and ref.respond_to?(:viewer)
+        name = i.respond_to?(:full_name) ? i.full_name : i.name
+        h_name = CGI.escapeHTML(name)
+        if ref and ref.document_self
+          path = url(ref.path)
+          res << { "name" => h_name, "aref" => path }
+        else
+          res << { "name" => h_name }
+        end
+      end
+      res
+    end
+  end
+
+  # This module is used to hold/generate a list of puppet resources
+  # this is used in HTMLPuppetClass and HTMLPuppetNode
+  module ResourceContainer
+    def collect_resources
+      list = @context.resource_list
+      @resources = list.collect {|m| HTMLPuppetResource.new(m, self, @options) }
+    end
+
+    def build_resource_summary_list(path_prefix='')
+      collect_resources unless @resources
+      resources = @resources.sort
+      res = []
+      resources.each do |r|
+        res << {
+          "name" => CGI.escapeHTML(r.name),
+          "aref" => CGI.escape(path_prefix)+"\#"+CGI.escape(r.aref)
+        }
+      end
+      res
+    end
+
+    def build_resource_detail_list(section)
+      outer = []
+      resources = @resources.sort
+      resources.each do |r|
+        row = {}
+        if r.section == section and r.document_self
+          row["name"]        = CGI.escapeHTML(r.name)
+          desc = r.description.strip
+          row["m_desc"]      = desc unless desc.empty?
+          row["aref"]        = r.aref
+          row["params"]      = r.params
+          outer << row
+        end
+      end
+      outer
+    end
+  end
+
+  class HTMLPuppetClass < HtmlClass
+    include ResourceContainer, ReferencedListBuilder
+
+    def value_hash
+      super
+      rl = build_resource_summary_list
+      @values["resources"] = rl unless rl.empty?
+
+      @context.sections.each do |section|
+        secdata = @values["sections"].select { |secdata| secdata["secsequence"] == section.sequence }
+        if secdata.size == 1
+          secdata = secdata[0]
+
+          rdl = build_resource_detail_list(section)
+          secdata["resource_list"] = rdl unless rdl.empty?
+        end
+      end
+
+      rl = build_require_list(@context)
+      @values["requires"] = rl unless rl.empty?
+
+      rl = build_realize_list(@context)
+      @values["realizes"] = rl unless rl.empty?
+
+      cl = build_child_list(@context)
+      @values["childs"] = cl unless cl.empty?
+
+      @values
+    end
+
+    def build_require_list(context)
+      build_referenced_list(context.requires)
+    end
+
+    def build_realize_list(context)
+      build_referenced_list(context.realizes)
+    end
+
+    def build_child_list(context)
+      build_referenced_list(context.childs)
+    end
+  end
+
+  class HTMLPuppetNode < ContextUser
+    include ResourceContainer, ReferencedListBuilder
+
+    attr_reader :path
+
+    def initialize(context, html_file, prefix, options)
+      super(context, options)
+
+      @html_file = html_file
+      @is_module = context.is_module?
+      @values    = {}
+
+      context.viewer = self
+
+      if options.all_one_file
+        @path = context.full_name
+      else
+        @path = http_url(context.full_name, prefix)
+      end
+
+      AllReferences.add("NODE(#{@context.full_name})", self)
+    end
+
+    def name
+      @context.name
+    end
+
+    # return the relative file name to store this class in,
+    # which is also its url
+    def http_url(full_name, prefix)
+      path = full_name.dup
+      path.gsub!(/<<\s*(\w*)/) { "from-#$1" } if path['<<']
+      File.join(prefix, path.split("::").collect { |p| Digest::MD5.hexdigest(p) }) + ".html"
+    end
+
+    def parent_name
+      @context.parent.full_name
+    end
+
+    def index_name
+      name
+    end
+
+    def write_on(f)
+      value_hash
+
+        template = TemplatePage.new(
+          RDoc::Page::BODYINC,
+            RDoc::Page::NODE_PAGE,
+
+            RDoc::Page::METHOD_LIST)
+      template.write_html_on(f, @values)
+    end
+
+    def value_hash
+      class_attribute_values
+      add_table_of_sections
+
+      @values["charset"] = @options.charset
+      @values["style_url"] = style_url(path, @options.css)
+
+      d = markup(@context.comment)
+      @values["description"] = d unless d.empty?
+
+      ml = build_method_summary_list
+      @values["methods"] = ml unless ml.empty?
+
+      rl = build_resource_summary_list
+      @values["resources"] = rl unless rl.empty?
+
+      il = build_include_list(@context)
+      @values["includes"] = il unless il.empty?
+
+      rl = build_require_list(@context)
+      @values["requires"] = rl unless rl.empty?
+
+      rl = build_realize_list(@context)
+      @values["realizes"] = rl unless rl.empty?
+
+      cl = build_child_list(@context)
+      @values["childs"] = cl unless cl.empty?
+
+      @values["sections"] = @context.sections.map do |section|
+
+        secdata = {
+          "sectitle" => section.title,
+          "secsequence" => section.sequence,
+          "seccomment" => markup(section.comment)
+        }
+
+        al = build_alias_summary_list(section)
+        secdata["aliases"] = al unless al.empty?
+
+        co = build_constants_summary_list(section)
+        secdata["constants"] = co unless co.empty?
+
+        al = build_attribute_list(section)
+        secdata["attributes"] = al unless al.empty?
+
+        cl = build_class_list(0, @context, section)
+        secdata["classlist"] = cl unless cl.empty?
+
+        mdl = build_method_detail_list(section)
+        secdata["method_list"] = mdl unless mdl.empty?
+
+        rdl = build_resource_detail_list(section)
+        secdata["resource_list"] = rdl unless rdl.empty?
+
+        secdata
+      end
+
+      @values
+    end
+
+    def build_attribute_list(section)
+      atts = @context.attributes.sort
+      res = []
+      atts.each do |att|
+        next unless att.section == section
+        if att.visibility == :public || att.visibility == :protected || @options.show_all
+          entry = {
+            "name"   => CGI.escapeHTML(att.name),
+            "rw"     => att.rw,
+            "a_desc" => markup(att.comment, true)
+          }
+          unless att.visibility == :public || att.visibility == :protected
+            entry["rw"] << "-"
+          end
+          res << entry
+        end
+      end
+      res
+    end
+
+    def class_attribute_values
+      h_name = CGI.escapeHTML(name)
+
+      @values["classmod"]  = "Node"
+      @values["title"]     = CGI.escapeHTML("#{@values['classmod']}: #{h_name}")
+
+      c = @context
+      c = c.parent while c and !c.diagram
+
+      @values["diagram"] = diagram_reference(c.diagram) if c && c.diagram
+
+      @values["full_name"] = h_name
+
+      parent_class = @context.superclass
+
+      if parent_class
+        @values["parent"] = CGI.escapeHTML(parent_class)
+
+        if parent_name
+          lookup = parent_name + "::#{parent_class}"
+        else
+          lookup = parent_class
+        end
+        lookup = "NODE(#{lookup})"
+        parent_url = AllReferences[lookup] || AllReferences[parent_class]
+        @values["par_url"] = aref_to(parent_url.path) if parent_url and parent_url.document_self
+      end
+
+      files = []
+      @context.in_files.each do |f|
+        res = {}
+        full_path = CGI.escapeHTML(f.file_absolute_name)
+
+        res["full_path"]     = full_path
+        res["full_path_url"] = aref_to(f.viewer.path) if f.document_self
+
+        res["cvsurl"] = cvs_url( @options.webcvs, full_path ) if @options.webcvs
+
+        files << res
+      end
+
+      @values['infiles'] = files
+    end
+
+    def build_require_list(context)
+      build_referenced_list(context.requires)
+    end
+
+    def build_realize_list(context)
+      build_referenced_list(context.realizes)
+    end
+
+    def build_child_list(context)
+      build_referenced_list(context.childs)
+    end
+
+    def <=>(other)
+      self.name <=> other.name
+    end
+  end
+
+  class HTMLPuppetModule < HtmlClass
+
+    def initialize(context, html_file, prefix, options)
+      super(context, html_file, prefix, options)
+    end
+
+    def value_hash
+      @values = super
+
+      fl = build_facts_summary_list
+      @values["facts"] = fl unless fl.empty?
+
+      pl = build_plugins_summary_list
+      @values["plugins"] = pl unless pl.empty?
+
+      nl = build_nodes_list(0, @context)
+      @values["nodelist"] = nl unless nl.empty?
+
+      @values
+    end
+
+    def build_nodes_list(level, context)
+      res = ""
+      prefix = "&nbsp;&nbsp;::" * level;
+
+      context.nodes.sort.each do |node|
+        if node.document_self
+          res <<
+          prefix <<
+          "Node " <<
+          href(url(node.viewer.path), "link", node.full_name) <<
+          "<br />\n"
+        end
+      end
+      res
+    end
+
+    def build_facts_summary_list
+      potentially_referenced_list(context.facts) {|fn| ["PLUGIN(#{fn})"] }
+    end
+
+    def build_plugins_summary_list
+      potentially_referenced_list(context.plugins) {|fn| ["PLUGIN(#{fn})"] }
+    end
+
+    def facts
+      @context.facts
+    end
+
+    def plugins
+      @context.plugins
+    end
+
+  end
+
+  class HTMLPuppetPlugin < ContextUser
+    attr_reader :path
+
+    def initialize(context, html_file, prefix, options)
+      super(context, options)
+
+      @html_file = html_file
+      @is_module = false
+      @values    = {}
+
+      context.viewer = self
+
+      if options.all_one_file
+        @path = context.full_name
+      else
+        @path = http_url(context.full_name, prefix)
+      end
+
+      AllReferences.add("PLUGIN(#{@context.full_name})", self)
+    end
+
+    def name
+      @context.name
+    end
+
+    # return the relative file name to store this class in,
+    # which is also its url
+    def http_url(full_name, prefix)
+      path = full_name.dup
+      path.gsub!(/<<\s*(\w*)/) { "from-#$1" } if path['<<']
+      File.join(prefix, path.split("::")) + ".html"
+    end
+
+    def parent_name
+      @context.parent.full_name
+    end
+
+    def index_name
+      name
+    end
+
+    def write_on(f)
+      value_hash
+
+        template = TemplatePage.new(
+          RDoc::Page::BODYINC,
+            RDoc::Page::PLUGIN_PAGE,
+
+            RDoc::Page::PLUGIN_LIST)
+      template.write_html_on(f, @values)
+    end
+
+    def value_hash
+      attribute_values
+      add_table_of_sections
+
+      @values["charset"] = @options.charset
+      @values["style_url"] = style_url(path, @options.css)
+
+      d = markup(@context.comment)
+      @values["description"] = d unless d.empty?
+
+      if context.is_fact?
+        unless context.confine.empty?
+          res = {}
+          res["type"] = context.confine[:type]
+          res["value"] = context.confine[:value]
+          @values["confine"] = [res]
+        end
+      else
+        @values["type"] = context.type
+      end
+
+      @values["sections"] = @context.sections.map do |section|
+        secdata = {
+          "sectitle" => section.title,
+          "secsequence" => section.sequence,
+          "seccomment" => markup(section.comment)
+        }
+        secdata
+      end
+
+      @values
+    end
+
+    def attribute_values
+      h_name = CGI.escapeHTML(name)
+
+      if @context.is_fact?
+        @values["classmod"]  = "Fact"
+      else
+        @values["classmod"]  = "Plugin"
+      end
+      @values["title"]     = "#{@values['classmod']}: #{h_name}"
+
+      @values["full_name"] = h_name
+
+      files = []
+      @context.in_files.each do |f|
+        res = {}
+        full_path = CGI.escapeHTML(f.file_absolute_name)
+
+        res["full_path"]     = full_path
+        res["full_path_url"] = aref_to(f.viewer.path) if f.document_self
+
+        res["cvsurl"] = cvs_url( @options.webcvs, full_path ) if @options.webcvs
+
+        files << res
+      end
+
+      @values['infiles'] = files
+    end
+
+    def <=>(other)
+      self.name <=> other.name
+    end
+
+  end
+
+  class HTMLPuppetResource
+    include MarkUp
+
+    attr_reader :context
+
+    @@seq = "R000000"
+
+    def initialize(context, html_class, options)
+      @context    = context
+      @html_class = html_class
+      @options    = options
+      @@seq       = @@seq.succ
+      @seq        = @@seq
+
+      context.viewer = self
+
+      AllReferences.add(name, self)
+    end
+
+    def as_href(from_path)
+      if @options.all_one_file
+        "##{path}"
+      else
+        HTMLGenerator.gen_url(from_path, path)
+      end
+    end
+
+    def name
+      @context.name
+    end
+
+    def section
+      @context.section
+    end
+
+    def index_name
+      "#{@context.name}"
+    end
+
+    def params
+      @context.params
+    end
+
+    def parent_name
+      if @context.parent.parent
+        @context.parent.parent.full_name
+      else
+        nil
+      end
+    end
+
+    def aref
+      @seq
+    end
+
+    def path
+      if @options.all_one_file
+        aref
+      else
+        @html_class.path + "##{aref}"
+      end
+    end
+
+    def description
+      markup(@context.comment)
+    end
+
+    def <=>(other)
+      @context <=> other.context
+    end
+
+    def document_self
+      @context.document_self
+    end
+
+    def find_symbol(symbol, method=nil)
+      res = @context.parent.find_symbol(symbol, method)
+      res &&= res.viewer
+    end
+
+  end
+
+  class PuppetGeneratorInOne < HTMLGeneratorInOne
+    def gen_method_index
+      gen_an_index(HtmlMethod.all_methods, 'Defines')
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc/generators/template/puppet/puppet.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc/generators/template/puppet/puppet.rb
new file mode 100644
index 0000000..6a1329a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc/generators/template/puppet/puppet.rb
@@ -0,0 +1,1085 @@
+#
+# = CSS2 RDoc HTML template
+#
+# This is a template for RDoc that uses XHTML 1.0 Transitional and dictates a
+# bit more of the appearance of the output to cascading stylesheets than the
+# default. It was designed for clean inline code display, and uses DHTMl to
+# toggle the visbility of each method's source with each click on the '[source]'
+# link.
+#
+# == Authors
+#
+# * Michael Granger <ged@FaerieMUD.org>
+#
+# Copyright (c) 2002, 2003 The FaerieMUD Consortium. Some rights reserved.
+#
+# This work is licensed under the Creative Commons Attribution License. To view
+# a copy of this license, visit http://creativecommons.org/licenses/by/1.0/ or
+# send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California
+# 94305, USA.
+#
+
+module RDoc
+  module Page
+
+    FONTS = "Verdana,Arial,Helvetica,sans-serif"
+
+STYLE = %{
+/* Reset */
+html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-weight:inherit;font-style:inherit;font-size:100%;font-family:inherit;vertical-align:baseline;}
+:focus{outline:0;}
+body{line-height:1;color:#282828;background:#fff;}
+ol,ul{list-style:none;}
+table{border-collapse:separate;border-spacing:0;}
+caption,th,td{text-align:left;font-weight:normal;}
+blockquote:before,blockquote:after,q:before,q:after{content:"";}
+blockquote,q{quotes:"""";}
+
+body {
+    font-family: Verdana,Arial,Helvetica,sans-serif;
+    font-size: 0.9em;
+}
+
+pre {
+    background: none repeat scroll 0 0 #F7F7F7;
+    border: 1px dashed #DDDDDD;
+    color: #555555;
+    font-family: courier;
+    margin: 10px 19px;
+    padding: 10px;
+ }
+
+h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
+h1 { font-size: 1.2em; }
+h2,h3,h4 { margin-top: 1em; color:#558; }
+h2,h3 { font-size: 1.1em; }
+
+a { color: #037; text-decoration: none; }
+a:hover { color: #04d; }
+
+/* Override the base stylesheet's Anchor inside a table cell */
+td > a {
+  background: transparent;
+  color: #039;
+  text-decoration: none;
+}
+
+/* and inside a section title */
+.section-title > a {
+  background: transparent;
+  color: #eee;
+  text-decoration: none;
+}
+
+/* === Structural elements =================================== */
+
+div#index {
+    padding: 0;
+}
+
+
+div#index a {
+	display:inline-block;
+	padding:2px 10px;
+}
+
+
+div#index .section-bar {
+	background: #ffe;
+	padding:10px;
+}
+
+
+div#classHeader, div#fileHeader {
+    border-bottom: 1px solid #ddd;
+	padding:10px;
+	font-size:0.9em;
+}
+
+div#classHeader a, div#fileHeader a {
+    background: inherit;
+    color: white;
+}
+
+div#classHeader td, div#fileHeader td {
+    color: white;
+	padding:3px;
+	font-size:0.9em;
+}
+
+
+div#fileHeader {
+    background: #057;
+}
+
+div#classHeader {
+    background: #048;
+}
+
+div#nodeHeader {
+    background: #7f7f7f;
+}
+
+.class-name-in-header {
+  font-weight: bold;
+}
+
+
+div#bodyContent {
+    padding: 10px;
+}
+
+div#description {
+    padding: 10px;
+    background: #f5f5f5;
+    border: 1px dotted #ddd;
+	line-height:1.2em;
+}
+
+div#description h1,h2,h3,h4,h5,h6 {
+    color: #125;;
+    background: transparent;
+}
+
+div#validator-badges {
+    text-align: center;
+}
+div#validator-badges img { border: 0; }
+
+div#copyright {
+    color: #333;
+    background: #efefef;
+    font: 0.75em sans-serif;
+    margin-top: 5em;
+    margin-bottom: 0;
+    padding: 0.5em 2em;
+}
+
+
+/* === Classes =================================== */
+
+table.header-table {
+    color: white;
+    font-size: small;
+}
+
+.type-note {
+    font-size: small;
+    color: #DEDEDE;
+}
+
+.xxsection-bar {
+    background: #eee;
+    color: #333;
+    padding: 3px;
+}
+
+.section-bar {
+   color: #333;
+   border-bottom: 1px solid #ddd;
+   padding:10px 0;
+   margin:5px 0 10px 0;
+}
+
+div#class-list, div#methods, div#includes, div#resources, div#requires, div#realizes, div#attribute-list { padding:10px; }
+
+.section-title {
+    background: #79a;
+    color: #eee;
+    padding: 3px;
+    margin-top: 2em;
+    border: 1px solid #999;
+}
+
+.top-aligned-row {  vertical-align: top }
+.bottom-aligned-row { vertical-align: bottom }
+
+/* --- Context section classes ----------------------- */
+
+.context-row { }
+.context-item-name { font-family: monospace; font-weight: bold; color: black; }
+.context-item-value { font-size: small; color: #448; }
+.context-item-desc { color: #333; padding-left: 2em; }
+
+/* --- Method classes -------------------------- */
+.method-detail {
+    background: #f5f5f5;
+}
+.method-heading {
+  color: #333;
+  font-style:italic;
+  background: #ddd;
+  padding:5px 10px;
+}
+.method-signature { color: black; background: inherit; }
+.method-name { font-weight: bold; }
+.method-args { font-style: italic; }
+.method-description { padding: 10px 10px 20px 10px; }
+
+/* --- Source code sections -------------------- */
+
+a.source-toggle { font-size: 90%; }
+div.method-source-code {
+    background: #262626;
+    color: #ffdead;
+    margin: 1em;
+    padding: 0.5em;
+    border: 1px dashed #999;
+    overflow: hidden;
+}
+
+div.method-source-code pre { color: #ffdead; overflow: hidden; }
+
+/* --- Ruby keyword styles --------------------- */
+
+.standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
+
+.ruby-constant  { color: #7fffd4; background: transparent; }
+.ruby-keyword { color: #00ffff; background: transparent; }
+.ruby-ivar    { color: #eedd82; background: transparent; }
+.ruby-operator  { color: #00ffee; background: transparent; }
+.ruby-identifier { color: #ffdead; background: transparent; }
+.ruby-node    { color: #ffa07a; background: transparent; }
+.ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
+.ruby-regexp  { color: #ffa07a; background: transparent; }
+.ruby-value   { color: #7fffd4; background: transparent; }
+}
+
+
+#####################################################################
+### H E A D E R   T E M P L A T E
+#####################################################################
+
+XHTML_PREAMBLE = %{<?xml version="1.0" encoding="%charset%"?>
+<!DOCTYPE html
+     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+}
+
+HEADER = XHTML_PREAMBLE + %{
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+  <title>%title%</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
+  <meta http-equiv="Content-Script-Type" content="text/javascript" />
+  <link rel="stylesheet" href="%style_url%" type="text/css" media="screen" />
+  <script type="text/javascript">
+  // <![CDATA[
+
+  function popupCode( url ) {
+    window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+  }
+
+  function toggleCode( id ) {
+    if ( document.getElementById )
+      elem = document.getElementById( id );
+    else if ( document.all )
+      elem = eval( "document.all." + id );
+    else
+      return false;
+
+    elemStyle = elem.style;
+
+    if ( elemStyle.display != "block" ) {
+      elemStyle.display = "block"
+    } else {
+      elemStyle.display = "none"
+    }
+
+    return true;
+  }
+
+  // Make codeblocks hidden by default
+  document.writeln( "<style type=\\"text/css\\">div.method-source-code { display: none }</style>" )
+
+  // ]]>
+  </script>
+
+</head>
+<body>
+}
+
+
+#####################################################################
+### C O N T E X T   C O N T E N T   T E M P L A T E
+#####################################################################
+
+CONTEXT_CONTENT = %{
+}
+
+
+#####################################################################
+### F O O T E R   T E M P L A T E
+#####################################################################
+FOOTER = %{
+<div id="validator-badges">
+  <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
+</div>
+
+</body>
+</html>
+}
+
+
+#####################################################################
+### F I L E   P A G E   H E A D E R   T E M P L A T E
+#####################################################################
+
+FILE_PAGE = %{
+  <div id="fileHeader">
+    <h1>%short_name%</h1>
+    <table class="header-table">
+    <tr class="top-aligned-row">
+      <td><strong>Path:</strong></td>
+      <td>%full_path%
+IF:cvsurl
+        &nbsp;(<a href="%cvsurl%"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
+ENDIF:cvsurl
+      </td>
+    </tr>
+    <tr class="top-aligned-row">
+      <td><strong>Last Update:</strong></td>
+      <td>%dtm_modified%</td>
+    </tr>
+    </table>
+  </div>
+}
+
+
+#####################################################################
+### C L A S S   P A G E   H E A D E R   T E M P L A T E
+#####################################################################
+
+CLASS_PAGE = %{
+    <div id="classHeader">
+        <table class="header-table">
+        <tr class="top-aligned-row">
+          <td><strong>%classmod%</strong></td>
+          <td class="class-name-in-header">%full_name%</td>
+        </tr>
+        <tr class="top-aligned-row">
+            <td><strong>In:</strong></td>
+            <td>
+START:infiles
+IF:full_path_url
+                <a href="%full_path_url%">
+ENDIF:full_path_url
+                %full_path%
+IF:full_path_url
+                </a>
+ENDIF:full_path_url
+IF:cvsurl
+        &nbsp;(<a href="%cvsurl%"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
+ENDIF:cvsurl
+        <br />
+END:infiles
+            </td>
+        </tr>
+
+IF:parent
+        <tr class="top-aligned-row">
+            <td><strong>Parent:</strong></td>
+            <td>
+IF:par_url
+                <a href="%par_url%">
+ENDIF:par_url
+                %parent%
+IF:par_url
+               </a>
+ENDIF:par_url
+            </td>
+        </tr>
+ENDIF:parent
+        </table>
+    </div>
+}
+
+NODE_PAGE = %{
+    <div id="nodeHeader">
+        <table class="header-table">
+        <tr class="top-aligned-row">
+          <td><strong>%classmod%</strong></td>
+          <td class="class-name-in-header">%full_name%</td>
+        </tr>
+        <tr class="top-aligned-row">
+            <td><strong>In:</strong></td>
+            <td>
+START:infiles
+IF:full_path_url
+                <a href="%full_path_url%">
+ENDIF:full_path_url
+                %full_path%
+IF:full_path_url
+                </a>
+ENDIF:full_path_url
+IF:cvsurl
+        &nbsp;(<a href="%cvsurl%"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
+ENDIF:cvsurl
+        <br />
+END:infiles
+            </td>
+        </tr>
+
+IF:parent
+        <tr class="top-aligned-row">
+            <td><strong>Parent:</strong></td>
+            <td>
+IF:par_url
+                <a href="%par_url%">
+ENDIF:par_url
+                %parent%
+IF:par_url
+               </a>
+ENDIF:par_url
+            </td>
+        </tr>
+ENDIF:parent
+        </table>
+    </div>
+}
+
+PLUGIN_PAGE = %{
+    <div id="classHeader">
+        <table class="header-table">
+        <tr class="top-aligned-row">
+          <td><strong>%classmod%</strong></td>
+          <td class="class-name-in-header">%full_name%</td>
+        </tr>
+        <tr class="top-aligned-row">
+            <td><strong>In:</strong></td>
+            <td>
+START:infiles
+IF:full_path_url
+                <a href="%full_path_url%">
+ENDIF:full_path_url
+                %full_path%
+IF:full_path_url
+                </a>
+ENDIF:full_path_url
+IF:cvsurl
+        &nbsp;(<a href="%cvsurl%"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
+ENDIF:cvsurl
+        <br />
+END:infiles
+            </td>
+        </tr>
+        </table>
+    </div>
+}
+
+
+#####################################################################
+### M E T H O D   L I S T   T E M P L A T E
+#####################################################################
+
+PLUGIN_LIST = %{
+
+  <div id="contextContent">
+IF:description
+    <div id="description">
+      %description%
+    </div>
+ENDIF:description
+
+
+IF:toc
+    <div id="contents-list">
+      <h3 class="section-bar">Contents</h3>
+      <ul>
+START:toc
+      <li><a href="#%href%">%secname%</a></li>
+END:toc
+     </ul>
+ENDIF:toc
+   </div>
+
+  </div>
+
+<!-- Confine -->
+IF:confine
+START:confine
+  <div id="attribute-list">
+    <h3 class="section-bar">Confine</h3>
+    %type%&nbsp;%value%
+    <div class="name-list">
+    </div>
+  </div>
+END:confine
+ENDIF:confine
+
+<!-- Type -->
+IF:type
+  <div id="attribute-list">
+    <h3 class="section-bar">Type</h3>
+    %type%
+    <div class="name-list">
+    </div>
+  </div>
+ENDIF:type
+
+START:sections
+    <div id="section">
+IF:sectitle
+      <h2 class="section-title"><a name="%secsequence%">%sectitle%</a></h2>
+IF:seccomment
+      <div class="section-comment">
+        %seccomment%
+      </div>
+ENDIF:seccomment
+ENDIF:sectitle
+END:sections
+}
+
+
+METHOD_LIST = %{
+
+  <div id="contextContent">
+IF:diagram
+    <div id="diagram">
+      %diagram%
+    </div>
+ENDIF:diagram
+
+IF:description
+    <div id="description">
+      %description%
+    </div>
+ENDIF:description
+
+
+IF:toc
+    <div id="contents-list">
+      <h3 class="section-bar">Contents</h3>
+      <ul>
+START:toc
+      <li><a href="#%href%">%secname%</a></li>
+END:toc
+     </ul>
+ENDIF:toc
+   </div>
+
+<!-- if childs -->
+IF:childs
+       <div id="childs">
+         <h3 class="section-bar">Inherited by</h3>
+         <div id="childs-list">
+START:childs
+           <span class="child-name">HREF:aref:name:</span>
+END:childs
+         </div>
+       </div>
+ENDIF:childs
+
+IF:methods
+    <div id="method-list">
+      <h3 class="section-bar">Defines</h3>
+
+      <div class="name-list">
+START:methods
+      HREF:aref:name:&nbsp;&nbsp;
+END:methods
+      </div>
+    </div>
+ENDIF:methods
+
+IF:resources
+    <div id="method-list">
+      <h3 class="section-bar">Resources</h3>
+
+      <div class="name-list">
+START:resources
+      HREF:aref:name:&nbsp;&nbsp;
+END:resources
+      </div>
+    </div>
+ENDIF:resources
+
+  </div>
+
+
+    <!-- if includes -->
+IF:includes
+    <div id="includes">
+      <h3 class="section-bar">Included Classes</h3>
+
+      <div id="includes-list">
+START:includes
+        <span class="include-name">HREF:aref:name:</span>
+END:includes
+      </div>
+    </div>
+ENDIF:includes
+
+    <!-- if requires -->
+IF:requires
+    <div id="requires">
+      <h3 class="section-bar">Required Classes</h3>
+
+      <div id="requires-list">
+START:requires
+        <span class="require-name">HREF:aref:name:</span>
+END:requires
+      </div>
+    </div>
+ENDIF:requires
+
+    <!-- if realizes -->
+IF:realizes
+    <div id="realizes">
+      <h3 class="section-bar">Realized Resources</h3>
+
+      <div id="realizes-list">
+START:realizes
+        <span class="realizes-name">HREF:aref:name:</span>
+END:realizes
+      </div>
+    </div>
+ENDIF:realizes
+
+START:sections
+    <div id="section">
+IF:sectitle
+      <h2 class="section-title"><a name="%secsequence%">%sectitle%</a></h2>
+IF:seccomment
+      <div class="section-comment">
+        %seccomment%
+      </div>
+ENDIF:seccomment
+ENDIF:sectitle
+
+<!-- if facts -->
+IF:facts
+    <div id="class-list">
+      <h3 class="section-bar">Custom Facts</h3>
+START:facts
+            HREF:aref:name:&nbsp;&nbsp;
+END:facts
+    </div>
+ENDIF:facts
+
+<!-- if plugins -->
+IF:plugins
+    <div id="class-list">
+      <h3 class="section-bar">Plugins</h3>
+START:plugins
+HREF:aref:name:&nbsp;&nbsp;
+END:plugins
+    </div>
+ENDIF:plugins
+
+<!-- if nodes -->
+IF:nodelist
+    <div id="class-list">
+      <h3 class="section-bar">Nodes</h3>
+
+      %nodelist%
+    </div>
+ENDIF:nodelist
+
+<!-- if class -->
+IF:classlist
+    <div id="class-list">
+      <h3 class="section-bar">Classes and Modules</h3>
+
+      %classlist%
+    </div>
+ENDIF:classlist
+
+IF:constants
+    <div id="constants-list">
+      <h3 class="section-bar">Global Variables</h3>
+
+      <div class="name-list">
+        <table summary="Variables">
+START:constants
+        <tr class="top-aligned-row context-row">
+          <td class="context-item-name">%name%</td>
+          <td>=</td>
+          <td class="context-item-value">%value%</td>
+IF:desc
+          <td width="3em">&nbsp;</td>
+          <td class="context-item-desc">%desc%</td>
+ENDIF:desc
+        </tr>
+END:constants
+        </table>
+      </div>
+    </div>
+ENDIF:constants
+
+IF:aliases
+    <div id="aliases-list">
+      <h3 class="section-bar">External Aliases</h3>
+
+      <div class="name-list">
+                        <table summary="aliases">
+START:aliases
+        <tr class="top-aligned-row context-row">
+          <td class="context-item-name">%old_name%</td>
+          <td>-&gt;</td>
+          <td class="context-item-value">%new_name%</td>
+        </tr>
+IF:desc
+      <tr class="top-aligned-row context-row">
+        <td>&nbsp;</td>
+        <td colspan="2" class="context-item-desc">%desc%</td>
+      </tr>
+ENDIF:desc
+END:aliases
+                        </table>
+      </div>
+    </div>
+ENDIF:aliases
+
+
+IF:attributes
+    <div id="attribute-list">
+      <h3 class="section-bar">Attributes</h3>
+
+      <div class="name-list">
+        <table>
+START:attributes
+        <tr class="top-aligned-row context-row">
+          <td class="context-item-name">%name%</td>
+IF:rw
+          <td class="context-item-value">&nbsp;[%rw%]&nbsp;</td>
+ENDIF:rw
+IFNOT:rw
+          <td class="context-item-value">&nbsp;&nbsp;</td>
+ENDIF:rw
+          <td class="context-item-desc">%a_desc%</td>
+        </tr>
+END:attributes
+        </table>
+      </div>
+    </div>
+ENDIF:attributes
+
+
+
+    <!-- if method_list -->
+IF:method_list
+    <div id="methods">
+START:method_list
+IF:methods
+      <h3 class="section-bar">Defines</h3>
+
+START:methods
+      <div id="method-%aref%" class="method-detail">
+        <a name="%aref%"></a>
+
+        <div class="method-heading">
+IF:codeurl
+          <a href="%codeurl%" target="Code" class="method-signature"
+            onclick="popupCode('%codeurl%');return false;">
+ENDIF:codeurl
+IF:sourcecode
+          <a href="#%aref%" class="method-signature">
+ENDIF:sourcecode
+IF:callseq
+          <span class="method-name">%callseq%</span>
+ENDIF:callseq
+IFNOT:callseq
+          <span class="method-name">%name%</span><span class="method-args">%params%</span>
+ENDIF:callseq
+IF:codeurl
+          </a>
+ENDIF:codeurl
+IF:sourcecode
+          </a>
+ENDIF:sourcecode
+        </div>
+
+        <div class="method-description">
+IF:m_desc
+          %m_desc%
+ENDIF:m_desc
+IF:sourcecode
+          <p><a class="source-toggle" href="#"
+            onclick="toggleCode('%aref%-source');return false;">[Source]</a></p>
+          <div class="method-source-code" id="%aref%-source">
+<pre>
+%sourcecode%
+</pre>
+          </div>
+ENDIF:sourcecode
+        </div>
+      </div>
+
+END:methods
+ENDIF:methods
+END:method_list
+
+    </div>
+ENDIF:method_list
+
+
+    <!-- if resource_list -->
+IF:resource_list
+    <div id="resources">
+    <h3 class="section-bar">Resources</h3>
+START:resource_list
+
+      <div id="method-%aref%" class="method-detail">
+        <a name="%aref%"></a>
+
+        <div class="method-heading">
+          <span class="method-name">%name%</span><br />
+IF:params
+START:params
+          &nbsp;&nbsp;&nbsp;<span class="method-args">%name% => %value%</span><br />
+END:params
+ENDIF:params
+        </div>
+
+        <div class="method-description">
+IF:m_desc
+          %m_desc%
+ENDIF:m_desc
+        </div>
+      </div>
+END:resource_list
+
+    </div>
+ENDIF:resource_list
+
+END:sections
+}
+
+
+#####################################################################
+### B O D Y   T E M P L A T E
+#####################################################################
+
+BODY = HEADER + %{
+
+!INCLUDE!  <!-- banner header -->
+
+  <div id="bodyContent">
+
+} +  METHOD_LIST + %{
+
+  </div>
+
+} + FOOTER
+
+BODYINC = HEADER + %{
+
+!INCLUDE!  <!-- banner header -->
+
+  <div id="bodyContent">
+
+!INCLUDE!
+
+  </div>
+
+} + FOOTER
+
+
+
+#####################################################################
+### S O U R C E   C O D E   T E M P L A T E
+#####################################################################
+
+SRC_PAGE = XHTML_PREAMBLE + %{
+<html>
+<head>
+  <title>%title%</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
+  <link rel="stylesheet" href="%style_url%" type="text/css" media="screen" />
+</head>
+<body class="standalone-code">
+  <pre>%code%</pre>
+</body>
+</html>
+}
+
+
+#####################################################################
+### I N D E X   F I L E   T E M P L A T E S
+#####################################################################
+
+FR_INDEX_BODY = %{
+!INCLUDE!
+}
+
+FILE_INDEX = XHTML_PREAMBLE + %{
+<!--
+
+    %list_title%
+
+  -->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+  <title>%list_title%</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
+  <link rel="stylesheet" href="%style_url%" type="text/css" />
+  <base target="docwin" />
+</head>
+<body>
+<div id="index">
+  <h1 class="section-bar">%list_title%</h1>
+  <div id="index-entries">
+START:entries
+    <a href="%href%">%name%</a><br />
+END:entries
+  </div>
+</div>
+</body>
+</html>
+}
+
+TOP_INDEX = XHTML_PREAMBLE + %{
+<!--
+
+    %list_title%
+
+  -->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+  <title>%list_title%</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
+  <link rel="stylesheet" href="%style_url%" type="text/css" />
+  <base target="classes" />
+  <SCRIPT LANGUAGE="JavaScript">
+  <!--
+  function load(classlist,module) {
+      parent.classes.location.href = classlist;
+      parent.docwin.location.href = module;
+  }
+  //--></SCRIPT>
+</head>
+<body>
+<div id="index">
+  <h1 class="section-bar">%list_title%</h1>
+  <div id="index-entries">
+START:entries
+    <a href="%classlist%" onclick="load('%classlist%','%module%'); return true;">%name%</a><br />
+END:entries
+  </div>
+</div>
+</body>
+</html>
+}
+
+
+CLASS_INDEX = FILE_INDEX
+METHOD_INDEX = FILE_INDEX
+
+COMBO_INDEX = XHTML_PREAMBLE + %{
+<!--
+
+    %classes_title% &amp; %defines_title%
+
+  -->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+  <title>%classes_title% &amp; %defines_title%</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
+  <link rel="stylesheet" href="../%style_url%" type="text/css" />
+  <base target="docwin" />
+  <SCRIPT LANGUAGE="JavaScript">
+  <!--
+  function load(url) {
+      parent.docwin.location.href = url;
+  }
+  //--></SCRIPT>
+
+</head>
+<body>
+<div id="index">
+
+    <a href="../fr_class_index.html" target="classes">All Classes</a><br />
+
+
+<h1 class="section-bar">Module</h1>
+  <div id="index-entries">
+START:module
+    <a href="%href%" onclick="load('%href%'); return true;">%name%</a><br />
+END:module
+  </div>
+  </div>
+<div id="index">
+
+IF:nodes
+  <h1 class="section-bar">%nodes_title%</h1>
+  <div id="index-entries">
+START:nodes
+<a href="%href%" onclick="load('%href%'); return true;">%name%</a><br />
+END:nodes
+  </div>
+ENDIF:nodes
+
+IF:classes
+  <h1 class="section-bar">%classes_title%</h1>
+  <div id="index-entries">
+START:classes
+<a href="%href%" onclick="load('%href%'); return true;">%name%</a><br />
+END:classes
+  </div>
+ENDIF:classes
+
+IF:defines
+  <h1 class="section-bar">%defines_title%</h1>
+    <div id="index-entries">
+START:defines
+<a href="%href%" onclick="load('%href%'); return true;">%name%</a><br />
+END:defines
+    </div>
+ENDIF:defines
+
+IF:facts
+  <h1 class="section-bar">%facts_title%</h1>
+    <div id="index-entries">
+START:facts
+<a href="%href%" onclick="load('%href%'); return true;">%name%</a><br />
+END:facts
+    </div>
+ENDIF:facts
+
+
+IF:plugins
+  <h1 class="section-bar">%plugins_title%</h1>
+    <div id="index-entries">
+START:plugins
+<a href="%href%" onclick="load('%href%'); return true;">%name%</a><br />
+END:plugins
+    </div>
+ENDIF:plugins
+
+</div>
+</body>
+</html>
+}
+
+INDEX = %{<?xml version="1.0" encoding="%charset%"?>
+<!DOCTYPE html
+     PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
+
+<!--
+
+    %title%
+
+  -->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+  <title>%title%</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
+</head>
+<frameset cols="20%, 80%">
+    <frameset rows="30%,70%">
+        <frame src="fr_modules_index.html"  title="All Modules" />
+        <frame src="fr_class_index.html" name="classes" title="Classes & Defines" />
+    </frameset>
+    <frame src="%initial_page%" name="docwin" />
+</frameset>
+</html>
+}
+
+
+
+  end # module Page
+end # class RDoc
+
+require 'rdoc/generators/template/html/one_page_html'
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc/parser.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc/parser.rb
new file mode 100644
index 0000000..6ecd492
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc/parser.rb
@@ -0,0 +1,22 @@
+# Puppet "parser" for the rdoc system
+# The parser uses puppet parser and traverse the AST to instruct RDoc about
+# our current structures. It also parses ruby files that could contain
+# either custom facts or puppet plugins (functions, types...)
+
+# rdoc mandatory includes
+require "rdoc/code_objects"
+require "puppet/util/rdoc/code_objects"
+
+begin
+  # Rdoc 1 imports
+  require "rdoc/tokenstream"
+  require "rdoc/markup/simple_markup/preprocess"
+  require "rdoc/parsers/parserfactory"
+  require "puppet/util/rdoc/parser/puppet_parser_rdoc1.rb"
+rescue LoadError
+  # Current version imports
+  require "rdoc/token_stream"
+  require "rdoc/markup/pre_process"
+  require "rdoc/parser"
+  require "puppet/util/rdoc/parser/puppet_parser_rdoc2.rb"
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc/parser/puppet_parser_core.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc/parser/puppet_parser_core.rb
new file mode 100644
index 0000000..4d29cc1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc/parser/puppet_parser_core.rb
@@ -0,0 +1,477 @@
+# Functionality common to both our RDoc version 1 and 2 parsers.
+module RDoc::PuppetParserCore
+
+  SITE = "__site__"
+
+  def self.included(base)
+    base.class_eval do
+      attr_accessor :input_file_name, :top_level
+
+      # parser registration into RDoc
+      parse_files_matching(/\.(rb|pp)$/)
+    end
+  end
+
+  # called with the top level file
+  def initialize(top_level, file_name, body, options, stats)
+    @options = options
+    @stats   = stats
+    @input_file_name = file_name
+    @top_level = top_level
+    @top_level.extend(RDoc::PuppetTopLevel)
+    @progress = $stderr unless options.quiet
+  end
+
+  # main entry point
+  def scan
+    environment = Puppet.lookup(:current_environment)
+    known_resource_types = environment.known_resource_types
+    unless known_resource_types.watching_file?(@input_file_name)
+      Puppet.info "rdoc: scanning #{@input_file_name}"
+      if @input_file_name =~ /\.pp$/
+        @parser = Puppet::Parser::Parser.new(environment)
+        @parser.file = @input_file_name
+        @parser.parse.instantiate('').each do |type|
+          known_resource_types.add type
+        end
+      end
+    end
+
+    scan_top_level(@top_level, environment)
+    @top_level
+  end
+
+  # Due to a bug in RDoc, we need to roll our own find_module_named
+  # The issue is that RDoc tries harder by asking the parent for a class/module
+  # of the name. But by doing so, it can mistakenly use a module of same name
+  # but from which we are not descendant.
+  def find_object_named(container, name)
+    return container if container.name == name
+    container.each_classmodule do |m|
+      return m if m.name == name
+    end
+    nil
+  end
+
+  # walk down the namespace and lookup/create container as needed
+  def get_class_or_module(container, name)
+
+    # class ::A -> A is in the top level
+    if name =~ /^::/
+      container = @top_level
+    end
+
+    names = name.split('::')
+
+    final_name = names.pop
+    names.each do |name|
+      prev_container = container
+      container = find_object_named(container, name)
+      container ||= prev_container.add_class(RDoc::PuppetClass, name, nil)
+    end
+    [container, final_name]
+  end
+
+  # split_module tries to find if +path+ belongs to the module path
+  # if it does, it returns the module name, otherwise if we are sure
+  # it is part of the global manifest path, "__site__" is returned.
+  # And finally if this path couldn't be mapped anywhere, nil is returned.
+  def split_module(path, environment)
+    # find a module
+    fullpath = File.expand_path(path)
+    Puppet.debug "rdoc: testing #{fullpath}"
+    if fullpath =~ /(.*)\/([^\/]+)\/(?:manifests|plugins|lib)\/.+\.(pp|rb)$/
+      modpath = $1
+      name = $2
+      Puppet.debug "rdoc: module #{name} into #{modpath} ?"
+      environment.modulepath.each do |mp|
+        if File.identical?(modpath,mp)
+          Puppet.debug "rdoc: found module #{name}"
+          return name
+        end
+      end
+    end
+    if fullpath =~ /\.(pp|rb)$/
+      # there can be paths we don't want to scan under modules
+      # imagine a ruby or manifest that would be distributed as part as a module
+      # but we don't want those to be hosted under <site>
+      environment.modulepath.each do |mp|
+        # check that fullpath is a descendant of mp
+        dirname = fullpath
+        previous = dirname
+        while (dirname = File.dirname(previous)) != previous
+          previous = dirname
+          return nil if File.identical?(dirname,mp)
+        end
+      end
+    end
+    # we are under a global manifests
+    Puppet.debug "rdoc: global manifests"
+    SITE
+  end
+
+  # create documentation for the top level +container+
+  def scan_top_level(container, environment)
+    # use the module README as documentation for the module
+    comment = ""
+    %w{README README.rdoc}.each do |rfile|
+      readme = File.join(File.dirname(File.dirname(@input_file_name)), rfile)
+      comment = File.open(readme,"r") { |f| f.read } if FileTest.readable?(readme)
+    end
+    look_for_directives_in(container, comment) unless comment.empty?
+
+    # infer module name from directory
+    name = split_module(@input_file_name, environment)
+    if name.nil?
+      # skip .pp files that are not in manifests directories as we can't guarantee they're part
+      # of a module or the global configuration.
+      container.document_self = false
+      return
+    end
+
+    Puppet.debug "rdoc: scanning for #{name}"
+
+    container.module_name = name
+    container.global=true if name == SITE
+
+    container, name  = get_class_or_module(container,name)
+    mod = container.add_module(RDoc::PuppetModule, name)
+    mod.record_location(@top_level)
+    mod.add_comment(comment, @input_file_name)
+
+    if @input_file_name =~ /\.pp$/
+      parse_elements(mod, environment.known_resource_types)
+    elsif @input_file_name =~ /\.rb$/
+      parse_plugins(mod)
+    end
+  end
+
+  # create documentation for include statements we can find in +code+
+  # and associate it with +container+
+  def scan_for_include_or_require(container, code)
+    code = [code] unless code.is_a?(Array)
+    code.each do |stmt|
+      scan_for_include_or_require(container,stmt.children) if stmt.is_a?(Puppet::Parser::AST::BlockExpression)
+
+      if stmt.is_a?(Puppet::Parser::AST::Function) and ['include','require'].include?(stmt.name)
+        stmt.arguments.each do |included|
+          Puppet.debug "found #{stmt.name}: #{included}"
+          container.send("add_#{stmt.name}", RDoc::Include.new(included.to_s, stmt.doc))
+        end
+      end
+    end
+  end
+
+  # create documentation for realize statements we can find in +code+
+  # and associate it with +container+
+  def scan_for_realize(container, code)
+    code = [code] unless code.is_a?(Array)
+    code.each do |stmt|
+      scan_for_realize(container,stmt.children) if stmt.is_a?(Puppet::Parser::AST::BlockExpression)
+
+      if stmt.is_a?(Puppet::Parser::AST::Function) and stmt.name == 'realize'
+        stmt.arguments.each do |realized|
+          Puppet.debug "found #{stmt.name}: #{realized}"
+          container.add_realize( RDoc::Include.new(realized.to_s, stmt.doc))
+        end
+      end
+    end
+  end
+
+  # create documentation for global variables assignements we can find in +code+
+  # and associate it with +container+
+  def scan_for_vardef(container, code)
+    code = [code] unless code.is_a?(Array)
+    code.each do |stmt|
+      scan_for_vardef(container,stmt.children) if stmt.is_a?(Puppet::Parser::AST::BlockExpression)
+
+      if stmt.is_a?(Puppet::Parser::AST::VarDef)
+        Puppet.debug "rdoc: found constant: #{stmt.name} = #{stmt.value}"
+        container.add_constant(RDoc::Constant.new(stmt.name.to_s, stmt.value.to_s, stmt.doc))
+      end
+    end
+  end
+
+  # create documentation for resources we can find in +code+
+  # and associate it with +container+
+  def scan_for_resource(container, code)
+    code = [code] unless code.is_a?(Array)
+    code.each do |stmt|
+      scan_for_resource(container,stmt.children) if stmt.is_a?(Puppet::Parser::AST::BlockExpression)
+
+      if stmt.is_a?(Puppet::Parser::AST::Resource) and !stmt.type.nil?
+        begin
+          type = stmt.type.split("::").collect { |s| s.capitalize }.join("::")
+          stmt.instances.each do |inst|
+            title = inst.title.is_a?(Puppet::Parser::AST::ASTArray) ? inst.title.to_s.gsub(/\[(.*)\]/,'\1') : inst.title.to_s
+            Puppet.debug "rdoc: found resource: #{type}[#{title}]"
+
+            param = []
+            inst.parameters.children.each do |p|
+              res = {}
+              res["name"] = p.param
+              res["value"] = "#{p.value.to_s}" unless p.value.nil?
+
+              param << res
+            end
+
+            container.add_resource(RDoc::PuppetResource.new(type, title, stmt.doc, param))
+          end
+        rescue => detail
+          raise Puppet::ParseError, "impossible to parse resource in #{stmt.file} at line #{stmt.line}: #{detail}", detail.backtrace
+        end
+      end
+    end
+  end
+
+  # create documentation for a class named +name+
+  def document_class(name, klass, container)
+    Puppet.debug "rdoc: found new class #{name}"
+    container, name = get_class_or_module(container, name)
+
+    superclass = klass.parent
+    superclass = "" if superclass.nil? or superclass.empty?
+
+    comment = klass.doc
+    look_for_directives_in(container, comment) unless comment.empty?
+    cls = container.add_class(RDoc::PuppetClass, name, superclass)
+    # it is possible we already encountered this class, while parsing some namespaces
+    # from other classes of other files. But at that time we couldn't know this class superclass
+    # so, now we know it and force it.
+    cls.superclass = superclass
+    cls.record_location(@top_level)
+
+    # scan class code for include
+    code = klass.code.children if klass.code.is_a?(Puppet::Parser::AST::BlockExpression)
+    code ||= klass.code
+    unless code.nil?
+      scan_for_include_or_require(cls, code)
+      scan_for_realize(cls, code)
+      scan_for_resource(cls, code) if Puppet.settings[:document_all]
+    end
+
+    cls.add_comment(comment, klass.file)
+  rescue => detail
+    raise Puppet::ParseError, "impossible to parse class '#{name}' in #{klass.file} at line #{klass.line}: #{detail}", detail.backtrace
+  end
+
+  # create documentation for a node
+  def document_node(name, node, container)
+    Puppet.debug "rdoc: found new node #{name}"
+    superclass = node.parent
+    superclass = "" if superclass.nil? or superclass.empty?
+
+    comment = node.doc
+    look_for_directives_in(container, comment) unless comment.empty?
+    n = container.add_node(name, superclass)
+    n.record_location(@top_level)
+
+    code = node.code.children if node.code.is_a?(Puppet::Parser::AST::BlockExpression)
+    code ||= node.code
+    unless code.nil?
+      scan_for_include_or_require(n, code)
+      scan_for_realize(n, code)
+      scan_for_vardef(n, code)
+      scan_for_resource(n, code) if Puppet.settings[:document_all]
+    end
+
+    n.add_comment(comment, node.file)
+  rescue => detail
+    raise Puppet::ParseError, "impossible to parse node '#{name}' in #{node.file} at line #{node.line}: #{detail}", detail.backtrace
+  end
+
+  # create documentation for a define
+  def document_define(name, define, container)
+    Puppet.debug "rdoc: found new definition #{name}"
+    # find superclas if any
+
+    # find the parent
+    # split define name by :: to find the complete module hierarchy
+    container, name = get_class_or_module(container,name)
+
+    # build up declaration
+    declaration = ""
+    define.arguments.each do |arg,value|
+      declaration << "\$#{arg}"
+      unless value.nil?
+        declaration << " => "
+        case value
+        when Puppet::Parser::AST::Leaf
+          declaration << "'#{value.value}'"
+        when Puppet::Parser::AST::BlockExpression
+          declaration << "[#{value.children.collect { |v| "'#{v}'" }.join(", ")}]"
+        else
+          declaration << "#{value.to_s}"
+        end
+      end
+      declaration << ", "
+    end
+    declaration.chop!.chop! if declaration.size > 1
+
+    # register method into the container
+    meth =  RDoc::AnyMethod.new(declaration, name)
+    meth.comment = define.doc
+    container.add_method(meth)
+    look_for_directives_in(container, meth.comment) unless meth.comment.empty?
+    meth.params = "( #{declaration} )"
+    meth.visibility = :public
+    meth.document_self = true
+    meth.singleton = false
+  rescue => detail
+    raise Puppet::ParseError, "impossible to parse definition '#{name}' in #{define.file} at line #{define.line}: #{detail}", detail.backtrace
+  end
+
+  # Traverse the AST tree and produce code-objects node
+  # that contains the documentation
+  def parse_elements(container, known_resource_types)
+    Puppet.debug "rdoc: scanning manifest"
+
+    known_resource_types.hostclasses.values.sort { |a,b| a.name <=> b.name }.each do |klass|
+      name = klass.name
+      if klass.file == @input_file_name
+        unless name.empty?
+          document_class(name,klass,container)
+        else # on main class document vardefs
+          code = klass.code.children if klass.code.is_a?(Puppet::Parser::AST::BlockExpression)
+          code ||= klass.code
+          scan_for_vardef(container, code) unless code.nil?
+        end
+      end
+    end
+
+    known_resource_types.definitions.each do |name, define|
+      if define.file == @input_file_name
+        document_define(name,define,container)
+      end
+    end
+
+    known_resource_types.nodes.each do |name, node|
+      if node.file == @input_file_name
+        document_node(name.to_s,node,container)
+      end
+    end
+  end
+
+  # create documentation for plugins
+  def parse_plugins(container)
+    Puppet.debug "rdoc: scanning plugin or fact"
+    if @input_file_name =~ /\/facter\/[^\/]+\.rb$/
+      parse_fact(container)
+    else
+      parse_puppet_plugin(container)
+    end
+  end
+
+  # this is a poor man custom fact parser :-)
+  def parse_fact(container)
+    comments = ""
+    current_fact = nil
+    parsed_facts = []
+    File.open(@input_file_name) do |of|
+      of.each do |line|
+        # fetch comments
+        if line =~ /^[ \t]*# ?(.*)$/
+          comments += $1 + "\n"
+        elsif line =~ /^[ \t]*Facter.add\(['"](.*?)['"]\)/
+          current_fact = RDoc::Fact.new($1,{})
+          look_for_directives_in(container, comments) unless comments.empty?
+          current_fact.comment = comments
+          parsed_facts << current_fact
+          comments = ""
+          Puppet.debug "rdoc: found custom fact #{current_fact.name}"
+        elsif line =~ /^[ \t]*confine[ \t]*:(.*?)[ \t]*=>[ \t]*(.*)$/
+          current_fact.confine = { :type => $1, :value => $2 } unless current_fact.nil?
+        else # unknown line type
+          comments =""
+        end
+      end
+    end
+    parsed_facts.each do |f|
+      container.add_fact(f)
+      f.record_location(@top_level)
+    end
+  end
+
+  # this is a poor man puppet plugin parser :-)
+  # it doesn't extract doc nor desc :-(
+  def parse_puppet_plugin(container)
+    comments = ""
+    current_plugin = nil
+
+    File.open(@input_file_name) do |of|
+      of.each do |line|
+        # fetch comments
+        if line =~ /^[ \t]*# ?(.*)$/
+          comments += $1 + "\n"
+        elsif line =~ /^[ \t]*(?:Puppet::Parser::Functions::)?newfunction[ \t]*\([ \t]*:(.*?)[ \t]*,[ \t]*:type[ \t]*=>[ \t]*(:rvalue|:lvalue)/
+          current_plugin = RDoc::Plugin.new($1, "function")
+          look_for_directives_in(container, comments) unless comments.empty?
+          current_plugin.comment = comments
+          current_plugin.record_location(@top_level)
+          container.add_plugin(current_plugin)
+          comments = ""
+          Puppet.debug "rdoc: found new function plugins #{current_plugin.name}"
+        elsif line =~ /^[ \t]*Puppet::Type.newtype[ \t]*\([ \t]*:(.*?)\)/
+          current_plugin = RDoc::Plugin.new($1, "type")
+          look_for_directives_in(container, comments) unless comments.empty?
+          current_plugin.comment = comments
+          current_plugin.record_location(@top_level)
+          container.add_plugin(current_plugin)
+          comments = ""
+          Puppet.debug "rdoc: found new type plugins #{current_plugin.name}"
+        elsif line =~ /module Puppet::Parser::Functions/
+          # skip
+        else # unknown line type
+          comments =""
+        end
+      end
+    end
+  end
+
+  # New instance of the appropriate PreProcess for our RDoc version.
+  def create_rdoc_preprocess
+    raise(NotImplementedError, "This method must be overwritten for whichever version of RDoc this parser is working with")
+  end
+
+  # look_for_directives_in scans the current +comment+ for RDoc directives
+  def look_for_directives_in(context, comment)
+    preprocess = create_rdoc_preprocess
+
+    preprocess.handle(comment) do |directive, param|
+      case directive
+      when "stopdoc"
+        context.stop_doc
+        ""
+      when "startdoc"
+        context.start_doc
+        context.force_documentation = true
+        ""
+      when "enddoc"
+        #context.done_documenting = true
+        #""
+        throw :enddoc
+      when "main"
+        options = Options.instance
+        options.main_page = param
+        ""
+      when "title"
+        options = Options.instance
+        options.title = param
+        ""
+      when "section"
+        context.set_current_section(param, comment)
+        comment.replace("") # 1.8 doesn't support #clear
+        break
+      else
+        warn "Unrecognized directive '#{directive}'"
+        break
+      end
+    end
+    remove_private_comments(comment)
+  end
+
+  def remove_private_comments(comment)
+    comment.gsub!(/^#--.*?^#\+\+/m, '')
+    comment.sub!(/^#--.*/m, '')
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc/parser/puppet_parser_rdoc1.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc/parser/puppet_parser_rdoc1.rb
new file mode 100644
index 0000000..656d2f7
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc/parser/puppet_parser_rdoc1.rb
@@ -0,0 +1,19 @@
+require 'puppet/util/rdoc/parser/puppet_parser_core.rb'
+
+module RDoc
+  PUPPET_RDOC_VERSION = 1
+
+  # @api private
+  class PuppetParserRDoc1
+    extend ParserFactory
+    include PuppetParserCore
+
+    def create_rdoc_preprocess
+      preprocess = SM::PreProcess.new(@input_file_name, @options.rdoc_include)
+    end
+  end
+
+  # For backwards compatibility
+  # @api private
+  Parser = PuppetParserRDoc1
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc/parser/puppet_parser_rdoc2.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc/parser/puppet_parser_rdoc2.rb
new file mode 100644
index 0000000..75a5cda
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rdoc/parser/puppet_parser_rdoc2.rb
@@ -0,0 +1,14 @@
+require 'puppet/util/rdoc/parser/puppet_parser_core.rb'
+
+module RDoc
+  PUPPET_RDOC_VERSION = 2
+
+  # @api private
+  class PuppetParserRDoc2 < Parser
+    include PuppetParserCore
+
+    def create_rdoc_preprocess
+      preprocess = Markup::PreProcess.new(@input_file_name, @options.rdoc_include)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/reference.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/reference.rb
new file mode 100644
index 0000000..81d3af0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/reference.rb
@@ -0,0 +1,124 @@
+require 'puppet/util/instance_loader'
+require 'puppet/util/methodhelper'
+require 'fileutils'
+
+# Manage Reference Documentation.
+class Puppet::Util::Reference
+  include Puppet::Util
+  include Puppet::Util::MethodHelper
+  include Puppet::Util::Docs
+
+  extend Puppet::Util::InstanceLoader
+
+  instance_load(:reference, 'puppet/reference')
+
+  def self.footer
+    "\n\n----------------\n\n*This page autogenerated on #{Time.now}*\n"
+  end
+
+  def self.modes
+    %w{pdf text}
+  end
+
+  def self.newreference(name, options = {}, &block)
+    ref = self.new(name, options, &block)
+    instance_hash(:reference)[name.intern] = ref
+
+    ref
+  end
+
+  def self.page(*sections)
+    depth = 4
+    # Use the minimum depth
+    sections.each do |name|
+      section = reference(name) or raise "Could not find section #{name}"
+      depth = section.depth if section.depth < depth
+    end
+  end
+
+  def self.pdf(text)
+    puts "creating pdf"
+    rst2latex = which('rst2latex') || which('rst2latex.py') ||
+      raise("Could not find rst2latex")
+
+    cmd = %{#{rst2latex} /tmp/puppetdoc.txt > /tmp/puppetdoc.tex}
+    Puppet::Util.replace_file("/tmp/puppetdoc.txt") {|f| f.puts text }
+    # There used to be an attempt to use secure_open / replace_file to secure
+    # the target, too, but that did nothing: the race was still here.  We can
+    # get exactly the same benefit from running this effort:
+    Puppet::FileSystem.unlink('/tmp/puppetdoc.tex') rescue nil
+    output = %x{#{cmd}}
+    unless $CHILD_STATUS == 0
+      $stderr.puts "rst2latex failed"
+      $stderr.puts output
+      exit(1)
+    end
+    $stderr.puts output
+
+    # Now convert to pdf
+    Dir.chdir("/tmp") do
+      %x{texi2pdf puppetdoc.tex >/dev/null 2>/dev/null}
+    end
+
+  end
+
+  def self.references
+    instance_loader(:reference).loadall
+    loaded_instances(:reference).sort { |a,b| a.to_s <=> b.to_s }
+  end
+
+  attr_accessor :page, :depth, :header, :title, :dynamic
+  attr_writer :doc
+
+  def doc
+    if defined?(@doc)
+      return "#{@name} - #{@doc}"
+    else
+      return @title
+    end
+  end
+
+  def dynamic?
+    self.dynamic
+  end
+
+  def initialize(name, options = {}, &block)
+    @name = name
+    set_options(options)
+
+    meta_def(:generate, &block)
+
+    # Now handle the defaults
+    @title ||= "#{@name.to_s.capitalize} Reference"
+    @page ||= @title.gsub(/\s+/, '')
+    @depth ||= 2
+    @header ||= ""
+  end
+
+  # Indent every line in the chunk except those which begin with '..'.
+  def indent(text, tab)
+    text.gsub(/(^|\A)/, tab).gsub(/^ +\.\./, "..")
+  end
+
+  def option(name, value)
+    ":#{name.to_s.capitalize}: #{value}\n"
+  end
+
+  def text
+    puts output
+  end
+
+  def to_markdown(withcontents = true)
+    # First the header
+    text = markdown_header(@title, 1)
+    text << "\n\n**This page is autogenerated; any changes will get overwritten** *(last generated on #{Time.now.to_s})*\n\n"
+
+    text << @header
+
+    text << generate
+
+    text << self.class.footer if withcontents
+
+    text
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/resource_template.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/resource_template.rb
new file mode 100644
index 0000000..d401c4b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/resource_template.rb
@@ -0,0 +1,61 @@
+require 'puppet/util'
+require 'puppet/util/logging'
+require 'erb'
+
+# A template wrapper that evaluates a template in the
+# context of a resource, allowing the resource attributes
+# to be looked up from within the template.
+#  This provides functionality essentially equivalent to
+# the language's template() function.  You pass your file
+# path and the resource you want to use into the initialization
+# method, then call result on the instance, and you get back
+# a chunk of text.
+#  The resource's parameters are available as instance variables
+# (as opposed to the language, where we use a method_missing trick).
+#  For example, say you have a resource that generates a file.  You would
+# need to implement the following style of `generate` method:
+#
+#   def generate
+#       template = Puppet::Util::ResourceTemplate.new("/path/to/template", self)
+#
+#       return Puppet::Type.type(:file).new :path => "/my/file",
+#           :content => template.evaluate
+#   end
+#
+# This generated file gets added to the catalog (which is what `generate` does),
+# and its content is the result of the template.  You need to use instance
+# variables in your template, so if your template just needs to have the name
+# of the generating resource, it would just have:
+#
+#   <%= @name %>
+#
+# Since the ResourceTemplate class sets as instance variables all of the resource's
+# parameters.
+#
+# Note that this example uses the generating resource as its source of
+# parameters, which is generally most useful, since it allows you to configure
+# the generated resource via the generating resource.
+class Puppet::Util::ResourceTemplate
+  include Puppet::Util::Logging
+
+  def evaluate
+    set_resource_variables
+    ERB.new(File.read(@file), 0, "-").result(binding)
+  end
+
+  def initialize(file, resource)
+    raise ArgumentError, "Template #{file} does not exist" unless Puppet::FileSystem.exist?(file)
+    @file = file
+    @resource = resource
+  end
+
+  private
+
+  def set_resource_variables
+    @resource.to_hash.each do |param, value|
+      var = "@#{param.to_s}"
+      instance_variable_set(var, value)
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/retryaction.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/retryaction.rb
new file mode 100644
index 0000000..a50ceb7
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/retryaction.rb
@@ -0,0 +1,47 @@
+module Puppet::Util::RetryAction
+  class RetryException < Exception; end
+  class RetryException::NoBlockGiven < RetryException; end
+  class RetryException::NoRetriesGiven < RetryException;end
+  class RetryException::RetriesExceeded < RetryException; end
+
+  def self.retry_action( parameters = { :retry_exceptions => nil, :retries => nil } )
+    # Retry actions for a specified amount of time. This method will allow the final
+    # retry to complete even if that extends beyond the timeout period.
+    unless block_given?
+      raise RetryException::NoBlockGiven
+    end
+
+    raise RetryException::NoRetriesGiven if parameters[:retries].nil?
+    parameters[:retry_exceptions] ||= Hash.new
+
+    failures = 0
+
+    begin
+      yield
+    rescue Exception => e
+      # If we were giving exceptions to catch,
+      # catch the excptions we care about and retry.
+      # All others fail hard
+
+      raise RetryException::RetriesExceeded, "#{parameters[:retries]} exceeded", e.backtrace if parameters[:retries] == 0
+
+      if (not parameters[:retry_exceptions].keys.empty?) and parameters[:retry_exceptions].keys.include?(e.class)
+        Puppet.info("Caught exception #{e.class}:#{e}")
+        Puppet.info(parameters[:retry_exceptions][e.class])
+      elsif (not parameters[:retry_exceptions].keys.empty?)
+        # If the exceptions is not in the list of retry_exceptions re-raise.
+        raise e
+      end
+
+      failures += 1
+      parameters[:retries] -= 1
+
+      # Increase the amount of time that we sleep after every
+      # failed retry attempt.
+      sleep (((2 ** failures) -1) * 0.1)
+
+      retry
+
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rubygems.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rubygems.rb
new file mode 100644
index 0000000..ad70f4c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/rubygems.rb
@@ -0,0 +1,75 @@
+require 'puppet/util'
+
+module Puppet::Util::RubyGems
+
+  # Base/factory class for rubygems source. These classes introspec into
+  # rubygems to in order to list where the rubygems system will look for files
+  # to load.
+  class Source
+    class << self
+      # @api private
+      def has_rubygems?
+        # Gems are not actually available when Bundler is loaded, even
+        # though the Gem constant is defined. This is because Bundler
+        # loads in rubygems, but then removes the custom require that
+        # rubygems installs. So when Bundler is around we have to act
+        # as though rubygems is not, e.g. we shouldn't be able to load
+        # a gem that Bundler doesn't want us to see.
+        defined? ::Gem and not defined? ::Bundler
+      end
+
+      # @api private
+      def source
+        if has_rubygems?
+          Gem::Specification.respond_to?(:latest_specs) ? Gems18Source : OldGemsSource
+        else
+          NoGemsSource
+        end
+      end
+
+      def new(*args)
+        object = source.allocate
+        object.send(:initialize, *args)
+        object
+      end
+    end
+  end
+
+  # For RubyGems >= 1.8.0
+  # @api private
+  class Gems18Source < Source
+    def directories
+      # `require 'mygem'` will consider and potentally load
+      # prerelease gems, so we need to match that behavior.
+      Gem::Specification.latest_specs(true).collect do |spec|
+        File.join(spec.full_gem_path, 'lib')
+      end
+    end
+
+    def clear_paths
+      Gem.clear_paths
+    end
+  end
+
+  # RubyGems < 1.8.0
+  # @api private
+  class OldGemsSource < Source
+    def directories
+      @paths ||= Gem.latest_load_paths
+    end
+
+    def clear_paths
+      Gem.clear_paths
+    end
+  end
+
+  # @api private
+  class NoGemsSource < Source
+    def directories
+      []
+    end
+
+    def clear_paths; end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/run_mode.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/run_mode.rb
new file mode 100644
index 0000000..9a736fb
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/run_mode.rb
@@ -0,0 +1,82 @@
+require 'etc'
+
+module Puppet
+  module Util
+    class RunMode
+      def initialize(name)
+        @name = name.to_sym
+      end
+
+      attr :name
+
+      def self.[](name)
+        @run_modes ||= {}
+        if Puppet.features.microsoft_windows?
+          @run_modes[name] ||= WindowsRunMode.new(name)
+        else
+          @run_modes[name] ||= UnixRunMode.new(name)
+        end
+      end
+
+      def master?
+        name == :master
+      end
+
+      def agent?
+        name == :agent
+      end
+
+      def user?
+        name == :user
+      end
+
+      def run_dir
+        "$vardir/run"
+      end
+
+      def log_dir
+        "$vardir/log"
+      end
+
+      private
+
+      ##
+      # select the system or the user directory depending on the context of
+      # this process.  The most common use is determining filesystem path
+      # values for confdir and vardir.  The intended semantics are:
+      # {http://projects.puppetlabs.com/issues/16637 #16637} for Puppet 3.x
+      #
+      # @todo this code duplicates {Puppet::Settings#which\_configuration\_file}
+      #   as described in {http://projects.puppetlabs.com/issues/16637 #16637}
+      def which_dir( system, user )
+        File.expand_path(if Puppet.features.root? then system else user end)
+      end
+    end
+
+    class UnixRunMode < RunMode
+      def conf_dir
+        which_dir("/etc/puppet", "~/.puppet")
+      end
+
+      def var_dir
+        which_dir("/var/lib/puppet", "~/.puppet/var")
+      end
+    end
+
+    class WindowsRunMode < RunMode
+      def conf_dir
+        which_dir(File.join(windows_common_base("etc")), "~/.puppet")
+      end
+
+      def var_dir
+        which_dir(File.join(windows_common_base("var")), "~/.puppet/var")
+      end
+
+    private
+
+      def windows_common_base(*extra)
+        [Dir::COMMON_APPDATA, "PuppetLabs", "puppet"] + extra
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/selinux.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/selinux.rb
new file mode 100644
index 0000000..feb5c32
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/selinux.rb
@@ -0,0 +1,222 @@
+# Provides utility functions to help interface Puppet to SELinux.
+#
+# This requires the very new SELinux Ruby bindings.  These bindings closely
+# mirror the SELinux C library interface.
+#
+# Support for the command line tools is not provided because the performance
+# was abysmal.  At this time (2008-11-02) the only distribution providing
+# these Ruby SELinux bindings which I am aware of is Fedora (in libselinux-ruby).
+
+Puppet.features.selinux? # check, but continue even if it's not
+
+require 'pathname'
+
+module Puppet::Util::SELinux
+
+  def selinux_support?
+    return false unless defined?(Selinux)
+    if Selinux.is_selinux_enabled == 1
+      return true
+    end
+    false
+  end
+
+  # Retrieve and return the full context of the file.  If we don't have
+  # SELinux support or if the SELinux call fails then return nil.
+  def get_selinux_current_context(file)
+    return nil unless selinux_support?
+    retval = Selinux.lgetfilecon(file)
+    if retval == -1
+      return nil
+    end
+    retval[1]
+  end
+
+  # Retrieve and return the default context of the file.  If we don't have
+  # SELinux support or if the SELinux call fails to file a default then return nil.
+  def get_selinux_default_context(file)
+    return nil unless selinux_support?
+    # If the filesystem has no support for SELinux labels, return a default of nil
+    # instead of what matchpathcon would return
+    return nil unless selinux_label_support?(file)
+    # If the file exists we should pass the mode to matchpathcon for the most specific
+    # matching.  If not, we can pass a mode of 0.
+    begin
+      filestat = file_lstat(file)
+      mode = filestat.mode
+    rescue Errno::EACCES, Errno::ENOENT
+      mode = 0
+    end
+
+    retval = Selinux.matchpathcon(file, mode)
+    if retval == -1
+      return nil
+    end
+    retval[1]
+  end
+
+  # Take the full SELinux context returned from the tools and parse it
+  # out to the three (or four) component parts.  Supports :seluser, :selrole,
+  # :seltype, and on systems with range support, :selrange.
+  def parse_selinux_context(component, context)
+    if context.nil? or context == "unlabeled"
+      return nil
+    end
+    unless context =~ /^([a-z0-9_]+):([a-z0-9_]+):([a-zA-Z0-9_]+)(?::([a-zA-Z0-9:,._-]+))?/
+      raise Puppet::Error, "Invalid context to parse: #{context}"
+    end
+    ret = {
+      :seluser => $1,
+      :selrole => $2,
+      :seltype => $3,
+      :selrange => $4,
+    }
+    ret[component]
+  end
+
+  # This updates the actual SELinux label on the file.  You can update
+  # only a single component or update the entire context.
+  # The caveat is that since setting a partial context makes no sense the
+  # file has to already exist.  Puppet (via the File resource) will always
+  # just try to set components, even if all values are specified by the manifest.
+  # I believe that the OS should always provide at least a fall-through context
+  # though on any well-running system.
+  def set_selinux_context(file, value, component = false)
+    return nil unless selinux_support? && selinux_label_support?(file)
+
+    if component
+      # Must first get existing context to replace a single component
+      context = Selinux.lgetfilecon(file)[1]
+      if context == -1
+        # We can't set partial context components when no context exists
+        # unless/until we can find a way to make Puppet call this method
+        # once for all selinux file label attributes.
+        Puppet.warning "Can't set SELinux context on file unless the file already has some kind of context"
+        return nil
+      end
+      context = context.split(':')
+      case component
+        when :seluser
+          context[0] = value
+        when :selrole
+          context[1] = value
+        when :seltype
+          context[2] = value
+        when :selrange
+          context[3] = value
+        else
+          raise ArguementError, "set_selinux_context component must be one of :seluser, :selrole, :seltype, or :selrange"
+      end
+      context = context.join(':')
+    else
+      context = value
+    end
+
+    retval = Selinux.lsetfilecon(file, context)
+    if retval == 0
+      return true
+    else
+      Puppet.warning "Failed to set SELinux context #{context} on #{file}"
+      return false
+    end
+  end
+
+  # Since this call relies on get_selinux_default_context it also needs a
+  # full non-relative path to the file.  Fortunately, that seems to be all
+  # Puppet uses.  This will set the file's SELinux context to the policy's
+  # default context (if any) if it differs from the context currently on
+  # the file.
+  def set_selinux_default_context(file)
+    new_context = get_selinux_default_context(file)
+    return nil unless new_context
+    cur_context = get_selinux_current_context(file)
+    if new_context != cur_context
+      set_selinux_context(file, new_context)
+      return new_context
+    end
+    nil
+  end
+
+  ########################################################################
+  # Internal helper methods from here on in, kids.  Don't fiddle.
+  private
+
+  # Check filesystem a path resides on for SELinux support against
+  # whitelist of known-good filesystems.
+  # Returns true if the filesystem can support SELinux labels and
+  # false if not.
+  def selinux_label_support?(file)
+    fstype = find_fs(file)
+    return false if fstype.nil?
+    filesystems = ['ext2', 'ext3', 'ext4', 'gfs', 'gfs2', 'xfs', 'jfs', 'btrfs']
+    filesystems.include?(fstype)
+  end
+
+  # Internal helper function to read and parse /proc/mounts
+  def read_mounts
+    mounts = ""
+    begin
+      if File.method_defined? "read_nonblock"
+        # If possible we use read_nonblock in a loop rather than read to work-
+        # a linux kernel bug.  See ticket #1963 for details.
+        mountfh = File.open("/proc/mounts")
+        mounts += mountfh.read_nonblock(1024) while true
+      else
+        # Otherwise we shell out and let cat do it for us
+        mountfh = IO.popen("/bin/cat /proc/mounts")
+        mounts = mountfh.read
+      end
+    rescue EOFError
+      # that's expected
+    rescue
+      return nil
+    ensure
+      mountfh.close if mountfh
+    end
+
+    mntpoint = {}
+
+    # Read all entries in /proc/mounts.  The second column is the
+    # mountpoint and the third column is the filesystem type.
+    # We skip rootfs because it is always mounted at /
+    mounts.each_line do |line|
+      params = line.split(' ')
+      next if params[2] == 'rootfs'
+      mntpoint[params[1]] = params[2]
+    end
+    mntpoint
+  end
+
+  # Internal helper function to return which type of filesystem a given file
+  # path resides on
+  def find_fs(path)
+    return nil unless mounts = read_mounts
+
+    # cleanpath eliminates useless parts of the path (like '.', or '..', or
+    # multiple slashes), without touching the filesystem, and without
+    # following symbolic links.  This gives the right (logical) tree to follow
+    # while we try and figure out what file-system the target lives on.
+    path = Pathname(path).cleanpath
+    unless path.absolute?
+      raise Puppet::DevError, "got a relative path in SELinux find_fs: #{path}"
+    end
+
+    # Now, walk up the tree until we find a match for that path in the hash.
+    path.ascend do |segment|
+      return mounts[segment.to_s] if mounts.has_key?(segment.to_s)
+    end
+
+    # Should never be reached...
+    return mounts['/']
+  end
+
+  ##
+  # file_lstat is an internal, private method to allow precise stubbing and
+  # mocking without affecting the rest of the system.
+  #
+  # @return [File::Stat] File.lstat result
+  def file_lstat(path)
+    Puppet::FileSystem.lstat(path)
+  end
+  private :file_lstat
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/ssl.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/ssl.rb
new file mode 100644
index 0000000..48faf52
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/ssl.rb
@@ -0,0 +1,53 @@
+##
+# SSL is a private module with class methods that help work with x.509
+# subjects.
+#
+# @api private
+module Puppet::Util::SSL
+  NO_NAME = OpenSSL::X509::Name.new
+
+  DN_PARSERS = [
+    OpenSSL::X509::Name.method(:parse_rfc2253),
+    OpenSSL::X509::Name.method(:parse_openssl),
+    lambda { |dn| NO_NAME }
+  ]
+
+  # Given a DN string, parse it into an OpenSSL certificate subject.  This
+  # method will flexibly handle both OpenSSl and RFC2253 formats, as given by
+  # nginx and Apache, respectively.
+  #
+  # @param [String] dn the x.509 Distinguished Name (DN) string.
+  #
+  # @return [OpenSSL::X509::Name] the certificate subject
+  def self.subject_from_dn(dn)
+    if is_possibly_valid_dn?(dn)
+      DN_PARSERS.each do |parser|
+        begin
+          return parser.call(dn)
+        rescue OpenSSL::X509::NameError
+        end
+      end
+    else
+      NO_NAME
+    end
+  end
+
+  ##
+  # cn_from_subject extracts the CN from the given OpenSSL certtificate
+  # subject.
+  #
+  # @api private
+  #
+  # @param [OpenSSL::X509::Name] subject the subject to extract the CN field from
+  #
+  # @return [String, nil] the CN, or nil if not found
+  def self.cn_from_subject(subject)
+    if subject.respond_to? :to_a
+      (subject.to_a.assoc('CN') || [])[1]
+    end
+  end
+
+  def self.is_possibly_valid_dn?(dn)
+    dn =~ /=/
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/storage.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/storage.rb
new file mode 100644
index 0000000..0568243
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/storage.rb
@@ -0,0 +1,89 @@
+require 'yaml'
+require 'sync'
+require 'singleton'
+require 'puppet/util/yaml'
+
+# a class for storing state
+class Puppet::Util::Storage
+  include Singleton
+  include Puppet::Util
+
+  def self.state
+    @@state
+  end
+
+  def initialize
+    self.class.load
+  end
+
+  # Return a hash that will be stored to disk.  It's worth noting
+  # here that we use the object's full path, not just the name/type
+  # combination.  At the least, this is useful for those non-isomorphic
+  # types like exec, but it also means that if an object changes locations
+  # in the configuration it will lose its cache.
+  def self.cache(object)
+    if object.is_a?(Symbol)
+      name = object
+    else
+      name = object.to_s
+    end
+
+    @@state[name] ||= {}
+  end
+
+  def self.clear
+    @@state.clear
+  end
+
+  def self.init
+    @@state = {}
+  end
+
+  self.init
+
+  def self.load
+    Puppet.settings.use(:main) unless FileTest.directory?(Puppet[:statedir])
+    filename = Puppet[:statefile]
+
+    unless Puppet::FileSystem.exist?(filename)
+      self.init if @@state.nil?
+      return
+    end
+    unless File.file?(filename)
+      Puppet.warning("Checksumfile #{filename} is not a file, ignoring")
+      return
+    end
+    Puppet::Util.benchmark(:debug, "Loaded state") do
+      begin
+        @@state = Puppet::Util::Yaml.load_file(filename)
+      rescue Puppet::Util::Yaml::YamlLoadError => detail
+        Puppet.err "Checksumfile #{filename} is corrupt (#{detail}); replacing"
+
+        begin
+          File.rename(filename, filename + ".bad")
+        rescue
+          raise Puppet::Error, "Could not rename corrupt #{filename}; remove manually", detail.backtrace
+        end
+      end
+    end
+
+    unless @@state.is_a?(Hash)
+      Puppet.err "State got corrupted"
+      self.init
+    end
+  end
+
+  def self.stateinspect
+    @@state.inspect
+  end
+
+  def self.store
+    Puppet.debug "Storing state"
+
+    Puppet.info "Creating state file #{Puppet[:statefile]}" unless Puppet::FileSystem.exist?(Puppet[:statefile])
+
+    Puppet::Util.benchmark(:debug, "Stored state") do
+      Puppet::Util::Yaml.dump(@@state, Puppet[:statefile])
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/suidmanager.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/suidmanager.rb
new file mode 100644
index 0000000..b4d77c7
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/suidmanager.rb
@@ -0,0 +1,191 @@
+require 'facter'
+require 'puppet/util/warnings'
+require 'forwardable'
+require 'etc'
+
+module Puppet::Util::SUIDManager
+  include Puppet::Util::Warnings
+  extend Forwardable
+
+  # Note groups= is handled specially due to a bug in OS X 10.6, 10.7,
+  # and probably upcoming releases...
+  to_delegate_to_process = [ :euid=, :euid, :egid=, :egid, :uid=, :uid, :gid=, :gid, :groups ]
+
+  to_delegate_to_process.each do |method|
+    def_delegator Process, method
+    module_function method
+  end
+
+  def osx_maj_ver
+    return @osx_maj_ver unless @osx_maj_ver.nil?
+    @osx_maj_ver = Facter.value('macosx_productversion_major') || false
+  end
+  module_function :osx_maj_ver
+
+  def groups=(grouplist)
+    begin
+      return Process.groups = grouplist
+    rescue Errno::EINVAL => e
+      #We catch Errno::EINVAL as some operating systems (OS X in particular) can
+      # cause troubles when using Process#groups= to change *this* user / process
+      # list of supplementary groups membership.  This is done via Ruby's function
+      # "static VALUE proc_setgroups(VALUE obj, VALUE ary)" which is effectively
+      # a wrapper for "int setgroups(size_t size, const gid_t *list)" (part of SVr4
+      # and 4.3BSD but not in POSIX.1-2001) that fails and sets errno to EINVAL.
+      #
+      # This does not appear to be a problem with Ruby but rather an issue on the
+      # operating system side.  Therefore we catch the exception and look whether
+      # we run under OS X or not -- if so, then we acknowledge the problem and
+      # re-throw the exception otherwise.
+      if osx_maj_ver and not osx_maj_ver.empty?
+        return true
+      else
+        raise e
+      end
+    end
+  end
+  module_function :groups=
+
+  def self.root?
+    return Process.uid == 0 unless Puppet.features.microsoft_windows?
+
+    require 'puppet/util/windows/user'
+    Puppet::Util::Windows::User.admin?
+  end
+
+  # Methods to handle changing uid/gid of the running process. In general,
+  # these will noop or fail on Windows, and require root to change to anything
+  # but the current uid/gid (which is a noop).
+
+  # Runs block setting euid and egid if provided then restoring original ids.
+  # If running on Windows or without root, the block will be run with the
+  # current euid/egid.
+  def asuser(new_uid=nil, new_gid=nil)
+    return yield if Puppet.features.microsoft_windows?
+    return yield unless root?
+    return yield unless new_uid or new_gid
+
+    old_euid, old_egid = self.euid, self.egid
+    begin
+      change_privileges(new_uid, new_gid, false)
+
+      yield
+    ensure
+      change_privileges(new_uid ? old_euid : nil, old_egid, false)
+    end
+  end
+  module_function :asuser
+
+  # If `permanently` is set, will permanently change the uid/gid of the
+  # process. If not, it will only set the euid/egid. If only uid is supplied,
+  # the primary group of the supplied gid will be used. If only gid is
+  # supplied, only gid will be changed. This method will fail if used on
+  # Windows.
+  def change_privileges(uid=nil, gid=nil, permanently=false)
+    return unless uid or gid
+
+    unless gid
+      uid = convert_xid(:uid, uid)
+      gid = Etc.getpwuid(uid).gid
+    end
+
+    change_group(gid, permanently)
+    change_user(uid, permanently) if uid
+  end
+  module_function :change_privileges
+
+  # Changes the egid of the process if `permanently` is not set, otherwise
+  # changes gid. This method will fail if used on Windows, or attempting to
+  # change to a different gid without root.
+  def change_group(group, permanently=false)
+    gid = convert_xid(:gid, group)
+    raise Puppet::Error, "No such group #{group}" unless gid
+
+    if permanently
+      Process::GID.change_privilege(gid)
+    else
+      Process.egid = gid
+    end
+  end
+  module_function :change_group
+
+  # As change_group, but operates on uids. If changing user permanently,
+  # supplementary groups will be set the to default groups for the new uid.
+  def change_user(user, permanently=false)
+    uid = convert_xid(:uid, user)
+    raise Puppet::Error, "No such user #{user}" unless uid
+
+    if permanently
+      # If changing uid, we must be root. So initgroups first here.
+      initgroups(uid)
+
+      Process::UID.change_privilege(uid)
+    else
+      # We must be root to initgroups, so initgroups before dropping euid if
+      # we're root, otherwise elevate euid before initgroups.
+      # change euid (to root) first.
+      if Process.euid == 0
+        initgroups(uid)
+        Process.euid = uid
+      else
+        Process.euid = uid
+        initgroups(uid)
+      end
+    end
+  end
+  module_function :change_user
+
+  # Make sure the passed argument is a number.
+  def convert_xid(type, id)
+    map = {:gid => :group, :uid => :user}
+    raise ArgumentError, "Invalid id type #{type}" unless map.include?(type)
+    ret = Puppet::Util.send(type, id)
+    if ret == nil
+      raise Puppet::Error, "Invalid #{map[type]}: #{id}"
+    end
+    ret
+  end
+  module_function :convert_xid
+
+  # Initialize primary and supplemental groups to those of the target user.  We
+  # take the UID and manually look up their details in the system database,
+  # including username and primary group. This method will fail on Windows, or
+  # if used without root to initgroups of another user.
+  def initgroups(uid)
+    pwent = Etc.getpwuid(uid)
+    Process.initgroups(pwent.name, pwent.gid)
+  end
+
+  module_function :initgroups
+
+  # Run a command and capture the output
+  # Parameters:
+  # [command] the command to execute
+  # [new_uid] (optional) a userid to run the command as
+  # [new_gid] (optional) a groupid to run the command as
+  # [options] (optional, defaults to {}) a hash of option key/value pairs; currently supported:
+  #   :override_locale (defaults to true) a flag indicating whether or puppet should temporarily override the
+  #     system locale for the duration of the command.  If true, the locale will be set to 'C' to ensure consistent
+  #     output / formatting from the command, which makes it much easier to parse the output.  If false, the system
+  #     locale will be respected.
+  #   :custom_environment (default {}) -- a hash of key/value pairs to set as environment variables for the duration
+  #     of the command
+  def run_and_capture(command, new_uid=nil, new_gid=nil, options = {})
+    Puppet.deprecation_warning("Puppet::Util::SUIDManager.run_and_capture is deprecated; please use Puppet::Util::Execution.execute instead.")
+    # specifying these here rather than in the method signature to allow callers to pass in a partial
+    # set of overrides without affecting the default values for options that they don't pass in
+    default_options = {
+        :override_locale => true,
+        :custom_environment => {},
+    }
+
+    options = default_options.merge(options)
+
+    output = Puppet::Util::Execution.execute(command, :failonfail => false, :combine => true,
+                                  :uid => new_uid, :gid => new_gid,
+                                  :override_locale => options[:override_locale],
+                                  :custom_environment => options[:custom_environment])
+    [output, $CHILD_STATUS.dup]
+  end
+  module_function :run_and_capture
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/symbolic_file_mode.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/symbolic_file_mode.rb
new file mode 100644
index 0000000..6924819
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/symbolic_file_mode.rb
@@ -0,0 +1,144 @@
+require 'puppet/util'
+
+module Puppet
+module Util
+module SymbolicFileMode
+  SetUIDBit = ReadBit  = 4
+  SetGIDBit = WriteBit = 2
+  StickyBit = ExecBit  = 1
+  SymbolicMode = { 'x' => ExecBit, 'w' => WriteBit, 'r' => ReadBit }
+  SymbolicSpecialToBit = {
+    't' => { 'u' => StickyBit, 'g' => StickyBit, 'o' => StickyBit },
+    's' => { 'u' => SetUIDBit, 'g' => SetGIDBit, 'o' => StickyBit }
+  }
+
+  def valid_symbolic_mode?(value)
+    value = normalize_symbolic_mode(value)
+    return true if value =~ /^0?[0-7]{1,4}$/
+    return true if value =~ /^([ugoa]*[-=+][-=+rstwxXugo]*)(,[ugoa]*[-=+][-=+rstwxXugo]*)*$/
+    return false
+  end
+
+  def normalize_symbolic_mode(value)
+    return nil if value.nil?
+
+    # We need to treat integers as octal numbers.
+    if value.is_a? Numeric then
+      return value.to_s(8)
+    elsif value =~ /^0?[0-7]{1,4}$/ then
+      return value.to_i(8).to_s(8)
+    else
+      return value
+    end
+  end
+
+  def symbolic_mode_to_int(modification, to_mode = 0, is_a_directory = false)
+    if modification.nil? or modification == '' then
+      raise Puppet::Error, "An empty mode string is illegal"
+    end
+    if modification =~ /^[0-7]+$/ then return modification.to_i(8) end
+    if modification =~ /^\d+$/ then
+      raise Puppet::Error, "Numeric modes must be in octal, not decimal!"
+    end
+
+    fail "non-numeric current mode (#{to_mode.inspect})" unless to_mode.is_a?(Numeric)
+
+    original_mode = {
+      's' => (to_mode & 07000) >> 9,
+      'u' => (to_mode & 00700) >> 6,
+      'g' => (to_mode & 00070) >> 3,
+      'o' => (to_mode & 00007) >> 0,
+      # Are there any execute bits set in the original mode?
+      'any x?' => (to_mode & 00111) != 0
+    }
+    final_mode = {
+      's' => original_mode['s'],
+      'u' => original_mode['u'],
+      'g' => original_mode['g'],
+      'o' => original_mode['o'],
+    }
+
+    modification.split(/\s*,\s*/).each do |part|
+      begin
+        _, to, dsl = /^([ugoa]*)([-+=].*)$/.match(part).to_a
+        if dsl.nil? then raise Puppet::Error, 'Missing action' end
+        to = "a" unless to and to.length > 0
+
+        # We want a snapshot of the mode before we start messing with it to
+        # make actions like 'a-g' atomic.  Various parts of the DSL refer to
+        # the original mode, the final mode, or the current snapshot of the
+        # mode, for added fun.
+        snapshot_mode = {}
+        final_mode.each {|k,v| snapshot_mode[k] = v }
+
+        to.gsub('a', 'ugo').split('').uniq.each do |who|
+          value = snapshot_mode[who]
+
+          action = '!'
+          actions = {
+            '!' => lambda {|_,_| raise Puppet::Error, 'Missing operation (-, =, or +)' },
+            '=' => lambda {|m,v| m | v },
+            '+' => lambda {|m,v| m | v },
+            '-' => lambda {|m,v| m & ~v },
+          }
+
+          dsl.split('').each do |op|
+            case op
+            when /[-+=]/ then
+              action = op
+              # Clear all bits, if this is assignment
+              value  = 0 if op == '='
+
+            when /[ugo]/ then
+              value = actions[action].call(value, snapshot_mode[op])
+
+            when /[rwx]/ then
+              value = actions[action].call(value, SymbolicMode[op])
+
+            when 'X' then
+              # Only meaningful in combination with "set" actions.
+              if action != '+' then
+                raise Puppet::Error, "X only works with the '+' operator"
+              end
+
+              # As per the BSD manual page, set if this is a directory, or if
+              # any execute bit is set on the original (unmodified) mode.
+              # Ignored otherwise; it is "add if", not "add or clear".
+              if is_a_directory or original_mode['any x?'] then
+                value = actions[action].call(value, ExecBit)
+              end
+
+            when /[st]/ then
+              bit = SymbolicSpecialToBit[op][who] or fail "internal error"
+              final_mode['s'] = actions[action].call(final_mode['s'], bit)
+
+            else
+              raise Puppet::Error, 'Unknown operation'
+            end
+          end
+
+          # Now, assign back the value.
+          final_mode[who] = value
+        end
+
+      rescue Puppet::Error => e
+        if part.inspect != modification.inspect then
+          rest = " at #{part.inspect}"
+        else
+          rest = ''
+        end
+
+        raise Puppet::Error, "#{e}#{rest} in symbolic mode #{modification.inspect}", e.backtrace
+      end
+    end
+
+    result =
+      final_mode['s'] << 9 |
+      final_mode['u'] << 6 |
+      final_mode['g'] << 3 |
+      final_mode['o'] << 0
+    return result
+  end
+end
+end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/tag_set.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/tag_set.rb
new file mode 100644
index 0000000..6f83ff8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/tag_set.rb
@@ -0,0 +1,41 @@
+require 'set'
+require 'puppet/network/format_support'
+
+class Puppet::Util::TagSet < Set
+  include Puppet::Network::FormatSupport
+
+  def self.from_yaml(yaml)
+    self.new(YAML.load(yaml))
+  end
+
+  def to_yaml
+    @hash.keys.to_yaml
+  end
+
+  def self.from_data_hash(data)
+    self.new(data)
+  end
+
+  def self.from_pson(data)
+    Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
+    self.from_data_hash(data)
+  end
+
+  def to_data_hash
+    to_a
+  end
+
+  def to_pson(*args)
+    to_data_hash.to_pson
+  end
+
+  # this makes puppet serialize it as an array for backwards
+  # compatibility
+  def to_zaml(z)
+    to_data_hash.to_zaml(z)
+  end
+
+  def join(*args)
+    to_a.join(*args)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/tagging.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/tagging.rb
new file mode 100644
index 0000000..d17d8b1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/tagging.rb
@@ -0,0 +1,81 @@
+require 'puppet/util/tag_set'
+
+module Puppet::Util::Tagging
+  ValidTagRegex = /^\w[-\w:.]*$/
+
+  # Add a tag to the current tag set.
+  # When a tag set is used for a scope, these tags will be added to all of
+  # the objects contained in this scope when the objects are finished.
+  #
+  def tag(*ary)
+    @tags ||= new_tags
+
+    ary.flatten.each do |tag|
+      name = tag.to_s.downcase
+      if name =~ ValidTagRegex
+        @tags << name
+        if split_qualified_tags?
+          name.split("::").each do |section|
+            @tags << section
+          end
+        end
+      else
+        fail(Puppet::ParseError, "Invalid tag '#{name}'")
+      end
+    end
+  end
+
+  # Answers if this resource is tagged with at least one of the given tags.
+  #
+  # The given tags are converted to downcased strings before the match is performed.
+  #
+  # @param *tags [String] splat of tags to look for
+  # @return [Boolean] true if this instance is tagged with at least one of the provided tags
+  #
+  def tagged?(*tags)
+    raw_tagged?(tags.collect {|t| t.to_s.downcase})
+  end
+
+  # Answers if this resource is tagged with at least one of the tags given in downcased string form.
+  #
+  # The method is a faster variant of the tagged? method that does no conversion of its
+  # arguments.
+  #
+  # @param tag_array [Array[String]] array of tags to look for
+  # @return [Boolean] true if this instance is tagged with at least one of the provided tags
+  #
+  def raw_tagged?(tag_array)
+    my_tags = self.tags
+    !tag_array.index { |t| my_tags.include?(t) }.nil?
+  end
+
+  # Return a copy of the tag list, so someone can't ask for our tags
+  # and then modify them.
+  def tags
+    @tags ||= new_tags
+    @tags.dup
+  end
+
+  def tags=(tags)
+    @tags = new_tags
+
+    return if tags.nil? or tags == ""
+
+    tags = tags.strip.split(/\s*,\s*/) if tags.is_a?(String)
+    tags.each {|t| tag(t) }
+  end
+
+  private
+
+  def valid_tag?(tag)
+    tag.is_a?(String) and tag =~ ValidTagRegex
+  end
+
+  def split_qualified_tags?
+    true
+  end
+
+  def new_tags
+    Puppet::Util::TagSet.new
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/terminal.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/terminal.rb
new file mode 100644
index 0000000..ba72570
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/terminal.rb
@@ -0,0 +1,16 @@
+module Puppet::Util::Terminal
+  # Attempts to determine the width of the terminal.  This is currently only
+  # supported on POSIX systems, and relies on the claims of `stty` (or `tput`).
+  #
+  # Inspired by code from Thor; thanks wycats!
+  # @return [Number] The column width of the terminal.  Defaults to 80 columns.
+  def self.width
+    if Puppet.features.posix?
+      result = %x{stty size 2>/dev/null}.split[1] ||
+               %x{tput cols 2>/dev/null}.split[0]
+    end
+    return (result || '80').to_i
+  rescue
+    return 80
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/user_attr.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/user_attr.rb
new file mode 100644
index 0000000..9b19058
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/user_attr.rb
@@ -0,0 +1,21 @@
+class UserAttr
+  def self.get_attributes_by_name(name)
+    attributes = nil
+
+    File.readlines('/etc/user_attr').each do |line|
+      next if line =~ /^#/
+
+      token = line.split(':')
+
+      if token[0] == name
+        attributes = {:name => name}
+        token[4].split(';').each do |attr|
+          key_value = attr.split('=')
+          attributes[key_value[0].intern] = key_value[1].strip
+        end
+        break
+      end
+    end
+    attributes
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/warnings.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/warnings.rb
new file mode 100644
index 0000000..82e80e4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/warnings.rb
@@ -0,0 +1,32 @@
+# Methods to help with handling warnings.
+module Puppet::Util::Warnings
+  module_function
+
+  def notice_once(msg)
+    Puppet::Util::Warnings.maybe_log(msg, self.class) { Puppet.notice msg }
+  end
+
+  def debug_once(msg)
+    Puppet::Util::Warnings.maybe_log(msg, self.class) { Puppet.debug msg }
+  end
+
+  def warnonce(msg)
+    Puppet::Util::Warnings.maybe_log(msg, self.class) { Puppet.warning msg }
+  end
+
+  def clear_warnings
+    @stampwarnings = {}
+    nil
+  end
+
+  protected
+
+  def self.maybe_log(message, klass)
+    @stampwarnings ||= {}
+    @stampwarnings[klass] ||= []
+    return nil if @stampwarnings[klass].include? message
+    yield
+    @stampwarnings[klass] << message
+    nil
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/watched_file.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/watched_file.rb
new file mode 100644
index 0000000..8843771
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/watched_file.rb
@@ -0,0 +1,37 @@
+require 'puppet/util/watcher'
+
+# Monitor a given file for changes on a periodic interval. Changes are detected
+# by looking for a change in the file ctime.
+class Puppet::Util::WatchedFile
+  # @!attribute [r] filename
+  #   @return [String] The fully qualified path to the file.
+  attr_reader :filename
+
+  # @param filename [String] The fully qualified path to the file.
+  # @param timer [Puppet::Util::Watcher::Timer] The polling interval for checking for file
+  #   changes. Setting the timeout to a negative value will treat the file as
+  #   always changed. Defaults to `Puppet[:filetimeout]`
+  def initialize(filename, timer = Puppet::Util::Watcher::Timer.new(Puppet[:filetimeout]))
+    @filename = filename
+    @timer = timer
+
+    @info = Puppet::Util::Watcher::PeriodicWatcher.new(
+      Puppet::Util::Watcher::Common.file_ctime_change_watcher(@filename),
+      timer)
+  end
+
+  # @return [true, false] If the file has changed since it was last checked.
+  def changed?
+    @info.changed?
+  end
+
+  # Allow this to be used as the name of the file being watched in various
+  # other methods (such as Puppet::FileSystem.exist?)
+  def to_str
+    @filename
+  end
+
+  def to_s
+    "<WatchedFile: filename = #{@filename}, timeout = #{@timer.timeout}>"
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/watcher.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/watcher.rb
new file mode 100644
index 0000000..a65788b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/watcher.rb
@@ -0,0 +1,17 @@
+module Puppet::Util::Watcher
+  require 'puppet/util/watcher/timer'
+  require 'puppet/util/watcher/change_watcher'
+  require 'puppet/util/watcher/periodic_watcher'
+
+  module Common
+    def self.file_ctime_change_watcher(filename)
+      Puppet::Util::Watcher::ChangeWatcher.watch(lambda do
+        begin
+          Puppet::FileSystem.stat(filename).ctime
+        rescue Errno::ENOENT, Errno::ENOTDIR
+          :absent
+        end
+      end)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/watcher/change_watcher.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/watcher/change_watcher.rb
new file mode 100644
index 0000000..1ce3002
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/watcher/change_watcher.rb
@@ -0,0 +1,33 @@
+# Watches for changes over time. It only re-examines the values when it is requested to update readings.
+# @api private
+class Puppet::Util::Watcher::ChangeWatcher
+  def self.watch(reader)
+    Puppet::Util::Watcher::ChangeWatcher.new(nil, nil, reader).next_reading
+  end
+
+  def initialize(previous, current, value_reader)
+    @previous = previous
+    @current = current
+    @value_reader = value_reader
+  end
+
+  def changed?
+    if uncertain?
+      false
+    else
+      @previous != @current
+    end
+  end
+
+  def uncertain?
+    @previous.nil? || @current.nil?
+  end
+
+  def change_current_reading_to(new_value)
+    Puppet::Util::Watcher::ChangeWatcher.new(@current, new_value, @value_reader)
+  end
+
+  def next_reading
+    change_current_reading_to(@value_reader.call)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/watcher/periodic_watcher.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/watcher/periodic_watcher.rb
new file mode 100644
index 0000000..0fe7ed5
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/watcher/periodic_watcher.rb
@@ -0,0 +1,37 @@
+# Monitor a given watcher for changes on a periodic interval.
+class Puppet::Util::Watcher::PeriodicWatcher
+  # @param watcher [Puppet::Util::Watcher::ChangeWatcher] a watcher for the value to watch
+  # @param timer [Puppet::Util::Watcher::Timer] A timer to determin when to
+  #   recheck the watcher. If the timout of the timer is negative, then the
+  #   watched value is always considered to be changed
+  def initialize(watcher, timer)
+    @watcher = watcher
+    @timer = timer
+
+    @timer.start
+  end
+
+  # @return [true, false] If the file has changed since it was last checked.
+  def changed?
+    return true if always_consider_changed?
+
+    @watcher = examine_watched_info(@watcher)
+    @watcher.changed?
+  end
+
+  private
+
+  def always_consider_changed?
+    @timer.timeout < 0
+  end
+
+  def examine_watched_info(known)
+    if @timer.expired?
+      @timer.start
+      known.next_reading
+    else
+      known
+    end
+  end
+end
+
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/watcher/timer.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/watcher/timer.rb
new file mode 100644
index 0000000..329b3ab
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/watcher/timer.rb
@@ -0,0 +1,19 @@
+class Puppet::Util::Watcher::Timer
+  attr_reader :timeout
+
+  def initialize(timeout)
+    @timeout = timeout
+  end
+
+  def start
+    @start_time = now
+  end
+
+  def expired?
+    (now - @start_time) >= @timeout
+  end
+
+  def now
+    Time.now.to_i
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows.rb
new file mode 100644
index 0000000..24aec49
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows.rb
@@ -0,0 +1,28 @@
+module Puppet::Util::Windows
+  module ADSI
+    class User; end
+    class UserProfile; end
+    class Group; end
+  end
+  module Registry
+  end
+
+  if Puppet::Util::Platform.windows?
+    # these reference platform specific gems
+    require 'puppet/util/windows/api_types'
+    require 'puppet/util/windows/string'
+    require 'puppet/util/windows/error'
+    require 'puppet/util/windows/com'
+    require 'puppet/util/windows/sid'
+    require 'puppet/util/windows/file'
+    require 'puppet/util/windows/security'
+    require 'puppet/util/windows/user'
+    require 'puppet/util/windows/process'
+    require 'puppet/util/windows/root_certs'
+    require 'puppet/util/windows/access_control_entry'
+    require 'puppet/util/windows/access_control_list'
+    require 'puppet/util/windows/security_descriptor'
+    require 'puppet/util/windows/adsi'
+    require 'puppet/util/windows/registry'
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/access_control_entry.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/access_control_entry.rb
new file mode 100644
index 0000000..5cd052d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/access_control_entry.rb
@@ -0,0 +1,84 @@
+# Windows Access Control Entry
+#
+# Represents an access control entry, which grants or denies a subject,
+# identified by a SID, rights to a securable object.
+#
+# @see http://msdn.microsoft.com/en-us/library/windows/desktop/aa374868(v=vs.85).aspx
+# @api private
+class Puppet::Util::Windows::AccessControlEntry
+  require 'puppet/util/windows/security'
+  include Puppet::Util::Windows::SID
+
+  attr_accessor :sid
+  attr_reader :mask, :flags, :type
+
+  OBJECT_INHERIT_ACE                      = 0x1
+  CONTAINER_INHERIT_ACE                   = 0x2
+  NO_PROPAGATE_INHERIT_ACE                = 0x4
+  INHERIT_ONLY_ACE                        = 0x8
+  INHERITED_ACE                           = 0x10
+
+  ACCESS_ALLOWED_ACE_TYPE                 = 0x0
+  ACCESS_DENIED_ACE_TYPE                  = 0x1
+
+  def initialize(sid, mask, flags = 0, type = ACCESS_ALLOWED_ACE_TYPE)
+    @sid = sid
+    @mask = mask
+    @flags = flags
+    @type = type
+  end
+
+  # Returns true if this ACE is inherited from a parent. If false,
+  # then the ACE is set directly on the object to which it refers.
+  #
+  # @return [Boolean] true if the ACE is inherited
+  def inherited?
+    (@flags & INHERITED_ACE) == INHERITED_ACE
+  end
+
+  # Returns true if this ACE only applies to children of the object.
+  # If false, it applies to the object.
+  #
+  # @return [Boolean] true if the ACE only applies to children and
+  # not the object itself.
+  def inherit_only?
+    (@flags & INHERIT_ONLY_ACE) == INHERIT_ONLY_ACE
+  end
+
+  # Returns true if this ACE applies to child directories.
+  #
+  # @return [Boolean] true if the ACE applies to child direcories
+  def container_inherit?
+    (@flags & CONTAINER_INHERIT_ACE) == CONTAINER_INHERIT_ACE
+  end
+
+  # Returns true if this ACE applies to child files.
+  #
+  # @return [Boolean] true if the ACE applies to child files.
+  def object_inherit?
+    (@flags & OBJECT_INHERIT_ACE) == OBJECT_INHERIT_ACE
+  end
+
+  def inspect
+    inheritance = ""
+    inheritance << '(I)' if inherited?
+    inheritance << '(OI)' if object_inherit?
+    inheritance << '(CI)' if container_inherit?
+    inheritance << '(IO)' if inherit_only?
+
+    left = "#{sid_to_name(sid)}:#{inheritance}"
+    left = left.ljust(45)
+    "#{left} 0x#{mask.to_s(16)}"
+  end
+
+  # Returns true if this ACE is equal to +other+
+  def ==(other)
+    self.class == other.class &&
+      sid == other.sid &&
+      mask == other.mask &&
+      flags == other.flags &&
+      type == other.type
+  end
+
+  alias eql? ==
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/access_control_list.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/access_control_list.rb
new file mode 100644
index 0000000..ce0e8e6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/access_control_list.rb
@@ -0,0 +1,113 @@
+# Windows Access Control List
+#
+# Represents a list of access control entries (ACEs).
+#
+# @see http://msdn.microsoft.com/en-us/library/windows/desktop/aa374872(v=vs.85).aspx
+# @api private
+class Puppet::Util::Windows::AccessControlList
+  include Enumerable
+
+  ACCESS_ALLOWED_ACE_TYPE                 = 0x0
+  ACCESS_DENIED_ACE_TYPE                  = 0x1
+
+  # Construct an ACL.
+  #
+  # @param acl [Enumerable] A list of aces to copy from.
+  def initialize(acl = nil)
+    if acl
+      @aces = acl.map(&:dup)
+    else
+      @aces = []
+    end
+  end
+
+  # Enumerate each ACE in the list.
+  #
+  # @yieldparam ace [Hash] the ace
+  def each
+    @aces.each {|ace| yield ace}
+  end
+
+  # Allow the +sid+ to access a resource with the specified access +mask+.
+  #
+  # @param sid [String] The SID that the ACE is granting access to
+  # @param mask [int] The access mask granted to the SID
+  # @param flags [int] The flags assigned to the ACE, e.g. +INHERIT_ONLY_ACE+
+  def allow(sid, mask, flags = 0)
+    @aces << Puppet::Util::Windows::AccessControlEntry.new(sid, mask, flags, ACCESS_ALLOWED_ACE_TYPE)
+  end
+
+  # Deny the +sid+ access to a resource with the specified access +mask+.
+  #
+  # @param sid [String] The SID that the ACE is denying access to
+  # @param mask [int] The access mask denied to the SID
+  # @param flags [int] The flags assigned to the ACE, e.g. +INHERIT_ONLY_ACE+
+  def deny(sid, mask, flags = 0)
+    @aces << Puppet::Util::Windows::AccessControlEntry.new(sid, mask, flags, ACCESS_DENIED_ACE_TYPE)
+  end
+
+  # Reassign all ACEs currently assigned to +old_sid+ to +new_sid+ instead.
+  # If an ACE is inherited or is not assigned to +old_sid+, then it will
+  # be copied as-is to the new ACL, preserving its order within the ACL.
+  #
+  # @param old_sid [String] The old SID, e.g. 'S-1-5-18'
+  # @param new_sid [String] The new SID
+  # @return [AccessControlList] The copied ACL.
+  def reassign!(old_sid, new_sid)
+    new_aces = []
+    prepend_needed = false
+    aces_to_prepend = []
+
+    @aces.each do |ace|
+      new_ace = ace.dup
+
+      if ace.sid == old_sid
+        if ace.inherited?
+          # create an explicit ACE granting or denying the
+          # new_sid the rights that the inherited ACE
+          # granted or denied the old_sid. We mask off all
+          # flags except those affecting inheritance of the
+          # ACE we're creating.
+          inherit_mask = Puppet::Util::Windows::AccessControlEntry::CONTAINER_INHERIT_ACE |
+            Puppet::Util::Windows::AccessControlEntry::OBJECT_INHERIT_ACE |
+            Puppet::Util::Windows::AccessControlEntry::INHERIT_ONLY_ACE
+          explicit_ace = Puppet::Util::Windows::AccessControlEntry.new(new_sid, ace.mask, ace.flags & inherit_mask, ace.type)
+          aces_to_prepend << explicit_ace
+        else
+          new_ace.sid = new_sid
+
+          prepend_needed = old_sid == Win32::Security::SID::LocalSystem
+        end
+      end
+      new_aces << new_ace
+    end
+
+    @aces = []
+
+    if prepend_needed
+      mask = Puppet::Util::Windows::File::STANDARD_RIGHTS_ALL | Puppet::Util::Windows::File::SPECIFIC_RIGHTS_ALL
+      ace = Puppet::Util::Windows::AccessControlEntry.new(
+              Win32::Security::SID::LocalSystem,
+              mask)
+      @aces << ace
+    end
+
+    @aces.concat(aces_to_prepend)
+    @aces.concat(new_aces)
+  end
+
+  def inspect
+    str = ""
+    @aces.each do |ace|
+      str << "  #{ace.inspect}\n"
+    end
+    str
+  end
+
+  def ==(other)
+    self.class == other.class &&
+      self.to_a == other.to_a
+  end
+
+  alias eql? ==
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/adsi.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/adsi.rb
new file mode 100644
index 0000000..5d2340f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/adsi.rb
@@ -0,0 +1,458 @@
+module Puppet::Util::Windows::ADSI
+  require 'ffi'
+
+  class << self
+    extend FFI::Library
+
+    def connectable?(uri)
+      begin
+        !! connect(uri)
+      rescue
+        false
+      end
+    end
+
+    def connect(uri)
+      begin
+        WIN32OLE.connect(uri)
+      rescue WIN32OLERuntimeError => e
+        raise Puppet::Error.new( "ADSI connection error: #{e}", e )
+      end
+    end
+
+    def create(name, resource_type)
+      Puppet::Util::Windows::ADSI.connect(computer_uri).Create(resource_type, name)
+    end
+
+    def delete(name, resource_type)
+      Puppet::Util::Windows::ADSI.connect(computer_uri).Delete(resource_type, name)
+    end
+
+    # taken from winbase.h
+    MAX_COMPUTERNAME_LENGTH = 31
+
+    def computer_name
+      unless @computer_name
+        max_length = MAX_COMPUTERNAME_LENGTH + 1 # NULL terminated
+        FFI::MemoryPointer.new(max_length * 2) do |buffer| # wide string
+          FFI::MemoryPointer.new(:dword, 1) do |buffer_size|
+            buffer_size.write_dword(max_length) # length in TCHARs
+
+            if GetComputerNameW(buffer, buffer_size) == FFI::WIN32_FALSE
+              raise Puppet::Util::Windows::Error.new("Failed to get computer name")
+            end
+            @computer_name = buffer.read_wide_string(buffer_size.read_dword)
+          end
+        end
+      end
+      @computer_name
+    end
+
+    def computer_uri(host = '.')
+      "WinNT://#{host}"
+    end
+
+    def wmi_resource_uri( host = '.' )
+      "winmgmts:{impersonationLevel=impersonate}!//#{host}/root/cimv2"
+    end
+
+    # @api private
+    def sid_uri_safe(sid)
+      return sid_uri(sid) if sid.kind_of?(Win32::Security::SID)
+
+      begin
+        sid = Win32::Security::SID.new(Win32::Security::SID.string_to_sid(sid))
+        sid_uri(sid)
+      rescue SystemCallError
+        nil
+      end
+    end
+
+    def sid_uri(sid)
+      raise Puppet::Error.new( "Must use a valid SID object" ) if !sid.kind_of?(Win32::Security::SID)
+      "WinNT://#{sid.to_s}"
+    end
+
+    def uri(resource_name, resource_type, host = '.')
+      "#{computer_uri(host)}/#{resource_name},#{resource_type}"
+    end
+
+    def wmi_connection
+      connect(wmi_resource_uri)
+    end
+
+    def execquery(query)
+      wmi_connection.execquery(query)
+    end
+
+    def sid_for_account(name)
+      Puppet.deprecation_warning "Puppet::Util::Windows::ADSI.sid_for_account is deprecated and will be removed in 3.0, use Puppet::Util::Windows::SID.name_to_sid instead."
+
+      Puppet::Util::Windows::SID.name_to_sid(name)
+    end
+
+    ffi_convention :stdcall
+
+    # http://msdn.microsoft.com/en-us/library/windows/desktop/ms724295(v=vs.85).aspx
+    # BOOL WINAPI GetComputerName(
+    #   _Out_    LPTSTR lpBuffer,
+    #   _Inout_  LPDWORD lpnSize
+    # );
+    ffi_lib :kernel32
+    attach_function_private :GetComputerNameW,
+      [:lpwstr, :lpdword], :win32_bool
+  end
+
+  class User
+    extend Enumerable
+    extend FFI::Library
+
+    attr_accessor :native_user
+    attr_reader :name, :sid
+    def initialize(name, native_user = nil)
+      @name = name
+      @native_user = native_user
+    end
+
+    def self.parse_name(name)
+      if name =~ /\//
+        raise Puppet::Error.new( "Value must be in DOMAIN\\user style syntax" )
+      end
+
+      matches = name.scan(/((.*)\\)?(.*)/)
+      domain = matches[0][1] || '.'
+      account = matches[0][2]
+
+      return account, domain
+    end
+
+    def native_user
+      @native_user ||= Puppet::Util::Windows::ADSI.connect(self.class.uri(*self.class.parse_name(@name)))
+    end
+
+    def sid
+      @sid ||= Puppet::Util::Windows::SID.octet_string_to_sid_object(native_user.objectSID)
+    end
+
+    def self.uri(name, host = '.')
+      if sid_uri = Puppet::Util::Windows::ADSI.sid_uri_safe(name) then return sid_uri end
+
+      host = '.' if ['NT AUTHORITY', 'BUILTIN', Socket.gethostname].include?(host)
+
+      Puppet::Util::Windows::ADSI.uri(name, 'user', host)
+    end
+
+    def uri
+      self.class.uri(sid.account, sid.domain)
+    end
+
+    def self.logon(name, password)
+      Puppet::Util::Windows::User.password_is?(name, password)
+    end
+
+    def [](attribute)
+      native_user.Get(attribute)
+    end
+
+    def []=(attribute, value)
+      native_user.Put(attribute, value)
+    end
+
+    def commit
+      begin
+        native_user.SetInfo unless native_user.nil?
+      rescue WIN32OLERuntimeError => e
+        # ERROR_BAD_USERNAME 2202L from winerror.h
+        if e.message =~ /8007089A/m
+          raise Puppet::Error.new(
+           "Puppet is not able to create/delete domain users with the user resource.",
+           e
+          )
+        end
+
+        raise Puppet::Error.new( "User update failed: #{e}", e )
+      end
+      self
+    end
+
+    def password_is?(password)
+      self.class.logon(name, password)
+    end
+
+    def add_flag(flag_name, value)
+      flag = native_user.Get(flag_name) rescue 0
+
+      native_user.Put(flag_name, flag | value)
+
+      commit
+    end
+
+    def password=(password)
+      if !password.nil?
+        native_user.SetPassword(password)
+        commit
+      end
+
+      fADS_UF_DONT_EXPIRE_PASSWD = 0x10000
+      add_flag("UserFlags", fADS_UF_DONT_EXPIRE_PASSWD)
+    end
+
+    def groups
+      # WIN32OLE objects aren't enumerable, so no map
+      groups = []
+      native_user.Groups.each {|g| groups << g.Name} rescue nil
+      groups
+    end
+
+    def add_to_groups(*group_names)
+      group_names.each do |group_name|
+        Puppet::Util::Windows::ADSI::Group.new(group_name).add_member_sids(sid)
+      end
+    end
+    alias add_to_group add_to_groups
+
+    def remove_from_groups(*group_names)
+      group_names.each do |group_name|
+        Puppet::Util::Windows::ADSI::Group.new(group_name).remove_member_sids(sid)
+      end
+    end
+    alias remove_from_group remove_from_groups
+
+    def set_groups(desired_groups, minimum = true)
+      return if desired_groups.nil? or desired_groups.empty?
+
+      desired_groups = desired_groups.split(',').map(&:strip)
+
+      current_groups = self.groups
+
+      # First we add the user to all the groups it should be in but isn't
+      groups_to_add = desired_groups - current_groups
+      add_to_groups(*groups_to_add)
+
+      # Then we remove the user from all groups it is in but shouldn't be, if
+      # that's been requested
+      groups_to_remove = current_groups - desired_groups
+      remove_from_groups(*groups_to_remove) unless minimum
+    end
+
+    def self.create(name)
+      # Windows error 1379: The specified local group already exists.
+      raise Puppet::Error.new( "Cannot create user if group '#{name}' exists." ) if Puppet::Util::Windows::ADSI::Group.exists? name
+      new(name, Puppet::Util::Windows::ADSI.create(name, 'user'))
+    end
+
+    # UNLEN from lmcons.h - http://stackoverflow.com/a/2155176
+    MAX_USERNAME_LENGTH = 256
+    def self.current_user_name
+      user_name = ''
+      max_length = MAX_USERNAME_LENGTH + 1 # NULL terminated
+      FFI::MemoryPointer.new(max_length * 2) do |buffer| # wide string
+        FFI::MemoryPointer.new(:dword, 1) do |buffer_size|
+          buffer_size.write_dword(max_length) # length in TCHARs
+
+          if GetUserNameW(buffer, buffer_size) == FFI::WIN32_FALSE
+            raise Puppet::Util::Windows::Error.new("Failed to get user name")
+          end
+          # buffer_size includes trailing NULL
+          user_name = buffer.read_wide_string(buffer_size.read_dword - 1)
+        end
+      end
+
+      user_name
+    end
+
+    def self.exists?(name)
+      Puppet::Util::Windows::ADSI::connectable?(User.uri(*User.parse_name(name)))
+    end
+
+    def self.delete(name)
+      Puppet::Util::Windows::ADSI.delete(name, 'user')
+    end
+
+    def self.each(&block)
+      wql = Puppet::Util::Windows::ADSI.execquery('select name from win32_useraccount where localaccount = "TRUE"')
+
+      users = []
+      wql.each do |u|
+        users << new(u.name)
+      end
+
+      users.each(&block)
+    end
+
+    ffi_convention :stdcall
+
+    # http://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx
+    # BOOL WINAPI GetUserName(
+    #   _Out_    LPTSTR lpBuffer,
+    #   _Inout_  LPDWORD lpnSize
+    # );
+    ffi_lib :advapi32
+    attach_function_private :GetUserNameW,
+      [:lpwstr, :lpdword], :win32_bool
+  end
+
+  class UserProfile
+    def self.delete(sid)
+      begin
+        Puppet::Util::Windows::ADSI.wmi_connection.Delete("Win32_UserProfile.SID='#{sid}'")
+      rescue WIN32OLERuntimeError => e
+        # http://social.technet.microsoft.com/Forums/en/ITCG/thread/0f190051-ac96-4bf1-a47f-6b864bfacee5
+        # Prior to Vista SP1, there's no builtin way to programmatically
+        # delete user profiles (except for delprof.exe). So try to delete
+        # but warn if we fail
+        raise e unless e.message.include?('80041010')
+
+        Puppet.warning "Cannot delete user profile for '#{sid}' prior to Vista SP1"
+      end
+    end
+  end
+
+  class Group
+    extend Enumerable
+
+    attr_accessor :native_group
+    attr_reader :name, :sid
+    def initialize(name, native_group = nil)
+      @name = name
+      @native_group = native_group
+    end
+
+    def uri
+      self.class.uri(name)
+    end
+
+    def self.uri(name, host = '.')
+      if sid_uri = Puppet::Util::Windows::ADSI.sid_uri_safe(name) then return sid_uri end
+
+      Puppet::Util::Windows::ADSI.uri(name, 'group', host)
+    end
+
+    def native_group
+      @native_group ||= Puppet::Util::Windows::ADSI.connect(uri)
+    end
+
+    def sid
+      @sid ||= Puppet::Util::Windows::SID.octet_string_to_sid_object(native_group.objectSID)
+    end
+
+    def commit
+      begin
+        native_group.SetInfo unless native_group.nil?
+      rescue WIN32OLERuntimeError => e
+        # ERROR_BAD_USERNAME 2202L from winerror.h
+        if e.message =~ /8007089A/m
+          raise Puppet::Error.new(
+            "Puppet is not able to create/delete domain groups with the group resource.",
+            e
+          )
+        end
+
+        raise Puppet::Error.new( "Group update failed: #{e}", e )
+      end
+      self
+    end
+
+    def self.name_sid_hash(names)
+      return [] if names.nil? or names.empty?
+
+      sids = names.map do |name|
+        sid = Puppet::Util::Windows::SID.name_to_sid_object(name)
+        raise Puppet::Error.new( "Could not resolve username: #{name}" ) if !sid
+        [sid.to_s, sid]
+      end
+
+      Hash[ sids ]
+    end
+
+    def add_members(*names)
+      Puppet.deprecation_warning('Puppet::Util::Windows::ADSI::Group#add_members is deprecated; please use Puppet::Util::Windows::ADSI::Group#add_member_sids')
+      sids = self.class.name_sid_hash(names)
+      add_member_sids(*sids.values)
+    end
+    alias add_member add_members
+
+    def remove_members(*names)
+      Puppet.deprecation_warning('Puppet::Util::Windows::ADSI::Group#remove_members is deprecated; please use Puppet::Util::Windows::ADSI::Group#remove_member_sids')
+      sids = self.class.name_sid_hash(names)
+      remove_member_sids(*sids.values)
+    end
+    alias remove_member remove_members
+
+    def add_member_sids(*sids)
+      sids.each do |sid|
+        native_group.Add(Puppet::Util::Windows::ADSI.sid_uri(sid))
+      end
+    end
+
+    def remove_member_sids(*sids)
+      sids.each do |sid|
+        native_group.Remove(Puppet::Util::Windows::ADSI.sid_uri(sid))
+      end
+    end
+
+    def members
+      # WIN32OLE objects aren't enumerable, so no map
+      members = []
+      native_group.Members.each {|m| members << m.Name}
+      members
+    end
+
+    def member_sids
+      sids = []
+      native_group.Members.each do |m|
+        sids << Puppet::Util::Windows::SID.octet_string_to_sid_object(m.objectSID)
+      end
+      sids
+    end
+
+    def set_members(desired_members, inclusive = true)
+      return if desired_members.nil?
+
+      current_hash = Hash[ self.member_sids.map { |sid| [sid.to_s, sid] } ]
+      desired_hash = self.class.name_sid_hash(desired_members)
+
+      # First we add all missing members
+      if !desired_hash.empty?
+        members_to_add = (desired_hash.keys - current_hash.keys).map { |sid| desired_hash[sid] }
+        add_member_sids(*members_to_add)
+      end
+
+      # Then we remove all extra members if inclusive
+      if inclusive
+        if desired_hash.empty?
+          members_to_remove = current_hash.values
+        else
+          members_to_remove = (current_hash.keys - desired_hash.keys).map { |sid| current_hash[sid] }
+        end
+
+        remove_member_sids(*members_to_remove)
+      end
+    end
+
+    def self.create(name)
+      # Windows error 2224: The account already exists.
+      raise Puppet::Error.new( "Cannot create group if user '#{name}' exists." ) if Puppet::Util::Windows::ADSI::User.exists? name
+      new(name, Puppet::Util::Windows::ADSI.create(name, 'group'))
+    end
+
+    def self.exists?(name)
+      Puppet::Util::Windows::ADSI.connectable?(Group.uri(name))
+    end
+
+    def self.delete(name)
+      Puppet::Util::Windows::ADSI.delete(name, 'group')
+    end
+
+    def self.each(&block)
+      wql = Puppet::Util::Windows::ADSI.execquery( 'select name from win32_group where localaccount = "TRUE"' )
+
+      groups = []
+      wql.each do |g|
+        groups << new(g.name)
+      end
+
+      groups.each(&block)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/api_types.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/api_types.rb
new file mode 100644
index 0000000..52645d8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/api_types.rb
@@ -0,0 +1,255 @@
+require 'ffi'
+require 'puppet/util/windows/string'
+
+module Puppet::Util::Windows::APITypes
+  module ::FFI
+    WIN32_FALSE = 0
+
+    # standard Win32 error codes
+    ERROR_SUCCESS = 0
+  end
+
+  module ::FFI::Library
+    # Wrapper method for attach_function + private
+    def attach_function_private(*args)
+      attach_function(*args)
+      private args[0]
+    end
+  end
+
+  class ::FFI::Pointer
+    NULL_HANDLE = 0
+    NULL_TERMINATOR_WCHAR = 0
+
+    def self.from_string_to_wide_string(str, &block)
+      str = Puppet::Util::Windows::String.wide_string(str)
+      FFI::MemoryPointer.new(:byte, str.bytesize) do |ptr|
+        # uchar here is synonymous with byte
+        ptr.put_array_of_uchar(0, str.bytes.to_a)
+
+        yield ptr
+      end
+
+      # ptr has already had free called, so nothing to return
+      nil
+    end
+
+    def read_win32_bool
+      # BOOL is always a 32-bit integer in Win32
+      # some Win32 APIs return 1 for true, while others are non-0
+      read_int32 != FFI::WIN32_FALSE
+    end
+
+    alias_method :read_dword, :read_uint32
+    alias_method :read_win32_ulong, :read_uint32
+
+    alias_method :read_hresult, :read_int32
+
+    def read_handle
+      type_size == 4 ? read_uint32 : read_uint64
+    end
+
+    alias_method :read_wchar, :read_uint16
+    alias_method :read_word,  :read_uint16
+
+    def read_wide_string(char_length)
+      # char_length is number of wide chars (typically excluding NULLs), *not* bytes
+      str = get_bytes(0, char_length * 2).force_encoding('UTF-16LE')
+      str.encode(Encoding.default_external)
+    end
+
+    def read_arbitrary_wide_string_up_to(max_char_length = 512)
+      # max_char_length is number of wide chars (typically excluding NULLs), *not* bytes
+      # use a pointer to read one UTF-16LE char (2 bytes) at a time
+      wchar_ptr = FFI::Pointer.new(:wchar, address)
+
+      # now iterate 2 bytes at a time until an offset lower than max_char_length is found
+      0.upto(max_char_length - 1) do |i|
+        if wchar_ptr[i].read_wchar == NULL_TERMINATOR_WCHAR
+          return read_wide_string(i)
+        end
+      end
+
+      read_wide_string(max_char_length)
+    end
+
+    def read_win32_local_pointer(&block)
+      ptr = nil
+      begin
+        ptr = read_pointer
+        yield ptr
+      ensure
+        if ptr && ! ptr.null?
+          if FFI::WIN32::LocalFree(ptr.address) != FFI::Pointer::NULL_HANDLE
+            Puppet.debug "LocalFree memory leak"
+          end
+        end
+      end
+
+      # ptr has already had LocalFree called, so nothing to return
+      nil
+    end
+
+    def read_com_memory_pointer(&block)
+      ptr = nil
+      begin
+        ptr = read_pointer
+        yield ptr
+      ensure
+        FFI::WIN32::CoTaskMemFree(ptr) if ptr && ! ptr.null?
+      end
+
+      # ptr has already had CoTaskMemFree called, so nothing to return
+      nil
+    end
+
+
+    alias_method :write_dword, :write_uint32
+    alias_method :write_word, :write_uint16
+  end
+
+  # FFI Types
+  # https://github.com/ffi/ffi/wiki/Types
+
+  # Windows - Common Data Types
+  # http://msdn.microsoft.com/en-us/library/cc230309.aspx
+
+  # Windows Data Types
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx
+
+  FFI.typedef :uint16, :word
+  FFI.typedef :uint32, :dword
+  # uintptr_t is defined in an FFI conf as platform specific, either
+  # ulong_long on x64 or just ulong on x86
+  FFI.typedef :uintptr_t, :handle
+  FFI.typedef :uintptr_t, :hwnd
+
+  # buffer_inout is similar to pointer (platform specific), but optimized for buffers
+  FFI.typedef :buffer_inout, :lpwstr
+  # buffer_in is similar to pointer (platform specific), but optimized for CONST read only buffers
+  FFI.typedef :buffer_in, :lpcwstr
+  FFI.typedef :buffer_in, :lpcolestr
+
+  # string is also similar to pointer, but should be used for const char *
+  # NOTE that this is not wide, useful only for A suffixed functions
+  FFI.typedef :string, :lpcstr
+
+  # pointer in FFI is platform specific
+  # NOTE: for API calls with reserved lpvoid parameters, pass a FFI::Pointer::NULL
+  FFI.typedef :pointer, :lpcvoid
+  FFI.typedef :pointer, :lpvoid
+  FFI.typedef :pointer, :lpword
+  FFI.typedef :pointer, :lpdword
+  FFI.typedef :pointer, :pdword
+  FFI.typedef :pointer, :phandle
+  FFI.typedef :pointer, :ulong_ptr
+  FFI.typedef :pointer, :pbool
+  FFI.typedef :pointer, :lpunknown
+
+  # any time LONG / ULONG is in a win32 API definition DO NOT USE platform specific width
+  # which is what FFI uses by default
+  # instead create new aliases for these very special cases
+  # NOTE: not a good idea to redefine FFI :ulong since other typedefs may rely on it
+  FFI.typedef :uint32, :win32_ulong
+  FFI.typedef :int32, :win32_long
+  # FFI bool can be only 1 byte at times,
+  # Win32 BOOL is a signed int, and is always 4 bytes, even on x64
+  # http://blogs.msdn.com/b/oldnewthing/archive/2011/03/28/10146459.aspx
+  FFI.typedef :int32, :win32_bool
+
+  # Same as a LONG, a 32-bit signed integer
+  FFI.typedef :int32, :hresult
+
+  # NOTE: FFI already defines (u)short as a 16-bit (un)signed like this:
+  # FFI.typedef :uint16, :ushort
+  # FFI.typedef :int16, :short
+
+  # 8 bits per byte
+  FFI.typedef :uchar, :byte
+  FFI.typedef :uint16, :wchar
+
+  module ::FFI::WIN32
+    extend ::FFI::Library
+
+    # http://msdn.microsoft.com/en-us/library/windows/desktop/aa373931(v=vs.85).aspx
+    # typedef struct _GUID {
+    #   DWORD Data1;
+    #   WORD  Data2;
+    #   WORD  Data3;
+    #   BYTE  Data4[8];
+    # } GUID;
+    class GUID < FFI::Struct
+      layout :Data1, :dword,
+             :Data2, :word,
+             :Data3, :word,
+             :Data4, [:byte, 8]
+
+      def self.[](s)
+        raise 'Bad GUID format.' unless s =~ /^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$/i
+
+        new.tap do |guid|
+          guid[:Data1] = s[0, 8].to_i(16)
+          guid[:Data2] = s[9, 4].to_i(16)
+          guid[:Data3] = s[14, 4].to_i(16)
+          guid[:Data4][0] = s[19, 2].to_i(16)
+          guid[:Data4][1] = s[21, 2].to_i(16)
+          s[24, 12].split('').each_slice(2).with_index do |a, i|
+            guid[:Data4][i + 2] = a.join('').to_i(16)
+          end
+        end
+      end
+
+      def ==(other) Windows.memcmp(other, self, size) == 0 end
+    end
+
+    # http://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx
+    # typedef struct _SYSTEMTIME {
+    #   WORD wYear;
+    #   WORD wMonth;
+    #   WORD wDayOfWeek;
+    #   WORD wDay;
+    #   WORD wHour;
+    #   WORD wMinute;
+    #   WORD wSecond;
+    #   WORD wMilliseconds;
+    # } SYSTEMTIME, *PSYSTEMTIME;
+    class SYSTEMTIME < FFI::Struct
+      layout :wYear, :word,
+             :wMonth, :word,
+             :wDayOfWeek, :word,
+             :wDay, :word,
+             :wHour, :word,
+             :wMinute, :word,
+             :wSecond, :word,
+             :wMilliseconds, :word
+
+      def to_local_time
+        Time.local(self[:wYear], self[:wMonth], self[:wDay],
+          self[:wHour], self[:wMinute], self[:wSecond], self[:wMilliseconds] * 1000)
+      end
+    end
+
+    ffi_convention :stdcall
+
+    # http://msdn.microsoft.com/en-us/library/windows/desktop/aa366730(v=vs.85).aspx
+    # HLOCAL WINAPI LocalFree(
+    #   _In_  HLOCAL hMem
+    # );
+    ffi_lib :kernel32
+    attach_function :LocalFree, [:handle], :handle
+
+    # http://msdn.microsoft.com/en-us/library/windows/desktop/ms724211(v=vs.85).aspx
+    # BOOL WINAPI CloseHandle(
+    #   _In_  HANDLE hObject
+    # );
+    ffi_lib :kernel32
+    attach_function_private :CloseHandle, [:handle], :win32_bool
+
+    # http://msdn.microsoft.com/en-us/library/windows/desktop/ms680722(v=vs.85).aspx
+    # void CoTaskMemFree(
+    #   _In_opt_  LPVOID pv
+    # );
+    ffi_lib :ole32
+    attach_function :CoTaskMemFree, [:lpvoid], :void
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/com.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/com.rb
new file mode 100644
index 0000000..0033d53
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/com.rb
@@ -0,0 +1,224 @@
+require 'ffi'
+
+module Puppet::Util::Windows::COM
+  extend FFI::Library
+
+  ffi_convention :stdcall
+
+  S_OK = 0
+  S_FALSE = 1
+
+  def SUCCEEDED(hr) hr >= 0 end
+  def FAILED(hr) hr < 0 end
+
+  module_function :SUCCEEDED, :FAILED
+
+  def raise_if_hresult_failed(name, *args)
+    failed = FAILED(result = send(name, *args)) and raise "#{name} failed (hresult #{format('%#08x', result)})."
+
+    result
+  ensure
+    yield failed if block_given?
+  end
+
+  module_function :raise_if_hresult_failed
+
+  CLSCTX_INPROC_SERVER = 0x1
+  CLSCTX_INPROC_HANDLER = 0x2
+  CLSCTX_LOCAL_SERVER = 0x4
+  CLSCTX_INPROC_SERVER16 = 0x8
+  CLSCTX_REMOTE_SERVER = 0x10
+  CLSCTX_INPROC_HANDLER16 = 0x20
+  CLSCTX_RESERVED1 = 0x40
+  CLSCTX_RESERVED2 = 0x80
+  CLSCTX_RESERVED3 = 0x100
+  CLSCTX_RESERVED4 = 0x200
+  CLSCTX_NO_CODE_DOWNLOAD = 0x400
+  CLSCTX_RESERVED5 = 0x800
+  CLSCTX_NO_CUSTOM_MARSHAL = 0x1000
+  CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000
+  CLSCTX_NO_FAILURE_LOG = 0x4000
+  CLSCTX_DISABLE_AAA = 0x8000
+  CLSCTX_ENABLE_AAA = 0x10000
+  CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000
+  CLSCTX_ACTIVATE_32_BIT_SERVER = 0x40000
+  CLSCTX_ACTIVATE_64_BIT_SERVER = 0x80000
+  CLSCTX_ENABLE_CLOAKING = 0x100000
+  CLSCTX_PS_DLL = -0x80000000
+  CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER
+  CLSCTX_ALL = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER
+  CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/ms686615(v=vs.85).aspx
+  # HRESULT CoCreateInstance(
+  #   _In_   REFCLSID rclsid,
+  #   _In_   LPUNKNOWN pUnkOuter,
+  #   _In_   DWORD dwClsContext,
+  #   _In_   REFIID riid,
+  #   _Out_  LPVOID *ppv
+  # );
+  ffi_lib :ole32
+  attach_function_private :CoCreateInstance,
+    [:pointer, :lpunknown, :dword, :pointer, :lpvoid], :hresult
+
+  # code modified from Unknownr project https://github.com/rpeev/Unknownr
+  # licensed under MIT
+  module Interface
+    def self.[](*args)
+      spec, iid, *ifaces = args.reverse
+
+      spec.each { |name, signature| signature[0].unshift(:pointer) }
+
+      Class.new(FFI::Struct) do
+        const_set(:IID, iid)
+
+        vtable = Class.new(FFI::Struct) do
+          vtable_hash = Hash[(ifaces.map { |iface| iface::VTBL::SPEC.to_a } << spec.to_a).flatten(1)]
+          const_set(:SPEC, vtable_hash)
+
+          layout \
+            *self::SPEC.map { |name, signature| [name, callback(*signature)] }.flatten
+        end
+
+        const_set(:VTBL, vtable)
+
+        layout \
+          :lpVtbl, :pointer
+      end
+    end
+  end
+
+  module Helpers
+    def QueryInstance(klass)
+      instance = nil
+
+      FFI::MemoryPointer.new(:pointer) do |ppv|
+        QueryInterface(klass::IID, ppv)
+
+        instance = klass.new(ppv.read_pointer)
+      end
+
+      begin
+        yield instance
+        return self
+      ensure
+        instance.Release
+      end if block_given?
+
+      instance
+    end
+
+    def UseInstance(klass, name, *args)
+      instance = nil
+
+      FFI::MemoryPointer.new(:pointer) do |ppv|
+        send(name, *args, ppv)
+
+        yield instance = klass.new(ppv.read_pointer)
+      end
+
+      self
+    ensure
+      instance.Release if instance && ! instance.null?
+    end
+  end
+
+  module Instance
+    def self.[](iface)
+      Class.new(iface) do
+        send(:include, Helpers)
+
+        def initialize(pointer)
+          self.pointer = pointer
+
+          @vtbl = self.class::VTBL.new(self[:lpVtbl])
+        end
+
+        attr_reader :vtbl
+
+        self::VTBL.members.each do |name|
+          define_method(name) do |*args|
+            if Puppet::Util::Windows::COM.FAILED(result = @vtbl[name].call(self, *args))
+              raise Puppet::Util::Windows::Error.new("Failed to call #{self}::#{name} with HRESULT: #{result}.", result)
+            end
+            result
+          end
+        end
+
+        layout \
+          :lpVtbl, :pointer
+      end
+    end
+  end
+
+  module Factory
+    def self.[](iface, clsid)
+      Class.new(iface) do
+        send(:include, Helpers)
+
+        const_set(:CLSID, clsid)
+
+        def initialize(opts = {})
+          @opts = opts
+
+          @opts[:clsctx] ||= CLSCTX_INPROC_SERVER
+
+          FFI::MemoryPointer.new(:pointer) do |ppv|
+            hr = Puppet::Util::Windows::COM.CoCreateInstance(self.class::CLSID, FFI::Pointer::NULL, @opts[:clsctx], self.class::IID, ppv)
+            if Puppet::Util::Windows::COM.FAILED(hr)
+              raise "CoCreateInstance failed (#{self.class})."
+            end
+
+            self.pointer = ppv.read_pointer
+          end
+
+          @vtbl = self.class::VTBL.new(self[:lpVtbl])
+        end
+
+        attr_reader :vtbl
+
+        self::VTBL.members.each do |name|
+          define_method(name) do |*args|
+            if Puppet::Util::Windows::COM.FAILED(result = @vtbl[name].call(self, *args))
+              raise Puppet::Util::Windows::Error.new("Failed to call #{self}::#{name} with HRESULT: #{result}.", result)
+            end
+            result
+          end
+        end
+
+        layout \
+          :lpVtbl, :pointer
+      end
+    end
+  end
+
+  IUnknown = Interface[
+    FFI::WIN32::GUID['00000000-0000-0000-C000-000000000046'],
+
+    QueryInterface: [[:pointer, :pointer], :hresult],
+    AddRef: [[], :win32_ulong],
+    Release: [[], :win32_ulong]
+  ]
+
+  Unknown = Instance[IUnknown]
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/ms678543(v=vs.85).aspx
+  # HRESULT CoInitialize(
+  #   _In_opt_  LPVOID pvReserved
+  # );
+  ffi_lib :ole32
+  attach_function_private :CoInitialize, [:lpvoid], :hresult
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/ms688715(v=vs.85).aspx
+  # void CoUninitialize(void);
+  ffi_lib :ole32
+  attach_function_private :CoUninitialize, [], :void
+
+  def InitializeCom
+    raise_if_hresult_failed(:CoInitialize, FFI::Pointer::NULL)
+
+    at_exit { CoUninitialize() }
+  end
+
+  module_function :InitializeCom
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/error.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/error.rb
new file mode 100644
index 0000000..4f54bca
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/error.rb
@@ -0,0 +1,83 @@
+require 'puppet/util/windows'
+
+# represents an error resulting from a Win32 error code
+class Puppet::Util::Windows::Error < Puppet::Error
+  require 'ffi'
+  extend FFI::Library
+
+  attr_reader :code
+
+  # NOTE: FFI.errno only works properly when prior Win32 calls have been made
+  # through FFI bindings.  Calls made through Win32API do not have their error
+  # codes captured by FFI.errno
+  def initialize(message, code = FFI.errno, original = nil)
+    super(message + ":  #{self.class.format_error_code(code)}", original)
+
+    @code = code
+  end
+
+  # Helper method that wraps FormatMessage that returns a human readable string.
+  def self.format_error_code(code)
+    # specifying 0 will look for LANGID in the following order
+    # 1.Language neutral
+    # 2.Thread LANGID, based on the thread's locale value
+    # 3.User default LANGID, based on the user's default locale value
+    # 4.System default LANGID, based on the system default locale value
+    # 5.US English
+    dwLanguageId = 0
+    flags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
+            FORMAT_MESSAGE_FROM_SYSTEM |
+            FORMAT_MESSAGE_ARGUMENT_ARRAY |
+            FORMAT_MESSAGE_IGNORE_INSERTS |
+            FORMAT_MESSAGE_MAX_WIDTH_MASK
+    error_string = ''
+
+    # this pointer actually points to a :lpwstr (pointer) since we're letting Windows allocate for us
+    FFI::MemoryPointer.new(:pointer, 1) do |buffer_ptr|
+      length = FormatMessageW(flags, FFI::Pointer::NULL, code, dwLanguageId,
+        buffer_ptr, 0, FFI::Pointer::NULL)
+
+      if length == FFI::WIN32_FALSE
+        # can't raise same error type here or potentially recurse infinitely
+        raise Puppet::Error.new("FormatMessageW could not format code #{code}")
+      end
+
+      # returns an FFI::Pointer with autorelease set to false, which is what we want
+      buffer_ptr.read_win32_local_pointer do |wide_string_ptr|
+        if wide_string_ptr.null?
+          raise Puppet::Error.new("FormatMessageW failed to allocate buffer for code #{code}")
+        end
+
+        error_string = wide_string_ptr.read_wide_string(length)
+      end
+    end
+
+    error_string
+  end
+
+  ERROR_FILE_NOT_FOUND      = 2
+  ERROR_ACCESS_DENIED       = 5
+
+  FORMAT_MESSAGE_ALLOCATE_BUFFER   = 0x00000100
+  FORMAT_MESSAGE_IGNORE_INSERTS    = 0x00000200
+  FORMAT_MESSAGE_FROM_SYSTEM       = 0x00001000
+  FORMAT_MESSAGE_ARGUMENT_ARRAY    = 0x00002000
+  FORMAT_MESSAGE_MAX_WIDTH_MASK    = 0x000000FF
+
+  ffi_convention :stdcall
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx
+  # DWORD WINAPI FormatMessage(
+  #   _In_      DWORD dwFlags,
+  #   _In_opt_  LPCVOID lpSource,
+  #   _In_      DWORD dwMessageId,
+  #   _In_      DWORD dwLanguageId,
+  #   _Out_     LPTSTR lpBuffer,
+  #   _In_      DWORD nSize,
+  #   _In_opt_  va_list *Arguments
+  # );
+  # NOTE: since we're not preallocating the buffer, use a :pointer for lpBuffer
+  ffi_lib :kernel32
+  attach_function_private :FormatMessageW,
+    [:dword, :lpcvoid, :dword, :dword, :pointer, :dword, :pointer], :dword
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/file.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/file.rb
new file mode 100644
index 0000000..07ffc1c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/file.rb
@@ -0,0 +1,401 @@
+require 'puppet/util/windows'
+
+module Puppet::Util::Windows::File
+  require 'ffi'
+  extend FFI::Library
+  extend Puppet::Util::Windows::String
+
+  FILE_ATTRIBUTE_READONLY      = 0x00000001
+
+  SYNCHRONIZE                 = 0x100000
+  STANDARD_RIGHTS_REQUIRED    = 0xf0000
+  STANDARD_RIGHTS_READ        = 0x20000
+  STANDARD_RIGHTS_WRITE       = 0x20000
+  STANDARD_RIGHTS_EXECUTE     = 0x20000
+  STANDARD_RIGHTS_ALL         = 0x1F0000
+  SPECIFIC_RIGHTS_ALL         = 0xFFFF
+
+  FILE_READ_DATA               = 1
+  FILE_WRITE_DATA              = 2
+  FILE_APPEND_DATA             = 4
+  FILE_READ_EA                 = 8
+  FILE_WRITE_EA                = 16
+  FILE_EXECUTE                 = 32
+  FILE_DELETE_CHILD            = 64
+  FILE_READ_ATTRIBUTES         = 128
+  FILE_WRITE_ATTRIBUTES        = 256
+
+  FILE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF
+
+  FILE_GENERIC_READ =
+     STANDARD_RIGHTS_READ |
+     FILE_READ_DATA |
+     FILE_READ_ATTRIBUTES |
+     FILE_READ_EA |
+     SYNCHRONIZE
+
+  FILE_GENERIC_WRITE =
+     STANDARD_RIGHTS_WRITE |
+     FILE_WRITE_DATA |
+     FILE_WRITE_ATTRIBUTES |
+     FILE_WRITE_EA |
+     FILE_APPEND_DATA |
+     SYNCHRONIZE
+
+  FILE_GENERIC_EXECUTE =
+     STANDARD_RIGHTS_EXECUTE |
+     FILE_READ_ATTRIBUTES |
+     FILE_EXECUTE |
+     SYNCHRONIZE
+
+  def replace_file(target, source)
+    target_encoded = wide_string(target.to_s)
+    source_encoded = wide_string(source.to_s)
+
+    flags = 0x1
+    backup_file = nil
+    result = ReplaceFileW(
+      target_encoded,
+      source_encoded,
+      backup_file,
+      flags,
+      FFI::Pointer::NULL,
+      FFI::Pointer::NULL
+    )
+
+    return true if result != FFI::WIN32_FALSE
+    raise Puppet::Util::Windows::Error.new("ReplaceFile(#{target}, #{source})")
+  end
+  module_function :replace_file
+
+  def move_file_ex(source, target, flags = 0)
+    result = MoveFileExW(wide_string(source.to_s),
+                         wide_string(target.to_s),
+                         flags)
+
+    return true if result != FFI::WIN32_FALSE
+    raise Puppet::Util::Windows::Error.
+      new("MoveFileEx(#{source}, #{target}, #{flags.to_s(8)})")
+  end
+  module_function :move_file_ex
+
+  def symlink(target, symlink)
+    flags = File.directory?(target) ? 0x1 : 0x0
+    result = CreateSymbolicLinkW(wide_string(symlink.to_s),
+      wide_string(target.to_s), flags)
+    return true if result != FFI::WIN32_FALSE
+    raise Puppet::Util::Windows::Error.new(
+      "CreateSymbolicLink(#{symlink}, #{target}, #{flags.to_s(8)})")
+  end
+  module_function :symlink
+
+  INVALID_FILE_ATTRIBUTES = 0xFFFFFFFF #define INVALID_FILE_ATTRIBUTES (DWORD (-1))
+
+  def get_file_attributes(file_name)
+    Puppet.deprecation_warning('Puppet::Util::Windows::File.get_file_attributes is deprecated; please use Puppet::Util::Windows::File.get_attributes')
+    get_attributes(file_name)
+  end
+  module_function :get_file_attributes
+
+  def get_attributes(file_name)
+    result = GetFileAttributesW(wide_string(file_name.to_s))
+    return result unless result == INVALID_FILE_ATTRIBUTES
+    raise Puppet::Util::Windows::Error.new("GetFileAttributes(#{file_name})")
+  end
+  module_function :get_attributes
+
+  def add_attributes(path, flags)
+    oldattrs = get_attributes(path)
+
+    if (oldattrs | flags) != oldattrs
+      set_attributes(path, oldattrs | flags)
+    end
+  end
+  module_function :add_attributes
+
+  def remove_attributes(path, flags)
+    oldattrs = get_attributes(path)
+
+    if (oldattrs & ~flags) != oldattrs
+      set_attributes(path, oldattrs & ~flags)
+    end
+  end
+  module_function :remove_attributes
+
+  def set_attributes(path, flags)
+    success = SetFileAttributesW(wide_string(path), flags) != FFI::WIN32_FALSE
+    raise Puppet::Util::Windows::Error.new("Failed to set file attributes") if !success
+
+    success
+  end
+  module_function :set_attributes
+
+  #define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1)
+  INVALID_HANDLE_VALUE = FFI::Pointer.new(-1).address
+  def self.create_file(file_name, desired_access, share_mode, security_attributes,
+    creation_disposition, flags_and_attributes, template_file_handle)
+
+    result = CreateFileW(wide_string(file_name.to_s),
+      desired_access, share_mode, security_attributes, creation_disposition,
+      flags_and_attributes, template_file_handle)
+
+    return result unless result == INVALID_HANDLE_VALUE
+    raise Puppet::Util::Windows::Error.new(
+      "CreateFile(#{file_name}, #{desired_access.to_s(8)}, #{share_mode.to_s(8)}, " +
+        "#{security_attributes}, #{creation_disposition.to_s(8)}, " +
+        "#{flags_and_attributes.to_s(8)}, #{template_file_handle})")
+  end
+
+  def self.get_reparse_point_data(handle, &block)
+    # must be multiple of 1024, min 10240
+    FFI::MemoryPointer.new(REPARSE_DATA_BUFFER.size) do |reparse_data_buffer_ptr|
+      device_io_control(handle, FSCTL_GET_REPARSE_POINT, nil, reparse_data_buffer_ptr)
+      yield REPARSE_DATA_BUFFER.new(reparse_data_buffer_ptr)
+    end
+
+    # underlying struct MemoryPointer has been cleaned up by this point, nothing to return
+    nil
+  end
+
+  def self.device_io_control(handle, io_control_code, in_buffer = nil, out_buffer = nil)
+    if out_buffer.nil?
+      raise Puppet::Util::Windows::Error.new("out_buffer is required")
+    end
+
+    FFI::MemoryPointer.new(:dword, 1) do |bytes_returned_ptr|
+      result = DeviceIoControl(
+        handle,
+        io_control_code,
+        in_buffer, in_buffer.nil? ? 0 : in_buffer.size,
+        out_buffer, out_buffer.size,
+        bytes_returned_ptr,
+        nil
+      )
+
+      if result == FFI::WIN32_FALSE
+        raise Puppet::Util::Windows::Error.new(
+          "DeviceIoControl(#{handle}, #{io_control_code}, " +
+          "#{in_buffer}, #{in_buffer ? in_buffer.size : ''}, " +
+          "#{out_buffer}, #{out_buffer ? out_buffer.size : ''}")
+      end
+    end
+
+    out_buffer
+  end
+
+  FILE_ATTRIBUTE_REPARSE_POINT = 0x400
+  def symlink?(file_name)
+    begin
+      attributes = get_attributes(file_name)
+      (attributes & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT
+    rescue
+      # raised INVALID_FILE_ATTRIBUTES is equivalent to file not found
+      false
+    end
+  end
+  module_function :symlink?
+
+  GENERIC_READ                  = 0x80000000
+  GENERIC_WRITE                 = 0x40000000
+  GENERIC_EXECUTE               = 0x20000000
+  GENERIC_ALL                   = 0x10000000
+  FILE_SHARE_READ               = 1
+  FILE_SHARE_WRITE              = 2
+  OPEN_EXISTING                 = 3
+  FILE_FLAG_OPEN_REPARSE_POINT  = 0x00200000
+  FILE_FLAG_BACKUP_SEMANTICS    = 0x02000000
+
+  def self.open_symlink(link_name)
+    begin
+      yield handle = create_file(
+      link_name,
+      GENERIC_READ,
+      FILE_SHARE_READ,
+      nil, # security_attributes
+      OPEN_EXISTING,
+      FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
+      0) # template_file
+    ensure
+      FFI::WIN32.CloseHandle(handle) if handle
+    end
+
+    # handle has had CloseHandle called against it, so nothing to return
+    nil
+  end
+
+  def readlink(link_name)
+    link = nil
+    open_symlink(link_name) do |handle|
+      link = resolve_symlink(handle)
+    end
+
+    link
+  end
+  module_function :readlink
+
+  def stat(file_name)
+    file_name = file_name.to_s # accomodate PathName or String
+    stat = File.stat(file_name)
+    singleton_class = class << stat; self; end
+    target_path = file_name
+
+    if symlink?(file_name)
+      target_path = readlink(file_name)
+      link_ftype = File.stat(target_path).ftype
+
+      # sigh, monkey patch instance method for instance, and close over link_ftype
+      singleton_class.send(:define_method, :ftype) do
+        link_ftype
+      end
+    end
+
+    singleton_class.send(:define_method, :mode) do
+      Puppet::Util::Windows::Security.get_mode(target_path)
+    end
+
+    stat
+  end
+  module_function :stat
+
+  def lstat(file_name)
+    file_name = file_name.to_s # accomodate PathName or String
+    # monkey'ing around!
+    stat = File.lstat(file_name)
+
+    singleton_class = class << stat; self; end
+    singleton_class.send(:define_method, :mode) do
+      Puppet::Util::Windows::Security.get_mode(file_name)
+    end
+
+    if symlink?(file_name)
+      def stat.ftype
+        "link"
+      end
+    end
+    stat
+  end
+  module_function :lstat
+
+  private
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa364571(v=vs.85).aspx
+  FSCTL_GET_REPARSE_POINT = 0x900a8
+
+  def self.resolve_symlink(handle)
+    path = nil
+    get_reparse_point_data(handle) do |reparse_data|
+      offset = reparse_data[:PrintNameOffset]
+      length = reparse_data[:PrintNameLength]
+
+      ptr = reparse_data.pointer + reparse_data.offset_of(:PathBuffer) + offset
+      path = ptr.read_wide_string(length / 2) # length is bytes, need UTF-16 wchars
+    end
+
+    path
+  end
+
+  ffi_convention :stdcall
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa365512(v=vs.85).aspx
+  # BOOL WINAPI ReplaceFile(
+  #   _In_        LPCTSTR lpReplacedFileName,
+  #   _In_        LPCTSTR lpReplacementFileName,
+  #   _In_opt_    LPCTSTR lpBackupFileName,
+  #   _In_        DWORD dwReplaceFlags - 0x1 REPLACEFILE_WRITE_THROUGH,
+  #                                      0x2 REPLACEFILE_IGNORE_MERGE_ERRORS,
+  #                                      0x4 REPLACEFILE_IGNORE_ACL_ERRORS
+  #   _Reserved_  LPVOID lpExclude,
+  #   _Reserved_  LPVOID lpReserved
+  # );
+  ffi_lib :kernel32
+  attach_function_private :ReplaceFileW,
+    [:lpcwstr, :lpcwstr, :lpcwstr, :dword, :lpvoid, :lpvoid], :win32_bool
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa365240(v=vs.85).aspx
+  # BOOL WINAPI MoveFileEx(
+  #   _In_      LPCTSTR lpExistingFileName,
+  #   _In_opt_  LPCTSTR lpNewFileName,
+  #   _In_      DWORD dwFlags
+  # );
+  ffi_lib :kernel32
+  attach_function_private :MoveFileExW,
+    [:lpcwstr, :lpcwstr, :dword], :win32_bool
+
+  # BOOLEAN WINAPI CreateSymbolicLink(
+  #   _In_  LPTSTR lpSymlinkFileName, - symbolic link to be created
+  #   _In_  LPTSTR lpTargetFileName, - name of target for symbolic link
+  #   _In_  DWORD dwFlags - 0x0 target is a file, 0x1 target is a directory
+  # );
+  # rescue on Windows < 6.0 so that code doesn't explode
+  begin
+    ffi_lib :kernel32
+    attach_function_private :CreateSymbolicLinkW,
+      [:lpwstr, :lpwstr, :dword], :win32_bool
+  rescue LoadError
+  end
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa364944(v=vs.85).aspx
+  # DWORD WINAPI GetFileAttributes(
+  #   _In_  LPCTSTR lpFileName
+  # );
+  ffi_lib :kernel32
+  attach_function_private :GetFileAttributesW,
+    [:lpcwstr], :dword
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa365535(v=vs.85).aspx
+  # BOOL WINAPI SetFileAttributes(
+  #   _In_  LPCTSTR lpFileName,
+  #   _In_  DWORD dwFileAttributes
+  # );
+  ffi_lib :kernel32
+  attach_function_private :SetFileAttributesW,
+    [:lpcwstr, :dword], :win32_bool
+
+  # HANDLE WINAPI CreateFile(
+  #   _In_      LPCTSTR lpFileName,
+  #   _In_      DWORD dwDesiredAccess,
+  #   _In_      DWORD dwShareMode,
+  #   _In_opt_  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+  #   _In_      DWORD dwCreationDisposition,
+  #   _In_      DWORD dwFlagsAndAttributes,
+  #   _In_opt_  HANDLE hTemplateFile
+  # );
+  ffi_lib :kernel32
+  attach_function_private :CreateFileW,
+    [:lpcwstr, :dword, :dword, :pointer, :dword, :dword, :handle], :handle
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa363216(v=vs.85).aspx
+  # BOOL WINAPI DeviceIoControl(
+  #   _In_         HANDLE hDevice,
+  #   _In_         DWORD dwIoControlCode,
+  #   _In_opt_     LPVOID lpInBuffer,
+  #   _In_         DWORD nInBufferSize,
+  #   _Out_opt_    LPVOID lpOutBuffer,
+  #   _In_         DWORD nOutBufferSize,
+  #   _Out_opt_    LPDWORD lpBytesReturned,
+  #   _Inout_opt_  LPOVERLAPPED lpOverlapped
+  # );
+  ffi_lib :kernel32
+  attach_function_private :DeviceIoControl,
+    [:handle, :dword, :lpvoid, :dword, :lpvoid, :dword, :lpdword, :pointer], :win32_bool
+
+  MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16384
+
+  # REPARSE_DATA_BUFFER
+  # http://msdn.microsoft.com/en-us/library/cc232006.aspx
+  # http://msdn.microsoft.com/en-us/library/windows/hardware/ff552012(v=vs.85).aspx
+  # struct is always MAXIMUM_REPARSE_DATA_BUFFER_SIZE bytes
+  class REPARSE_DATA_BUFFER < FFI::Struct
+    layout :ReparseTag, :win32_ulong,
+           :ReparseDataLength, :ushort,
+           :Reserved, :ushort,
+           :SubstituteNameOffset, :ushort,
+           :SubstituteNameLength, :ushort,
+           :PrintNameOffset, :ushort,
+           :PrintNameLength, :ushort,
+           :Flags, :win32_ulong,
+           # max less above fields dword / uint 4 bytes, ushort 2 bytes
+           # technically a WCHAR buffer, but we care about size in bytes here
+           :PathBuffer, [:byte, MAXIMUM_REPARSE_DATA_BUFFER_SIZE - 20]
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/process.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/process.rb
new file mode 100644
index 0000000..c6a8c0d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/process.rb
@@ -0,0 +1,354 @@
+require 'puppet/util/windows'
+require 'win32/process'
+require 'ffi'
+
+module Puppet::Util::Windows::Process
+  extend Puppet::Util::Windows::String
+  extend FFI::Library
+
+  WAIT_TIMEOUT = 0x102
+
+  def execute(command, arguments, stdin, stdout, stderr)
+    Process.create( :command_line => command, :startup_info => {:stdin => stdin, :stdout => stdout, :stderr => stderr}, :close_handles => false )
+  end
+  module_function :execute
+
+  def wait_process(handle)
+    while WaitForSingleObject(handle, 0) == WAIT_TIMEOUT
+      sleep(1)
+    end
+
+    exit_status = -1
+    FFI::MemoryPointer.new(:dword, 1) do |exit_status_ptr|
+      if GetExitCodeProcess(handle, exit_status_ptr) == FFI::WIN32_FALSE
+        raise Puppet::Util::Windows::Error.new("Failed to get child process exit code")
+      end
+      exit_status = exit_status_ptr.read_dword
+
+      # $CHILD_STATUS is not set when calling win32/process Process.create
+      # and since it's read-only, we can't set it. But we can execute a
+      # a shell that simply returns the desired exit status, which has the
+      # desired effect.
+      %x{#{ENV['COMSPEC']} /c exit #{exit_status}}
+    end
+
+    exit_status
+  end
+  module_function :wait_process
+
+  def get_current_process
+    # this pseudo-handle does not require closing per MSDN docs
+    GetCurrentProcess()
+  end
+  module_function :get_current_process
+
+  def open_process_token(handle, desired_access, &block)
+    token_handle = nil
+    begin
+      FFI::MemoryPointer.new(:handle, 1) do |token_handle_ptr|
+        result = OpenProcessToken(handle, desired_access, token_handle_ptr)
+        if result == FFI::WIN32_FALSE
+          raise Puppet::Util::Windows::Error.new(
+            "OpenProcessToken(#{handle}, #{desired_access.to_s(8)}, #{token_handle_ptr})")
+        end
+
+        yield token_handle = token_handle_ptr.read_handle
+      end
+
+      token_handle
+    ensure
+      FFI::WIN32.CloseHandle(token_handle) if token_handle
+    end
+
+    # token_handle has had CloseHandle called against it, so nothing to return
+    nil
+  end
+  module_function :open_process_token
+
+  # Execute a block with the current process token
+  def with_process_token(access, &block)
+    handle = get_current_process
+    open_process_token(handle, access) do |token_handle|
+      yield token_handle
+    end
+
+    # all handles have been closed, so nothing to safely return
+    nil
+  end
+  module_function :with_process_token
+
+  def lookup_privilege_value(name, system_name = '', &block)
+    FFI::MemoryPointer.new(LUID.size) do |luid_ptr|
+      result = LookupPrivilegeValueW(
+        wide_string(system_name),
+        wide_string(name.to_s),
+        luid_ptr
+        )
+
+      if result == FFI::WIN32_FALSE
+        raise Puppet::Util::Windows::Error.new(
+          "LookupPrivilegeValue(#{system_name}, #{name}, #{luid_ptr})")
+      end
+
+      yield LUID.new(luid_ptr)
+    end
+
+    # the underlying MemoryPointer for LUID is cleaned up by this point
+    nil
+  end
+  module_function :lookup_privilege_value
+
+  def get_token_information(token_handle, token_information, &block)
+    # to determine buffer size
+    FFI::MemoryPointer.new(:dword, 1) do |return_length_ptr|
+      result = GetTokenInformation(token_handle, token_information, nil, 0, return_length_ptr)
+      return_length = return_length_ptr.read_dword
+
+      if return_length <= 0
+        raise Puppet::Util::Windows::Error.new(
+          "GetTokenInformation(#{token_handle}, #{token_information}, nil, 0, #{return_length_ptr})")
+      end
+
+      # re-call API with properly sized buffer for all results
+      FFI::MemoryPointer.new(return_length) do |token_information_buf|
+        result = GetTokenInformation(token_handle, token_information,
+          token_information_buf, return_length, return_length_ptr)
+
+        if result == FFI::WIN32_FALSE
+          raise Puppet::Util::Windows::Error.new(
+            "GetTokenInformation(#{token_handle}, #{token_information}, #{token_information_buf}, " +
+              "#{return_length}, #{return_length_ptr})")
+        end
+
+        yield token_information_buf
+      end
+    end
+
+    # GetTokenInformation buffer has been cleaned up by this point, nothing to return
+    nil
+  end
+  module_function :get_token_information
+
+  def parse_token_information_as_token_privileges(token_information_buf)
+    raw_privileges = TOKEN_PRIVILEGES.new(token_information_buf)
+    privileges = { :count => raw_privileges[:PrivilegeCount], :privileges => [] }
+
+    offset = token_information_buf + TOKEN_PRIVILEGES.offset_of(:Privileges)
+    privilege_ptr = FFI::Pointer.new(LUID_AND_ATTRIBUTES, offset)
+
+    # extract each instance of LUID_AND_ATTRIBUTES
+    0.upto(privileges[:count] - 1) do |i|
+      privileges[:privileges] <<  LUID_AND_ATTRIBUTES.new(privilege_ptr[i])
+    end
+
+    privileges
+  end
+  module_function :parse_token_information_as_token_privileges
+
+  def parse_token_information_as_token_elevation(token_information_buf)
+    TOKEN_ELEVATION.new(token_information_buf)
+  end
+  module_function :parse_token_information_as_token_elevation
+
+  TOKEN_ALL_ACCESS = 0xF01FF
+  ERROR_NO_SUCH_PRIVILEGE = 1313
+  def process_privilege_symlink?
+    privilege_symlink = false
+    handle = get_current_process
+    open_process_token(handle, TOKEN_ALL_ACCESS) do |token_handle|
+      lookup_privilege_value('SeCreateSymbolicLinkPrivilege') do |luid|
+        get_token_information(token_handle, :TokenPrivileges) do |token_info|
+          token_privileges = parse_token_information_as_token_privileges(token_info)
+          privilege_symlink = token_privileges[:privileges].any? { |p| p[:Luid].values == luid.values }
+        end
+      end
+    end
+
+    privilege_symlink
+  rescue Puppet::Util::Windows::Error => e
+    if e.code == ERROR_NO_SUCH_PRIVILEGE
+      false # pre-Vista
+    else
+      raise e
+    end
+  end
+  module_function :process_privilege_symlink?
+
+  TOKEN_QUERY = 0x0008
+  # Returns whether or not the owner of the current process is running
+  # with elevated security privileges.
+  #
+  # Only supported on Windows Vista or later.
+  #
+  def elevated_security?
+    # default / pre-Vista
+    elevated = false
+    handle = nil
+
+    begin
+      handle = get_current_process
+      open_process_token(handle, TOKEN_QUERY) do |token_handle|
+        get_token_information(token_handle, :TokenElevation) do |token_info|
+          token_elevation = parse_token_information_as_token_elevation(token_info)
+          # TokenIsElevated member of the TOKEN_ELEVATION struct
+          elevated = token_elevation[:TokenIsElevated] != 0
+        end
+      end
+
+      elevated
+    rescue Puppet::Util::Windows::Error => e
+      raise e if e.code != ERROR_NO_SUCH_PRIVILEGE
+    ensure
+      FFI::WIN32.CloseHandle(handle) if handle
+    end
+  end
+  module_function :elevated_security?
+
+  ABOVE_NORMAL_PRIORITY_CLASS = 0x0008000
+  BELOW_NORMAL_PRIORITY_CLASS = 0x0004000
+  HIGH_PRIORITY_CLASS         = 0x0000080
+  IDLE_PRIORITY_CLASS         = 0x0000040
+  NORMAL_PRIORITY_CLASS       = 0x0000020
+  REALTIME_PRIORITY_CLASS     = 0x0000010
+
+  ffi_convention :stdcall
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx
+  # DWORD WINAPI WaitForSingleObject(
+  #   _In_  HANDLE hHandle,
+  #   _In_  DWORD dwMilliseconds
+  # );
+  ffi_lib :kernel32
+  attach_function_private :WaitForSingleObject,
+    [:handle, :dword], :dword
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/ms683189(v=vs.85).aspx
+  # BOOL WINAPI GetExitCodeProcess(
+  #   _In_   HANDLE hProcess,
+  #   _Out_  LPDWORD lpExitCode
+  # );
+  ffi_lib :kernel32
+  attach_function_private :GetExitCodeProcess,
+    [:handle, :lpdword], :win32_bool
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/ms683179(v=vs.85).aspx
+  # HANDLE WINAPI GetCurrentProcess(void);
+  ffi_lib :kernel32
+  attach_function_private :GetCurrentProcess, [], :handle
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa379295(v=vs.85).aspx
+  # BOOL WINAPI OpenProcessToken(
+  #   _In_   HANDLE ProcessHandle,
+  #   _In_   DWORD DesiredAccess,
+  #   _Out_  PHANDLE TokenHandle
+  # );
+  ffi_lib :advapi32
+  attach_function_private :OpenProcessToken,
+    [:handle, :dword, :phandle], :win32_bool
+
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa379261(v=vs.85).aspx
+  # typedef struct _LUID {
+  #   DWORD LowPart;
+  #   LONG  HighPart;
+  # } LUID, *PLUID;
+  class LUID < FFI::Struct
+    layout :LowPart, :dword,
+           :HighPart, :win32_long
+  end
+
+  # http://msdn.microsoft.com/en-us/library/Windows/desktop/aa379180(v=vs.85).aspx
+  # BOOL WINAPI LookupPrivilegeValue(
+  #   _In_opt_  LPCTSTR lpSystemName,
+  #   _In_      LPCTSTR lpName,
+  #   _Out_     PLUID lpLuid
+  # );
+  ffi_lib :advapi32
+  attach_function_private :LookupPrivilegeValueW,
+    [:lpcwstr, :lpcwstr, :pointer], :win32_bool
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa379626(v=vs.85).aspx
+  TOKEN_INFORMATION_CLASS = enum(
+      :TokenUser, 1,
+      :TokenGroups,
+      :TokenPrivileges,
+      :TokenOwner,
+      :TokenPrimaryGroup,
+      :TokenDefaultDacl,
+      :TokenSource,
+      :TokenType,
+      :TokenImpersonationLevel,
+      :TokenStatistics,
+      :TokenRestrictedSids,
+      :TokenSessionId,
+      :TokenGroupsAndPrivileges,
+      :TokenSessionReference,
+      :TokenSandBoxInert,
+      :TokenAuditPolicy,
+      :TokenOrigin,
+      :TokenElevationType,
+      :TokenLinkedToken,
+      :TokenElevation,
+      :TokenHasRestrictions,
+      :TokenAccessInformation,
+      :TokenVirtualizationAllowed,
+      :TokenVirtualizationEnabled,
+      :TokenIntegrityLevel,
+      :TokenUIAccess,
+      :TokenMandatoryPolicy,
+      :TokenLogonSid,
+      :TokenIsAppContainer,
+      :TokenCapabilities,
+      :TokenAppContainerSid,
+      :TokenAppContainerNumber,
+      :TokenUserClaimAttributes,
+      :TokenDeviceClaimAttributes,
+      :TokenRestrictedUserClaimAttributes,
+      :TokenRestrictedDeviceClaimAttributes,
+      :TokenDeviceGroups,
+      :TokenRestrictedDeviceGroups,
+      :TokenSecurityAttributes,
+      :TokenIsRestricted,
+      :MaxTokenInfoClass
+  )
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa379263(v=vs.85).aspx
+  # typedef struct _LUID_AND_ATTRIBUTES {
+  #   LUID  Luid;
+  #   DWORD Attributes;
+  # } LUID_AND_ATTRIBUTES, *PLUID_AND_ATTRIBUTES;
+  class LUID_AND_ATTRIBUTES < FFI::Struct
+    layout :Luid, LUID,
+           :Attributes, :dword
+  end
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa379630(v=vs.85).aspx
+  # typedef struct _TOKEN_PRIVILEGES {
+  #   DWORD               PrivilegeCount;
+  #   LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY];
+  # } TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
+  class TOKEN_PRIVILEGES < FFI::Struct
+    layout :PrivilegeCount, :dword,
+           :Privileges, [LUID_AND_ATTRIBUTES, 1]    # placeholder for offset
+  end
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/bb530717(v=vs.85).aspx
+  # typedef struct _TOKEN_ELEVATION {
+  #   DWORD TokenIsElevated;
+  # } TOKEN_ELEVATION, *PTOKEN_ELEVATION;
+  class TOKEN_ELEVATION < FFI::Struct
+    layout :TokenIsElevated, :dword
+  end
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa446671(v=vs.85).aspx
+  # BOOL WINAPI GetTokenInformation(
+  #   _In_       HANDLE TokenHandle,
+  #   _In_       TOKEN_INFORMATION_CLASS TokenInformationClass,
+  #   _Out_opt_  LPVOID TokenInformation,
+  #   _In_       DWORD TokenInformationLength,
+  #   _Out_      PDWORD ReturnLength
+  # );
+  ffi_lib :advapi32
+  attach_function_private :GetTokenInformation,
+    [:handle, TOKEN_INFORMATION_CLASS, :lpvoid, :dword, :pdword ], :win32_bool
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/registry.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/registry.rb
new file mode 100644
index 0000000..84cdde7
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/registry.rb
@@ -0,0 +1,80 @@
+require 'puppet/util/windows'
+
+module Puppet::Util::Windows
+  module Registry
+    require 'ffi'
+    extend FFI::Library
+
+    # http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129(v=vs.85).aspx
+    KEY64 = 0x100
+    KEY32 = 0x200
+
+    KEY_READ       = 0x20019
+    KEY_WRITE      = 0x20006
+    KEY_ALL_ACCESS = 0x2003f
+
+    def root(name)
+      Win32::Registry.const_get(name)
+    rescue NameError
+      raise Puppet::Error, "Invalid registry key '#{name}'", $!.backtrace
+    end
+
+    def open(name, path, mode = KEY_READ | KEY64, &block)
+      hkey = root(name)
+      begin
+        hkey.open(path, mode) do |subkey|
+          return yield subkey
+        end
+      rescue Win32::Registry::Error => error
+        raise Puppet::Util::Windows::Error.new("Failed to open registry key '#{hkey.keyname}\\#{path}'", error.code, error)
+      end
+    end
+
+    def values(subkey)
+      values = {}
+      subkey.each_value do |name, type, data|
+        case type
+        when Win32::Registry::REG_MULTI_SZ
+          data.each { |str| force_encoding(str) }
+        when Win32::Registry::REG_SZ, Win32::Registry::REG_EXPAND_SZ
+          force_encoding(data)
+        end
+        values[name] = data
+      end
+      values
+    end
+
+    if defined?(Encoding)
+      def force_encoding(str)
+        if @encoding.nil?
+          # See https://bugs.ruby-lang.org/issues/8943
+          # Ruby uses ANSI versions of Win32 APIs to read values from the
+          # registry. The encoding of these strings depends on the active
+          # code page. However, ruby incorrectly sets the string
+          # encoding to US-ASCII. So we must force the encoding to the
+          # correct value.
+          begin
+            cp = GetACP()
+            @encoding = Encoding.const_get("CP#{cp}")
+          rescue
+            @encoding = Encoding.default_external
+          end
+        end
+
+        str.force_encoding(@encoding)
+      end
+    else
+      def force_encoding(str, enc)
+      end
+    end
+    private :force_encoding
+
+
+    ffi_convention :stdcall
+
+    # http://msdn.microsoft.com/en-us/library/windows/desktop/dd318070(v=vs.85).aspx
+    # UINT GetACP(void);
+    ffi_lib :kernel32
+    attach_function_private :GetACP, [], :uint32
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/root_certs.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/root_certs.rb
new file mode 100644
index 0000000..e15a203
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/root_certs.rb
@@ -0,0 +1,108 @@
+require 'puppet/util/windows'
+require 'openssl'
+require 'ffi'
+
+# Represents a collection of trusted root certificates.
+#
+# @api public
+class Puppet::Util::Windows::RootCerts
+  include Enumerable
+  extend FFI::Library
+
+  def initialize(roots)
+    @roots = roots
+  end
+
+  # Enumerates each root certificate.
+  # @yieldparam cert [OpenSSL::X509::Certificate] each root certificate
+  # @api public
+  def each
+    @roots.each {|cert| yield cert}
+  end
+
+  # Returns a new instance.
+  # @return [Puppet::Util::Windows::RootCerts] object constructed from current root certificates
+  def self.instance
+    new(self.load_certs)
+  end
+
+  # Returns an array of root certificates.
+  #
+  # @return [Array<[OpenSSL::X509::Certificate]>] an array of root certificates
+  # @api private
+  def self.load_certs
+    certs = []
+
+    # This is based on a patch submitted to openssl:
+    # http://www.mail-archive.com/openssl-dev@openssl.org/msg26958.html
+    ptr = FFI::Pointer::NULL
+    store = CertOpenSystemStoreA(nil, "ROOT")
+    begin
+      while (ptr = CertEnumCertificatesInStore(store, ptr)) and not ptr.null?
+        context = CERT_CONTEXT.new(ptr)
+        cert_buf = context[:pbCertEncoded].read_bytes(context[:cbCertEncoded])
+        begin
+          certs << OpenSSL::X509::Certificate.new(cert_buf)
+        rescue => detail
+          Puppet.warning("Failed to import root certificate: #{detail.inspect}")
+        end
+      end
+    ensure
+      CertCloseStore(store, 0)
+    end
+
+    certs
+  end
+
+  ffi_convention :stdcall
+  # typedef void *HCERTSTORE;
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa377189(v=vs.85).aspx
+  # typedef struct _CERT_CONTEXT {
+  #   DWORD      dwCertEncodingType;
+  #   BYTE       *pbCertEncoded;
+  #   DWORD      cbCertEncoded;
+  #   PCERT_INFO pCertInfo;
+  #   HCERTSTORE hCertStore;
+  # } CERT_CONTEXT, *PCERT_CONTEXT;typedef const CERT_CONTEXT *PCCERT_CONTEXT;
+  class CERT_CONTEXT < FFI::Struct
+    layout(
+      :dwCertEncodingType, :dword,
+      :pbCertEncoded,      :pointer,
+      :cbCertEncoded,      :dword,
+      :pCertInfo,          :pointer,
+      :hCertStore,         :handle
+    )
+  end
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa376560(v=vs.85).aspx
+  # HCERTSTORE
+  # WINAPI
+  # CertOpenSystemStoreA(
+  #   __in_opt HCRYPTPROV_LEGACY hProv,
+  #   __in LPCSTR szSubsystemProtocol
+  #   );
+  # typedef ULONG_PTR HCRYPTPROV_LEGACY;
+  ffi_lib :crypt32
+  attach_function_private :CertOpenSystemStoreA, [:ulong_ptr, :lpcstr], :handle
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa376050(v=vs.85).aspx
+  # PCCERT_CONTEXT
+  # WINAPI
+  # CertEnumCertificatesInStore(
+  #   __in HCERTSTORE hCertStore,
+  #   __in_opt PCCERT_CONTEXT pPrevCertContext
+  #   );
+  ffi_lib :crypt32
+  attach_function_private :CertEnumCertificatesInStore, [:handle, :pointer], :pointer
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa376026(v=vs.85).aspx
+  # BOOL
+  # WINAPI
+  # CertCloseStore(
+  #   __in_opt HCERTSTORE hCertStore,
+  #   __in DWORD dwFlags
+  #   );
+  ffi_lib :crypt32
+  attach_function_private :CertCloseStore, [:handle, :dword], :win32_bool
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/security.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/security.rb
new file mode 100644
index 0000000..41a80af
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/security.rb
@@ -0,0 +1,923 @@
+# This class maps POSIX owner, group, and modes to the Windows
+# security model, and back.
+#
+# The primary goal of this mapping is to ensure that owner, group, and
+# modes can be round-tripped in a consistent and deterministic
+# way. Otherwise, Puppet might think file resources are out-of-sync
+# every time it runs. A secondary goal is to provide equivalent
+# permissions for common use-cases. For example, setting the owner to
+# "Administrators", group to "Users", and mode to 750 (which also
+# denies access to everyone else.
+#
+# There are some well-known problems mapping windows and POSIX
+# permissions due to differences between the two security
+# models. Search for "POSIX permission mapping leak". In POSIX, access
+# to a file is determined solely based on the most specific class
+# (user, group, other). So a mode of 460 would deny write access to
+# the owner even if they are a member of the group. But in Windows,
+# the entire access control list is walked until the user is
+# explicitly denied or allowed (denied take precedence, and if neither
+# occurs they are denied). As a result, a user could be allowed access
+# based on their group membership. To solve this problem, other people
+# have used deny access control entries to more closely model POSIX,
+# but this introduces a lot of complexity.
+#
+# In general, this implementation only supports "typical" permissions,
+# where group permissions are a subset of user, and other permissions
+# are a subset of group, e.g. 754, but not 467.  However, there are
+# some Windows quirks to be aware of.
+#
+# * The owner can be either a user or group SID, and most system files
+#   are owned by the Administrators group.
+# * The group can be either a user or group SID.
+# * Unexpected results can occur if the owner and group are the
+#   same, but the user and group classes are different, e.g. 750. In
+#   this case, it is not possible to allow write access to the owner,
+#   but not the group. As a result, the actual permissions set on the
+#   file would be 770.
+# * In general, only privileged users can set the owner, group, or
+#   change the mode for files they do not own. In 2003, the user must
+#   be a member of the Administrators group. In Vista/2008, the user
+#   must be running with elevated privileges.
+# * A file/dir can be deleted by anyone with the DELETE access right
+#   OR by anyone that has the FILE_DELETE_CHILD access right for the
+#   parent. See http://support.microsoft.com/kb/238018. But on Unix,
+#   the user must have write access to the file/dir AND execute access
+#   to all of the parent path components.
+# * Many access control entries are inherited from parent directories,
+#   and it is common for file/dirs to have more than 3 entries,
+#   e.g. Users, Power Users, Administrators, SYSTEM, etc, which cannot
+#   be mapped into the 3 class POSIX model. The get_mode method will
+#   set the S_IEXTRA bit flag indicating that an access control entry
+#   was found whose SID is neither the owner, group, or other. This
+#   enables Puppet to detect when file/dirs are out-of-sync,
+#   especially those that Puppet did not create, but is attempting
+#   to manage.
+# * A special case of this is S_ISYSTEM_MISSING, which is set when the
+#   SYSTEM permissions are *not* present on the DACL.
+# * On Unix, the owner and group can be modified without changing the
+#   mode. But on Windows, an access control entry specifies which SID
+#   it applies to. As a result, the set_owner and set_group methods
+#   automatically rebuild the access control list based on the new
+#   (and different) owner or group.
+
+require 'puppet/util/windows'
+require 'pathname'
+require 'ffi'
+
+require 'win32/security'
+
+module Puppet::Util::Windows::Security
+  include Puppet::Util::Windows::String
+
+  extend Puppet::Util::Windows::Security
+  extend FFI::Library
+
+  # file modes
+  S_IRUSR = 0000400
+  S_IRGRP = 0000040
+  S_IROTH = 0000004
+  S_IWUSR = 0000200
+  S_IWGRP = 0000020
+  S_IWOTH = 0000002
+  S_IXUSR = 0000100
+  S_IXGRP = 0000010
+  S_IXOTH = 0000001
+  S_IRWXU = 0000700
+  S_IRWXG = 0000070
+  S_IRWXO = 0000007
+  S_ISVTX = 0001000
+  S_IEXTRA = 02000000  # represents an extra ace
+  S_ISYSTEM_MISSING = 04000000
+
+  # constants that are missing from Windows::Security
+  PROTECTED_DACL_SECURITY_INFORMATION   = 0x80000000
+  UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000
+  NO_INHERITANCE = 0x0
+  SE_DACL_PROTECTED = 0x1000
+
+  FILE = Puppet::Util::Windows::File
+
+  SE_BACKUP_NAME              = 'SeBackupPrivilege'
+  SE_RESTORE_NAME             = 'SeRestorePrivilege'
+
+  DELETE                      = 0x00010000
+  READ_CONTROL                = 0x20000
+  WRITE_DAC                   = 0x40000
+  WRITE_OWNER                 = 0x80000
+
+  OWNER_SECURITY_INFORMATION  = 1
+  GROUP_SECURITY_INFORMATION  = 2
+  DACL_SECURITY_INFORMATION   = 4
+
+  # Set the owner of the object referenced by +path+ to the specified
+  # +owner_sid+.  The owner sid should be of the form "S-1-5-32-544"
+  # and can either be a user or group.  Only a user with the
+  # SE_RESTORE_NAME privilege in their process token can overwrite the
+  # object's owner to something other than the current user.
+  def set_owner(owner_sid, path)
+    sd = get_security_descriptor(path)
+
+    if owner_sid != sd.owner
+      sd.owner = owner_sid
+      set_security_descriptor(path, sd)
+    end
+  end
+
+  # Get the owner of the object referenced by +path+.  The returned
+  # value is a SID string, e.g. "S-1-5-32-544".  Any user with read
+  # access to an object can get the owner. Only a user with the
+  # SE_BACKUP_NAME privilege in their process token can get the owner
+  # for objects they do not have read access to.
+  def get_owner(path)
+    return unless supports_acl?(path)
+
+    get_security_descriptor(path).owner
+  end
+
+  # Set the owner of the object referenced by +path+ to the specified
+  # +group_sid+.  The group sid should be of the form "S-1-5-32-544"
+  # and can either be a user or group.  Any user with WRITE_OWNER
+  # access to the object can change the group (regardless of whether
+  # the current user belongs to that group or not).
+  def set_group(group_sid, path)
+    sd = get_security_descriptor(path)
+
+    if group_sid != sd.group
+      sd.group = group_sid
+      set_security_descriptor(path, sd)
+    end
+  end
+
+  # Get the group of the object referenced by +path+.  The returned
+  # value is a SID string, e.g. "S-1-5-32-544".  Any user with read
+  # access to an object can get the group. Only a user with the
+  # SE_BACKUP_NAME privilege in their process token can get the group
+  # for objects they do not have read access to.
+  def get_group(path)
+    return unless supports_acl?(path)
+
+    get_security_descriptor(path).group
+  end
+
+  FILE_PERSISTENT_ACLS           = 0x00000008
+
+  def supports_acl?(path)
+    supported = false
+    root = Pathname.new(path).enum_for(:ascend).to_a.last.to_s
+    # 'A trailing backslash is required'
+    root = "#{root}\\" unless root =~ /[\/\\]$/
+
+    FFI::MemoryPointer.new(:pointer, 1) do |flags_ptr|
+      if GetVolumeInformationW(wide_string(root), FFI::Pointer::NULL, 0,
+          FFI::Pointer::NULL, FFI::Pointer::NULL,
+          flags_ptr, FFI::Pointer::NULL, 0) == FFI::WIN32_FALSE
+        raise Puppet::Util::Windows::Error.new("Failed to get volume information")
+      end
+      supported = flags_ptr.read_dword & FILE_PERSISTENT_ACLS == FILE_PERSISTENT_ACLS
+    end
+
+    supported
+  end
+
+  def get_attributes(path)
+    Puppet.deprecation_warning('Puppet::Util::Windows::Security.get_attributes is deprecated; please use Puppet::Util::Windows::File.get_attributes')
+    FILE.get_attributes(file_name)
+  end
+
+  def add_attributes(path, flags)
+    Puppet.deprecation_warning('Puppet::Util::Windows::Security.add_attributes is deprecated; please use Puppet::Util::Windows::File.add_attributes')
+    FILE.add_attributes(path, flags)
+  end
+
+  def remove_attributes(path, flags)
+    Puppet.deprecation_warning('Puppet::Util::Windows::Security.remove_attributes is deprecated; please use Puppet::Util::Windows::File.remove_attributes')
+    FILE.remove_attributes(path, flags)
+  end
+
+  def set_attributes(path, flags)
+    Puppet.deprecation_warning('Puppet::Util::Windows::Security.set_attributes is deprecated; please use Puppet::Util::Windows::File.set_attributes')
+    FILE.set_attributes(path, flags)
+  end
+
+  MASK_TO_MODE = {
+    FILE::FILE_GENERIC_READ => S_IROTH,
+    FILE::FILE_GENERIC_WRITE => S_IWOTH,
+    (FILE::FILE_GENERIC_EXECUTE & ~FILE::FILE_READ_ATTRIBUTES) => S_IXOTH
+  }
+
+  def get_aces_for_path_by_sid(path, sid)
+    get_security_descriptor(path).dacl.select { |ace| ace.sid == sid }
+  end
+
+  # Get the mode of the object referenced by +path+.  The returned
+  # integer value represents the POSIX-style read, write, and execute
+  # modes for the user, group, and other classes, e.g. 0640.  Any user
+  # with read access to an object can get the mode. Only a user with
+  # the SE_BACKUP_NAME privilege in their process token can get the
+  # mode for objects they do not have read access to.
+  def get_mode(path)
+    return unless supports_acl?(path)
+
+    well_known_world_sid = Win32::Security::SID::Everyone
+    well_known_nobody_sid = Win32::Security::SID::Nobody
+    well_known_system_sid = Win32::Security::SID::LocalSystem
+
+    mode = S_ISYSTEM_MISSING
+
+    sd = get_security_descriptor(path)
+    sd.dacl.each do |ace|
+      next if ace.inherit_only?
+
+      case ace.sid
+      when sd.owner
+        MASK_TO_MODE.each_pair do |k,v|
+          if (ace.mask & k) == k
+            mode |= (v << 6)
+          end
+        end
+      when sd.group
+        MASK_TO_MODE.each_pair do |k,v|
+          if (ace.mask & k) == k
+            mode |= (v << 3)
+          end
+        end
+      when well_known_world_sid
+        MASK_TO_MODE.each_pair do |k,v|
+          if (ace.mask & k) == k
+            mode |= (v << 6) | (v << 3) | v
+          end
+        end
+        if File.directory?(path) &&
+          (ace.mask & (FILE::FILE_WRITE_DATA | FILE::FILE_EXECUTE | FILE::FILE_DELETE_CHILD)) == (FILE::FILE_WRITE_DATA | FILE::FILE_EXECUTE)
+          mode |= S_ISVTX;
+        end
+      when well_known_nobody_sid
+        if (ace.mask & FILE::FILE_APPEND_DATA).nonzero?
+          mode |= S_ISVTX
+        end
+      when well_known_system_sid
+      else
+        #puts "Warning, unable to map SID into POSIX mode: #{ace.sid}"
+        mode |= S_IEXTRA
+      end
+
+      if ace.sid == well_known_system_sid
+        mode &= ~S_ISYSTEM_MISSING
+      end
+
+      # if owner and group the same, then user and group modes are the OR of both
+      if sd.owner == sd.group
+        mode |= ((mode & S_IRWXG) << 3) | ((mode & S_IRWXU) >> 3)
+        #puts "owner: #{sd.group}, 0x#{ace.mask.to_s(16)}, #{mode.to_s(8)}"
+      end
+    end
+
+    #puts "get_mode: #{mode.to_s(8)}"
+    mode
+  end
+
+  MODE_TO_MASK = {
+    S_IROTH => FILE::FILE_GENERIC_READ,
+    S_IWOTH => FILE::FILE_GENERIC_WRITE,
+    S_IXOTH => (FILE::FILE_GENERIC_EXECUTE & ~FILE::FILE_READ_ATTRIBUTES),
+  }
+
+  # Set the mode of the object referenced by +path+ to the specified
+  # +mode+.  The mode should be specified as POSIX-stye read, write,
+  # and execute modes for the user, group, and other classes,
+  # e.g. 0640. The sticky bit, S_ISVTX, is supported, but is only
+  # meaningful for directories. If set, group and others are not
+  # allowed to delete child objects for which they are not the owner.
+  # By default, the DACL is set to protected, meaning it does not
+  # inherit access control entries from parent objects. This can be
+  # changed by setting +protected+ to false. The owner of the object
+  # (with READ_CONTROL and WRITE_DACL access) can always change the
+  # mode. Only a user with the SE_BACKUP_NAME and SE_RESTORE_NAME
+  # privileges in their process token can change the mode for objects
+  # that they do not have read and write access to.
+  def set_mode(mode, path, protected = true)
+    sd = get_security_descriptor(path)
+    well_known_world_sid = Win32::Security::SID::Everyone
+    well_known_nobody_sid = Win32::Security::SID::Nobody
+    well_known_system_sid = Win32::Security::SID::LocalSystem
+
+    owner_allow = FILE::STANDARD_RIGHTS_ALL  |
+      FILE::FILE_READ_ATTRIBUTES |
+      FILE::FILE_WRITE_ATTRIBUTES
+    group_allow = FILE::STANDARD_RIGHTS_READ |
+      FILE::FILE_READ_ATTRIBUTES |
+      FILE::SYNCHRONIZE
+    other_allow = FILE::STANDARD_RIGHTS_READ |
+      FILE::FILE_READ_ATTRIBUTES |
+      FILE::SYNCHRONIZE
+    nobody_allow = 0
+    system_allow = 0
+
+    MODE_TO_MASK.each do |k,v|
+      if ((mode >> 6) & k) == k
+        owner_allow |= v
+      end
+      if ((mode >> 3) & k) == k
+        group_allow |= v
+      end
+      if (mode & k) == k
+        other_allow |= v
+      end
+    end
+
+    if (mode & S_ISVTX).nonzero?
+      nobody_allow |= FILE::FILE_APPEND_DATA;
+    end
+
+    # caller is NOT managing SYSTEM by using group or owner, so set to FULL
+    if ! [sd.owner, sd.group].include? well_known_system_sid
+      # we don't check S_ISYSTEM_MISSING bit, but automatically carry over existing SYSTEM perms
+      # by default set SYSTEM perms to full
+      system_allow = FILE::FILE_ALL_ACCESS
+    end
+
+    isdir = File.directory?(path)
+
+    if isdir
+      if (mode & (S_IWUSR | S_IXUSR)) == (S_IWUSR | S_IXUSR)
+        owner_allow |= FILE::FILE_DELETE_CHILD
+      end
+      if (mode & (S_IWGRP | S_IXGRP)) == (S_IWGRP | S_IXGRP) && (mode & S_ISVTX) == 0
+        group_allow |= FILE::FILE_DELETE_CHILD
+      end
+      if (mode & (S_IWOTH | S_IXOTH)) == (S_IWOTH | S_IXOTH) && (mode & S_ISVTX) == 0
+        other_allow |= FILE::FILE_DELETE_CHILD
+      end
+    end
+
+    # if owner and group the same, then map group permissions to the one owner ACE
+    isownergroup = sd.owner == sd.group
+    if isownergroup
+      owner_allow |= group_allow
+    end
+
+    # if any ACE allows write, then clear readonly bit, but do this before we overwrite
+    # the DACl and lose our ability to set the attribute
+    if ((owner_allow | group_allow | other_allow ) & FILE::FILE_WRITE_DATA) == FILE::FILE_WRITE_DATA
+      FILE.remove_attributes(path, FILE::FILE_ATTRIBUTE_READONLY)
+    end
+
+    dacl = Puppet::Util::Windows::AccessControlList.new
+    dacl.allow(sd.owner, owner_allow)
+    unless isownergroup
+      dacl.allow(sd.group, group_allow)
+    end
+    dacl.allow(well_known_world_sid, other_allow)
+    dacl.allow(well_known_nobody_sid, nobody_allow)
+
+    # TODO: system should be first?
+    flags = !isdir ? 0 :
+      Puppet::Util::Windows::AccessControlEntry::CONTAINER_INHERIT_ACE |
+      Puppet::Util::Windows::AccessControlEntry::OBJECT_INHERIT_ACE
+    dacl.allow(well_known_system_sid, system_allow, flags)
+
+    # add inherit-only aces for child dirs and files that are created within the dir
+    inherit_only = Puppet::Util::Windows::AccessControlEntry::INHERIT_ONLY_ACE
+    if isdir
+      inherit = inherit_only | Puppet::Util::Windows::AccessControlEntry::CONTAINER_INHERIT_ACE
+      dacl.allow(Win32::Security::SID::CreatorOwner, owner_allow, inherit)
+      dacl.allow(Win32::Security::SID::CreatorGroup, group_allow, inherit)
+
+      inherit = inherit_only | Puppet::Util::Windows::AccessControlEntry::OBJECT_INHERIT_ACE
+      dacl.allow(Win32::Security::SID::CreatorOwner, owner_allow & ~FILE::FILE_EXECUTE, inherit)
+      dacl.allow(Win32::Security::SID::CreatorGroup, group_allow & ~FILE::FILE_EXECUTE, inherit)
+    end
+
+    new_sd = Puppet::Util::Windows::SecurityDescriptor.new(sd.owner, sd.group, dacl, protected)
+    set_security_descriptor(path, new_sd)
+
+    nil
+  end
+
+  ACL_REVISION                   = 2
+
+  def add_access_allowed_ace(acl, mask, sid, inherit = nil)
+    inherit ||= NO_INHERITANCE
+
+    Puppet::Util::Windows::SID.string_to_sid_ptr(sid) do |sid_ptr|
+      if Puppet::Util::Windows::SID.IsValidSid(sid_ptr) == FFI::WIN32_FALSE
+        raise Puppet::Util::Windows::Error.new("Invalid SID")
+      end
+
+      if AddAccessAllowedAceEx(acl, ACL_REVISION, inherit, mask, sid_ptr) == FFI::WIN32_FALSE
+        raise Puppet::Util::Windows::Error.new("Failed to add access control entry")
+      end
+    end
+
+    # ensure this method is void if it doesn't raise
+    nil
+  end
+
+  def add_access_denied_ace(acl, mask, sid, inherit = nil)
+    inherit ||= NO_INHERITANCE
+
+    Puppet::Util::Windows::SID.string_to_sid_ptr(sid) do |sid_ptr|
+      if Puppet::Util::Windows::SID.IsValidSid(sid_ptr) == FFI::WIN32_FALSE
+        raise Puppet::Util::Windows::Error.new("Invalid SID")
+      end
+
+      if AddAccessDeniedAceEx(acl, ACL_REVISION, inherit, mask, sid_ptr) == FFI::WIN32_FALSE
+        raise Puppet::Util::Windows::Error.new("Failed to add access control entry")
+      end
+    end
+
+    # ensure this method is void if it doesn't raise
+    nil
+  end
+
+  def parse_dacl(dacl_ptr)
+    # REMIND: need to handle NULL DACL
+    if IsValidAcl(dacl_ptr) == FFI::WIN32_FALSE
+      raise Puppet::Util::Windows::Error.new("Invalid DACL")
+    end
+
+    dacl_struct = ACL.new(dacl_ptr)
+    ace_count = dacl_struct[:AceCount]
+
+    dacl = Puppet::Util::Windows::AccessControlList.new
+
+    # deny all
+    return dacl if ace_count == 0
+
+    0.upto(ace_count - 1) do |i|
+      FFI::MemoryPointer.new(:pointer, 1) do |ace_ptr|
+
+        next if GetAce(dacl_ptr, i, ace_ptr) == FFI::WIN32_FALSE
+
+        # ACE structures vary depending on the type. We are only concerned with
+        # ACCESS_ALLOWED_ACE and ACCESS_DENIED_ACEs, which have the same layout
+        ace = GENERIC_ACCESS_ACE.new(ace_ptr.get_pointer(0)) #deref LPVOID *
+
+        ace_type = ace[:Header][:AceType]
+        if ace_type != Puppet::Util::Windows::AccessControlEntry::ACCESS_ALLOWED_ACE_TYPE &&
+          ace_type != Puppet::Util::Windows::AccessControlEntry::ACCESS_DENIED_ACE_TYPE
+          Puppet.warning "Unsupported access control entry type: 0x#{ace_type.to_s(16)}"
+          next
+        end
+
+        # using pointer addition gives the FFI::Pointer a size, but that's OK here
+        sid = Puppet::Util::Windows::SID.sid_ptr_to_string(ace.pointer + GENERIC_ACCESS_ACE.offset_of(:SidStart))
+        mask = ace[:Mask]
+        ace_flags = ace[:Header][:AceFlags]
+
+        case ace_type
+        when Puppet::Util::Windows::AccessControlEntry::ACCESS_ALLOWED_ACE_TYPE
+          dacl.allow(sid, mask, ace_flags)
+        when Puppet::Util::Windows::AccessControlEntry::ACCESS_DENIED_ACE_TYPE
+          dacl.deny(sid, mask, ace_flags)
+        end
+      end
+    end
+
+    dacl
+  end
+
+  # Open an existing file with the specified access mode, and execute a
+  # block with the opened file HANDLE.
+  def open_file(path, access, &block)
+    handle = CreateFileW(
+             wide_string(path),
+             access,
+             FILE::FILE_SHARE_READ | FILE::FILE_SHARE_WRITE,
+             FFI::Pointer::NULL, # security_attributes
+             FILE::OPEN_EXISTING,
+             FILE::FILE_FLAG_OPEN_REPARSE_POINT | FILE::FILE_FLAG_BACKUP_SEMANTICS,
+             FFI::Pointer::NULL_HANDLE) # template
+
+    if handle == Puppet::Util::Windows::File::INVALID_HANDLE_VALUE
+      raise Puppet::Util::Windows::Error.new("Failed to open '#{path}'")
+    end
+
+    begin
+      yield handle
+    ensure
+      FFI::WIN32.CloseHandle(handle) if handle
+    end
+
+    # handle has already had CloseHandle called against it, nothing to return
+    nil
+  end
+
+  # Execute a block with the specified privilege enabled
+  def with_privilege(privilege, &block)
+    set_privilege(privilege, true)
+    yield
+  ensure
+    set_privilege(privilege, false)
+  end
+
+  SE_PRIVILEGE_ENABLED    = 0x00000002
+  TOKEN_ADJUST_PRIVILEGES = 0x0020
+
+  # Enable or disable a privilege. Note this doesn't add any privileges the
+  # user doesn't already has, it just enables privileges that are disabled.
+  def set_privilege(privilege, enable)
+    return unless Puppet.features.root?
+
+    Puppet::Util::Windows::Process.with_process_token(TOKEN_ADJUST_PRIVILEGES) do |token|
+      Puppet::Util::Windows::Process.lookup_privilege_value(privilege) do |luid|
+        FFI::MemoryPointer.new(Puppet::Util::Windows::Process::LUID_AND_ATTRIBUTES.size) do |luid_and_attributes_ptr|
+          # allocate unmanaged memory for structs that we clean up afterwards
+          luid_and_attributes = Puppet::Util::Windows::Process::LUID_AND_ATTRIBUTES.new(luid_and_attributes_ptr)
+          luid_and_attributes[:Luid] = luid
+          luid_and_attributes[:Attributes] = enable ? SE_PRIVILEGE_ENABLED : 0
+
+          FFI::MemoryPointer.new(Puppet::Util::Windows::Process::TOKEN_PRIVILEGES.size) do |token_privileges_ptr|
+            token_privileges = Puppet::Util::Windows::Process::TOKEN_PRIVILEGES.new(token_privileges_ptr)
+            token_privileges[:PrivilegeCount] = 1
+            token_privileges[:Privileges][0] = luid_and_attributes
+
+            # size is correct given we only have 1 LUID, otherwise would be:
+            # [:PrivilegeCount].size + [:PrivilegeCount] * LUID_AND_ATTRIBUTES.size
+            if AdjustTokenPrivileges(token, FFI::WIN32_FALSE,
+                token_privileges, token_privileges.size,
+                FFI::MemoryPointer::NULL, FFI::MemoryPointer::NULL) == FFI::WIN32_FALSE
+              raise Puppet::Util::Windows::Error.new("Failed to adjust process privileges")
+            end
+          end
+        end
+      end
+    end
+
+    # token / luid structs freed by this point, so return true as nothing raised
+    true
+  end
+
+  def with_process_token(access, &block)
+    Puppet.deprecation_warning('Puppet::Util::Windows::Security.with_process_token is deprecated; please use Puppet::Util::Windows::Process.with_process_token')
+    Puppet::Util::Windows::Process.with_process_token(access) do |token|
+      yield token
+    end
+
+    nil
+  end
+
+  def get_security_descriptor(path)
+    sd = nil
+
+    with_privilege(SE_BACKUP_NAME) do
+      open_file(path, READ_CONTROL) do |handle|
+        FFI::MemoryPointer.new(:pointer, 1) do |owner_sid_ptr_ptr|
+          FFI::MemoryPointer.new(:pointer, 1) do |group_sid_ptr_ptr|
+            FFI::MemoryPointer.new(:pointer, 1) do |dacl_ptr_ptr|
+              FFI::MemoryPointer.new(:pointer, 1) do |sd_ptr_ptr|
+
+                rv = GetSecurityInfo(
+                  handle,
+                  :SE_FILE_OBJECT,
+                  OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
+                  owner_sid_ptr_ptr,
+                  group_sid_ptr_ptr,
+                  dacl_ptr_ptr,
+                  FFI::Pointer::NULL, #sacl
+                  sd_ptr_ptr) #sec desc
+                raise Puppet::Util::Windows::Error.new("Failed to get security information") if rv != FFI::ERROR_SUCCESS
+
+                # these 2 convenience params are not freed since they point inside sd_ptr
+                owner = Puppet::Util::Windows::SID.sid_ptr_to_string(owner_sid_ptr_ptr.get_pointer(0))
+                group = Puppet::Util::Windows::SID.sid_ptr_to_string(group_sid_ptr_ptr.get_pointer(0))
+
+                FFI::MemoryPointer.new(:word, 1) do |control|
+                  FFI::MemoryPointer.new(:dword, 1) do |revision|
+                    sd_ptr_ptr.read_win32_local_pointer do |sd_ptr|
+
+                      if GetSecurityDescriptorControl(sd_ptr, control, revision) == FFI::WIN32_FALSE
+                        raise Puppet::Util::Windows::Error.new("Failed to get security descriptor control")
+                      end
+
+                      protect = (control.read_word & SE_DACL_PROTECTED) == SE_DACL_PROTECTED
+                      dacl = parse_dacl(dacl_ptr_ptr.get_pointer(0))
+                      sd = Puppet::Util::Windows::SecurityDescriptor.new(owner, group, dacl, protect)
+                    end
+                  end
+                end
+              end
+            end
+          end
+        end
+      end
+    end
+
+    sd
+  end
+
+  def get_max_generic_acl_size(ace_count)
+    # http://msdn.microsoft.com/en-us/library/windows/desktop/aa378853(v=vs.85).aspx
+    # To calculate the initial size of an ACL, add the following together, and then align the result to the nearest DWORD:
+    # * Size of the ACL structure.
+    # * Size of each ACE structure that the ACL is to contain minus the SidStart member (DWORD) of the ACE.
+    # * Length of the SID that each ACE is to contain.
+    ACL.size + ace_count * MAXIMUM_GENERIC_ACE_SIZE
+  end
+
+  # setting DACL requires both READ_CONTROL and WRITE_DACL access rights,
+  # and their respective privileges, SE_BACKUP_NAME and SE_RESTORE_NAME.
+  def set_security_descriptor(path, sd)
+    FFI::MemoryPointer.new(:byte, get_max_generic_acl_size(sd.dacl.count)) do |acl_ptr|
+      if InitializeAcl(acl_ptr, acl_ptr.size, ACL_REVISION) == FFI::WIN32_FALSE
+        raise Puppet::Util::Windows::Error.new("Failed to initialize ACL")
+      end
+
+      if IsValidAcl(acl_ptr) == FFI::WIN32_FALSE
+        raise Puppet::Util::Windows::Error.new("Invalid DACL")
+      end
+
+      with_privilege(SE_BACKUP_NAME) do
+        with_privilege(SE_RESTORE_NAME) do
+          open_file(path, READ_CONTROL | WRITE_DAC | WRITE_OWNER) do |handle|
+            Puppet::Util::Windows::SID.string_to_sid_ptr(sd.owner) do |owner_sid_ptr|
+              Puppet::Util::Windows::SID.string_to_sid_ptr(sd.group) do |group_sid_ptr|
+                sd.dacl.each do |ace|
+                  case ace.type
+                  when Puppet::Util::Windows::AccessControlEntry::ACCESS_ALLOWED_ACE_TYPE
+                    #puts "ace: allow, sid #{Puppet::Util::Windows::SID.sid_to_name(ace.sid)}, mask 0x#{ace.mask.to_s(16)}"
+                    add_access_allowed_ace(acl_ptr, ace.mask, ace.sid, ace.flags)
+                  when Puppet::Util::Windows::AccessControlEntry::ACCESS_DENIED_ACE_TYPE
+                    #puts "ace: deny, sid #{Puppet::Util::Windows::SID.sid_to_name(ace.sid)}, mask 0x#{ace.mask.to_s(16)}"
+                    add_access_denied_ace(acl_ptr, ace.mask, ace.sid, ace.flags)
+                  else
+                    raise "We should never get here"
+                    # TODO: this should have been a warning in an earlier commit
+                  end
+                end
+
+                # protected means the object does not inherit aces from its parent
+                flags = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION
+                flags |= sd.protect ? PROTECTED_DACL_SECURITY_INFORMATION : UNPROTECTED_DACL_SECURITY_INFORMATION
+
+                rv = SetSecurityInfo(handle,
+                                     :SE_FILE_OBJECT,
+                                     flags,
+                                     owner_sid_ptr,
+                                     group_sid_ptr,
+                                     acl_ptr,
+                                     FFI::MemoryPointer::NULL)
+
+                if rv != FFI::ERROR_SUCCESS
+                  raise Puppet::Util::Windows::Error.new("Failed to set security information")
+                end
+              end
+            end
+          end
+        end
+      end
+    end
+
+    def name_to_sid(name)
+      Puppet.deprecation_warning('Puppet::Util::Windows::Security.name_to_sid is deprecated; please use Puppet::Util::Windows::SID.name_to_sid')
+      Puppet::Util::Windows::SID.name_to_sid(name)
+    end
+
+    def name_to_sid_object(name)
+      Puppet.deprecation_warning('Puppet::Util::Windows::Security.name_to_sid_object is deprecated; please use Puppet::Util::Windows::SID.name_to_sid_object')
+      Puppet::Util::Windows::SID.name_to_sid_object(name)
+    end
+
+    def octet_string_to_sid_object(bytes)
+      Puppet.deprecation_warning('Puppet::Util::Windows::Security.octet_string_to_sid_object is deprecated; please use Puppet::Util::Windows::SID.octet_string_to_sid_object')
+      Puppet::Util::Windows::SID.octet_string_to_sid_object(bytes)
+    end
+
+    def sid_to_name(value)
+      Puppet.deprecation_warning('Puppet::Util::Windows::Security.sid_to_name is deprecated; please use Puppet::Util::Windows::SID.sid_to_name')
+      Puppet::Util::Windows::SID.sid_to_name(value)
+    end
+
+    def sid_ptr_to_string(psid)
+      Puppet.deprecation_warning('Puppet::Util::Windows::Security.sid_ptr_to_string is deprecated; please use Puppet::Util::Windows::SID.sid_ptr_to_string')
+      Puppet::Util::Windows::SID.sid_ptr_to_string(psid)
+    end
+
+    def string_to_sid_ptr(string_sid, &block)
+      Puppet.deprecation_warning('Puppet::Util::Windows::Security.string_to_sid_ptr is deprecated; please use Puppet::Util::Windows::SID.string_to_sid_ptr')
+      Puppet::Util::Windows::SID.string_to_sid_ptr(string_sid, &block)
+    end
+
+    def valid_sid?(string_sid)
+      Puppet.deprecation_warning('Puppet::Util::Windows::Security.valid_sid? is deprecated; please use Puppet::Util::Windows::SID.valid_sid?')
+      Puppet::Util::Windows::SID.valid_sid?(string_sid)
+    end
+  end
+
+  ffi_convention :stdcall
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
+  # HANDLE WINAPI CreateFile(
+  #   _In_      LPCTSTR lpFileName,
+  #   _In_      DWORD dwDesiredAccess,
+  #   _In_      DWORD dwShareMode,
+  #   _In_opt_  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+  #   _In_      DWORD dwCreationDisposition,
+  #   _In_      DWORD dwFlagsAndAttributes,
+  #   _In_opt_  HANDLE hTemplateFile
+  # );
+  ffi_lib :kernel32
+  attach_function_private :CreateFileW,
+    [:lpcwstr, :dword, :dword, :pointer, :dword, :dword, :handle], :handle
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa364993(v=vs.85).aspx
+  # BOOL WINAPI GetVolumeInformation(
+  #   _In_opt_   LPCTSTR lpRootPathName,
+  #   _Out_opt_  LPTSTR lpVolumeNameBuffer,
+  #   _In_       DWORD nVolumeNameSize,
+  #   _Out_opt_  LPDWORD lpVolumeSerialNumber,
+  #   _Out_opt_  LPDWORD lpMaximumComponentLength,
+  #   _Out_opt_  LPDWORD lpFileSystemFlags,
+  #   _Out_opt_  LPTSTR lpFileSystemNameBuffer,
+  #   _In_       DWORD nFileSystemNameSize
+  # );
+  ffi_lib :kernel32
+  attach_function_private :GetVolumeInformationW,
+    [:lpcwstr, :lpwstr, :dword, :lpdword, :lpdword, :lpdword, :lpwstr, :dword], :win32_bool
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa374951(v=vs.85).aspx
+  # BOOL WINAPI AddAccessAllowedAceEx(
+  #   _Inout_  PACL pAcl,
+  #   _In_     DWORD dwAceRevision,
+  #   _In_     DWORD AceFlags,
+  #   _In_     DWORD AccessMask,
+  #   _In_     PSID pSid
+  # );
+  ffi_lib :advapi32
+  attach_function_private :AddAccessAllowedAceEx,
+    [:pointer, :dword, :dword, :dword, :pointer], :win32_bool
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa374964(v=vs.85).aspx
+  # BOOL WINAPI AddAccessDeniedAceEx(
+  #   _Inout_  PACL pAcl,
+  #   _In_     DWORD dwAceRevision,
+  #   _In_     DWORD AceFlags,
+  #   _In_     DWORD AccessMask,
+  #   _In_     PSID pSid
+  # );
+  ffi_lib :advapi32
+  attach_function_private :AddAccessDeniedAceEx,
+    [:pointer, :dword, :dword, :dword, :pointer], :win32_bool
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa374931(v=vs.85).aspx
+  # typedef struct _ACL {
+  #   BYTE AclRevision;
+  #   BYTE Sbz1;
+  #   WORD AclSize;
+  #   WORD AceCount;
+  #   WORD Sbz2;
+  # } ACL, *PACL;
+  class ACL < FFI::Struct
+    layout :AclRevision, :byte,
+           :Sbz1, :byte,
+           :AclSize, :word,
+           :AceCount, :word,
+           :Sbz2, :word
+  end
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa374912(v=vs.85).aspx
+  # ACE types
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa374919(v=vs.85).aspx
+  # typedef struct _ACE_HEADER {
+  #   BYTE AceType;
+  #   BYTE AceFlags;
+  #   WORD AceSize;
+  # } ACE_HEADER, *PACE_HEADER;
+  class ACE_HEADER < FFI::Struct
+    layout :AceType, :byte,
+           :AceFlags, :byte,
+           :AceSize,  :word
+  end
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa374892(v=vs.85).aspx
+  # ACCESS_MASK
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa374847(v=vs.85).aspx
+  # typedef struct _ACCESS_ALLOWED_ACE {
+  #   ACE_HEADER  Header;
+  #   ACCESS_MASK Mask;
+  #   DWORD       SidStart;
+  # } ACCESS_ALLOWED_ACE, *PACCESS_ALLOWED_ACE;
+  #
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa374879(v=vs.85).aspx
+  # typedef struct _ACCESS_DENIED_ACE {
+  #   ACE_HEADER  Header;
+  #   ACCESS_MASK Mask;
+  #   DWORD       SidStart;
+  # } ACCESS_DENIED_ACE, *PACCESS_DENIED_ACE;
+  class GENERIC_ACCESS_ACE < FFI::Struct
+    # ACE structures must be aligned on DWORD boundaries. All Windows
+    # memory-management functions return DWORD-aligned handles to memory
+    pack 4
+    layout :Header, ACE_HEADER,
+           :Mask, :dword,
+           :SidStart, :dword
+  end
+
+  # http://stackoverflow.com/a/1792930
+  MAXIMUM_SID_BYTES_LENGTH = 68
+  MAXIMUM_GENERIC_ACE_SIZE = GENERIC_ACCESS_ACE.offset_of(:SidStart) +
+    MAXIMUM_SID_BYTES_LENGTH
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa446634(v=vs.85).aspx
+  # BOOL WINAPI GetAce(
+  #   _In_   PACL pAcl,
+  #   _In_   DWORD dwAceIndex,
+  #   _Out_  LPVOID *pAce
+  # );
+  ffi_lib :advapi32
+  attach_function_private :GetAce,
+    [:pointer, :dword, :pointer], :win32_bool
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa375202(v=vs.85).aspx
+  # BOOL WINAPI AdjustTokenPrivileges(
+  #   _In_       HANDLE TokenHandle,
+  #   _In_       BOOL DisableAllPrivileges,
+  #   _In_opt_   PTOKEN_PRIVILEGES NewState,
+  #   _In_       DWORD BufferLength,
+  #   _Out_opt_  PTOKEN_PRIVILEGES PreviousState,
+  #   _Out_opt_  PDWORD ReturnLength
+  # );
+  ffi_lib :advapi32
+  attach_function_private :AdjustTokenPrivileges,
+    [:handle, :win32_bool, :pointer, :dword, :pointer, :pdword], :win32_bool
+
+  # http://msdn.microsoft.com/en-us/library/windows/hardware/ff556610(v=vs.85).aspx
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa379561(v=vs.85).aspx
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa446647(v=vs.85).aspx
+  # typedef WORD SECURITY_DESCRIPTOR_CONTROL, *PSECURITY_DESCRIPTOR_CONTROL;
+  # BOOL WINAPI GetSecurityDescriptorControl(
+  #   _In_   PSECURITY_DESCRIPTOR pSecurityDescriptor,
+  #   _Out_  PSECURITY_DESCRIPTOR_CONTROL pControl,
+  #   _Out_  LPDWORD lpdwRevision
+  # );
+  ffi_lib :advapi32
+  attach_function_private :GetSecurityDescriptorControl,
+    [:pointer, :lpword, :lpdword], :win32_bool
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa378853(v=vs.85).aspx
+  # BOOL WINAPI InitializeAcl(
+  #   _Out_  PACL pAcl,
+  #   _In_   DWORD nAclLength,
+  #   _In_   DWORD dwAclRevision
+  # );
+  ffi_lib :advapi32
+  attach_function_private :InitializeAcl,
+    [:pointer, :dword, :dword], :win32_bool
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa379142(v=vs.85).aspx
+  # BOOL WINAPI IsValidAcl(
+  #   _In_  PACL pAcl
+  # );
+  ffi_lib :advapi32
+  attach_function_private :IsValidAcl,
+    [:pointer], :win32_bool
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa379593(v=vs.85).aspx
+  SE_OBJECT_TYPE = enum(
+    :SE_UNKNOWN_OBJECT_TYPE, 0,
+    :SE_FILE_OBJECT,
+    :SE_SERVICE,
+    :SE_PRINTER,
+    :SE_REGISTRY_KEY,
+    :SE_LMSHARE,
+    :SE_KERNEL_OBJECT,
+    :SE_WINDOW_OBJECT,
+    :SE_DS_OBJECT,
+    :SE_DS_OBJECT_ALL,
+    :SE_PROVIDER_DEFINED_OBJECT,
+    :SE_WMIGUID_OBJECT,
+    :SE_REGISTRY_WOW64_32KEY
+  )
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa446654(v=vs.85).aspx
+  # DWORD WINAPI GetSecurityInfo(
+  #   _In_       HANDLE handle,
+  #   _In_       SE_OBJECT_TYPE ObjectType,
+  #   _In_       SECURITY_INFORMATION SecurityInfo,
+  #   _Out_opt_  PSID *ppsidOwner,
+  #   _Out_opt_  PSID *ppsidGroup,
+  #   _Out_opt_  PACL *ppDacl,
+  #   _Out_opt_  PACL *ppSacl,
+  #   _Out_opt_  PSECURITY_DESCRIPTOR *ppSecurityDescriptor
+  # );
+  ffi_lib :advapi32
+  attach_function_private :GetSecurityInfo,
+    [:handle, SE_OBJECT_TYPE, :dword, :pointer, :pointer, :pointer, :pointer, :pointer], :dword
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa379588(v=vs.85).aspx
+  # DWORD WINAPI SetSecurityInfo(
+  #   _In_      HANDLE handle,
+  #   _In_      SE_OBJECT_TYPE ObjectType,
+  #   _In_      SECURITY_INFORMATION SecurityInfo,
+  #   _In_opt_  PSID psidOwner,
+  #   _In_opt_  PSID psidGroup,
+  #   _In_opt_  PACL pDacl,
+  #   _In_opt_  PACL pSacl
+  # );
+  ffi_lib :advapi32
+  # TODO: SECURITY_INFORMATION is actually a bitmask the size of a DWORD
+  attach_function_private :SetSecurityInfo,
+    [:handle, SE_OBJECT_TYPE, :dword, :pointer, :pointer, :pointer, :pointer], :dword
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/security_descriptor.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/security_descriptor.rb
new file mode 100644
index 0000000..9c95cee
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/security_descriptor.rb
@@ -0,0 +1,62 @@
+# Windows Security Descriptor
+#
+# Represents a security descriptor that can be applied to any Windows securable
+# object, e.g. file, registry key, service, etc. It consists of an owner, group,
+# flags, DACL, and SACL. The SACL is not currently supported, though it has the
+# same layout as a DACL.
+#
+# @see http://msdn.microsoft.com/en-us/library/windows/desktop/aa379563(v=vs.85).aspx
+# @api private
+class Puppet::Util::Windows::SecurityDescriptor
+  require 'puppet/util/windows/security'
+  include Puppet::Util::Windows::SID
+
+  attr_reader :owner, :group, :dacl
+  attr_accessor :protect
+
+  # Construct a security descriptor
+  #
+  # @param owner [String] The SID of the owner, e.g. 'S-1-5-18'
+  # @param group [String] The SID of the group
+  # @param dacl [AccessControlList] The ACL specifying the rights granted to
+  # each user for accessing the object that the security descriptor refers to.
+  # @param protect [Boolean] If true, then inheritable access control
+  # entries will be blocked, and not applied to the object.
+  def initialize(owner, group, dacl, protect = false)
+    @owner = owner
+    @group = group
+    @dacl = dacl
+    @protect = protect
+  end
+
+  # Set the owner. Non-inherited access control entries assigned to the
+  # current owner will be assigned to the new owner.
+  #
+  # @param new_owner [String] The SID of the new owner, e.g. 'S-1-5-18'
+  def owner=(new_owner)
+    if @owner != new_owner
+      @dacl.reassign!(@owner, new_owner)
+      @owner = new_owner
+    end
+  end
+
+  # Set the group. Non-inherited access control entries assigned to the
+  # current group will be assigned to the new group.
+  #
+  # @param new_group [String] The SID of the new group, e.g. 'S-1-0-0'
+  def group=(new_group)
+    if @group != new_group
+      @dacl.reassign!(@group, new_group)
+      @group = new_group
+    end
+  end
+
+  def inspect
+    str = sid_to_name(owner)
+    str << "\n"
+    str << sid_to_name(group)
+    str << "\n"
+    str << @dacl.inspect
+    str
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/sid.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/sid.rb
new file mode 100644
index 0000000..68a780f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/sid.rb
@@ -0,0 +1,162 @@
+require 'puppet/util/windows'
+
+module Puppet::Util::Windows
+  module SID
+    require 'ffi'
+    extend FFI::Library
+
+    # missing from Windows::Error
+    ERROR_NONE_MAPPED           = 1332
+    ERROR_INVALID_SID_STRUCTURE = 1337
+
+    # Convert an account name, e.g. 'Administrators' into a SID string,
+    # e.g. 'S-1-5-32-544'. The name can be specified as 'Administrators',
+    # 'BUILTIN\Administrators', or 'S-1-5-32-544', and will return the
+    # SID. Returns nil if the account doesn't exist.
+    def name_to_sid(name)
+      sid = name_to_sid_object(name)
+
+      sid ? sid.to_s : nil
+    end
+    module_function :name_to_sid
+
+    # Convert an account name, e.g. 'Administrators' into a SID object,
+    # e.g. 'S-1-5-32-544'. The name can be specified as 'Administrators',
+    # 'BUILTIN\Administrators', or 'S-1-5-32-544', and will return the
+    # SID object. Returns nil if the account doesn't exist.
+    def name_to_sid_object(name)
+      # Apparently, we accept a symbol..
+      name = name.to_s.strip if name
+
+      # if it's in SID string form, convert to user
+      parsed_sid = Win32::Security::SID.string_to_sid(name) rescue nil
+
+      parsed_sid ? Win32::Security::SID.new(parsed_sid) : Win32::Security::SID.new(name)
+    rescue
+      nil
+    end
+    module_function :name_to_sid_object
+
+    # Converts an octet string array of bytes to a SID object,
+    # e.g. [1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0] is the representation for
+    # S-1-5-18, the local 'SYSTEM' account.
+    # Raises an Error for nil or non-array input.
+    def octet_string_to_sid_object(bytes)
+      if !bytes || !bytes.respond_to?('pack') || bytes.empty?
+        raise Puppet::Util::Windows::Error.new("Octet string must be an array of bytes")
+      end
+
+      Win32::Security::SID.new(bytes.pack('C*'))
+    end
+    module_function :octet_string_to_sid_object
+
+    # Convert a SID string, e.g. "S-1-5-32-544" to a name,
+    # e.g. 'BUILTIN\Administrators'. Returns nil if an account
+    # for that SID does not exist.
+    def sid_to_name(value)
+      sid = Win32::Security::SID.new(Win32::Security::SID.string_to_sid(value))
+
+      if sid.domain and sid.domain.length > 0
+        "#{sid.domain}\\#{sid.account}"
+      else
+        sid.account
+      end
+    rescue
+      nil
+    end
+    module_function :sid_to_name
+
+    # http://stackoverflow.com/a/1792930 - 68 bytes, 184 characters in a string
+    MAXIMUM_SID_STRING_LENGTH = 184
+
+    # Convert a SID pointer to a SID string, e.g. "S-1-5-32-544".
+    def sid_ptr_to_string(psid)
+      if ! psid.instance_of?(FFI::Pointer) || IsValidSid(psid) == FFI::WIN32_FALSE
+        raise Puppet::Util::Windows::Error.new("Invalid SID")
+      end
+
+      sid_string = nil
+      FFI::MemoryPointer.new(:pointer, 1) do |buffer_ptr|
+        if ConvertSidToStringSidW(psid, buffer_ptr) == FFI::WIN32_FALSE
+          raise Puppet::Util::Windows::Error.new("Failed to convert binary SID")
+        end
+
+        buffer_ptr.read_win32_local_pointer do |wide_string_ptr|
+          if wide_string_ptr.null?
+            raise Puppet::Error.new("ConvertSidToStringSidW failed to allocate buffer for sid")
+          end
+
+          sid_string = wide_string_ptr.read_arbitrary_wide_string_up_to(MAXIMUM_SID_STRING_LENGTH)
+        end
+      end
+
+      sid_string
+    end
+    module_function :sid_ptr_to_string
+
+    # Convert a SID string, e.g. "S-1-5-32-544" to a pointer (containing the
+    # address of the binary SID structure). The returned value can be used in
+    # Win32 APIs that expect a PSID, e.g. IsValidSid. The account for this
+    # SID may or may not exist.
+    def string_to_sid_ptr(string_sid, &block)
+      FFI::MemoryPointer.from_string_to_wide_string(string_sid) do |lpcwstr|
+        FFI::MemoryPointer.new(:pointer, 1) do |sid_ptr_ptr|
+
+          if ConvertStringSidToSidW(lpcwstr, sid_ptr_ptr) == FFI::WIN32_FALSE
+            raise Puppet::Util::Windows::Error.new("Failed to convert string SID: #{string_sid}")
+          end
+
+          sid_ptr_ptr.read_win32_local_pointer do |sid_ptr|
+            yield sid_ptr
+          end
+        end
+      end
+
+      # yielded sid_ptr has already had LocalFree called, nothing to return
+      nil
+    end
+    module_function :string_to_sid_ptr
+
+    # Return true if the string is a valid SID, e.g. "S-1-5-32-544", false otherwise.
+    def valid_sid?(string_sid)
+      valid = false
+
+      begin
+        string_to_sid_ptr(string_sid) { |ptr| valid = ! ptr.nil? && ! ptr.null? }
+      rescue Puppet::Util::Windows::Error => e
+        raise if e.code != ERROR_INVALID_SID_STRUCTURE
+      end
+
+      valid
+    end
+    module_function :valid_sid?
+
+    ffi_convention :stdcall
+
+    # http://msdn.microsoft.com/en-us/library/windows/desktop/aa379151(v=vs.85).aspx
+    # BOOL WINAPI IsValidSid(
+    #   _In_  PSID pSid
+    # );
+    ffi_lib :advapi32
+    attach_function_private :IsValidSid,
+      [:pointer], :win32_bool
+
+    # http://msdn.microsoft.com/en-us/library/windows/desktop/aa376399(v=vs.85).aspx
+    # BOOL ConvertSidToStringSid(
+    #   _In_   PSID Sid,
+    #   _Out_  LPTSTR *StringSid
+    # );
+    ffi_lib :advapi32
+    attach_function_private :ConvertSidToStringSidW,
+      [:pointer, :pointer], :win32_bool
+
+    # http://msdn.microsoft.com/en-us/library/windows/desktop/aa376402(v=vs.85).aspx
+    # BOOL WINAPI ConvertStringSidToSid(
+    #   _In_   LPCTSTR StringSid,
+    #   _Out_  PSID *Sid
+    # );
+    ffi_lib :advapi32
+    attach_function_private :ConvertStringSidToSidW,
+      [:lpcwstr, :pointer], :win32_bool
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/string.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/string.rb
new file mode 100644
index 0000000..147c929
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/string.rb
@@ -0,0 +1,16 @@
+require 'puppet/util/windows'
+
+module Puppet::Util::Windows::String
+  def wide_string(str)
+    # if given a nil string, assume caller wants to pass a nil pointer to win32
+    return nil if str.nil?
+    # ruby (< 2.1) does not respect multibyte terminators, so it is possible
+    # for a string to contain a single trailing null byte, followed by garbage
+    # causing buffer overruns.
+    #
+    # See http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?revision=41920&view=revision
+    newstr = str + "\0".encode(str.encoding)
+    newstr.encode!('UTF-16LE')
+  end
+  module_function :wide_string
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/taskscheduler.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/taskscheduler.rb
new file mode 100644
index 0000000..ef598ab
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/taskscheduler.rb
@@ -0,0 +1,1241 @@
+require 'puppet/util/windows'
+
+# The Win32 module serves as a namespace only
+module Win32
+  # The TaskScheduler class encapsulates taskscheduler settings and behavior
+  class TaskScheduler
+    include Puppet::Util::Windows::String
+
+    require 'ffi'
+    extend FFI::Library
+
+    # The error class raised if any task scheduler specific calls fail.
+    class Error < Puppet::Util::Windows::Error; end
+
+    private
+
+    class << self
+      attr_accessor :com_initialized
+    end
+
+    # :stopdoc:
+    TASK_TIME_TRIGGER_ONCE            = :TASK_TIME_TRIGGER_ONCE
+    TASK_TIME_TRIGGER_DAILY           = :TASK_TIME_TRIGGER_DAILY
+    TASK_TIME_TRIGGER_WEEKLY          = :TASK_TIME_TRIGGER_WEEKLY
+    TASK_TIME_TRIGGER_MONTHLYDATE     = :TASK_TIME_TRIGGER_MONTHLYDATE
+    TASK_TIME_TRIGGER_MONTHLYDOW      = :TASK_TIME_TRIGGER_MONTHLYDOW
+    TASK_EVENT_TRIGGER_ON_IDLE        = :TASK_EVENT_TRIGGER_ON_IDLE
+    TASK_EVENT_TRIGGER_AT_SYSTEMSTART = :TASK_EVENT_TRIGGER_AT_SYSTEMSTART
+    TASK_EVENT_TRIGGER_AT_LOGON       = :TASK_EVENT_TRIGGER_AT_LOGON
+
+    TASK_SUNDAY       = 0x1
+    TASK_MONDAY       = 0x2
+    TASK_TUESDAY      = 0x4
+    TASK_WEDNESDAY    = 0x8
+    TASK_THURSDAY     = 0x10
+    TASK_FRIDAY       = 0x20
+    TASK_SATURDAY     = 0x40
+    TASK_FIRST_WEEK   = 1
+    TASK_SECOND_WEEK  = 2
+    TASK_THIRD_WEEK   = 3
+    TASK_FOURTH_WEEK  = 4
+    TASK_LAST_WEEK    = 5
+    TASK_JANUARY      = 0x1
+    TASK_FEBRUARY     = 0x2
+    TASK_MARCH        = 0x4
+    TASK_APRIL        = 0x8
+    TASK_MAY          = 0x10
+    TASK_JUNE         = 0x20
+    TASK_JULY         = 0x40
+    TASK_AUGUST       = 0x80
+    TASK_SEPTEMBER    = 0x100
+    TASK_OCTOBER      = 0x200
+    TASK_NOVEMBER     = 0x400
+    TASK_DECEMBER     = 0x800
+
+    TASK_FLAG_INTERACTIVE                  = 0x1
+    TASK_FLAG_DELETE_WHEN_DONE             = 0x2
+    TASK_FLAG_DISABLED                     = 0x4
+    TASK_FLAG_START_ONLY_IF_IDLE           = 0x10
+    TASK_FLAG_KILL_ON_IDLE_END             = 0x20
+    TASK_FLAG_DONT_START_IF_ON_BATTERIES   = 0x40
+    TASK_FLAG_KILL_IF_GOING_ON_BATTERIES   = 0x80
+    TASK_FLAG_RUN_ONLY_IF_DOCKED           = 0x100
+    TASK_FLAG_HIDDEN                       = 0x200
+    TASK_FLAG_RUN_IF_CONNECTED_TO_INTERNET = 0x400
+    TASK_FLAG_RESTART_ON_IDLE_RESUME       = 0x800
+    TASK_FLAG_SYSTEM_REQUIRED              = 0x1000
+    TASK_FLAG_RUN_ONLY_IF_LOGGED_ON        = 0x2000
+    TASK_TRIGGER_FLAG_HAS_END_DATE         = 0x1
+    TASK_TRIGGER_FLAG_KILL_AT_DURATION_END = 0x2
+    TASK_TRIGGER_FLAG_DISABLED             = 0x4
+
+    TASK_MAX_RUN_TIMES = 1440
+    TASKS_TO_RETRIEVE  = 5
+
+    # COM
+
+    CLSID_CTask = FFI::WIN32::GUID['148BD520-A2AB-11CE-B11F-00AA00530503']
+    IID_ITask = FFI::WIN32::GUID['148BD524-A2AB-11CE-B11F-00AA00530503']
+    IID_IPersistFile = FFI::WIN32::GUID['0000010b-0000-0000-C000-000000000046']
+
+    SCHED_S_TASK_READY                    = 0x00041300
+    SCHED_S_TASK_RUNNING                  = 0x00041301
+    SCHED_S_TASK_HAS_NOT_RUN              = 0x00041303
+    SCHED_S_TASK_NOT_SCHEDULED            = 0x00041305
+    # HRESULT error codes
+    # http://blogs.msdn.com/b/eldar/archive/2007/04/03/a-lot-of-hresult-codes.aspx
+    # in Ruby, an 0x8XXXXXXX style HRESULT can be resolved to 2s complement
+    # by using "0x8XXXXXXX".to_i(16) - - 0x100000000
+    SCHED_E_ACCOUNT_INFORMATION_NOT_SET   = -2147216625 # 0x8004130F
+    SCHED_E_NO_SECURITY_SERVICES          = -2147216622 # 0x80041312
+    # No mapping between account names and security IDs was done.
+    ERROR_NONE_MAPPED                     = -2147023564 # 0x80070534  WIN32 Error CODE 1332 (0x534)
+
+    public
+
+    # :startdoc:
+
+    # Shorthand constants
+    IDLE = Puppet::Util::Windows::Process::IDLE_PRIORITY_CLASS
+    NORMAL = Puppet::Util::Windows::Process::NORMAL_PRIORITY_CLASS
+    HIGH = Puppet::Util::Windows::Process::HIGH_PRIORITY_CLASS
+    REALTIME = Puppet::Util::Windows::Process::REALTIME_PRIORITY_CLASS
+    BELOW_NORMAL = Puppet::Util::Windows::Process::BELOW_NORMAL_PRIORITY_CLASS
+    ABOVE_NORMAL = Puppet::Util::Windows::Process::ABOVE_NORMAL_PRIORITY_CLASS
+
+    ONCE = TASK_TIME_TRIGGER_ONCE
+    DAILY = TASK_TIME_TRIGGER_DAILY
+    WEEKLY = TASK_TIME_TRIGGER_WEEKLY
+    MONTHLYDATE = TASK_TIME_TRIGGER_MONTHLYDATE
+    MONTHLYDOW = TASK_TIME_TRIGGER_MONTHLYDOW
+
+    ON_IDLE = TASK_EVENT_TRIGGER_ON_IDLE
+    AT_SYSTEMSTART = TASK_EVENT_TRIGGER_AT_SYSTEMSTART
+    AT_LOGON = TASK_EVENT_TRIGGER_AT_LOGON
+    FIRST_WEEK = TASK_FIRST_WEEK
+    SECOND_WEEK = TASK_SECOND_WEEK
+    THIRD_WEEK = TASK_THIRD_WEEK
+    FOURTH_WEEK = TASK_FOURTH_WEEK
+    LAST_WEEK = TASK_LAST_WEEK
+    SUNDAY = TASK_SUNDAY
+    MONDAY = TASK_MONDAY
+    TUESDAY = TASK_TUESDAY
+    WEDNESDAY = TASK_WEDNESDAY
+    THURSDAY = TASK_THURSDAY
+    FRIDAY = TASK_FRIDAY
+    SATURDAY = TASK_SATURDAY
+    JANUARY = TASK_JANUARY
+    FEBRUARY = TASK_FEBRUARY
+    MARCH = TASK_MARCH
+    APRIL = TASK_APRIL
+    MAY = TASK_MAY
+    JUNE = TASK_JUNE
+    JULY = TASK_JULY
+    AUGUST = TASK_AUGUST
+    SEPTEMBER = TASK_SEPTEMBER
+    OCTOBER = TASK_OCTOBER
+    NOVEMBER = TASK_NOVEMBER
+    DECEMBER = TASK_DECEMBER
+
+    INTERACTIVE = TASK_FLAG_INTERACTIVE
+    DELETE_WHEN_DONE = TASK_FLAG_DELETE_WHEN_DONE
+    DISABLED = TASK_FLAG_DISABLED
+    START_ONLY_IF_IDLE = TASK_FLAG_START_ONLY_IF_IDLE
+    KILL_ON_IDLE_END = TASK_FLAG_KILL_ON_IDLE_END
+    DONT_START_IF_ON_BATTERIES = TASK_FLAG_DONT_START_IF_ON_BATTERIES
+    KILL_IF_GOING_ON_BATTERIES = TASK_FLAG_KILL_IF_GOING_ON_BATTERIES
+    RUN_ONLY_IF_DOCKED = TASK_FLAG_RUN_ONLY_IF_DOCKED
+    HIDDEN = TASK_FLAG_HIDDEN
+    RUN_IF_CONNECTED_TO_INTERNET = TASK_FLAG_RUN_IF_CONNECTED_TO_INTERNET
+    RESTART_ON_IDLE_RESUME = TASK_FLAG_RESTART_ON_IDLE_RESUME
+    SYSTEM_REQUIRED = TASK_FLAG_SYSTEM_REQUIRED
+    RUN_ONLY_IF_LOGGED_ON = TASK_FLAG_RUN_ONLY_IF_LOGGED_ON
+
+    FLAG_HAS_END_DATE = TASK_TRIGGER_FLAG_HAS_END_DATE
+    FLAG_KILL_AT_DURATION_END = TASK_TRIGGER_FLAG_KILL_AT_DURATION_END
+    FLAG_DISABLED = TASK_TRIGGER_FLAG_DISABLED
+
+    MAX_RUN_TIMES = TASK_MAX_RUN_TIMES
+
+    # Returns a new TaskScheduler object. If a work_item (and possibly the
+    # the trigger) are passed as arguments then a new work item is created and
+    # associated with that trigger, although you can still activate other tasks
+    # with the same handle.
+    #
+    # This is really just a bit of convenience. Passing arguments to the
+    # constructor is the same as calling TaskScheduler.new plus
+    # TaskScheduler#new_work_item.
+    #
+    def initialize(work_item=nil, trigger=nil)
+      @pITS   = nil
+      @pITask = nil
+
+      if ! self.class.com_initialized
+        Puppet::Util::Windows::COM.InitializeCom()
+        self.class.com_initialized = true
+      end
+
+      @pITS = COM::TaskScheduler.new
+      at_exit do
+        begin
+          @pITS.Release if @pITS && !@pITS.null?
+          @pITS = nil
+        rescue
+        end
+      end
+
+      if work_item
+        if trigger
+          raise TypeError unless trigger.is_a?(Hash)
+          new_work_item(work_item, trigger)
+        end
+      end
+    end
+
+    # Returns an array of scheduled task names.
+    #
+    def enum
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+      array = []
+
+      @pITS.UseInstance(COM::EnumWorkItems, :Enum) do |pIEnum|
+        FFI::MemoryPointer.new(:pointer) do |names_array_ptr_ptr|
+          FFI::MemoryPointer.new(:win32_ulong) do |fetched_count_ptr|
+            # awkward usage, if number requested is available, returns S_OK (0), or if less were returned returns S_FALSE (1)
+            while (pIEnum.Next(TASKS_TO_RETRIEVE, names_array_ptr_ptr, fetched_count_ptr) >= Puppet::Util::Windows::COM::S_OK)
+              count = fetched_count_ptr.read_win32_ulong
+              break if count == 0
+
+              names_array_ptr_ptr.read_com_memory_pointer do |names_array_ptr|
+                # iterate over the array of pointers
+                name_ptr_ptr = FFI::Pointer.new(:pointer, names_array_ptr)
+                for i in 0 ... count
+                  name_ptr_ptr[i].read_com_memory_pointer do |name_ptr|
+                    array << name_ptr.read_arbitrary_wide_string_up_to(256)
+                  end
+                end
+              end
+            end
+          end
+        end
+      end
+
+      array
+    end
+
+    alias :tasks :enum
+
+    # Activate the specified task.
+    #
+    def activate(task)
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+      raise TypeError unless task.is_a?(String)
+
+      FFI::MemoryPointer.new(:pointer) do |ptr|
+        @pITS.Activate(wide_string(task), IID_ITask, ptr)
+
+        reset_current_task
+        @pITask = COM::Task.new(ptr.read_pointer)
+      end
+
+      @pITask
+    end
+
+    # Delete the specified task name.
+    #
+    def delete(task)
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+      raise TypeError unless task.is_a?(String)
+
+      @pITS.Delete(wide_string(task))
+
+      true
+    end
+
+    # Execute the current task.
+    #
+    def run
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+
+      @pITask.Run
+    end
+
+    # Saves the current task. Tasks must be saved before they can be activated.
+    # The .job file itself is typically stored in the C:\WINDOWS\Tasks folder.
+    #
+    # If +file+ (an absolute path) is specified then the job is saved to that
+    # file instead. A '.job' extension is recommended but not enforced.
+    #
+    def save(file = nil)
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+
+      reset = true
+
+      begin
+        @pITask.QueryInstance(COM::PersistFile) do |pIPersistFile|
+          pIPersistFile.Save(wide_string(file), 1)
+        end
+      rescue
+        reset = false
+      ensure
+        reset_current_task if reset
+      end
+    end
+
+    # Terminate the current task.
+    #
+    def terminate
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+
+      @pITask.Terminate
+    end
+
+    # Set the host on which the various TaskScheduler methods will execute.
+    #
+    def machine=(host)
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+      raise TypeError unless host.is_a?(String)
+
+      @pITS.SetTargetComputer(wide_string(host))
+
+      host
+    end
+
+    alias :host= :machine=
+
+    # Sets the +user+ and +password+ for the given task. If the user and
+    # password are set properly then true is returned.
+    #
+    # In some cases the job may be created, but the account information was
+    # bad. In this case the task is created but a warning is generated and
+    # false is returned.
+    #
+    def set_account_information(user, password)
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+
+      bool = false
+
+      begin
+        if (user.nil? || user=="") && (password.nil? || password=="")
+          @pITask.SetAccountInformation(wide_string(""), FFI::Pointer::NULL)
+        else
+          user = wide_string(user)
+          password = wide_string(password)
+          @pITask.SetAccountInformation(user, password)
+        end
+
+        bool = true
+      rescue Puppet::Util::Windows::Error => e
+        raise e unless e.code == SCHED_E_ACCOUNT_INFORMATION_NOT_SET
+
+        warn 'job created, but password was invalid'
+      end
+
+      bool
+    end
+
+    # Returns the user associated with the task or nil if no user has yet
+    # been associated with the task.
+    #
+    def account_information
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+
+      # default under certain failures
+      user = nil
+
+      begin
+        FFI::MemoryPointer.new(:pointer) do |ptr|
+          @pITask.GetAccountInformation(ptr)
+          ptr.read_com_memory_pointer do |str_ptr|
+            user = str_ptr.read_arbitrary_wide_string_up_to(256) if ! str_ptr.null?
+          end
+        end
+      rescue Puppet::Util::Windows::Error => e
+        raise e unless e.code == SCHED_E_ACCOUNT_INFORMATION_NOT_SET ||
+                       e.code == SCHED_E_NO_SECURITY_SERVICES ||
+                       e.code == ERROR_NONE_MAPPED
+      end
+
+      user
+    end
+
+    # Returns the name of the application associated with the task.
+    #
+    def application_name
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+
+      app = nil
+
+      FFI::MemoryPointer.new(:pointer) do |ptr|
+        @pITask.GetApplicationName(ptr)
+
+        ptr.read_com_memory_pointer do |str_ptr|
+          app = str_ptr.read_arbitrary_wide_string_up_to(256) if ! str_ptr.null?
+        end
+      end
+
+      app
+    end
+
+    # Sets the application name associated with the task.
+    #
+    def application_name=(app)
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+      raise TypeError unless app.is_a?(String)
+
+      @pITask.SetApplicationName(wide_string(app))
+
+      app
+    end
+
+    # Returns the command line parameters for the task.
+    #
+    def parameters
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+
+      param = nil
+
+      FFI::MemoryPointer.new(:pointer) do |ptr|
+        @pITask.GetParameters(ptr)
+
+        ptr.read_com_memory_pointer do |str_ptr|
+          param = str_ptr.read_arbitrary_wide_string_up_to(256) if ! str_ptr.null?
+        end
+      end
+
+      param
+    end
+
+    # Sets the parameters for the task. These parameters are passed as command
+    # line arguments to the application the task will run. To clear the command
+    # line parameters set it to an empty string.
+    #
+    def parameters=(param)
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+      raise TypeError unless param.is_a?(String)
+
+      @pITask.SetParameters(wide_string(param))
+
+      param
+    end
+
+    # Returns the working directory for the task.
+    #
+    def working_directory
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+
+      dir = nil
+
+      FFI::MemoryPointer.new(:pointer) do |ptr|
+        @pITask.GetWorkingDirectory(ptr)
+
+        ptr.read_com_memory_pointer do |str_ptr|
+          dir = str_ptr.read_arbitrary_wide_string_up_to(256) if ! str_ptr.null?
+        end
+      end
+
+      dir
+    end
+
+    # Sets the working directory for the task.
+    #
+    def working_directory=(dir)
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+      raise TypeError unless dir.is_a?(String)
+
+      @pITask.SetWorkingDirectory(wide_string(dir))
+
+      dir
+    end
+
+    # Returns the task's priority level. Possible values are 'idle',
+    # 'normal', 'high', 'realtime', 'below_normal', 'above_normal',
+    # and 'unknown'.
+    #
+    def priority
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+
+      FFI::MemoryPointer.new(:dword, 1) do |ptr|
+        @pITask.GetPriority(ptr)
+
+        pri = ptr.read_dword
+        if (pri & IDLE) != 0
+          priority = 'idle'
+        elsif (pri & NORMAL) != 0
+          priority = 'normal'
+        elsif (pri & HIGH) != 0
+          priority = 'high'
+        elsif (pri & REALTIME) != 0
+          priority = 'realtime'
+        elsif (pri & BELOW_NORMAL) != 0
+          priority = 'below_normal'
+        elsif (pri & ABOVE_NORMAL) != 0
+          priority = 'above_normal'
+        else
+          priority = 'unknown'
+        end
+      end
+
+      priority
+    end
+
+    # Sets the priority of the task. The +priority+ should be a numeric
+    # priority constant value.
+    #
+    def priority=(priority)
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+      raise TypeError unless priority.is_a?(Numeric)
+
+      @pITask.SetPriority(priority)
+
+      priority
+    end
+
+    # Creates a new work item (scheduled job) with the given +trigger+. The
+    # trigger variable is a hash of options that define when the scheduled
+    # job should run.
+    #
+    def new_work_item(task, trigger)
+      raise TypeError unless trigger.is_a?(Hash)
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+
+      # I'm working around github issue #1 here.
+      enum.each{ |name|
+        if name.downcase == task.downcase + '.job'
+          raise Error.new("task '#{task}' already exists")
+        end
+      }
+
+      FFI::MemoryPointer.new(:pointer) do |ptr|
+        @pITS.NewWorkItem(wide_string(task), CLSID_CTask, IID_ITask, ptr)
+
+        reset_current_task
+        @pITask = COM::Task.new(ptr.read_pointer)
+
+        FFI::MemoryPointer.new(:word, 1) do |trigger_index_ptr|
+          # Without the 'enum.include?' check above the code segfaults here if the
+          # task already exists. This should probably be handled properly instead
+          # of simply avoiding the issue.
+
+          @pITask.UseInstance(COM::TaskTrigger, :CreateTrigger, trigger_index_ptr) do |pITaskTrigger|
+            populate_trigger(pITaskTrigger, trigger)
+          end
+        end
+      end
+
+      @pITask
+    end
+
+    alias :new_task :new_work_item
+
+    # Returns the number of triggers associated with the active task.
+    #
+    def trigger_count
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+
+      count = 0
+
+      FFI::MemoryPointer.new(:word, 1) do |ptr|
+        @pITask.GetTriggerCount(ptr)
+        count = ptr.read_word
+      end
+
+      count
+    end
+
+    # Returns a string that describes the current trigger at the specified
+    # index for the active task.
+    #
+    # Example: "At 7:14 AM every day, starting 4/11/2009"
+    #
+    def trigger_string(index)
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+      raise TypeError unless index.is_a?(Numeric)
+
+      FFI::MemoryPointer.new(:pointer) do |ptr|
+        @pITask.GetTriggerString(index, ptr)
+
+        ptr.read_com_memory_pointer do |str_ptr|
+          trigger = str_ptr.read_arbitrary_wide_string_up_to(256)
+        end
+      end
+
+      trigger
+    end
+
+    # Deletes the trigger at the specified index.
+    #
+    def delete_trigger(index)
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+
+      @pITask.DeleteTrigger(index)
+      index
+    end
+
+    # Returns a hash that describes the trigger at the given index for the
+    # current task.
+    #
+    def trigger(index)
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+
+      trigger = {}
+
+      @pITask.UseInstance(COM::TaskTrigger, :GetTrigger, index) do |pITaskTrigger|
+        FFI::MemoryPointer.new(COM::TASK_TRIGGER.size) do |task_trigger_ptr|
+          pITaskTrigger.GetTrigger(task_trigger_ptr)
+          trigger = populate_hash_from_trigger(COM::TASK_TRIGGER.new(task_trigger_ptr))
+        end
+      end
+
+      trigger
+    end
+
+    # Sets the trigger for the currently active task.
+    #
+    def trigger=(trigger)
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+      raise TypeError unless trigger.is_a?(Hash)
+
+      FFI::MemoryPointer.new(:word, 1) do |trigger_index_ptr|
+        # Without the 'enum.include?' check above the code segfaults here if the
+        # task already exists. This should probably be handled properly instead
+        # of simply avoiding the issue.
+
+        @pITask.UseInstance(COM::TaskTrigger, :CreateTrigger, trigger_index_ptr) do |pITaskTrigger|
+          populate_trigger(pITaskTrigger, trigger)
+        end
+      end
+
+      trigger
+    end
+
+    # Adds a trigger at the specified index.
+    #
+    def add_trigger(index, trigger)
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+      raise TypeError unless trigger.is_a?(Hash)
+
+      @pITask.UseInstance(COM::TaskTrigger, :GetTrigger, index) do |pITaskTrigger|
+        populate_trigger(pITaskTrigger, trigger)
+      end
+    end
+
+    # Returns the flags (integer) that modify the behavior of the work item. You
+    # must OR the return value to determine the flags yourself.
+    #
+    def flags
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+
+      flags = 0
+
+      FFI::MemoryPointer.new(:dword, 1) do |ptr|
+        @pITask.GetFlags(ptr)
+        flags = ptr.read_dword
+      end
+
+      flags
+    end
+
+    # Sets an OR'd value of flags that modify the behavior of the work item.
+    #
+    def flags=(flags)
+      raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil?
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+
+      @pITask.SetFlags(flags)
+      flags
+    end
+
+    # Returns the status of the currently active task. Possible values are
+    # 'ready', 'running', 'not scheduled' or 'unknown'.
+    #
+    def status
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+
+      st = nil
+
+      FFI::MemoryPointer.new(:hresult, 1) do |ptr|
+        @pITask.GetStatus(ptr)
+        st = ptr.read_hresult
+      end
+
+      case st
+        when SCHED_S_TASK_READY
+           status = 'ready'
+        when SCHED_S_TASK_RUNNING
+           status = 'running'
+        when SCHED_S_TASK_NOT_SCHEDULED
+           status = 'not scheduled'
+        else
+           status = 'unknown'
+      end
+
+      status
+    end
+
+    # Returns the exit code from the last scheduled run.
+    #
+    def exit_code
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+
+      status = 0
+
+      begin
+        FFI::MemoryPointer.new(:dword, 1) do |ptr|
+          @pITask.GetExitCode(ptr)
+          status = ptr.read_dword
+        end
+      rescue Puppet::Util::Windows::Error => e
+        raise e unless e.code == SCHED_S_TASK_HAS_NOT_RUN
+      end
+
+      status
+    end
+
+    # Returns the comment associated with the task, if any.
+    #
+    def comment
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+
+      comment = nil
+
+      FFI::MemoryPointer.new(:pointer) do |ptr|
+        @pITask.GetComment(ptr)
+
+        ptr.read_com_memory_pointer do |str_ptr|
+          comment = str_ptr.read_arbitrary_wide_string_up_to(256) if ! str_ptr.null?
+        end
+      end
+
+      comment
+    end
+
+    # Sets the comment for the task.
+    #
+    def comment=(comment)
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+      raise TypeError unless comment.is_a?(String)
+
+      @pITask.SetComment(wide_string(comment))
+      comment
+    end
+
+    # Returns the name of the user who created the task.
+    #
+    def creator
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+
+      creator = nil
+
+      FFI::MemoryPointer.new(:pointer) do |ptr|
+        @pITask.GetCreator(ptr)
+
+        ptr.read_com_memory_pointer do |str_ptr|
+          creator = str_ptr.read_arbitrary_wide_string_up_to(256) if ! str_ptr.null?
+        end
+      end
+
+      creator
+    end
+
+    # Sets the creator for the task.
+    #
+    def creator=(creator)
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+      raise TypeError unless creator.is_a?(String)
+
+      @pITask.SetCreator(wide_string(creator))
+      creator
+    end
+
+    # Returns a Time object that indicates the next time the task will run.
+    #
+    def next_run_time
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+
+      time = nil
+
+      FFI::MemoryPointer.new(WIN32::SYSTEMTIME.size) do |ptr|
+        @pITask.GetNextRunTime(ptr)
+        time = WIN32::SYSTEMTIME.new(ptr).to_local_time
+      end
+
+      time
+    end
+
+    # Returns a Time object indicating the most recent time the task ran or
+    # nil if the task has never run.
+    #
+    def most_recent_run_time
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+
+      time = nil
+
+      begin
+        FFI::MemoryPointer.new(WIN32::SYSTEMTIME.size) do |ptr|
+          @pITask.GetMostRecentRunTime(ptr)
+          time = WIN32::SYSTEMTIME.new(ptr).to_local_time
+        end
+      rescue Puppet::Util::Windows::Error => e
+        raise e unless e.code == SCHED_S_TASK_HAS_NOT_RUN
+      end
+
+      time
+    end
+
+    # Returns the maximum length of time, in milliseconds, that the task
+    # will run before terminating.
+    #
+    def max_run_time
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+
+      max_run_time = nil
+
+      FFI::MemoryPointer.new(:dword, 1) do |ptr|
+        @pITask.GetMaxRunTime(ptr)
+        max_run_time = ptr.read_dword
+      end
+
+      max_run_time
+    end
+
+    # Sets the maximum length of time, in milliseconds, that the task can run
+    # before terminating. Returns the value you specified if successful.
+    #
+    def max_run_time=(max_run_time)
+      raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil?
+      raise TypeError unless max_run_time.is_a?(Numeric)
+
+      @pITask.SetMaxRunTime(max_run_time)
+      max_run_time
+    end
+
+    # Returns whether or not the scheduled task exists.
+    def exists?(job_name)
+      bool = false
+      Dir.foreach('C:/Windows/Tasks'){ |file|
+        if File.basename(file, '.job') == job_name
+          bool = true
+          break
+        end
+      }
+      bool
+    end
+
+    private
+
+    # :stopdoc:
+
+    # Used for the new_work_item method
+    ValidTriggerKeys = [
+      'end_day',
+      'end_month',
+      'end_year',
+      'flags',
+      'minutes_duration',
+      'minutes_interval',
+      'random_minutes_interval',
+      'start_day',
+      'start_hour',
+      'start_minute',
+      'start_month',
+      'start_year',
+      'trigger_type',
+      'type'
+    ]
+
+    ValidTypeKeys = [
+       'days_interval',
+       'weeks_interval',
+       'days_of_week',
+       'months',
+       'days',
+       'weeks'
+    ]
+
+    # Private method that validates keys, and converts all keys to lowercase
+    # strings.
+    #
+    def transform_and_validate(hash)
+      new_hash = {}
+
+      hash.each{ |key, value|
+        key = key.to_s.downcase
+        if key == 'type'
+          new_type_hash = {}
+          raise ArgumentError unless value.is_a?(Hash)
+          value.each{ |subkey, subvalue|
+            subkey = subkey.to_s.downcase
+            if ValidTypeKeys.include?(subkey)
+              new_type_hash[subkey] = subvalue
+            else
+              raise ArgumentError, "Invalid type key '#{subkey}'"
+            end
+          }
+          new_hash[key] = new_type_hash
+        else
+          if ValidTriggerKeys.include?(key)
+            new_hash[key] = value
+          else
+            raise ArgumentError, "Invalid key '#{key}'"
+          end
+        end
+      }
+
+      new_hash
+    end
+
+    private
+
+    def reset_current_task
+      # Ensure that COM reference is decremented properly
+      @pITask.Release if @pITask && ! @pITask.null?
+      @pITask = nil
+    end
+
+    def populate_trigger(task_trigger, trigger)
+      raise TypeError unless task_trigger.is_a?(COM::TaskTrigger)
+      trigger = transform_and_validate(trigger)
+
+      FFI::MemoryPointer.new(COM::TASK_TRIGGER.size) do |trigger_ptr|
+        FFI::MemoryPointer.new(COM::TRIGGER_TYPE_UNION.size) do |trigger_type_union_ptr|
+          trigger_type_union = COM::TRIGGER_TYPE_UNION.new(trigger_type_union_ptr)
+
+          tmp = trigger['type'].is_a?(Hash) ? trigger['type'] : nil
+          case trigger['trigger_type']
+            when :TASK_TIME_TRIGGER_DAILY
+              if tmp && tmp['days_interval']
+                trigger_type_union[:Daily][:DaysInterval] = tmp['days_interval']
+              end
+            when :TASK_TIME_TRIGGER_WEEKLY
+              if tmp && tmp['weeks_interval'] && tmp['days_of_week']
+                trigger_type_union[:Weekly][:WeeksInterval] = tmp['weeks_interval']
+                trigger_type_union[:Weekly][:rgfDaysOfTheWeek] = tmp['days_of_week']
+              end
+            when :TASK_TIME_TRIGGER_MONTHLYDATE
+              if tmp && tmp['months'] && tmp['days']
+                trigger_type_union[:MonthlyDate][:rgfDays] = tmp['days']
+                trigger_type_union[:MonthlyDate][:rgfMonths] = tmp['months']
+              end
+            when :TASK_TIME_TRIGGER_MONTHLYDOW
+              if tmp && tmp['weeks'] && tmp['days_of_week'] && tmp['months']
+                trigger_type_union[:MonthlyDOW][:wWhichWeek] = tmp['weeks']
+                trigger_type_union[:MonthlyDOW][:rgfDaysOfTheWeek] = tmp['days_of_week']
+                trigger_type_union[:MonthlyDOW][:rgfMonths] = tmp['months']
+              end
+            when :TASK_TIME_TRIGGER_ONCE
+              # Do nothing. The Type member of the TASK_TRIGGER struct is ignored.
+            else
+              raise Error.new("Unknown trigger type #{trigger['trigger_type']}")
+          end
+
+          trigger_struct = COM::TASK_TRIGGER.new(trigger_ptr)
+          trigger_struct[:cbTriggerSize] = COM::TASK_TRIGGER.size
+          trigger_struct[:wBeginYear] = trigger['start_year'] || 0
+          trigger_struct[:wBeginMonth] = trigger['start_month'] || 0
+          trigger_struct[:wBeginDay] = trigger['start_day'] || 0
+          trigger_struct[:wEndYear] = trigger['end_year'] || 0
+          trigger_struct[:wEndMonth] = trigger['end_month'] || 0
+          trigger_struct[:wEndDay] = trigger['end_day'] || 0
+          trigger_struct[:wStartHour] = trigger['start_hour'] || 0
+          trigger_struct[:wStartMinute] = trigger['start_minute'] || 0
+          trigger_struct[:MinutesDuration] = trigger['minutes_duration'] || 0
+          trigger_struct[:MinutesInterval] = trigger['minutes_interval'] || 0
+          trigger_struct[:rgFlags] = trigger['flags'] || 0
+          trigger_struct[:TriggerType] = trigger['trigger_type'] || :TASK_TIME_TRIGGER_ONCE
+          trigger_struct[:Type] = trigger_type_union
+          trigger_struct[:wRandomMinutesInterval] = trigger['random_minutes_interval']
+
+          task_trigger.SetTrigger(trigger_struct)
+        end
+      end
+    end
+
+    def populate_hash_from_trigger(task_trigger)
+      raise TypeError unless task_trigger.is_a?(COM::TASK_TRIGGER)
+
+      trigger = {
+        'start_year' => task_trigger[:wBeginYear],
+        'start_month' => task_trigger[:wBeginMonth],
+        'start_day' => task_trigger[:wBeginDay],
+        'end_year' => task_trigger[:wEndYear],
+        'end_month' => task_trigger[:wEndMonth],
+        'end_day' => task_trigger[:wEndDay],
+        'start_hour' => task_trigger[:wStartHour],
+        'start_minute' => task_trigger[:wStartMinute],
+        'minutes_duration' => task_trigger[:MinutesDuration],
+        'minutes_interval' => task_trigger[:MinutesInterval],
+        'flags' => task_trigger[:rgFlags],
+        'trigger_type' => task_trigger[:TriggerType],
+        'random_minutes_interval' => task_trigger[:wRandomMinutesInterval]
+      }
+
+      case task_trigger[:TriggerType]
+        when :TASK_TIME_TRIGGER_DAILY
+          trigger['type'] = { 'days_interval' => task_trigger[:Type][:Daily][:DaysInterval] }
+        when :TASK_TIME_TRIGGER_WEEKLY
+          trigger['type'] = {
+            'weeks_interval' => task_trigger[:Type][:Weekly][:WeeksInterval],
+            'days_of_week' => task_trigger[:Type][:Weekly][:rgfDaysOfTheWeek]
+          }
+        when :TASK_TIME_TRIGGER_MONTHLYDATE
+          trigger['type'] = {
+            'days' => task_trigger[:Type][:MonthlyDate][:rgfDays],
+            'months' => task_trigger[:Type][:MonthlyDate][:rgfMonths]
+          }
+        when :TASK_TIME_TRIGGER_MONTHLYDOW
+          trigger['type'] = {
+            'weeks' => task_trigger[:Type][:MonthlyDOW][:wWhichWeek],
+            'days_of_week' => task_trigger[:Type][:MonthlyDOW][:rgfDaysOfTheWeek],
+            'months' => task_trigger[:Type][:MonthlyDOW][:rgfMonths]
+          }
+        when :TASK_TIME_TRIGGER_ONCE
+          trigger['type'] = { 'once' => nil }
+        else
+          raise Error.new("Unknown trigger type #{task_trigger[:TriggerType]}")
+      end
+
+      trigger
+    end
+
+    module COM
+      extend FFI::Library
+      private
+
+      com = Puppet::Util::Windows::COM
+
+      public
+
+      # http://msdn.microsoft.com/en-us/library/windows/desktop/aa381811(v=vs.85).aspx
+      ITaskScheduler = com::Interface[com::IUnknown,
+        FFI::WIN32::GUID['148BD527-A2AB-11CE-B11F-00AA00530503'],
+
+        SetTargetComputer: [[:lpcwstr], :hresult],
+        # LPWSTR *
+        GetTargetComputer: [[:pointer], :hresult],
+        # IEnumWorkItems **
+        Enum: [[:pointer], :hresult],
+        # LPCWSTR, REFIID, IUnknown **
+        Activate: [[:lpcwstr, :pointer, :pointer], :hresult],
+        Delete: [[:lpcwstr], :hresult],
+        # LPCWSTR, REFCLSID, REFIID, IUnknown **
+        NewWorkItem: [[:lpcwstr, :pointer, :pointer, :pointer], :hresult],
+        # LPCWSTR, IScheduledWorkItem *
+        AddWorkItem: [[:lpcwstr, :pointer], :hresult],
+        # LPCWSTR, REFIID
+        IsOfType: [[:lpcwstr, :pointer], :hresult]
+      ]
+
+      TaskScheduler = com::Factory[ITaskScheduler,
+        FFI::WIN32::GUID['148BD52A-A2AB-11CE-B11F-00AA00530503']]
+
+      # http://msdn.microsoft.com/en-us/library/windows/desktop/aa380706(v=vs.85).aspx
+      IEnumWorkItems = com::Interface[com::IUnknown,
+        FFI::WIN32::GUID['148BD528-A2AB-11CE-B11F-00AA00530503'],
+
+        # ULONG, LPWSTR **, ULONG *
+        Next: [[:win32_ulong, :pointer, :pointer], :hresult],
+        Skip: [[:win32_ulong], :hresult],
+        Reset: [[], :hresult],
+        # IEnumWorkItems ** ppEnumWorkItems
+        Clone: [[:pointer], :hresult]
+      ]
+
+      EnumWorkItems = com::Instance[IEnumWorkItems]
+
+      # http://msdn.microsoft.com/en-us/library/windows/desktop/aa381216(v=vs.85).aspx
+      IScheduledWorkItem = com::Interface[com::IUnknown,
+        FFI::WIN32::GUID['a6b952f0-a4b1-11d0-997d-00aa006887ec'],
+
+        # WORD *, ITaskTrigger **
+        CreateTrigger: [[:pointer, :pointer], :hresult],
+        DeleteTrigger: [[:word], :hresult],
+        # WORD *
+        GetTriggerCount: [[:pointer], :hresult],
+        # WORD, ITaskTrigger **
+        GetTrigger: [[:word, :pointer], :hresult],
+        # WORD, LPWSTR *
+        GetTriggerString: [[:word, :pointer], :hresult],
+        # LPSYSTEMTIME, LPSYSTEMTIME, WORD *, LPSYSTEMTIME *
+        GetRunTimes: [[:pointer, :pointer, :pointer, :pointer], :hresult],
+        # SYSTEMTIME *
+        GetNextRunTime: [[:pointer], :hresult],
+        SetIdleWait: [[:word, :word], :hresult],
+        # WORD *, WORD *
+        GetIdleWait: [[:pointer, :pointer], :hresult],
+        Run: [[], :hresult],
+        Terminate: [[], :hresult],
+        EditWorkItem: [[:hwnd, :dword], :hresult],
+        # SYSTEMTIME *
+        GetMostRecentRunTime: [[:pointer], :hresult],
+        # HRESULT *
+        GetStatus: [[:pointer], :hresult],
+        GetExitCode: [[:pdword], :hresult],
+        SetComment: [[:lpcwstr], :hresult],
+        # LPWSTR *
+        GetComment: [[:pointer], :hresult],
+        SetCreator: [[:lpcwstr], :hresult],
+        # LPWSTR *
+        GetCreator: [[:pointer], :hresult],
+        # WORD, BYTE[]
+        SetWorkItemData: [[:word, :buffer_in], :hresult],
+        # WORD *, BYTE **
+        GetWorkItemData: [[:pointer, :pointer], :hresult],
+        SetErrorRetryCount: [[:word], :hresult],
+        # WORD *
+        GetErrorRetryCount: [[:pointer], :hresult],
+        SetErrorRetryInterval: [[:word], :hresult],
+        # WORD *
+        GetErrorRetryInterval: [[:pointer], :hresult],
+        SetFlags: [[:dword], :hresult],
+        # WORD *
+        GetFlags: [[:pointer], :hresult],
+        SetAccountInformation: [[:lpcwstr, :lpcwstr], :hresult],
+        # LPWSTR *
+        GetAccountInformation: [[:pointer], :hresult]
+      ]
+
+      # http://msdn.microsoft.com/en-us/library/windows/desktop/aa381311(v=vs.85).aspx
+      ITask = com::Interface[IScheduledWorkItem,
+        FFI::WIN32::GUID['148BD524-A2AB-11CE-B11F-00AA00530503'],
+
+        SetApplicationName: [[:lpcwstr], :hresult],
+        # LPWSTR *
+        GetApplicationName: [[:pointer], :hresult],
+        SetParameters: [[:lpcwstr], :hresult],
+        # LPWSTR *
+        GetParameters: [[:pointer], :hresult],
+        SetWorkingDirectory: [[:lpcwstr], :hresult],
+        # LPWSTR *
+        GetWorkingDirectory: [[:pointer], :hresult],
+        SetPriority: [[:dword], :hresult],
+        # DWORD *
+        GetPriority: [[:pointer], :hresult],
+        SetTaskFlags: [[:dword], :hresult],
+        # DWORD *
+        GetTaskFlags: [[:pointer], :hresult],
+        SetMaxRunTime: [[:dword], :hresult],
+        # DWORD *
+        GetMaxRunTime: [[:pointer], :hresult]
+      ]
+
+      Task = com::Instance[ITask]
+
+      # http://msdn.microsoft.com/en-us/library/windows/desktop/ms688695(v=vs.85).aspx
+      IPersist = com::Interface[com::IUnknown,
+        FFI::WIN32::GUID['0000010c-0000-0000-c000-000000000046'],
+        # CLSID *
+        GetClassID: [[:pointer], :hresult]
+      ]
+
+      # http://msdn.microsoft.com/en-us/library/windows/desktop/ms687223(v=vs.85).aspx
+      IPersistFile = com::Interface[IPersist,
+        FFI::WIN32::GUID['0000010b-0000-0000-C000-000000000046'],
+
+        IsDirty: [[], :hresult],
+        Load: [[:lpcolestr, :dword], :hresult],
+        Save: [[:lpcolestr, :win32_bool], :hresult],
+        SaveCompleted: [[:lpcolestr], :hresult],
+        # LPOLESTR *
+        GetCurFile: [[:pointer], :hresult]
+      ]
+
+      PersistFile = com::Instance[IPersistFile]
+
+      # http://msdn.microsoft.com/en-us/library/windows/desktop/aa381864(v=vs.85).aspx
+      ITaskTrigger = com::Interface[com::IUnknown,
+        FFI::WIN32::GUID['148BD52B-A2AB-11CE-B11F-00AA00530503'],
+
+        SetTrigger: [[:pointer], :hresult],
+        GetTrigger: [[:pointer], :hresult],
+        GetTriggerString: [[:pointer], :hresult]
+      ]
+
+      TaskTrigger = com::Instance[ITaskTrigger]
+
+      # http://msdn.microsoft.com/en-us/library/windows/desktop/aa383620(v=vs.85).aspx
+      # The TASK_TRIGGER_TYPE field of the TASK_TRIGGER structure determines
+      # which member of the TRIGGER_TYPE_UNION field to use.
+      TASK_TRIGGER_TYPE = enum(
+        :TASK_TIME_TRIGGER_ONCE, 0,             # Ignore the Type field
+        :TASK_TIME_TRIGGER_DAILY, 1,
+        :TASK_TIME_TRIGGER_WEEKLY, 2,
+        :TASK_TIME_TRIGGER_MONTHLYDATE, 3,
+        :TASK_TIME_TRIGGER_MONTHLYDOW,  4,
+        :TASK_EVENT_TRIGGER_ON_IDLE, 5,         # Ignore the Type field
+        :TASK_EVENT_TRIGGER_AT_SYSTEMSTART, 6,  # Ignore the Type field
+        :TASK_EVENT_TRIGGER_AT_LOGON, 7         # Ignore the Type field
+      )
+
+      # http://msdn.microsoft.com/en-us/library/windows/desktop/aa446857(v=vs.85).aspx
+      class DAILY < FFI::Struct
+        layout :DaysInterval, :word
+      end
+
+      # http://msdn.microsoft.com/en-us/library/windows/desktop/aa384014(v=vs.85).aspx
+      class WEEKLY < FFI::Struct
+        layout :WeeksInterval, :word,
+               :rgfDaysOfTheWeek, :word
+      end
+
+      # http://msdn.microsoft.com/en-us/library/windows/desktop/aa381918(v=vs.85).aspx
+      class MONTHLYDATE < FFI::Struct
+        layout :rgfDays, :dword,
+               :rgfMonths, :word
+      end
+
+      # http://msdn.microsoft.com/en-us/library/windows/desktop/aa381918(v=vs.85).aspx
+      class MONTHLYDOW < FFI::Struct
+        layout :wWhichWeek, :word,
+               :rgfDaysOfTheWeek, :word,
+               :rgfMonths, :word
+      end
+
+      # http://msdn.microsoft.com/en-us/library/windows/desktop/aa384002(v=vs.85).aspx
+      class TRIGGER_TYPE_UNION < FFI::Union
+        layout :Daily, DAILY,
+               :Weekly, WEEKLY,
+               :MonthlyDate, MONTHLYDATE,
+               :MonthlyDOW, MONTHLYDOW
+      end
+
+      # http://msdn.microsoft.com/en-us/library/windows/desktop/aa383618(v=vs.85).aspx
+      class TASK_TRIGGER < FFI::Struct
+        layout :cbTriggerSize, :word,            # Structure size.
+               :Reserved1, :word,                # Reserved. Must be zero.
+               :wBeginYear, :word,               # Trigger beginning date year.
+               :wBeginMonth, :word,              # Trigger beginning date month.
+               :wBeginDay, :word,                # Trigger beginning date day.
+               :wEndYear, :word,                 # Optional trigger ending date year.
+               :wEndMonth, :word,                # Optional trigger ending date month.
+               :wEndDay, :word,                  # Optional trigger ending date day.
+               :wStartHour, :word,               # Run bracket start time hour.
+               :wStartMinute, :word,             # Run bracket start time minute.
+               :MinutesDuration, :dword,         # Duration of run bracket.
+               :MinutesInterval, :dword,         # Run bracket repetition interval.
+               :rgFlags, :dword,                 # Trigger flags.
+               :TriggerType, TASK_TRIGGER_TYPE,  # Trigger type.
+               :Type, TRIGGER_TYPE_UNION,        # Trigger data.
+               :Reserved2, :word,                # Reserved. Must be zero.
+               :wRandomMinutesInterval, :word    # Maximum number of random minutes after start time
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/user.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/user.rb
new file mode 100644
index 0000000..a2277f6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/windows/user.rb
@@ -0,0 +1,292 @@
+require 'puppet/util/windows'
+
+require 'facter'
+require 'ffi'
+
+module Puppet::Util::Windows::User
+  extend Puppet::Util::Windows::String
+  extend FFI::Library
+
+  def admin?
+    majversion = Facter.value(:kernelmajversion)
+    return false unless majversion
+
+    # if Vista or later, check for unrestricted process token
+    return Puppet::Util::Windows::Process.elevated_security? unless majversion.to_f < 6.0
+
+    # otherwise 2003 or less
+    check_token_membership
+  end
+  module_function :admin?
+
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/ee207397(v=vs.85).aspx
+  SECURITY_MAX_SID_SIZE = 68
+
+  def check_token_membership
+    is_admin = false
+    FFI::MemoryPointer.new(:byte, SECURITY_MAX_SID_SIZE) do |sid_pointer|
+      FFI::MemoryPointer.new(:dword, 1) do |size_pointer|
+        size_pointer.write_uint32(SECURITY_MAX_SID_SIZE)
+
+        if CreateWellKnownSid(:WinBuiltinAdministratorsSid, FFI::Pointer::NULL, sid_pointer, size_pointer) == FFI::WIN32_FALSE
+          raise Puppet::Util::Windows::Error.new("Failed to create administrators SID")
+        end
+      end
+
+      if IsValidSid(sid_pointer) == FFI::WIN32_FALSE
+        raise Puppet::Util::Windows::Error.new("Invalid SID")
+      end
+
+      FFI::MemoryPointer.new(:win32_bool, 1) do |ismember_pointer|
+        if CheckTokenMembership(FFI::Pointer::NULL_HANDLE, sid_pointer, ismember_pointer) == FFI::WIN32_FALSE
+          raise Puppet::Util::Windows::Error.new("Failed to check membership")
+        end
+
+        # Is administrators SID enabled in calling thread's access token?
+        is_admin = ismember_pointer.read_win32_bool != FFI::WIN32_FALSE
+      end
+    end
+
+    is_admin
+  end
+  module_function :check_token_membership
+
+  def password_is?(name, password)
+    logon_user(name, password) { |token| }
+  rescue Puppet::Util::Windows::Error
+    false
+  end
+  module_function :password_is?
+
+  def logon_user(name, password, &block)
+    fLOGON32_LOGON_NETWORK = 3
+    fLOGON32_PROVIDER_DEFAULT = 0
+
+    token = nil
+    begin
+      FFI::MemoryPointer.new(:handle, 1) do |token_pointer|
+        if LogonUserW(wide_string(name), wide_string('.'), wide_string(password),
+            fLOGON32_LOGON_NETWORK, fLOGON32_PROVIDER_DEFAULT, token_pointer) == FFI::WIN32_FALSE
+          raise Puppet::Util::Windows::Error.new("Failed to logon user #{name.inspect}")
+        end
+
+        yield token = token_pointer.read_handle
+      end
+    ensure
+      FFI::WIN32.CloseHandle(token) if token
+    end
+
+    # token has been closed by this point
+    true
+  end
+  module_function :logon_user
+
+  def load_profile(user, password)
+    logon_user(user, password) do |token|
+      FFI::MemoryPointer.from_string_to_wide_string(user) do |lpUserName|
+        pi = PROFILEINFO.new
+        pi[:dwSize] = PROFILEINFO.size
+        pi[:dwFlags] = 1 # PI_NOUI - prevents display of profile error msgs
+        pi[:lpUserName] = lpUserName
+
+        # Load the profile. Since it doesn't exist, it will be created
+        if LoadUserProfileW(token, pi.pointer) == FFI::WIN32_FALSE
+          raise Puppet::Util::Windows::Error.new("Failed to load user profile #{user.inspect}")
+        end
+
+        Puppet.debug("Loaded profile for #{user}")
+
+        if UnloadUserProfile(token, pi[:hProfile]) == FFI::WIN32_FALSE
+          raise Puppet::Util::Windows::Error.new("Failed to unload user profile #{user.inspect}")
+        end
+      end
+    end
+  end
+  module_function :load_profile
+
+  ffi_convention :stdcall
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa378184(v=vs.85).aspx
+  # BOOL LogonUser(
+  #   _In_      LPTSTR lpszUsername,
+  #   _In_opt_  LPTSTR lpszDomain,
+  #   _In_opt_  LPTSTR lpszPassword,
+  #   _In_      DWORD dwLogonType,
+  #   _In_      DWORD dwLogonProvider,
+  #   _Out_     PHANDLE phToken
+  # );
+  ffi_lib :advapi32
+  attach_function_private :LogonUserW,
+    [:lpwstr, :lpwstr, :lpwstr, :dword, :dword, :phandle], :win32_bool
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/bb773378(v=vs.85).aspx
+  # typedef struct _PROFILEINFO {
+  #   DWORD  dwSize;
+  #   DWORD  dwFlags;
+  #   LPTSTR lpUserName;
+  #   LPTSTR lpProfilePath;
+  #   LPTSTR lpDefaultPath;
+  #   LPTSTR lpServerName;
+  #   LPTSTR lpPolicyPath;
+  #   HANDLE hProfile;
+  # } PROFILEINFO, *LPPROFILEINFO;
+  # technically
+  # NOTE: that for structs, buffer_* (lptstr alias) cannot be used
+  class PROFILEINFO < FFI::Struct
+    layout :dwSize, :dword,
+           :dwFlags, :dword,
+           :lpUserName, :pointer,
+           :lpProfilePath, :pointer,
+           :lpDefaultPath, :pointer,
+           :lpServerName, :pointer,
+           :lpPolicyPath, :pointer,
+           :hProfile, :handle
+  end
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/bb762281(v=vs.85).aspx
+  # BOOL WINAPI LoadUserProfile(
+  #   _In_     HANDLE hToken,
+  #   _Inout_  LPPROFILEINFO lpProfileInfo
+  # );
+  ffi_lib :userenv
+  attach_function_private :LoadUserProfileW,
+    [:handle, :pointer], :win32_bool
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/bb762282(v=vs.85).aspx
+  # BOOL WINAPI UnloadUserProfile(
+  #   _In_  HANDLE hToken,
+  #   _In_  HANDLE hProfile
+  # );
+  ffi_lib :userenv
+  attach_function_private :UnloadUserProfile,
+    [:handle, :handle], :win32_bool
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa376389(v=vs.85).aspx
+  # BOOL WINAPI CheckTokenMembership(
+  #   _In_opt_  HANDLE TokenHandle,
+  #   _In_      PSID SidToCheck,
+  #   _Out_     PBOOL IsMember
+  # );
+  ffi_lib :advapi32
+  attach_function_private :CheckTokenMembership,
+    [:handle, :pointer, :pbool], :win32_bool
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa379650(v=vs.85).aspx
+  WELL_KNOWN_SID_TYPE = enum(
+    :WinNullSid                                   , 0,
+    :WinWorldSid                                  , 1,
+    :WinLocalSid                                  , 2,
+    :WinCreatorOwnerSid                           , 3,
+    :WinCreatorGroupSid                           , 4,
+    :WinCreatorOwnerServerSid                     , 5,
+    :WinCreatorGroupServerSid                     , 6,
+    :WinNtAuthoritySid                            , 7,
+    :WinDialupSid                                 , 8,
+    :WinNetworkSid                                , 9,
+    :WinBatchSid                                  , 10,
+    :WinInteractiveSid                            , 11,
+    :WinServiceSid                                , 12,
+    :WinAnonymousSid                              , 13,
+    :WinProxySid                                  , 14,
+    :WinEnterpriseControllersSid                  , 15,
+    :WinSelfSid                                   , 16,
+    :WinAuthenticatedUserSid                      , 17,
+    :WinRestrictedCodeSid                         , 18,
+    :WinTerminalServerSid                         , 19,
+    :WinRemoteLogonIdSid                          , 20,
+    :WinLogonIdsSid                               , 21,
+    :WinLocalSystemSid                            , 22,
+    :WinLocalServiceSid                           , 23,
+    :WinNetworkServiceSid                         , 24,
+    :WinBuiltinDomainSid                          , 25,
+    :WinBuiltinAdministratorsSid                  , 26,
+    :WinBuiltinUsersSid                           , 27,
+    :WinBuiltinGuestsSid                          , 28,
+    :WinBuiltinPowerUsersSid                      , 29,
+    :WinBuiltinAccountOperatorsSid                , 30,
+    :WinBuiltinSystemOperatorsSid                 , 31,
+    :WinBuiltinPrintOperatorsSid                  , 32,
+    :WinBuiltinBackupOperatorsSid                 , 33,
+    :WinBuiltinReplicatorSid                      , 34,
+    :WinBuiltinPreWindows2000CompatibleAccessSid  , 35,
+    :WinBuiltinRemoteDesktopUsersSid              , 36,
+    :WinBuiltinNetworkConfigurationOperatorsSid   , 37,
+    :WinAccountAdministratorSid                   , 38,
+    :WinAccountGuestSid                           , 39,
+    :WinAccountKrbtgtSid                          , 40,
+    :WinAccountDomainAdminsSid                    , 41,
+    :WinAccountDomainUsersSid                     , 42,
+    :WinAccountDomainGuestsSid                    , 43,
+    :WinAccountComputersSid                       , 44,
+    :WinAccountControllersSid                     , 45,
+    :WinAccountCertAdminsSid                      , 46,
+    :WinAccountSchemaAdminsSid                    , 47,
+    :WinAccountEnterpriseAdminsSid                , 48,
+    :WinAccountPolicyAdminsSid                    , 49,
+    :WinAccountRasAndIasServersSid                , 50,
+    :WinNTLMAuthenticationSid                     , 51,
+    :WinDigestAuthenticationSid                   , 52,
+    :WinSChannelAuthenticationSid                 , 53,
+    :WinThisOrganizationSid                       , 54,
+    :WinOtherOrganizationSid                      , 55,
+    :WinBuiltinIncomingForestTrustBuildersSid     , 56,
+    :WinBuiltinPerfMonitoringUsersSid             , 57,
+    :WinBuiltinPerfLoggingUsersSid                , 58,
+    :WinBuiltinAuthorizationAccessSid             , 59,
+    :WinBuiltinTerminalServerLicenseServersSid    , 60,
+    :WinBuiltinDCOMUsersSid                       , 61,
+    :WinBuiltinIUsersSid                          , 62,
+    :WinIUserSid                                  , 63,
+    :WinBuiltinCryptoOperatorsSid                 , 64,
+    :WinUntrustedLabelSid                         , 65,
+    :WinLowLabelSid                               , 66,
+    :WinMediumLabelSid                            , 67,
+    :WinHighLabelSid                              , 68,
+    :WinSystemLabelSid                            , 69,
+    :WinWriteRestrictedCodeSid                    , 70,
+    :WinCreatorOwnerRightsSid                     , 71,
+    :WinCacheablePrincipalsGroupSid               , 72,
+    :WinNonCacheablePrincipalsGroupSid            , 73,
+    :WinEnterpriseReadonlyControllersSid          , 74,
+    :WinAccountReadonlyControllersSid             , 75,
+    :WinBuiltinEventLogReadersGroup               , 76,
+    :WinNewEnterpriseReadonlyControllersSid       , 77,
+    :WinBuiltinCertSvcDComAccessGroup             , 78,
+    :WinMediumPlusLabelSid                        , 79,
+    :WinLocalLogonSid                             , 80,
+    :WinConsoleLogonSid                           , 81,
+    :WinThisOrganizationCertificateSid            , 82,
+    :WinApplicationPackageAuthoritySid            , 83,
+    :WinBuiltinAnyPackageSid                      , 84,
+    :WinCapabilityInternetClientSid               , 85,
+    :WinCapabilityInternetClientServerSid         , 86,
+    :WinCapabilityPrivateNetworkClientServerSid   , 87,
+    :WinCapabilityPicturesLibrarySid              , 88,
+    :WinCapabilityVideosLibrarySid                , 89,
+    :WinCapabilityMusicLibrarySid                 , 90,
+    :WinCapabilityDocumentsLibrarySid             , 91,
+    :WinCapabilitySharedUserCertificatesSid       , 92,
+    :WinCapabilityEnterpriseAuthenticationSid     , 93,
+    :WinCapabilityRemovableStorageSid             , 94
+  )
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa446585(v=vs.85).aspx
+  # BOOL WINAPI CreateWellKnownSid(
+  #   _In_       WELL_KNOWN_SID_TYPE WellKnownSidType,
+  #   _In_opt_   PSID DomainSid,
+  #   _Out_opt_  PSID pSid,
+  #   _Inout_    DWORD *cbSid
+  # );
+  ffi_lib :advapi32
+  attach_function_private :CreateWellKnownSid,
+    [WELL_KNOWN_SID_TYPE, :pointer, :pointer, :lpdword], :win32_bool
+
+  # http://msdn.microsoft.com/en-us/library/windows/desktop/aa379151(v=vs.85).aspx
+  # BOOL WINAPI IsValidSid(
+  #   _In_  PSID pSid
+  # );
+  ffi_lib :advapi32
+  attach_function_private :IsValidSid,
+    [:pointer], :win32_bool
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/yaml.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/yaml.rb
new file mode 100644
index 0000000..2460808
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/yaml.rb
@@ -0,0 +1,24 @@
+require 'yaml'
+
+module Puppet::Util::Yaml
+  if defined?(::Psych::SyntaxError)
+    YamlLoadExceptions = [::StandardError, ::Psych::SyntaxError]
+  else
+    YamlLoadExceptions = [::StandardError]
+  end
+
+  class YamlLoadError < Puppet::Error; end
+
+  def self.load_file(filename, default_value = false)
+    yaml = YAML.load_file(filename)
+    yaml || default_value
+  rescue *YamlLoadExceptions => detail
+    raise YamlLoadError.new(detail.message, detail)
+  end
+
+  def self.dump(structure, filename)
+    Puppet::Util.replace_file(filename, 0660) do |fh|
+      YAML.dump(structure, fh)
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/zaml.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/zaml.rb
new file mode 100644
index 0000000..abd36a0
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/util/zaml.rb
@@ -0,0 +1,419 @@
+# encoding: UTF-8
+#
+# The above encoding line is a magic comment to set the default source encoding
+# of this file for the Ruby interpreter.  It must be on the first or second
+# line of the file if an interpreter is in use.  In Ruby 1.9 and later, the
+# source encoding determines the encoding of String and Regexp objects created
+# from this source file.  This explicit encoding is important becuase otherwise
+# Ruby will pick an encoding based on LANG or LC_CTYPE environment variables.
+# These may be different from site to site so it's important for us to
+# establish a consistent behavior.  For more information on M17n please see:
+# http://links.puppetlabs.com/understanding_m17n
+
+# ZAML -- A partial replacement for YAML, writen with speed and code clarity
+#         in mind.  ZAML fixes one YAML bug (loading Exceptions) and provides
+#         a replacement for YAML.dump unimaginatively called ZAML.dump,
+#         which is faster on all known cases and an order of magnitude faster
+#         with complex structures.
+#
+# http://github.com/hallettj/zaml
+#
+# ## License (from upstream)
+#
+# Copyright (c) 2008-2009 ZAML contributers
+#
+# This program is dual-licensed under the GNU General Public License
+# version 3 or later and under the Apache License, version 2.0.
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version; or under the terms of the Apache License,
+# Version 2.0.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License and the Apache License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see
+# <http://www.gnu.org/licenses/>.
+#
+# You may obtain a copy of the Apache License at
+# <https://www.apache.org/licenses/LICENSE-2.0.html>.
+
+require 'yaml'
+
+class ZAML
+  VERSION = "0.1.3"
+  #
+  # Class Methods
+  #
+  def self.dump(stuff, where='')
+    z = new
+    stuff.to_zaml(z)
+    where << z.to_s
+  end
+
+  #
+  # Instance Methods
+  #
+  def initialize
+    @result = []
+    @indent = nil
+    @structured_key_prefix = nil
+    @previously_emitted_object = {}
+    @next_free_label_number = 0
+    emit('--- ')
+  end
+
+  def nested(tail='  ')
+    old_indent = @indent
+    @indent = "#{@indent || "\n"}#{tail}"
+    yield
+    @indent = old_indent
+  end
+
+  class Label
+    #
+    # YAML only wants objects in the datastream once; if the same object
+    #    occurs more than once, we need to emit a label ("&idxxx") on the
+    #    first occurrence and then emit a back reference (*idxxx") on any
+    #    subsequent occurrence(s).
+    #
+    # To accomplish this we keeps a hash (by object id) of the labels of
+    #    the things we serialize as we begin to serialize them.  The labels
+    #    initially serialize as an empty string (since most objects are only
+    #    going to be be encountered once), but can be changed to a valid
+    #    (by assigning it a number) the first time it is subsequently used,
+    #    if it ever is.  Note that we need to do the label setup BEFORE we
+    #    start to serialize the object so that circular structures (in
+    #    which we will encounter a reference to the object as we serialize
+    #    it can be handled).
+    #
+    attr_accessor :this_label_number
+
+    def initialize(obj,indent)
+      @indent = indent
+      @this_label_number = nil
+      @obj = obj # prevent garbage collection so that object id isn't reused
+    end
+
+    def to_s
+      @this_label_number ? ('&id%03d%s' % [@this_label_number, @indent]) : ''
+    end
+
+    def reference
+      @reference         ||= '*id%03d' % @this_label_number
+    end
+  end
+
+  def label_for(obj)
+    @previously_emitted_object[obj.object_id]
+  end
+
+  def new_label_for(obj)
+    label = Label.new(obj,(Hash === obj || Array === obj) ? "#{@indent || "\n"}  " : ' ')
+    @previously_emitted_object[obj.object_id] = label
+    label
+  end
+
+  def first_time_only(obj)
+    if label = label_for(obj)
+      label.this_label_number ||= (@next_free_label_number += 1)
+      emit(label.reference)
+    else
+      with_structured_prefix(obj) do
+        emit(new_label_for(obj))
+        yield
+      end
+    end
+  end
+
+  def with_structured_prefix(obj)
+    if @structured_key_prefix
+      unless obj.is_a?(String) and obj !~ /\n/
+        emit(@structured_key_prefix)
+        @structured_key_prefix = nil
+      end
+    end
+    yield
+  end
+
+  def emit(s)
+    @result << s
+    @recent_nl = false unless s.kind_of?(Label)
+  end
+
+  def nl(s = nil)
+    emit(@indent || "\n") unless @recent_nl
+    emit(s) if s
+    @recent_nl = true
+  end
+
+  def to_s
+    @result.join
+  end
+
+  def prefix_structured_keys(x)
+    @structured_key_prefix = x
+    yield
+    nl unless @structured_key_prefix
+    @structured_key_prefix = nil
+  end
+end
+
+################################################################
+#
+#   Behavior for custom classes
+#
+################################################################
+
+class Object
+  # Users of this method need to do set math consistently with the
+  # result. Since #instance_variables returns strings in 1.8 and symbols
+  # on 1.9, standardize on symbols
+  if RUBY_VERSION[0,3] == '1.8'
+    def to_yaml_properties
+      instance_variables.map(&:to_sym)
+    end
+  else
+    def to_yaml_properties
+      instance_variables
+    end
+  end
+
+  def yaml_property_munge(x)
+    x
+  end
+
+  def zamlized_class_name(root)
+    cls = self.class
+    "!ruby/#{root.name.downcase}#{cls == root ? '' : ":#{cls.respond_to?(:name) ? cls.name : cls}"}"
+  end
+
+  def to_zaml(z)
+    z.first_time_only(self) {
+      z.emit(zamlized_class_name(Object))
+      z.nested {
+        instance_variables = to_yaml_properties
+        if instance_variables.empty?
+          z.emit(" {}")
+        else
+          instance_variables.each { |v|
+            z.nl
+            v.to_s[1..-1].to_zaml(z)       # Remove leading '@'
+            z.emit(': ')
+            yaml_property_munge(instance_variable_get(v)).to_zaml(z)
+          }
+        end
+      }
+    }
+  end
+end
+
+################################################################
+#
+#   Behavior for built-in classes
+#
+################################################################
+
+class NilClass
+  def to_zaml(z)
+    z.emit('')        # NOTE: blank turns into nil in YAML.load
+  end
+end
+
+class Symbol
+  def to_zaml(z)
+    z.emit("!ruby/sym ")
+    to_s.to_zaml(z)
+  end
+end
+
+class TrueClass
+  def to_zaml(z)
+    z.emit('true')
+  end
+end
+
+class FalseClass
+  def to_zaml(z)
+    z.emit('false')
+  end
+end
+
+class Numeric
+  def to_zaml(z)
+    z.emit(self)
+  end
+end
+
+class Regexp
+  def to_zaml(z)
+    z.first_time_only(self) { z.emit("#{zamlized_class_name(Regexp)} #{inspect}") }
+  end
+end
+
+class Exception
+  def to_zaml(z)
+    z.emit(zamlized_class_name(Exception))
+    z.nested {
+      z.nl("message: ")
+      message.to_zaml(z)
+    }
+  end
+  #
+  # Monkey patch for buggy Exception restore in YAML
+  #
+  #     This makes it work for now but is not very future-proof; if things
+  #     change we'll most likely want to remove this.  To mitigate the risks
+  #     as much as possible, we test for the bug before appling the patch.
+  #
+  if respond_to? :yaml_new and yaml_new(self, :tag, "message" => "blurp").message != "blurp"
+    def self.yaml_new( klass, tag, val )
+      o = YAML.object_maker( klass, {} ).exception(val.delete( 'message'))
+      val.each_pair do |k,v|
+        o.instance_variable_set("@#{k}", v)
+      end
+      o
+    end
+  end
+end
+
+class String
+  ZAML_ESCAPES = {
+    "\a" => "\\a", "\e" => "\\e", "\f" => "\\f", "\n" => "\\n",
+    "\r" => "\\r", "\t" => "\\t", "\v" => "\\v"
+  }
+
+  def to_zaml(z)
+    z.with_structured_prefix(self) do
+      case
+      when self == ''
+        z.emit('""')
+      when self.to_ascii8bit !~ /\A(?: # ?: non-capturing group (grouping with no back references)
+                 [\x09\x0A\x0D\x20-\x7E]            # ASCII
+               | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
+               |  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
+               | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
+               |  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
+               |  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
+               | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
+               |  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
+               )*\z/mnx
+        # Emit the binary tag, then recurse. Ruby splits BASE64 output at the 60
+        # character mark when packing strings, and we can wind up a multi-line
+        # string here.  We could reimplement the multi-line string logic,
+        # but why would we - this does just as well for producing solid output.
+        z.emit("!binary ")
+        [self].pack("m*").to_zaml(z)
+
+      # Only legal UTF-8 characters can make it this far, so we are safe
+      # against emitting something dubious. That means we don't need to mess
+      # about, just emit them directly. --daniel 2012-07-14
+      when ((self =~ /\A[a-zA-Z\/][-\[\]_\/.a-zA-Z0-9]*\z/) and
+          (self !~ /^(?:true|false|yes|no|on|null|off)$/i))
+        # simple string literal, safe to emit unquoted.
+        z.emit(self)
+      when (self =~ /\n/ and self !~ /\A\s/ and self !~ /\s\z/)
+        # embedded newline, split line-wise in quoted string block form.
+        if self[-1..-1] == "\n" then z.emit('|+') else z.emit('|-') end
+        z.nested { split("\n",-1).each { |line| z.nl; z.emit(line) } }
+      else
+        # ...though we still have to escape unsafe characters.
+        escaped = gsub(/[\\"\x00-\x1F]/) do |c|
+          ZAML_ESCAPES[c] || "\\x#{c[0].ord.to_s(16)}"
+        end
+        z.emit("\"#{escaped}\"")
+      end
+    end
+  end
+
+  # Return a guranteed ASCII-8BIT encoding for Ruby 1.9 This is a helper
+  # method for other methods that perform regular expressions against byte
+  # sequences deliberately rather than dealing with characters.
+  # The method may or may not return a new instance.
+  if String.method_defined?(:encoding)
+    ASCII_ENCODING = Encoding.find("ASCII-8BIT")
+    def to_ascii8bit
+      if self.encoding == ASCII_ENCODING
+        self
+      else
+        self.dup.force_encoding(ASCII_ENCODING)
+      end
+    end
+  else
+    def to_ascii8bit
+      self
+    end
+  end
+end
+
+class Hash
+  def to_zaml(z)
+    z.first_time_only(self) {
+      z.nested {
+        if empty?
+          z.emit('{}')
+        else
+          each_pair { |k, v|
+            z.nl
+            z.prefix_structured_keys('? ') { k.to_zaml(z) }
+            z.emit(': ')
+            v.to_zaml(z)
+          }
+        end
+      }
+    }
+  end
+end
+
+class Array
+  def to_zaml(z)
+    z.first_time_only(self) {
+      z.nested {
+        if empty?
+          z.emit('[]')
+        else
+          each { |v| z.nl('- '); v.to_zaml(z) }
+        end
+      }
+    }
+  end
+end
+
+class Time
+  def to_zaml(z)
+    # 2008-12-06 10:06:51.373758 -07:00
+    ms = ("%0.6f" % (usec * 1e-6))[2..-1]
+    offset = "%+0.2i:%0.2i" % [utc_offset / 3600.0, (utc_offset / 60) % 60]
+    z.emit(self.strftime("%Y-%m-%d %H:%M:%S.#{ms} #{offset}"))
+  end
+end
+
+class Date
+  def to_zaml(z)
+    z.emit(strftime('%Y-%m-%d'))
+  end
+end
+
+class Range
+  def to_zaml(z)
+    z.first_time_only(self) {
+      z.emit(zamlized_class_name(Range))
+      z.nested {
+        z.nl
+        z.emit('begin: ')
+        z.emit(first)
+        z.nl
+        z.emit('end: ')
+        z.emit(last)
+        z.nl
+        z.emit('excl: ')
+        z.emit(exclude_end?)
+      }
+    }
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor.rb
new file mode 100644
index 0000000..7c6be4e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor.rb
@@ -0,0 +1,57 @@
+module Puppet
+  # Simple module to manage vendored code.
+  #
+  # To vendor a library:
+  #
+  # * Download its whole git repo or untar into `lib/puppet/vendor/<libname>`
+  # * Create a vendor/puppetload_libraryname.rb file to add its libdir into the $:.
+  #   (Look at existing load_xxx files, they should all follow the same pattern).
+  # * Add a <libname>/PUPPET_README.md file describing what the library is for
+  #   and where it comes from.
+  # * To load the vendored lib upfront, add a `require '<vendorlib>'`line to
+  #   `vendor/require_vendored.rb`.
+  # * To load the vendored lib on demand, add a comment to `vendor/require_vendored.rb`
+  #    to make it clear it should not be loaded upfront.
+  #
+  # At runtime, the #load_vendored method should be called. It will ensure
+  # all vendored libraries are added to the global `$:` path, and
+  # will then call execute the up-front loading specified in `vendor/require_vendored.rb`.
+  #
+  # The intention is to not change vendored libraries and to eventually
+  # make adding them in optional so that distros can simply adjust their
+  # packaging to exclude this directory and the various load_xxx.rb scripts
+  # if they wish to install these gems as native packages.
+  #
+  class Vendor
+    class << self
+      # @api private
+      def vendor_dir
+        File.join([File.dirname(File.expand_path(__FILE__)), "vendor"])
+      end
+
+      # @api private
+      def load_entry(entry)
+        Puppet.debug("Loading vendored #{$1}")
+        load "#{vendor_dir}/#{entry}"
+      end
+
+      # @api private
+      def require_libs
+        require 'puppet/vendor/require_vendored'
+      end
+
+      # Configures the path for all vendored libraries and loads required libraries.
+      # (This is the entry point for loading vendored libraries).
+      #
+      def load_vendored
+        Dir.entries(vendor_dir).each do |entry|
+          if entry.match(/load_(\w+?)\.rb$/)
+            load_entry entry
+          end
+        end
+
+        require_libs
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/load_pathspec.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/load_pathspec.rb
new file mode 100644
index 0000000..afdbc22
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/load_pathspec.rb
@@ -0,0 +1 @@
+$: << File.join([File.dirname(__FILE__), "pathspec/lib"])
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/load_rgen.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/load_rgen.rb
new file mode 100644
index 0000000..ba1f1c5
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/load_rgen.rb
@@ -0,0 +1 @@
+$: << File.join([File.dirname(__FILE__), "rgen/lib"])
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/load_safe_yaml.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/load_safe_yaml.rb
new file mode 100644
index 0000000..07aa0a6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/load_safe_yaml.rb
@@ -0,0 +1 @@
+$: << File.join([File.dirname(__FILE__), "safe_yaml/lib"])
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/load_semantic.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/load_semantic.rb
new file mode 100644
index 0000000..7818c0a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/load_semantic.rb
@@ -0,0 +1 @@
+$: << File.join([File.dirname(__FILE__), "semantic/lib"])
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/CHANGELOG.md b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/CHANGELOG.md
new file mode 100644
index 0000000..e4fe66d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/CHANGELOG.md
@@ -0,0 +1,2 @@
+0.0.2: Misc. Windows/regex fixes.
+0.0.1: Initial version.
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/LICENSE b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/LICENSE
new file mode 100644
index 0000000..5c304d1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/LICENSE
@@ -0,0 +1,201 @@
+Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/PUPPET_README.md b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/PUPPET_README.md
new file mode 100644
index 0000000..e7cedde
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/PUPPET_README.md
@@ -0,0 +1,6 @@
+Pathspec-ruby - Gitignore parsing in Ruby
+=============================================
+
+Pathspec-ruby version 0.0.2
+
+Copied from https://github.com/highb/pathspec-ruby/releases/tag/0.0.2 
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/README.md b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/README.md
new file mode 100644
index 0000000..ecbd64d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/README.md
@@ -0,0 +1,53 @@
+pathspec-ruby
+=============
+
+Match Path Specifications, such as .gitignore, in Ruby!
+
+Follows .gitignore syntax defined on [gitscm](http://git-scm.com/docs/gitignore)
+
+.gitignore functionality ported from [Python pathspec](https://pypi.python.org/pypi/pathspec/0.2.2) by [@cpburnz](https://github.com/cpburnz/python-path-specification)
+
+[Travis Status](https://travis-ci.org/highb/pathspec-ruby) ![Travis CI Status](https://travis-ci.org/highb/pathspec-ruby.svg?branch=master)
+
+## Build/Install from Rubygems
+```shell
+gem install pathspec
+```
+
+## Usage
+```ruby
+require 'pathspec'
+
+# Create a .gitignore-style Pathspec by giving it newline separated gitignore
+# lines, an array of gitignore lines, or any other enumable object that will
+# give strings matching the .gitignore-style (File, etc.)
+gitignore = Pathspec.new File.read('.gitignore', 'r')
+
+# Our .gitignore in this example contains:
+# !**/important.txt
+# abc/**
+
+# true, matches "abc/**"
+gitignore.match 'abc/def.rb'
+
+# false, because it has been negated using the line "!**/important.txt"
+gitignore.match 'abc/important.txt'
+
+# Give a path somewhere in the filesystem, and the Pathspec will return all
+# matching files underneath.
+# Returns ['/src/repo/abc/', '/src/repo/abc/123']
+gitignore.match_tree '/src/repo'
+
+# Give an enumerable of paths, and Pathspec will return the ones that match.
+# Returns ['/abc/123', '/abc/']
+gitignore.match_paths ['/abc/123', '/abc/important.txt', '/abc/']
+```
+
+## Building/Installing from Source
+```shell
+git clone git@github.com:highb/pathspec-ruby.git
+cd pathspec-ruby && bash ./build_from_source.sh
+```
+
+## Contributing
+Pull requests, bug reports, and feature requests welcome! :smile: I've tried to write exhaustive tests but who knows what cases I've missed.
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/lib/pathspec.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/lib/pathspec.rb
new file mode 100644
index 0000000..9d9a928
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/lib/pathspec.rb
@@ -0,0 +1,121 @@
+require 'pathspec/gitignorespec'
+require 'pathspec/regexspec'
+require 'find'
+require 'pathname'
+
+class PathSpec
+  attr_reader :specs
+
+  def initialize(lines=nil, type=:git)
+    @specs = []
+
+    if lines
+      add(lines, type)
+    end
+
+    self
+  end
+
+  # Check if a path matches the pathspecs described
+  # Returns true if there are matches and none are excluded
+  # Returns false if there aren't matches or none are included
+  def match(path)
+    matches = specs_matching(path.to_s)
+    !matches.empty? && matches.all? {|m| m.inclusive?}
+  end
+
+  def specs_matching(path)
+    @specs.select do |spec|
+      if spec.match(path)
+        spec
+      end
+    end
+  end
+
+  # Check if any files in a given directory or subdirectories match the specs
+  # Returns matched paths or nil if no paths matched
+  def match_tree(root)
+    rootpath = Pathname.new(root)
+    matching = []
+
+    Find.find(root) do |path|
+      relpath = Pathname.new(path).relative_path_from(rootpath).to_s
+      relpath += '/' if File.directory? path
+      if match(relpath)
+        matching << path
+      end
+    end
+
+    matching
+  end
+
+  def match_path(path, root='/')
+    rootpath = Pathname.new(drive_letter_to_path(root))
+    relpath = Pathname.new(drive_letter_to_path(path)).relative_path_from(rootpath).to_s
+    relpath = relpath + '/' if path[-1].chr == '/'
+
+    match(relpath)
+  end
+
+  def match_paths(paths, root='/')
+    matching = []
+
+    paths.each do |path|
+      if match_path(path, root)
+        matching << path
+      end
+    end
+
+    matching
+  end
+
+  def drive_letter_to_path(path)
+    path.gsub(/^([a-zA-z]):\//, '/\1/')
+  end
+
+  # Generate specs from a filename, such as a .gitignore
+  def self.from_filename(filename, type=:git)
+    self.from_lines(File.open(filename, 'r'))
+  end
+
+  def self.from_lines(lines, type=:git)
+    self.new lines, type
+  end
+
+  # Generate specs from lines of text
+  def add(obj, type=:git)
+    spec_class = spec_type(type)
+
+    if obj.respond_to?(:each_line)
+      obj.each_line do |l|
+        spec = spec_class.new(l.rstrip)
+
+        if !spec.regex.nil? && !spec.inclusive?.nil?
+          @specs << spec
+        end
+      end
+    elsif obj.respond_to?(:each)
+      obj.each do |l|
+        add(l, type)
+      end
+    else
+      raise 'Cannot make Pathspec from non-string/non-enumerable object.'
+    end
+
+    self
+  end
+
+  def empty?
+    @specs.empty?
+  end
+
+  def spec_type(type)
+    if type == :git
+      GitIgnoreSpec
+    elsif type == :regex
+      RegexSpec
+    else
+      raise "Unknown spec type #{type}"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/lib/pathspec/gitignorespec.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/lib/pathspec/gitignorespec.rb
new file mode 100644
index 0000000..f7a94b3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/lib/pathspec/gitignorespec.rb
@@ -0,0 +1,275 @@
+# encoding: utf-8
+
+require 'pathspec/regexspec'
+
+class GitIgnoreSpec < RegexSpec
+  attr_reader :regex
+
+  def initialize(pattern)
+    pattern = pattern.strip unless pattern.nil?
+
+    # A pattern starting with a hash ('#') serves as a comment
+    # (neither includes nor excludes files). Escape the hash with a
+    # back-slash to match a literal hash (i.e., '\#').
+    if pattern.start_with?('#')
+      @regex = nil
+      @inclusive = nil
+
+    # A blank pattern is a null-operation (neither includes nor
+    # excludes files).
+    elsif pattern.empty?
+      @regex = nil
+      @inclusive = nil
+
+    # Patterns containing three or more consecutive stars are invalid and
+    # will be ignored.
+    elsif pattern =~ /\*\*\*+/
+      @regex = nil
+      @inclusive = nil
+
+    # We have a valid pattern!
+    else
+      # A pattern starting with an exclamation mark ('!') negates the
+      # pattern (exclude instead of include). Escape the exclamation
+      # mark with a back-slash to match a literal exclamation mark
+      # (i.e., '\!').
+      if pattern.start_with?('!')
+        @inclusive = false
+        # Remove leading exclamation mark.
+        pattern = pattern[1..-1]
+      else
+        @inclusive = true
+      end
+
+      # Remove leading back-slash escape for escaped hash ('#') or
+      # exclamation mark ('!').
+      if pattern.start_with?('\\')
+        pattern = pattern[1..-1]
+      end
+
+      # Split pattern into segments. -1 to allow trailing slashes.
+      pattern_segs = pattern.split('/', -1)
+
+      # Normalize pattern to make processing easier.
+
+      # A pattern beginning with a slash ('/') will only match paths
+      # directly on the root directory instead of any descendant
+      # paths. So, remove empty first segment to make pattern relative
+      # to root.
+      if pattern_segs[0].empty?
+        pattern_segs.shift
+      else
+        # A pattern without a beginning slash ('/') will match any
+        # descendant path. This is equivilent to "**/{pattern}". So,
+        # prepend with double-asterisks to make pattern relative to
+        # root.
+        if pattern_segs.length == 1 && pattern_segs[0] != '**'
+          pattern_segs.insert(0, '**')
+        end
+      end
+
+      # A pattern ending with a slash ('/') will match all descendant
+      # paths of if it is a directory but not if it is a regular file.
+      # This is equivilent to "{pattern}/**". So, set last segment to
+      # double asterisks to include all descendants.
+      if pattern_segs[-1].empty?
+        pattern_segs[-1] = '**'
+      end
+
+      # Handle platforms with backslash separated paths
+      if File::SEPARATOR == '\\'
+        path_sep = '\\\\'
+      else
+        path_sep = '/'
+      end
+
+
+      # Build regular expression from pattern.
+      regex = '^'
+      need_slash = false
+      regex_end = pattern_segs.size - 1
+      pattern_segs.each_index do |i|
+        seg = pattern_segs[i]
+
+        if seg == '**'
+          # A pattern consisting solely of double-asterisks ('**')
+          # will match every path.
+          if i == 0 && i == regex_end
+            regex.concat('.+')
+
+          # A normalized pattern beginning with double-asterisks
+          # ('**') will match any leading path segments.
+          elsif i == 0
+            regex.concat("(?:.+#{path_sep})?")
+            need_slash = false
+
+          # A normalized pattern ending with double-asterisks ('**')
+          # will match any trailing path segments.
+          elsif i == regex_end
+            regex.concat("#{path_sep}.*")
+
+          # A pattern with inner double-asterisks ('**') will match
+          # multiple (or zero) inner path segments.
+          else
+            regex.concat("(?:#{path_sep}.+)?")
+            need_slash = true
+          end
+
+        # Match single path segment.
+        elsif seg == '*'
+          if need_slash
+            regex.concat(path_sep)
+          end
+
+          regex.concat("[^#{path_sep}]+")
+          need_slash = true
+
+        else
+          # Match segment glob pattern.
+          if need_slash
+            regex.concat(path_sep)
+          end
+
+          regex.concat(translate_segment_glob(seg))
+          need_slash = true
+        end
+      end
+
+      regex.concat('$')
+      super(regex)
+    end
+  end
+
+  def match(path)
+    super(path)
+  end
+
+  def translate_segment_glob(pattern)
+    """
+    Translates the glob pattern to a regular expression. This is used in
+    the constructor to translate a path segment glob pattern to its
+    corresponding regular expression.
+
+    *pattern* (``str``) is the glob pattern.
+
+    Returns the regular expression (``str``).
+    """
+    # NOTE: This is derived from `fnmatch.translate()` and is similar to
+    # the POSIX function `fnmatch()` with the `FNM_PATHNAME` flag set.
+
+    escape = false
+    regex = ''
+    i = 0
+
+    while i < pattern.size
+      # Get next character.
+      char = pattern[i].chr
+      i += 1
+
+      # Escape the character.
+      if escape
+        escape = false
+        regex += Regexp.escape(char)
+
+      # Escape character, escape next character.
+      elsif char == '\\'
+        escape = true
+
+      # Multi-character wildcard. Match any string (except slashes),
+      # including an empty string.
+      elsif char == '*'
+        regex += '[^/]*'
+
+      # Single-character wildcard. Match any single character (except
+      # a slash).
+      elsif char == '?'
+        regex += '[^/]'
+
+      # Braket expression wildcard. Except for the beginning
+      # exclamation mark, the whole braket expression can be used
+      # directly as regex but we have to find where the expression
+      # ends.
+      # - "[][!]" matchs ']', '[' and '!'.
+      # - "[]-]" matchs ']' and '-'.
+      # - "[!]a-]" matchs any character except ']', 'a' and '-'.
+      elsif char == '['
+        j = i
+        # Pass brack expression negation.
+        if j < pattern.size && pattern[j].chr == '!'
+          j += 1
+        end
+
+        # Pass first closing braket if it is at the beginning of the
+        # expression.
+        if j < pattern.size && pattern[j].chr == ']'
+          j += 1
+        end
+
+        # Find closing braket. Stop once we reach the end or find it.
+        while j < pattern.size && pattern[j].chr != ']'
+          j += 1
+        end
+
+
+        if j < pattern.size
+          expr = '['
+
+          # Braket expression needs to be negated.
+          if pattern[i].chr == '!'
+            expr += '^'
+            i += 1
+
+          # POSIX declares that the regex braket expression negation
+          # "[^...]" is undefined in a glob pattern. Python's
+          # `fnmatch.translate()` escapes the caret ('^') as a
+          # literal. To maintain consistency with undefined behavior,
+          # I am escaping the '^' as well.
+          elsif pattern[i].chr == '^'
+            expr += '\\^'
+            i += 1
+          end
+
+          # Escape brackets contained within pattern
+          if pattern[i].chr == ']' && i != j
+            expr += '\]'
+            i += 1
+          end
+
+
+          # Build regex braket expression. Escape slashes so they are
+          # treated as literal slashes by regex as defined by POSIX.
+          expr += pattern[i..j].sub('\\', '\\\\')
+
+          # Add regex braket expression to regex result.
+          regex += expr
+
+          # Found end of braket expression. Increment j to be one past
+          # the closing braket:
+          #
+          #  [...]
+          #   ^   ^
+          #   i   j
+          #
+          j += 1
+          # Set i to one past the closing braket.
+          i = j
+
+        # Failed to find closing braket, treat opening braket as a
+        # braket literal instead of as an expression.
+        else
+          regex += '\['
+        end
+
+      # Regular character, escape it for regex.
+      else
+        regex << Regexp.escape(char)
+      end
+    end
+
+    regex
+  end
+
+  def inclusive?
+    @inclusive
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/lib/pathspec/regexspec.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/lib/pathspec/regexspec.rb
new file mode 100644
index 0000000..af043f4
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/lib/pathspec/regexspec.rb
@@ -0,0 +1,17 @@
+require 'pathspec/spec'
+
+class RegexSpec < Spec
+  def initialize(regex)
+    @regex = Regexp.compile regex
+
+    super
+  end
+
+  def inclusive?
+    true
+  end
+
+  def match(path)
+    @regex.match(path) if @regex
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/lib/pathspec/spec.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/lib/pathspec/spec.rb
new file mode 100644
index 0000000..756588b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/pathspec/lib/pathspec/spec.rb
@@ -0,0 +1,14 @@
+class Spec
+  attr_reader :regex
+
+  def initialize(*_)
+  end
+
+  def match(files)
+    raise "Unimplemented"
+  end
+
+  def inclusive?
+    true
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/require_vendored.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/require_vendored.rb
new file mode 100644
index 0000000..d9f38fa
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/require_vendored.rb
@@ -0,0 +1,9 @@
+# This adds upfront requirements on vendored code found under lib/vendor/x
+# Add one requirement per vendored package (or a comment if it is loaded on demand).
+
+require 'safe_yaml'
+require 'puppet/vendor/safe_yaml_patches'
+
+# The vendored library 'semantic' is loaded on demand.
+# The vendored library 'rgen' is loaded on demand.
+# The vendored library 'pathspec' is loaded on demand.
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/safe_yaml_patches.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/safe_yaml_patches.rb
new file mode 100644
index 0000000..8c4763e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/safe_yaml_patches.rb
@@ -0,0 +1,9 @@
+module SafeYAML
+  class Parse
+    class Date
+      def self.value(value)
+        Time.parse(value)
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/Gemfile b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/Gemfile
new file mode 100644
index 0000000..b4d232e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/Gemfile
@@ -0,0 +1,20 @@
+source "https://rubygems.org"
+
+group :development do
+  gem 'rake'
+  gem 'rubygems-tasks'
+end
+
+group :test do
+  gem 'rspec'
+end
+
+group :metrics do
+  gem 'cane',      :platform => [ :mri_19, :mri_20, :mri_21 ]
+  gem 'simplecov', :platform => [ :mri_19, :mri_20, :mri_21 ]
+end
+
+group :doc do
+  gem 'yard', '~> 0.8', :platform => [ :mri_19, :mri_20, :mri_21 ]
+  gem 'redcarpet',      :platform => [ :mri_19, :mri_20, :mri_21 ]
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/PUPPET_README.md b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/PUPPET_README.md
new file mode 100644
index 0000000..dc9d4ae
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/PUPPET_README.md
@@ -0,0 +1,6 @@
+Semantic
+========
+
+Semantic 0.0.1
+
+Copied from https://github.com/puppetlabs/semantic/tree/6d17d5283e0868cfc3d74d1e9d37b572e1739b6e
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/Rakefile b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/Rakefile
new file mode 100644
index 0000000..e6a0e2b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/Rakefile
@@ -0,0 +1,69 @@
+# RSpec tasks
+begin
+  require 'rspec/core/rake_task'
+
+  # Create the 'spec' task
+  RSpec::Core::RakeTask.new(:spec) do |task|
+    task.rspec_opts = '--color'
+  end
+
+  namespace :spec do
+    desc "Run the test suite and generate coverage metrics"
+    task :coverage => [ :simplecov, :spec ]
+
+    # Add test coverage to the 'spec' task.
+    task :simplecov do
+      ENV['COVERAGE'] = '1'
+    end
+  end
+
+  task :default => :spec
+rescue LoadError
+  warn "[Warning]: Could not load `rspec`."
+end
+
+# YARD tasks
+begin
+  require 'yard'
+  require 'yard/rake/yardoc_task'
+
+  YARD::Rake::YardocTask.new(:doc) do |yardoc|
+    yardoc.files = [ 'lib/**/*.rb', '-', '**/*.md' ]
+  end
+rescue LoadError
+  warn "[Warning]: Could not load `yard`."
+end
+
+# Cane tasks
+begin
+  require 'cane/rake_task'
+
+  Cane::RakeTask.new(:cane) do |cane|
+    cane.add_threshold 'coverage/.last_run.json', :>=, 100
+    cane.abc_max = 15
+  end
+
+  Rake::Task['cane'].prerequisites << Rake::Task['spec:coverage']
+  Rake::Task[:default].clear_prerequisites
+  task :default => :cane
+rescue LoadError
+  warn "[Warning]: Could not load `cane`."
+end
+
+# Gem tasks
+begin
+  require 'rubygems/tasks'
+
+  task :gem => 'gem:build'
+  task :validate => [ 'cane', 'doc', 'gem:validate' ]
+
+  namespace :gem do
+    Gem::Tasks.new(
+      :tag => { :format => 'v%s' },
+      :sign => { :checksum => true, :pgp => true },
+      :build => { :tar => true }
+    )
+  end
+rescue LoadError
+  warn "[Warning]: Could not load `rubygems/tasks`."
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic.rb
new file mode 100644
index 0000000..fce2eed
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic.rb
@@ -0,0 +1,7 @@
+module Semantic
+  autoload :Version, 'semantic/version'
+  autoload :VersionRange, 'semantic/version_range'
+  autoload :Dependency, 'semantic/dependency'
+
+  VERSION = '0.0.1'
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/dependency.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/dependency.rb
new file mode 100644
index 0000000..6e66de7
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/dependency.rb
@@ -0,0 +1,181 @@
+require 'semantic'
+
+module Semantic
+  module Dependency
+    extend self
+
+    autoload :Graph,         'semantic/dependency/graph'
+    autoload :GraphNode,     'semantic/dependency/graph_node'
+    autoload :ModuleRelease, 'semantic/dependency/module_release'
+    autoload :Source,        'semantic/dependency/source'
+
+    autoload :UnsatisfiableGraph, 'semantic/dependency/unsatisfiable_graph'
+
+    # @!group Sources
+
+    # @return [Array<Source>] a frozen copy of the {Source} list
+    def sources
+      (@sources ||= []).dup.freeze
+    end
+
+    # Appends a new {Source} to the current list.
+    # @param source [Source] the {Source} to add
+    # @return [void]
+    def add_source(source)
+      sources
+      @sources << source
+      nil
+    end
+
+    # Clears the current list of {Source}s.
+    # @return [void]
+    def clear_sources
+      sources
+      @sources.clear
+      nil
+    end
+
+    # @!endgroup
+
+    # Fetches a graph of modules and their dependencies from the currently
+    # configured list of {Source}s.
+    #
+    # @todo Return a specialized "Graph" object.
+    # @todo Allow for external constraints to be added to the graph.
+    # @see #sources
+    # @see #add_source
+    # @see #clear_sources
+    #
+    # @param modules [{ String => String }]
+    # @return [Graph] the root of a dependency graph
+    def query(modules)
+      constraints = Hash[modules.map { |k, v| [ k, VersionRange.parse(v) ] }]
+
+      graph = Graph.new(constraints)
+      fetch_dependencies(graph)
+      return graph
+    end
+
+    # Given a graph result from {#query}, this method will resolve the graph of
+    # dependencies, if possible, into a flat list of the best suited modules. If
+    # the dependency graph does not have a suitable resolution, this method will
+    # raise an exception to that effect.
+    #
+    # @param graph [Graph] the root of a dependency graph
+    # @return [Array<ModuleRelease>] the list of releases to act on
+    def resolve(graph)
+      catch :next do
+        return walk(graph, graph.dependencies.dup)
+      end
+      raise UnsatisfiableGraph.new(graph)
+    end
+
+    # Fetches all available releases for the given module name.
+    #
+    # @param name [String] the module name to find releases for
+    # @return [Array<ModuleRelease>] the available releases
+    def fetch_releases(name)
+      releases = {}
+
+      sources.each do |source|
+        source.fetch(name).each do |dependency|
+          releases[dependency.version] ||= dependency
+        end
+      end
+
+      return releases.values
+    end
+
+    private
+
+    # Iterates over a changing set of dependencies in search of the best
+    # solution available. Fitness is specified as meeting all the constraints
+    # placed on it, being {ModuleRelease#satisfied? satisfied}, and having the
+    # greatest version number (with stability being preferred over prereleases).
+    #
+    # @todo Traversal order is not presently guaranteed.
+    #
+    # @param graph [Graph] the root of a dependency graph
+    # @param dependencies [{ String => Array<ModuleRelease> }] the dependencies
+    # @param considering [Array<GraphNode>] the set of releases being tested
+    # @return [Array<GraphNode>] the list of releases to use, if successful
+    def walk(graph, dependencies, *considering)
+      return considering if dependencies.empty?
+
+      # Selecting a dependency from the collection...
+      name = dependencies.keys.sort.first
+      deps = dependencies.delete(name)
+
+      # ... (and stepping over it if we've seen it before) ...
+      unless (deps & considering).empty?
+        return walk(graph, dependencies, *considering)
+      end
+
+      # ... we'll iterate through the list of possible versions in order.
+      preferred_releases(deps).reverse_each do |dep|
+
+        # We should skip any releases that violate any module's constraints.
+        unless [graph, *considering].all? { |x| x.satisfies_constraints?(dep) }
+          next
+        end
+
+        # We should skip over any releases that violate graph-level constraints.
+        potential_solution = considering.dup << dep
+        unless graph.satisfies_graph? potential_solution
+          next
+        end
+
+        catch :next do
+          # After adding any new dependencies and imposing our own constraints
+          # on existing dependencies, we'll mark ourselves as "under
+          # consideration" and recurse.
+          merged = dependencies.merge(dep.dependencies) { |_,a,b| a & b }
+
+          # If all subsequent dependencies resolved well, the recursive call
+          # will return a completed dependency list. If there were problems
+          # resolving our dependencies, we'll catch `:next`, which will cause
+          # us to move to the next possibility.
+          return walk(graph, merged, *potential_solution)
+        end
+      end
+
+      # Once we've exhausted all of our possible versions, we know that our
+      # last choice was unusable, so we'll unwind the stack and make a new
+      # choice.
+      throw :next
+    end
+
+    # Given a {ModuleRelease}, this method will iterate through the current
+    # list of {Source}s to find the complete list of versions available for its
+    # dependencies.
+    #
+    # @param node [GraphNode] the node to fetch details for
+    # @return [void]
+    def fetch_dependencies(node, cache = {})
+      node.dependency_names.each do |name|
+        unless cache.key?(name)
+          cache[name] = fetch_releases(name)
+          cache[name].each { |dep| fetch_dependencies(dep, cache) }
+        end
+
+        node << cache[name]
+      end
+    end
+
+    # Given a list of potential releases, this method returns the most suitable
+    # releases for exploration. Only {ModuleRelease#satisfied? satisfied}
+    # releases are considered, and releases with stable versions are preferred.
+    #
+    # @param releases [Array<ModuleRelease>] a list of potential releases
+    # @return [Array<ModuleRelease>] releases open for consideration
+    def preferred_releases(releases)
+      satisfied = releases.select { |x| x.satisfied? }
+
+      if satisfied.any? { |x| x.version.stable? }
+        return satisfied.select { |x| x.version.stable? }
+      else
+        return satisfied
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/dependency/graph.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/dependency/graph.rb
new file mode 100644
index 0000000..8326ed1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/dependency/graph.rb
@@ -0,0 +1,60 @@
+require 'semantic/dependency'
+
+module Semantic
+  module Dependency
+    class Graph
+      include GraphNode
+
+      attr_reader :modules
+
+      # Create a new instance of a dependency graph.
+      #
+      # @param modules [{String => VersionRange}] the required module
+      #        set and their version constraints
+      def initialize(modules = {})
+        @modules = modules.keys
+
+        modules.each do |name, range|
+          add_constraint('initialize', name, range.to_s) do |node|
+            range === node.version
+          end
+
+          add_dependency(name)
+        end
+      end
+
+      # Constrains graph solutions based on the given block.  Graph constraints
+      # are used to describe fundamental truths about the tooling or module
+      # system (e.g.: module names contain a namespace component which is
+      # dropped during install, so module names must be unique excluding the
+      # namespace).
+      #
+      # @example Ensuring a single source for all modules
+      #     @graph.add_constraint('installed', mod.name) do |nodes|
+      #       nodes.count { |node| node.source } == 1
+      #     end
+      #
+      # @see #considering_solution?
+      #
+      # @param source [String, Symbol] a name describing the source of the
+      #               constraint
+      # @yieldparam nodes [Array<GraphNode>] the nodes to test the constraint
+      #             against
+      # @yieldreturn [Boolean] whether the node passed the constraint
+      # @return [void]
+      def add_graph_constraint(source, &block)
+        constraints[:graph] << [ source, block ]
+      end
+
+      # Checks the proposed solution (or partial solution) against the graph's
+      # constraints.
+      #
+      # @see #add_graph_constraint
+      #
+      # @return [Boolean] true if none of the graph constraints are violated
+      def satisfies_graph?(solution)
+        constraints[:graph].all? { |_, check| check[solution] }
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/dependency/graph_node.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/dependency/graph_node.rb
new file mode 100644
index 0000000..ad42306
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/dependency/graph_node.rb
@@ -0,0 +1,117 @@
+require 'semantic/dependency'
+require 'set'
+
+module Semantic
+  module Dependency
+    module GraphNode
+      include Comparable
+
+      def name
+      end
+
+      # Determines whether the modules dependencies are satisfied by the known
+      # releases.
+      #
+      # @return [Boolean] true if all dependencies are satisfied
+      def satisfied?
+        dependencies.none? { |_, v| v.empty? }
+      end
+
+      def children
+        @_children ||= {}
+      end
+
+      def populate_children(nodes)
+        if children.empty?
+          nodes = nodes.select { |node| satisfies_dependency?(node) }
+          nodes.each do |node|
+            children[node.name] = node
+            node.populate_children(nodes)
+          end
+          self.freeze
+        end
+      end
+
+      # @api internal
+      # @return [{ String => SortedSet<GraphNode> }] the satisfactory
+      #         dependency nodes
+      def dependencies
+        @_dependencies ||= Hash.new { |h, k| h[k] = SortedSet.new }
+      end
+
+      # Adds the given dependency name to the list of dependencies.
+      #
+      # @param name [String] the dependency name
+      # @return [void]
+      def add_dependency(name)
+        dependencies[name]
+      end
+
+      # @return [Array<String>] the list of dependency names
+      def dependency_names
+        dependencies.keys
+      end
+
+      def constraints
+        @_constraints ||= Hash.new { |h, k| h[k] = [] }
+      end
+
+      def constraints_for(name)
+        return [] unless constraints.has_key?(name)
+
+        constraints[name].map do |constraint|
+          {
+            :source      => constraint[0],
+            :description => constraint[1],
+            :test        => constraint[2],
+          }
+        end
+      end
+
+      # Constrains the named module to suitable releases, as determined by the
+      # given block.
+      #
+      # @example Version-locking currently installed modules
+      #     installed_modules.each do |m|
+      #       @graph.add_constraint('installed', m.name, m.version) do |node|
+      #         m.version == node.version
+      #       end
+      #     end
+      #
+      # @param source [String, Symbol] a name describing the source of the
+      #               constraint
+      # @param mod [String] the name of the module
+      # @param desc [String] a description of the enforced constraint
+      # @yieldparam node [GraphNode] the node to test the constraint against
+      # @yieldreturn [Boolean] whether the node passed the constraint
+      # @return [void]
+      def add_constraint(source, mod, desc, &block)
+        constraints["#{mod}"] << [ source, desc, block ]
+      end
+
+      def satisfies_dependency?(node)
+        dependencies.key?(node.name) && satisfies_constraints?(node)
+      end
+
+      # @param release [ModuleRelease] the release to test
+      def satisfies_constraints?(release)
+        constraints_for(release.name).all? { |x| x[:test].call(release) }
+      end
+
+      def << (nodes)
+        Array(nodes).each do |node|
+          next unless dependencies.key?(node.name)
+          if satisfies_dependency?(node)
+            dependencies[node.name] << node
+          end
+        end
+
+        return self
+      end
+
+      def <=>(other)
+        name <=> other.name
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/dependency/module_release.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/dependency/module_release.rb
new file mode 100644
index 0000000..df4ca4d
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/dependency/module_release.rb
@@ -0,0 +1,46 @@
+require 'semantic/dependency'
+
+module Semantic
+  module Dependency
+    class ModuleRelease
+      include GraphNode
+
+      attr_reader :name, :version
+
+      # Create a new instance of a module release.
+      #
+      # @param source [Semantic::Dependency::Source]
+      # @param name [String]
+      # @param version [Semantic::Version]
+      # @param dependencies [{String => Semantic::VersionRange}]
+      def initialize(source, name, version, dependencies = {})
+        @source      = source
+        @name        = name.freeze
+        @version     = version.freeze
+
+        dependencies.each do |name, range|
+          add_constraint('initialize', name, range.to_s) do |node|
+            range === node.version
+          end
+
+          add_dependency(name)
+        end
+      end
+
+      def priority
+        @source.priority
+      end
+
+      def <=>(oth)
+        our_key   = [ priority, name, version ]
+        their_key = [ oth.priority, oth.name, oth.version ]
+
+        return our_key <=> their_key
+      end
+
+      def to_s
+        "#<#{self.class} #{name}@#{version}>"
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/dependency/source.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/dependency/source.rb
new file mode 100644
index 0000000..f052281
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/dependency/source.rb
@@ -0,0 +1,25 @@
+require 'semantic/dependency'
+
+module Semantic
+  module Dependency
+    class Source
+      def self.priority
+        0
+      end
+
+      def priority
+        self.class.priority
+      end
+
+      def create_release(name, version, dependencies = {})
+        version = Version.parse(version) if version.is_a? String
+        dependencies = dependencies.inject({}) do |hash, (key, value)|
+          hash[key] = VersionRange.parse(value || '>= 0.0.0')
+          hash[key] ||= VersionRange::EMPTY_RANGE
+          hash
+        end
+        ModuleRelease.new(self, name, version, dependencies)
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/dependency/unsatisfiable_graph.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/dependency/unsatisfiable_graph.rb
new file mode 100644
index 0000000..44899d6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/dependency/unsatisfiable_graph.rb
@@ -0,0 +1,31 @@
+require 'semantic/dependency'
+
+module Semantic
+  module Dependency
+    class UnsatisfiableGraph < StandardError
+      attr_reader :graph
+
+      def initialize(graph)
+        @graph = graph
+
+        deps = sentence_from_list(graph.modules)
+        super "Could not find satisfying releases for #{deps}"
+      end
+
+      private
+
+      def sentence_from_list(list)
+        case list.length
+        when 1
+          list.first
+        when 2
+          list.join(' and ')
+        else
+          list = list.dup
+          list.push("and #{list.pop}")
+          list.join(', ')
+        end
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/version.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/version.rb
new file mode 100644
index 0000000..4533b36
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/version.rb
@@ -0,0 +1,168 @@
+require 'semantic'
+
+module Semantic
+
+  # @note Semantic::Version subclasses Numeric so that it has sane Range
+  #       semantics in Ruby 1.9+.
+  class Version < Numeric
+    include Comparable
+
+    class ValidationFailure < ArgumentError; end
+
+    class << self
+      LOOSE_REGEX = /
+        \A
+        (\d+)[.](\d+)[.](\d+) # Major . Minor . Patch
+        (?: [-](.*?))?        # Prerelease
+        (?: [+](.*?))?        # Build
+        \Z
+      /x
+
+      # Parse a Semantic Version string.
+      #
+      # @param ver [String] the version string to parse
+      # @return [Version] a comparable {Version} object
+      def parse(ver)
+        match, major, minor, patch, prerelease, build = *ver.match(LOOSE_REGEX)
+
+        if match.nil?
+          raise 'Version numbers MUST begin with three dot-separated numbers'
+        elsif [major, minor, patch].any? { |x| x =~ /^0\d+/ }
+          raise 'Version numbers MUST NOT contain leading zeroes'
+        end
+
+        prerelease = parse_prerelease(prerelease) if prerelease
+        build = parse_build_metadata(build) if build
+
+        self.new(major.to_i, minor.to_i, patch.to_i, prerelease, build)
+      end
+
+      private
+      def parse_prerelease(prerelease)
+        subject = 'Prerelease identifiers'
+        prerelease = prerelease.split('.', -1)
+
+        if prerelease.empty? or prerelease.any? { |x| x.empty? }
+          raise "#{subject} MUST NOT be empty"
+        elsif prerelease.any? { |x| x =~ /[^0-9a-zA-Z-]/ }
+          raise "#{subject} MUST use only ASCII alphanumerics and hyphens"
+        elsif prerelease.any? { |x| x =~ /^0\d+$/ }
+          raise "#{subject} MUST NOT contain leading zeroes"
+        end
+
+        return prerelease.map { |x| x =~ /^\d+$/ ? x.to_i : x }
+      end
+
+      def parse_build_metadata(build)
+        subject = 'Build identifiers'
+        build = build.split('.', -1)
+
+        if build.empty? or build.any? { |x| x.empty? }
+          raise "#{subject} MUST NOT be empty"
+        elsif build.any? { |x| x =~ /[^0-9a-zA-Z-]/ }
+          raise "#{subject} MUST use only ASCII alphanumerics and hyphens"
+        end
+
+        return build
+      end
+
+      def raise(msg)
+        super ValidationFailure, msg, caller.drop_while { |x| x !~ /\bparse\b/ }
+      end
+    end
+
+    attr_reader :major, :minor, :patch
+
+    def initialize(major, minor, patch, prerelease = nil, build = nil)
+      @major      = major
+      @minor      = minor
+      @patch      = patch
+      @prerelease = prerelease
+      @build      = build
+    end
+
+    def next(part)
+      case part
+      when :major
+        self.class.new(@major.next, 0, 0)
+      when :minor
+        self.class.new(@major, @minor.next, 0)
+      when :patch
+        self.class.new(@major, @minor, @patch.next)
+      end
+    end
+
+    def prerelease
+      @prerelease && @prerelease.join('.')
+    end
+
+    # @return [Boolean] true if this is a stable release
+    def stable?
+      @prerelease.nil?
+    end
+
+    def build
+      @build && @build.join('.')
+    end
+
+    def <=>(other)
+      return self.major <=> other.major unless self.major == other.major
+      return self.minor <=> other.minor unless self.minor == other.minor
+      return self.patch <=> other.patch unless self.patch == other.patch
+      return compare_prerelease(other)
+    end
+
+    def to_s
+      "#{major}.#{minor}.#{patch}" +
+      (@prerelease.nil? || prerelease.empty? ? '' : "-" + prerelease) +
+      (@build.nil?      || build.empty?      ? '' : "+" + build     )
+    end
+
+    def hash
+      self.to_s.hash
+    end
+
+    private
+    # This is a hack; tildes sort later than any valid identifier. The
+    # advantage is that we don't need to handle stable vs. prerelease
+    # comparisons separately.
+    @@STABLE_RELEASE = [ '~' ].freeze
+
+    def compare_prerelease(other)
+      all_mine  = @prerelease                               || @@STABLE_RELEASE
+      all_yours = other.instance_variable_get(:@prerelease) || @@STABLE_RELEASE
+
+      # Precedence is determined by comparing each dot separated identifier from
+      # left to right...
+      size = [ all_mine.size, all_yours.size ].max
+      Array.new(size).zip(all_mine, all_yours) do |_, mine, yours|
+
+        # ...until a difference is found.
+        next if mine == yours
+
+        # Numbers are compared numerically, strings are compared ASCIIbetically.
+        if mine.class == yours.class
+          return mine <=> yours
+
+        # A larger set of pre-release fields has a higher precedence.
+        elsif mine.nil?
+          return -1
+        elsif yours.nil?
+          return 1
+
+        # Numeric identifiers always have lower precedence than non-numeric.
+        elsif mine.is_a? Numeric
+          return -1
+        elsif yours.is_a? Numeric
+          return 1
+        end
+      end
+
+      return 0
+    end
+
+    def first_prerelease
+      self.class.new(@major, @minor, @patch, [])
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/version_range.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/version_range.rb
new file mode 100644
index 0000000..e25ce41
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/lib/semantic/version_range.rb
@@ -0,0 +1,424 @@
+require 'semantic'
+
+module Semantic
+  class VersionRange < Range
+    class << self
+      # Parses a version range string into a comparable {VersionRange} instance.
+      #
+      # Currently parsed version range string may take any of the following:
+      # forms:
+      #
+      # * Regular Semantic Version strings
+      #   * ex. `"1.0.0"`, `"1.2.3-pre"`
+      # * Partial Semantic Version strings
+      #   * ex. `"1.0.x"`, `"1"`, `"2.X"`
+      # * Inequalities
+      #   * ex. `"> 1.0.0"`, `"<3.2.0"`, `">=4.0.0"`
+      # * Approximate Versions
+      #   * ex. `"~1.0.0"`, `"~ 3.2.0"`, `"~4.0.0"`
+      # * Inclusive Ranges
+      #   * ex. `"1.0.0 - 1.3.9"`
+      # * Range Intersections
+      #   * ex. `">1.0.0 <=2.3.0"`
+      #
+      # @param range_str [String] the version range string to parse
+      # @return [VersionRange] a new {VersionRange} instance
+      def parse(range_str)
+        partial = '\d+(?:[.]\d+)?(?:[.][x]|[.]\d+(?:[-][0-9a-z.-]*)?)?'
+        exact   = '\d+[.]\d+[.]\d+(?:[-][0-9a-z.-]*)?'
+
+        range = range_str.gsub(/([(><=~])[ ]+/, '\1')
+        range = range.gsub(/ - /, '#').strip
+
+        return case range
+        when /\A(#{partial})\Z/i
+          parse_loose_version_expression($1)
+        when /\A([><][=]?)(#{exact})\Z/i
+          parse_inequality_expression($1, $2)
+        when /\A~(#{partial})\Z/i
+          parse_reasonably_close_expression($1)
+        when /\A(#{exact})#(#{exact})\Z/i
+          parse_inclusive_range_expression($1, $2)
+        when /[ ]+/
+          parse_intersection_expression(range)
+        else
+          raise ArgumentError
+        end
+
+      rescue ArgumentError
+        raise ArgumentError, "Unparsable version range: #{range_str.inspect}"
+      end
+
+      private
+
+      # Creates a new {VersionRange} from a range intersection expression.
+      #
+      # @param expr [String] a range intersection expression
+      # @return [VersionRange] a version range representing `expr`
+      def parse_intersection_expression(expr)
+        expr.split(/[ ]+/).map { |x| parse(x) }.inject { |a,b| a & b }
+      end
+
+      # Creates a new {VersionRange} from a "loose" description of a Semantic
+      # Version number.
+      #
+      # @see .process_loose_expr
+      #
+      # @param expr [String] a "loose" version expression
+      # @return [VersionRange] a version range representing `expr`
+      def parse_loose_version_expression(expr)
+        start, finish = process_loose_expr(expr)
+
+        if start.stable?
+          start = start.send(:first_prerelease)
+        end
+
+        if finish.stable?
+          exclude = true
+          finish = finish.send(:first_prerelease)
+        end
+
+        self.new(start, finish, exclude)
+      end
+
+      # Creates an open-ended version range from an inequality expression.
+      #
+      # @overload parse_inequality_expression('<', expr)
+      #   {include:.parse_lt_expression}
+      #
+      # @overload parse_inequality_expression('<=', expr)
+      #   {include:.parse_lte_expression}
+      #
+      # @overload parse_inequality_expression('>', expr)
+      #   {include:.parse_gt_expression}
+      #
+      # @overload parse_inequality_expression('>=', expr)
+      #   {include:.parse_gte_expression}
+      #
+      # @param comp ['<', '<=', '>', '>='] an inequality operator
+      # @param expr [String] a "loose" version expression
+      # @return [VersionRange] a range covering all versions in the inequality
+      def parse_inequality_expression(comp, expr)
+        case comp
+        when '>'
+          parse_gt_expression(expr)
+        when '>='
+          parse_gte_expression(expr)
+        when '<'
+          parse_lt_expression(expr)
+        when '<='
+          parse_lte_expression(expr)
+        end
+      end
+
+      # Returns a range covering all versions greater than the given `expr`.
+      #
+      # @param expr [String] the version to be greater than
+      # @return [VersionRange] a range covering all versions greater than the
+      #         given `expr`
+      def parse_gt_expression(expr)
+        if expr =~ /^[^+]*-/
+          start = Version.parse("#{expr}.0")
+        else
+          start = process_loose_expr(expr).last.send(:first_prerelease)
+        end
+
+        self.new(start, MAX_VERSION)
+      end
+
+      # Returns a range covering all versions greater than or equal to the given
+      # `expr`.
+      #
+      # @param expr [String] the version to be greater than or equal to
+      # @return [VersionRange] a range covering all versions greater than or
+      #         equal to the given `expr`
+      def parse_gte_expression(expr)
+        if expr =~ /^[^+]*-/
+          start = Version.parse(expr)
+        else
+          start = process_loose_expr(expr).first.send(:first_prerelease)
+        end
+
+        self.new(start, MAX_VERSION)
+      end
+
+      # Returns a range covering all versions less than the given `expr`.
+      #
+      # @param expr [String] the version to be less than
+      # @return [VersionRange] a range covering all versions less than the
+      #         given `expr`
+      def parse_lt_expression(expr)
+        if expr =~ /^[^+]*-/
+          finish = Version.parse(expr)
+        else
+          finish = process_loose_expr(expr).first.send(:first_prerelease)
+        end
+
+        self.new(MIN_VERSION, finish, true)
+      end
+
+      # Returns a range covering all versions less than or equal to the given
+      # `expr`.
+      #
+      # @param expr [String] the version to be less than or equal to
+      # @return [VersionRange] a range covering all versions less than or equal
+      #         to the given `expr`
+      def parse_lte_expression(expr)
+        if expr =~ /^[^+]*-/
+          finish = Version.parse(expr)
+          self.new(MIN_VERSION, finish)
+        else
+          finish = process_loose_expr(expr).last.send(:first_prerelease)
+          self.new(MIN_VERSION, finish, true)
+        end
+      end
+
+      # The "reasonably close" expression is used to designate ranges that have
+      # a reasonable proximity to the given "loose" version number. These take
+      # the form:
+      #
+      #     ~[Version]
+      #
+      # The general semantics of these expressions are that the given version
+      # forms a lower bound for the range, and the upper bound is either the
+      # next version number increment (at whatever precision the expression
+      # provides) or the next stable version (in the case of a prerelease
+      # version).
+      #
+      # @example "Reasonably close" major version
+      #   "~1" # => (>=1.0.0 <2.0.0)
+      # @example "Reasonably close" minor version
+      #   "~1.2" # => (>=1.2.0 <1.3.0)
+      # @example "Reasonably close" patch version
+      #   "~1.2.3" # => (1.2.3)
+      # @example "Reasonably close" prerelease version
+      #   "~1.2.3-alpha" # => (>=1.2.3-alpha <1.2.4)
+      #
+      # @param expr [String] a "loose" expression to build the range around
+      # @return [VersionRange] a "reasonably close" version range
+      def parse_reasonably_close_expression(expr)
+        parsed, succ = process_loose_expr(expr)
+
+        if parsed.stable?
+          parsed = parsed.send(:first_prerelease)
+          succ = succ.send(:first_prerelease)
+          self.new(parsed, succ, true)
+        else
+          self.new(parsed, succ.next(:patch).send(:first_prerelease), true)
+        end
+      end
+
+      # An "inclusive range" expression takes two version numbers (or partial
+      # version numbers) and creates a range that covers all versions between
+      # them. These take the form:
+      #
+      #     [Version] - [Version]
+      #
+      # @param start [String] a "loose" expresssion for the start of the range
+      # @param finish [String] a "loose" expression for the end of the range
+      # @return [VersionRange] a {VersionRange} covering `start` to `finish`
+      def parse_inclusive_range_expression(start, finish)
+        start, _ = process_loose_expr(start)
+        _, finish = process_loose_expr(finish)
+
+        start = start.send(:first_prerelease) if start.stable?
+        if finish.stable?
+          exclude = true
+          finish = finish.send(:first_prerelease)
+        end
+
+        self.new(start, finish, exclude)
+      end
+
+      # A "loose expression" is one that takes the form of all or part of a
+      # valid Semantic Version number. Particularly:
+      #
+      # * [Major].[Minor].[Patch]-[Prerelease]
+      # * [Major].[Minor].[Patch]
+      # * [Major].[Minor]
+      # * [Major]
+      #
+      # Various placeholders are also permitted in "loose expressions"
+      # (typically an 'x' or an asterisk).
+      #
+      # This method parses these expressions into a minimal and maximal version
+      # number pair.
+      #
+      # @todo Stabilize whether the second value is inclusive or exclusive
+      #
+      # @param expr [String] a string containing a "loose" version expression
+      # @return [(VersionNumber, VersionNumber)] a minimal and maximal
+      #         version pair for the given expression
+      def process_loose_expr(expr)
+        case expr
+        when /^(\d+)(?:[.][xX*])?$/
+          expr = "#{$1}.0.0"
+          arity = :major
+        when /^(\d+[.]\d+)(?:[.][xX*])?$/
+          expr = "#{$1}.0"
+          arity = :minor
+        when /^\d+[.]\d+[.]\d+$/
+          arity = :patch
+        end
+
+        version = next_version = Version.parse(expr)
+
+        if arity
+          next_version = version.next(arity)
+        end
+
+        [ version, next_version ]
+      end
+    end
+
+    # Computes the intersection of a pair of ranges. If the ranges have no
+    # useful intersection, an empty range is returned.
+    #
+    # @param other [VersionRange] the range to intersect with
+    # @return [VersionRange] the common subset
+    def intersection(other)
+      raise NOT_A_VERSION_RANGE unless other.kind_of?(VersionRange)
+
+      if self.begin < other.begin
+        return other.intersection(self)
+      end
+
+      unless include?(other.begin) || other.include?(self.begin)
+        return EMPTY_RANGE
+      end
+
+      endpoint = ends_before?(other) ? self : other
+      VersionRange.new(self.begin, endpoint.end, endpoint.exclude_end?)
+    end
+    alias :& :intersection
+
+    # Returns a string representation of this range, prefering simple common
+    # expressions for comprehension.
+    #
+    # @return [String] a range expression representing this VersionRange
+    def to_s
+      start, finish  = self.begin, self.end
+      inclusive = exclude_end? ? '' : '='
+
+      case
+      when EMPTY_RANGE == self
+        "<0.0.0"
+      when exact_version?, patch_version?
+        "#{ start }"
+      when minor_version?
+        "#{ start }".sub(/.0$/, '.x')
+      when major_version?
+        "#{ start }".sub(/.0.0$/, '.x')
+      when open_end? && start.to_s =~ /-.*[.]0$/
+        ">#{ start }".sub(/.0$/, '')
+      when open_end?
+        ">=#{ start }"
+      when open_begin?
+        "<#{ inclusive }#{ finish }"
+      else
+        ">=#{ start } <#{ inclusive }#{ finish }"
+      end
+    end
+    alias :inspect :to_s
+
+    private
+
+    # The lowest precedence Version possible
+    MIN_VERSION = Version.new(0, 0, 0, []).freeze
+
+    # The highest precedence Version possible
+    MAX_VERSION = Version.new((1.0/0.0), 0, 0).freeze
+
+    # Determines whether this {VersionRange} has an earlier endpoint than the
+    # give `other` range.
+    #
+    # @param other [VersionRange] the range to compare against
+    # @return [Boolean] true if the endpoint for this range is less than or
+    #         equal to the endpoint of the `other` range.
+    def ends_before?(other)
+      self.end < other.end || (self.end == other.end && self.exclude_end?)
+    end
+
+    # Describes whether this range has an upper limit.
+    # @return [Boolean] true if this range has no upper limit
+    def open_end?
+      self.end == MAX_VERSION
+    end
+
+    # Describes whether this range has a lower limit.
+    # @return [Boolean] true if this range has no lower limit
+    def open_begin?
+      self.begin == MIN_VERSION
+    end
+
+    # Describes whether this range follows the patterns for matching all
+    # releases with the same exact version.
+    # @return [Boolean] true if this range matches only a single exact version
+    def exact_version?
+      self.begin == self.end
+    end
+
+    # Describes whether this range follows the patterns for matching all
+    # releases with the same major version.
+    # @return [Boolean] true if this range matches only a single major version
+    def major_version?
+      start, finish = self.begin, self.end
+
+      exclude_end? &&
+      start.major.next == finish.major &&
+      same_minor? && start.minor == 0 &&
+      same_patch? && start.patch == 0 &&
+      [start.prerelease, finish.prerelease] == ['', '']
+    end
+
+    # Describes whether this range follows the patterns for matching all
+    # releases with the same minor version.
+    # @return [Boolean] true if this range matches only a single minor version
+    def minor_version?
+      start, finish = self.begin, self.end
+
+      exclude_end? &&
+      same_major? &&
+      start.minor.next == finish.minor &&
+      same_patch? && start.patch == 0 &&
+      [start.prerelease, finish.prerelease] == ['', '']
+    end
+
+    # Describes whether this range follows the patterns for matching all
+    # releases with the same patch version.
+    # @return [Boolean] true if this range matches only a single patch version
+    def patch_version?
+      start, finish = self.begin, self.end
+
+      exclude_end? &&
+      same_major? &&
+      same_minor? &&
+      start.patch.next == finish.patch &&
+      [start.prerelease, finish.prerelease] == ['', '']
+    end
+
+    # @return [Boolean] true if `begin` and `end` share the same major verion
+    def same_major?
+      self.begin.major == self.end.major
+    end
+
+    # @return [Boolean] true if `begin` and `end` share the same minor verion
+    def same_minor?
+      self.begin.minor == self.end.minor
+    end
+
+    # @return [Boolean] true if `begin` and `end` share the same patch verion
+    def same_patch?
+      self.begin.patch == self.end.patch
+    end
+
+    undef :to_a
+
+    NOT_A_VERSION_RANGE = ArgumentError.new("value must be a #{VersionRange}")
+
+    public
+
+    # A range that matches no versions
+    EMPTY_RANGE = VersionRange.parse('< 0.0.0').freeze
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/spec_helper.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/spec_helper.rb
new file mode 100644
index 0000000..bf4c784
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/spec_helper.rb
@@ -0,0 +1,24 @@
+PROJECT_ROOT = File.join(File.dirname(__FILE__), '..')
+
+if ENV['COVERAGE']
+  require 'simplecov'
+  SimpleCov.start do
+    add_filter "/spec/"
+  end
+end
+
+RSpec.configure do |config|
+  config.treat_symbols_as_metadata_keys_with_true_values = true
+  config.run_all_when_everything_filtered = true
+  config.filter_run :focus
+
+  # Run specs in random order to surface order dependencies. If you find an
+  # order dependency and want to debug it, you can fix the order by providing
+  # the seed, which is printed after each run.
+  #     --seed 1234
+  config.order = 'random'
+
+  config.before do
+    Semantic::Dependency.instance_variable_set(:@sources, nil)
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/dependency/graph_node_spec.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/dependency/graph_node_spec.rb
new file mode 100644
index 0000000..39740d8
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/dependency/graph_node_spec.rb
@@ -0,0 +1,141 @@
+require 'spec_helper'
+require 'semantic/dependency/graph_node'
+
+describe Semantic::Dependency::GraphNode do
+  let(:klass) do
+    Class.new do
+      include Semantic::Dependency::GraphNode
+
+      attr_accessor :name
+
+      def initialize(name, *satisfying)
+        @name = name
+        @satisfying = satisfying
+        @satisfying.each { |x| add_dependency(x.name) }
+      end
+
+      # @override
+      def satisfies_dependency?(node)
+        @satisfying.include?(node)
+      end
+    end
+  end
+
+  def instance(*args)
+    name = args.first.name unless args.empty?
+    klass.new(name || 'unnamed', *args)
+  end
+
+  context 'dependencies' do
+    subject { instance() }
+
+    example 'are added by #add_dependency' do
+      subject.add_dependency('foo')
+      subject.add_dependency('bar')
+      subject.add_dependency('baz')
+      expect(subject.dependency_names).to match_array %w[ foo bar baz ]
+    end
+
+    example 'are maintained in the #dependencies Hash' do
+      expect(subject.dependencies).to be_empty
+      subject.add_dependency('foo')
+      expect(subject.dependencies).to have_key 'foo'
+      expect(subject.dependencies).to respond_to :to_a
+    end
+  end
+
+  describe '#<<' do
+    let(:foo) { double('Node', :name => 'foo') }
+    let(:bar1) { double('Node', :name => 'bar', :'<=>' => 0) }
+    let(:bar2) { double('Node', :name => 'bar', :'<=>' => 0) }
+    let(:bar3) { double('Node', :name => 'bar') }
+    let(:baz) { double('Node', :name => 'baz') }
+
+    subject { instance(foo, bar1, bar2) }
+
+    it 'appends satisfying nodes to the dependencies' do
+      subject << foo << bar1 << bar2
+      expect(Array(subject.dependencies['foo'])).to match_array [ foo ]
+      expect(Array(subject.dependencies['bar'])).to match_array [ bar1, bar2 ]
+    end
+
+    it 'does not append nodes with unknown names' do
+      subject << baz
+      expect(Array(subject.dependencies['baz'])).to be_empty
+    end
+
+    it 'does not append unsatisfying nodes' do
+      subject << bar3
+      expect(Array(subject.dependencies['bar'])).to be_empty
+    end
+  end
+
+  describe '#satisfied' do
+    let(:foo) { double('Node', :name => 'foo') }
+    let(:bar) { double('Node', :name => 'bar') }
+
+    subject { instance(foo, bar) }
+
+    it 'is unsatisfied when no nodes have been appended' do
+      expect(subject).to_not be_satisfied
+    end
+
+    it 'is unsatisfied when any dependencies are missing' do
+      subject << foo
+      expect(subject).to_not be_satisfied
+    end
+
+    it 'is satisfied when all dependencies are fulfilled' do
+      subject << foo << bar
+      expect(subject).to be_satisfied
+    end
+  end
+
+  describe '#populate_children' do
+    let(:foo) { double('Node', :name => 'foo') }
+    let(:bar1) { double('Node', :name => 'bar', :'<=>' => 0) }
+    let(:bar2) { double('Node', :name => 'bar', :'<=>' => 0) }
+    let(:baz1) { double('Node', :name => 'baz', :'<=>' => 0) }
+    let(:baz2) { double('Node', :name => 'baz', :'<=>' => 0) }
+    let(:quxx) { double('Node', :name => 'quxx') }
+
+    subject do
+      graph = instance(foo, bar1, bar2, baz1, baz2)
+      graph << foo << bar1 << bar2 << baz1 << baz2
+    end
+
+    it 'saves all relevant nodes as its children' do
+      nodes = [ foo, bar2, baz1, quxx ]
+      nodes.each do |node|
+        allow(node).to receive(:populate_children)
+      end
+
+      subject.populate_children(nodes)
+
+      expected = { 'foo' => foo, 'bar' => bar2, 'baz' => baz1 }
+      expect(subject.children).to eql expected
+    end
+
+    it 'accepts a graph solution and populates it across all nodes' do
+      nodes = [ foo, bar2, baz1 ]
+      nodes.each do |node|
+        expect(node).to receive(:populate_children).with(nodes)
+      end
+
+      subject.populate_children(nodes)
+    end
+  end
+
+  describe '#<=>' do
+    it 'can be compared' do
+      a = instance(double('Node', :name => 'a'))
+      b = instance(double('Node', :name => 'b'))
+
+      expect(a).to be < b
+      expect(b).to be > a
+      expect([b, a].sort).to eql [a, b]
+      expect([a, b].sort).to eql [a, b]
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/dependency/graph_spec.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/dependency/graph_spec.rb
new file mode 100644
index 0000000..60233a7
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/dependency/graph_spec.rb
@@ -0,0 +1,162 @@
+require 'spec_helper'
+require 'semantic/dependency/graph'
+
+describe Semantic::Dependency::Graph do
+  Graph         = Semantic::Dependency::Graph
+  GraphNode     = Semantic::Dependency::GraphNode
+  ModuleRelease = Semantic::Dependency::ModuleRelease
+  Version       = Semantic::Version
+  VersionRange  = Semantic::VersionRange
+
+  describe '#initialize' do
+    it 'can be called without arguments' do
+      expect { Graph.new }.to_not raise_error
+    end
+
+    it 'implements the GraphNode protocol' do
+      expect(Graph.new).to be_a GraphNode
+    end
+
+    it 'adds constraints for every key in the passed hash' do
+      graph = Graph.new('foo' => 1, 'bar' => 2, 'baz' => 3)
+      expect(graph.constraints.keys).to match_array %w[ foo bar baz ]
+    end
+
+    it 'adds the named dependencies for every key in the passed hash' do
+      graph = Graph.new('foo' => 1, 'bar' => 2, 'baz' => 3)
+      expect(graph.dependency_names).to match_array %w[ foo bar baz ]
+    end
+  end
+
+  describe '#add_constraint' do
+    let(:graph) { Graph.new }
+
+    it 'can create a new constraint on a module' do
+      expect(graph.constraints.keys).to be_empty
+
+      graph.add_constraint('test', 'module-name', 'nil') { }
+      expect(graph.constraints.keys).to match_array %w[ module-name ]
+    end
+
+    it 'permits multiple constraints against the same module name' do
+      expect(graph.constraints.keys).to be_empty
+
+      graph.add_constraint('test', 'module-name', 'nil') { }
+      graph.add_constraint('test', 'module-name', 'nil') { }
+
+      expect(graph.constraints.keys).to match_array %w[ module-name ]
+    end
+  end
+
+  describe '#satisfies_dependency?' do
+    it 'is not satisfied by modules it does not depend on' do
+      graph = Graph.new('foo' => VersionRange.parse('1.x'))
+      release = ModuleRelease.new(nil, 'bar', Version.parse('1.0.0'))
+
+      expect(graph.satisfies_dependency?(release)).to_not be true
+    end
+
+    it 'is not satisfied by modules that do not fulfill the constraint' do
+      graph = Graph.new('foo' => VersionRange.parse('1.x'))
+      release = ModuleRelease.new(nil, 'foo', Version.parse('2.3.1'))
+
+      expect(graph.satisfies_dependency?(release)).to_not be true
+    end
+
+    it 'is not satisfied by modules that do not fulfill all the constraints' do
+      graph = Graph.new('foo' => VersionRange.parse('1.x'))
+      graph.add_constraint('me', 'foo', '1.2.3') do |node|
+        node.version.to_s == '1.2.3'
+      end
+
+      release = ModuleRelease.new(nil, 'foo', Version.parse('1.2.1'))
+
+      expect(graph.satisfies_dependency?(release)).to_not be true
+    end
+
+    it 'is satisfied by modules that do fulfill all the constraints' do
+      graph = Graph.new('foo' => VersionRange.parse('1.x'))
+      graph.add_constraint('me', 'foo', '1.2.3') do |node|
+        node.version.to_s == '1.2.3'
+      end
+
+      release = ModuleRelease.new(nil, 'foo', Version.parse('1.2.3'))
+
+      expect(graph.satisfies_dependency?(release)).to be true
+    end
+  end
+
+  describe '#add_graph_constraint' do
+    let(:graph) { Graph.new }
+
+    it 'can create a new constraint on a graph' do
+      expect(graph.constraints.keys).to be_empty
+
+      graph.add_graph_constraint('test') { }
+      expect(graph.constraints.keys).to match_array [ :graph ]
+    end
+
+    it 'permits multiple graph constraints' do
+      expect(graph.constraints.keys).to be_empty
+
+      graph.add_graph_constraint('test') { }
+      graph.add_graph_constraint('test') { }
+
+      expect(graph.constraints.keys).to match_array [ :graph ]
+    end
+  end
+
+  describe '#satisfies_graph?' do
+    it 'returns false if the solution violates a graph constraint' do
+      graph = Graph.new
+      graph.add_graph_constraint('me') do |nodes|
+        nodes.none? { |node| node.name =~ /z/ }
+      end
+
+      releases = [
+        double('Node', :name => 'foo'),
+        double('Node', :name => 'bar'),
+        double('Node', :name => 'baz'),
+      ]
+
+      expect(graph.satisfies_graph?(releases)).to_not be true
+    end
+
+    it 'returns false if the solution violates any graph constraint' do
+      graph = Graph.new
+      graph.add_graph_constraint('me') do |nodes|
+        nodes.all? { |node| node.name.length < 5 }
+      end
+      graph.add_graph_constraint('me') do |nodes|
+        nodes.none? { |node| node.name =~ /z/ }
+      end
+
+      releases = [
+        double('Node', :name => 'foo'),
+        double('Node', :name => 'bar'),
+        double('Node', :name => 'bangerang'),
+      ]
+
+      expect(graph.satisfies_graph?(releases)).to_not be true
+    end
+
+    it 'returns true if the solution violates no graph constraints' do
+      graph = Graph.new
+      graph.add_graph_constraint('me') do |nodes|
+        nodes.all? { |node| node.name.length < 5 }
+      end
+      graph.add_graph_constraint('me') do |nodes|
+        nodes.none? { |node| node.name =~ /z/ }
+      end
+
+      releases = [
+        double('Node', :name => 'foo'),
+        double('Node', :name => 'bar'),
+        double('Node', :name => 'boom'),
+      ]
+
+      expect(graph.satisfies_graph?(releases)).to be true
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/dependency/module_release_spec.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/dependency/module_release_spec.rb
new file mode 100644
index 0000000..274b960
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/dependency/module_release_spec.rb
@@ -0,0 +1,143 @@
+require 'spec_helper'
+require 'semantic/dependency/module_release'
+
+describe Semantic::Dependency::ModuleRelease do
+  def source
+    @source ||= Semantic::Dependency::Source.new
+  end
+
+  def make_release(name, version, deps = {})
+    source.create_release(name, version, deps)
+  end
+
+  let(:no_dependencies) do
+    make_release('module', '1.2.3')
+  end
+
+  let(:one_dependency) do
+    make_release('module', '1.2.3', 'foo' => '1.0.0')
+  end
+
+  let(:three_dependencies) do
+    dependencies = { 'foo' => '1.0.0', 'bar' => '2.0.0', 'baz' => '3.0.0' }
+    make_release('module', '1.2.3', dependencies)
+  end
+
+  describe '#dependency_names' do
+
+    it "lists the names of all the release's dependencies" do
+      expect(no_dependencies.dependency_names).to    match_array %w[]
+      expect(one_dependency.dependency_names).to     match_array %w[foo]
+      expect(three_dependencies.dependency_names).to match_array %w[foo bar baz]
+    end
+
+  end
+
+  describe '#to_s' do
+
+    let(:name) { 'foobarbaz' }
+    let(:version) { '1.2.3' }
+
+    subject { make_release(name, version).to_s }
+
+    it { should =~ /#{name}/ }
+    it { should =~ /#{version}/ }
+
+  end
+
+  describe '#<<' do
+
+    it 'marks matching dependencies as satisfied' do
+      one_dependency << make_release('foo', '1.0.0')
+      expect(one_dependency).to be_satisfied
+    end
+
+    it 'does not mark mis-matching dependency names as satisfied' do
+      one_dependency << make_release('WAT', '1.0.0')
+      expect(one_dependency).to_not be_satisfied
+    end
+
+    it 'does not mark mis-matching dependency versions as satisfied' do
+      one_dependency << make_release('foo', '0.0.1')
+      expect(one_dependency).to_not be_satisfied
+    end
+
+  end
+
+  describe '#<=>' do
+
+    it 'considers releases with greater version numbers greater' do
+      expect(make_release('foo', '1.0.0')).to be > make_release('foo', '0.1.0')
+    end
+
+    it 'considers releases with lesser version numbers lesser' do
+      expect(make_release('foo', '0.1.0')).to be < make_release('foo', '1.0.0')
+    end
+
+    it 'orders releases with different names lexographically' do
+      expect(make_release('bar', '1.0.0')).to be < make_release('foo', '1.0.0')
+    end
+
+    it 'orders releases by name first' do
+      expect(make_release('bar', '2.0.0')).to be < make_release('foo', '1.0.0')
+    end
+
+  end
+
+  describe '#satisfied?' do
+
+    it 'returns true when there are no dependencies to satisfy' do
+      expect(no_dependencies).to be_satisfied
+    end
+
+    it 'returns false when no dependencies have been satisified' do
+      expect(one_dependency).to_not be_satisfied
+    end
+
+    it 'returns false when not all dependencies have been satisified' do
+      releases = %w[ 0.9.0 1.0.0 1.0.1 ].map { |ver| make_release('foo', ver) }
+      three_dependencies << releases
+
+      expect(three_dependencies).to_not be_satisfied
+    end
+
+    it 'returns false when not all dependency versions have been satisified' do
+      releases = %w[ 0.9.0 1.0.1 ].map { |ver| make_release('foo', ver) }
+      one_dependency << releases
+
+      expect(one_dependency).to_not be_satisfied
+    end
+
+    it 'returns true when all dependencies have been satisified' do
+      releases = %w[ 0.9.0 1.0.0 1.0.1 ].map { |ver| make_release('foo', ver) }
+      one_dependency << releases
+
+      expect(one_dependency).to be_satisfied
+    end
+
+  end
+
+  describe '#satisfies_dependency?' do
+
+    it 'returns false when there are no dependencies to satisfy' do
+      release = make_release('foo', '1.0.0')
+      expect(no_dependencies.satisfies_dependency?(release)).to_not be true
+    end
+
+    it 'returns false when the release does not match the dependency name' do
+      release = make_release('bar', '1.0.0')
+      expect(one_dependency.satisfies_dependency?(release)).to_not be true
+    end
+
+    it 'returns false when the release does not match the dependency version' do
+      release = make_release('foo', '4.0.0')
+      expect(one_dependency.satisfies_dependency?(release)).to_not be true
+    end
+
+    it 'returns true when the release matches the dependency' do
+      release = make_release('foo', '1.0.0')
+      expect(one_dependency.satisfies_dependency?(release)).to be true
+    end
+
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/dependency/source_spec.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/dependency/source_spec.rb
new file mode 100644
index 0000000..85f40bf
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/dependency/source_spec.rb
@@ -0,0 +1,5 @@
+require 'spec_helper'
+require 'semantic/dependency/source'
+
+describe Semantic::Dependency::Source do
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/dependency/unsatisfiable_graph_spec.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/dependency/unsatisfiable_graph_spec.rb
new file mode 100644
index 0000000..67a0985
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/dependency/unsatisfiable_graph_spec.rb
@@ -0,0 +1,44 @@
+require 'spec_helper'
+require 'semantic/dependency/unsatisfiable_graph'
+
+describe Semantic::Dependency::UnsatisfiableGraph do
+
+  let(:modules) { %w[ foo bar baz ] }
+  let(:graph) { double('Graph', :modules => modules) }
+  let(:instance) { described_class.new(graph) }
+
+  subject { instance }
+
+  describe '#message' do
+    subject { instance.message }
+
+    it { should match /#{instance.send(:sentence_from_list, modules)}/ }
+  end
+
+  describe '#sentence_from_list' do
+
+    subject { instance.send(:sentence_from_list, modules) }
+
+    context 'with a list of one item' do
+      let(:modules) { %w[ foo ] }
+      it { should eql 'foo' }
+    end
+
+    context 'with a list of two items' do
+      let(:modules) { %w[ foo bar ] }
+      it { should eql 'foo and bar' }
+    end
+
+    context 'with a list of three items' do
+      let(:modules) { %w[ foo bar baz ] }
+      it { should eql 'foo, bar, and baz' }
+    end
+
+    context 'with a list of more than three items' do
+      let(:modules) { %w[ foo bar baz quux ] }
+      it { should eql 'foo, bar, baz, and quux' }
+    end
+
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/dependency_spec.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/dependency_spec.rb
new file mode 100644
index 0000000..049acf1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/dependency_spec.rb
@@ -0,0 +1,383 @@
+require 'spec_helper'
+require 'semantic/dependency'
+
+describe Semantic::Dependency do
+  def create_release(source, name, version, deps = {})
+    Semantic::Dependency::ModuleRelease.new(
+      source,
+      name,
+      Semantic::Version.parse(version),
+      Hash[deps.map { |k, v| [k, Semantic::VersionRange.parse(v) ] }]
+    )
+  end
+
+  describe '.sources' do
+    it 'defaults to an empty list' do
+      expect(subject.sources).to be_empty
+    end
+
+    it 'is frozen' do
+      expect(subject.sources).to be_frozen
+    end
+
+    it 'can be modified by using #add_source' do
+      subject.add_source(Semantic::Dependency::Source.new)
+      expect(subject.sources).to_not be_empty
+    end
+
+    it 'can be emptied by using #clear_sources' do
+      subject.add_source(Semantic::Dependency::Source.new)
+      subject.clear_sources
+      expect(subject.sources).to be_empty
+    end
+  end
+
+  describe '.query' do
+    context 'without sources' do
+      it 'returns an unsatisfied ModuleRelease' do
+        expect(subject.query('module_name' => '1.0.0')).to_not be_satisfied
+      end
+    end
+
+    context 'with one source' do
+      let(:source) { double('Source') }
+
+      before { Semantic::Dependency.add_source(source) }
+
+      it 'queries the source for release information' do
+        source.should_receive(:fetch).with('module_name').and_return([])
+
+        Semantic::Dependency.query('module_name' => '1.0.0')
+      end
+
+      it 'queries the source for each dependency' do
+        source.should_receive(:fetch).with('module_name').and_return([
+          create_release(source, 'module_name', '1.0.0', 'bar' => '1.0.0')
+        ])
+        source.should_receive(:fetch).with('bar').and_return([])
+
+        Semantic::Dependency.query('module_name' => '1.0.0')
+      end
+
+      it 'queries the source for each dependency only once' do
+        source.should_receive(:fetch).with('module_name').and_return([
+          create_release(
+            source,
+            'module_name',
+            '1.0.0',
+            'bar' => '1.0.0', 'baz' => '0.0.2'
+          )
+        ])
+        source.should_receive(:fetch).with('bar').and_return([
+          create_release(source, 'bar', '1.0.0', 'baz' => '0.0.3')
+        ])
+        source.should_receive(:fetch).with('baz').once.and_return([])
+
+        Semantic::Dependency.query('module_name' => '1.0.0')
+      end
+
+      it 'returns a ModuleRelease with the requested dependencies' do
+        source.stub(:fetch).and_return([])
+
+        result = Semantic::Dependency.query('foo' => '1.0.0', 'bar' => '1.0.0')
+        expect(result.dependency_names).to match_array %w[ foo bar ]
+      end
+
+      it 'populates the returned ModuleRelease with related dependencies' do
+        source.stub(:fetch).and_return(
+          [ foo = create_release(source, 'foo', '1.0.0', 'bar' => '1.0.0') ],
+          [ bar = create_release(source, 'bar', '1.0.0') ]
+        )
+
+        result = Semantic::Dependency.query('foo' => '1.0.0', 'bar' => '1.0.0')
+        expect(result.dependencies['foo']).to eql SortedSet.new([ foo ])
+        expect(result.dependencies['bar']).to eql SortedSet.new([ bar ])
+      end
+
+      it 'populates all returned ModuleReleases with related dependencies' do
+        source.stub(:fetch).and_return(
+          [ foo = create_release(source, 'foo', '1.0.0', 'bar' => '1.0.0') ],
+          [ bar = create_release(source, 'bar', '1.0.0', 'baz' => '0.1.0') ],
+          [ baz = create_release(source, 'baz', '0.1.0', 'baz' => '1.0.0') ]
+        )
+
+        result = Semantic::Dependency.query('foo' => '1.0.0')
+        expect(result.dependencies['foo']).to eql SortedSet.new([ foo ])
+        expect(foo.dependencies['bar']).to eql SortedSet.new([ bar ])
+        expect(bar.dependencies['baz']).to eql SortedSet.new([ baz ])
+      end
+    end
+
+    context 'with multiple sources' do
+      let(:source1) { double('SourceOne') }
+      let(:source2) { double('SourceTwo') }
+      let(:source3) { double('SourceThree') }
+
+      before do
+        Semantic::Dependency.add_source(source1)
+        Semantic::Dependency.add_source(source2)
+        Semantic::Dependency.add_source(source3)
+      end
+
+      it 'queries each source in turn' do
+        source1.should_receive(:fetch).with('module_name').and_return([])
+        source2.should_receive(:fetch).with('module_name').and_return([])
+        source3.should_receive(:fetch).with('module_name').and_return([])
+
+        Semantic::Dependency.query('module_name' => '1.0.0')
+      end
+
+      it 'resolves all dependencies against all sources' do
+        source1.should_receive(:fetch).with('module_name').and_return([
+          create_release(source1, 'module_name', '1.0.0', 'bar' => '1.0.0')
+        ])
+        source2.should_receive(:fetch).with('module_name').and_return([])
+        source3.should_receive(:fetch).with('module_name').and_return([])
+
+        source1.should_receive(:fetch).with('bar').and_return([])
+        source2.should_receive(:fetch).with('bar').and_return([])
+        source3.should_receive(:fetch).with('bar').and_return([])
+
+        Semantic::Dependency.query('module_name' => '1.0.0')
+      end
+    end
+  end
+
+  describe '.resolve' do
+    def add_source_modules(name, versions, deps = {})
+      versions = Array(versions)
+      releases = versions.map { |ver| create_release(source, name, ver, deps) }
+      source.stub(:fetch).with(name).and_return(modules[name].concat(releases))
+    end
+
+    def subject(specs)
+      graph = Semantic::Dependency.query(specs)
+      yield graph if block_given?
+      expect(graph.dependencies).to_not be_empty
+      result = Semantic::Dependency.resolve(graph)
+      expect(graph.dependencies).to_not be_empty
+      result.map { |rel| [ rel.name, rel.version.to_s ] }
+    end
+
+    let(:modules) { Hash.new { |h,k| h[k] = [] }}
+    let(:source) { double('Source', :priority => 0) }
+
+    before { Semantic::Dependency.add_source(source) }
+
+    context 'for a module without dependencies' do
+      def foo(range)
+        subject('foo' => range).map { |x| x.last }
+      end
+
+      it 'returns the greatest release matching the version range' do
+        add_source_modules('foo', %w[ 0.9.0 1.0.0 1.1.0 2.0.0 ])
+
+        expect(foo('1.x')).to eql %w[ 1.1.0 ]
+      end
+
+      context 'when the query includes both stable and prerelease versions' do
+        it 'returns the greatest stable release matching the range' do
+          add_source_modules('foo', %w[ 0.9.0 1.0.0 1.1.0 1.2.0-pre 2.0.0 ])
+
+          expect(foo('1.x')).to eql %w[ 1.1.0 ]
+        end
+      end
+
+      context 'when the query omits all stable versions' do
+        it 'returns the greatest prerelease version matching the range' do
+          add_source_modules('foo', %w[ 1.0.0 1.1.0-a 1.1.0-b 2.0.0 ])
+
+          expect(foo('1.1.x')).to   eql %w[ 1.1.0-b ]
+          expect(foo('1.1.0-a')).to eql %w[ 1.1.0-a ]
+        end
+      end
+
+      context 'when the query omits all versions' do
+        it 'fails with an appropriate message' do
+          add_source_modules('foo', %w[ 1.0.0 1.1.0-a 1.1.0 ])
+
+          with_message = /Could not find satisfying releases/
+          expect { foo('2.x') }.to raise_exception with_message
+          expect { foo('2.x') }.to raise_exception /\bfoo\b/
+        end
+      end
+    end
+
+    context 'for a module with dependencies' do
+      def foo(range)
+        subject('foo' => range)
+      end
+
+      it 'returns the greatest releases matching the dependency range' do
+        add_source_modules('foo', '1.1.0', 'bar' => '1.x')
+        add_source_modules('bar', %w[ 0.9.0 1.0.0 1.1.0 1.2.0 2.0.0 ])
+
+        expect(foo('1.1.0')).to include %w[ foo 1.1.0 ], %w[ bar 1.2.0 ]
+      end
+
+      context 'when the dependency has both stable and prerelease versions' do
+        it 'returns the greatest stable release matching the range' do
+          add_source_modules('foo', '1.1.0', 'bar' => '1.x')
+          add_source_modules('bar', %w[ 0.9.0 1.0.0 1.1.0 1.2.0-pre 2.0.0 ])
+
+          expect(foo('1.1.0')).to include %w[ foo 1.1.0 ], %w[ bar 1.1.0 ]
+        end
+      end
+
+      context 'when the dependency has no stable versions' do
+        it 'returns the greatest prerelease version matching the range' do
+          add_source_modules('foo', '1.1.0', 'bar' => '1.1.x')
+          add_source_modules('foo', '1.1.1', 'bar' => '1.1.0-a')
+          add_source_modules('bar', %w[ 1.0.0 1.1.0-a 1.1.0-b 2.0.0 ])
+
+          expect(foo('1.1.0')).to include %w[ foo 1.1.0 ], %w[ bar 1.1.0-b ]
+          expect(foo('1.1.1')).to include %w[ foo 1.1.1 ], %w[ bar 1.1.0-a ]
+        end
+      end
+
+      context 'when the dependency cannot be satisfied' do
+        it 'fails with an appropriate message' do
+          add_source_modules('foo', %w[ 1.1.0 ], 'bar' => '1.x')
+          add_source_modules('bar', %w[ 0.0.1 0.1.0-a 0.1.0 ])
+
+          with_message = /Could not find satisfying releases/
+          expect { foo('1.1.0') }.to raise_exception with_message
+          expect { foo('1.1.0') }.to raise_exception /\bfoo\b/
+        end
+      end
+    end
+
+    context 'for a module with competing dependencies' do
+      def foo(range)
+        subject('foo' => range)
+      end
+
+      context 'that overlap' do
+        it 'returns the greatest release satisfying all dependencies' do
+          add_source_modules('foo', '1.1.0', 'bar' => '1.0.0', 'baz' => '1.0.0')
+          add_source_modules('bar', '1.0.0', 'quxx' => '1.x')
+          add_source_modules('baz', '1.0.0', 'quxx' => '1.1.x')
+          add_source_modules('quxx', %w[ 0.9.0 1.0.0 1.1.0 1.1.1 1.2.0 2.0.0 ])
+
+          expect(foo('1.1.0')).to_not include %w[ quxx 1.2.0 ]
+          expect(foo('1.1.0')).to include %w[ quxx 1.1.1 ]
+        end
+      end
+
+      context 'that do not overlap' do
+        it 'fails with an appropriate message' do
+          add_source_modules('foo','1.1.0', 'bar' => '1.0.0', 'baz' => '1.0.0')
+          add_source_modules('bar','1.0.0', 'quxx' => '1.x')
+          add_source_modules('baz','1.0.0', 'quxx' => '2.x')
+          add_source_modules('quxx', %w[ 0.9.0 1.0.0 1.1.0 1.1.1 1.2.0 2.0.0 ])
+
+          with_message = /Could not find satisfying releases/
+          expect { foo('1.1.0') }.to raise_exception with_message
+          expect { foo('1.1.0') }.to raise_exception /\bfoo\b/
+        end
+      end
+    end
+
+    context 'for a module with circular dependencies' do
+      def foo(range)
+        subject('foo' => range)
+      end
+
+      context 'that can be resolved' do
+        it 'terminates' do
+          add_source_modules('foo', '1.1.0', 'foo' => '1.x')
+
+          expect(foo('1.1.0')).to include %w[ foo 1.1.0 ]
+        end
+      end
+
+      context 'that cannot be resolved' do
+        it 'fails with an appropriate message' do
+          add_source_modules('foo', '1.1.0', 'foo' => '1.0.0')
+
+          with_message = /Could not find satisfying releases/
+          expect { foo('1.1.0') }.to raise_exception with_message
+          expect { foo('1.1.0') }.to raise_exception /\bfoo\b/
+        end
+      end
+    end
+
+    context 'for a module with dependencies' do
+      context 'that violate module constraints on the graph' do
+        def foo(range)
+          subject('foo' => range) do |graph|
+            graph.add_constraint('no downgrade', 'bar', '> 3.0.0') do |node|
+              Semantic::VersionRange.parse('> 3.0.0') === node.version
+            end
+          end
+        end
+
+        context 'that can be resolved' do
+          it 'terminates' do
+            add_source_modules('foo', '1.1.0', 'bar' => '1.x')
+            add_source_modules('foo', '1.2.0', 'bar' => '>= 2.0.0')
+            add_source_modules('bar', '1.0.0')
+            add_source_modules('bar', '2.0.0', 'baz' => '>= 1.0.0')
+            add_source_modules('bar', '3.0.0')
+            add_source_modules('bar', '3.0.1')
+            add_source_modules('baz', '1.0.0')
+
+            expect(foo('1.x')).to include %w[ foo 1.2.0 ], %w[ bar 3.0.1 ]
+          end
+        end
+
+        context 'that cannot be resolved' do
+          it 'fails with an appropriate message' do
+            add_source_modules('foo', '1.1.0', 'bar' => '1.x')
+            add_source_modules('foo', '1.2.0', 'bar' => '2.x')
+            add_source_modules('bar', '1.0.0', 'baz' => '1.x')
+            add_source_modules('bar', '2.0.0', 'baz' => '1.x')
+            add_source_modules('baz', '1.0.0')
+            add_source_modules('baz', '3.0.0')
+            add_source_modules('baz', '3.0.1')
+
+            with_message = /Could not find satisfying releases/
+            expect { foo('1.x') }.to raise_exception with_message
+            expect { foo('1.x') }.to raise_exception /\bfoo\b/
+          end
+        end
+      end
+    end
+
+    context 'that violate graph constraints' do
+      def foo(range)
+        subject('foo' => range) do |graph|
+          graph.add_graph_constraint('uniqueness') do |nodes|
+            nodes.none? { |node| node.name =~ /z/ }
+          end
+        end
+      end
+
+      context 'that can be resolved' do
+        it 'terminates' do
+          add_source_modules('foo', '1.1.0', 'bar' => '1.x')
+          add_source_modules('foo', '1.2.0', 'bar' => '2.x')
+          add_source_modules('bar', '1.0.0')
+          add_source_modules('bar', '2.0.0', 'baz' => '1.0.0')
+          add_source_modules('baz', '1.0.0')
+
+          expect(foo('1.x')).to include %w[ foo 1.1.0 ], %w[ bar 1.0.0 ]
+        end
+      end
+
+      context 'that cannot be resolved' do
+        it 'fails with an appropriate message' do
+          add_source_modules('foo', '1.1.0', 'bar' => '1.x')
+          add_source_modules('foo', '1.2.0', 'bar' => '2.x')
+          add_source_modules('bar', '1.0.0', 'baz' => '1.0.0')
+          add_source_modules('bar', '2.0.0', 'baz' => '1.0.0')
+          add_source_modules('baz', '1.0.0')
+
+          with_message = /Could not find satisfying releases/
+          expect { foo('1.1.0') }.to raise_exception with_message
+          expect { foo('1.1.0') }.to raise_exception /\bfoo\b/
+        end
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/version_range_spec.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/version_range_spec.rb
new file mode 100644
index 0000000..802805c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/version_range_spec.rb
@@ -0,0 +1,307 @@
+require 'spec_helper'
+require 'semantic/version'
+
+describe Semantic::VersionRange do
+
+  describe '.parse' do
+    def self.test_range(range_list, str, includes, excludes)
+      Array(range_list).each do |expr|
+        example "#{expr.inspect} stringifies as #{str}" do
+          range = Semantic::VersionRange.parse(expr)
+          expect(range.to_s).to eql str
+        end
+
+        includes.each do |vstring|
+          example "#{expr.inspect} includes #{vstring}" do
+            range = Semantic::VersionRange.parse(expr)
+            expect(range).to include(Semantic::Version.parse(vstring))
+          end
+
+          example "parse(#{expr.inspect}).to_s includes #{vstring}" do
+            range = Semantic::VersionRange.parse(expr)
+            range = Semantic::VersionRange.parse(range.to_s)
+            expect(range).to include(Semantic::Version.parse(vstring))
+          end
+        end
+
+        excludes.each do |vstring|
+          example "#{expr.inspect} excludes #{vstring}" do
+            range = Semantic::VersionRange.parse(expr)
+            expect(range).to_not include(Semantic::Version.parse(vstring))
+          end
+
+          example "parse(#{expr.inspect}).to_s excludes #{vstring}" do
+            range = Semantic::VersionRange.parse(expr)
+            range = Semantic::VersionRange.parse(range.to_s)
+            expect(range).to_not include(Semantic::Version.parse(vstring))
+          end
+        end
+      end
+    end
+
+    context 'loose version expressions' do
+      expressions = {
+        [ '1.2.3-alpha' ] => {
+          :to_str   => '1.2.3-alpha',
+          :includes => [ '1.2.3-alpha'  ],
+          :excludes => [ '1.2.3-999', '1.2.3-beta' ],
+        },
+        [ '1.2.3' ] => {
+          :to_str   => '1.2.3',
+          :includes => [ '1.2.3-alpha', '1.2.3' ],
+          :excludes => [ '1.2.2', '1.2.4-alpha' ],
+        },
+        [ '1.2', '1.2.x', '1.2.X' ] => {
+          :to_str   => '1.2.x',
+          :includes => [ '1.2.0-alpha', '1.2.0', '1.2.999' ],
+          :excludes => [ '1.1.999', '1.3.0-0' ],
+        },
+        [ '1', '1.x', '1.X' ] => {
+          :to_str   => '1.x',
+          :includes => [ '1.0.0-alpha', '1.999.0' ],
+          :excludes => [ '0.999.999', '2.0.0-0' ],
+        },
+      }
+
+      expressions.each do |range, vs|
+        test_range(range, vs[:to_str], vs[:includes], vs[:excludes])
+      end
+    end
+
+    context 'open-ended expressions' do
+      expressions = {
+        [ '>1.2.3', '> 1.2.3' ] => {
+          :to_str   => '>=1.2.4',
+          :includes => [ '1.2.4-0', '999.0.0' ],
+          :excludes => [ '1.2.3' ],
+        },
+        [ '>1.2.3-alpha', '> 1.2.3-alpha' ] => {
+          :to_str   => '>1.2.3-alpha',
+          :includes => [ '1.2.3-alpha.0', '1.2.3-alpha0', '999.0.0' ],
+          :excludes => [ '1.2.3-alpha' ],
+        },
+
+        [ '>=1.2.3', '>= 1.2.3' ] => {
+          :to_str   => '>=1.2.3',
+          :includes => [ '1.2.3-0', '999.0.0' ],
+          :excludes => [ '1.2.2' ],
+        },
+        [ '>=1.2.3-alpha', '>= 1.2.3-alpha' ] => {
+          :to_str   => '>=1.2.3-alpha',
+          :includes => [ '1.2.3-alpha', '1.2.3-alpha0', '999.0.0' ],
+          :excludes => [ '1.2.3-alph' ],
+        },
+
+        [ '<1.2.3', '< 1.2.3' ] => {
+          :to_str   => '<1.2.3',
+          :includes => [ '0.0.0-0', '1.2.2' ],
+          :excludes => [ '1.2.3-0', '2.0.0' ],
+        },
+        [ '<1.2.3-alpha', '< 1.2.3-alpha' ] => {
+          :to_str   => '<1.2.3-alpha',
+          :includes => [ '0.0.0-0', '1.2.3-alph' ],
+          :excludes => [ '1.2.3-alpha', '2.0.0' ],
+        },
+
+        [ '<=1.2.3', '<= 1.2.3' ] => {
+          :to_str   => '<1.2.4',
+          :includes => [ '0.0.0-0', '1.2.3' ],
+          :excludes => [ '1.2.4-0' ],
+        },
+        [ '<=1.2.3-alpha', '<= 1.2.3-alpha' ] => {
+          :to_str   => '<=1.2.3-alpha',
+          :includes => [ '0.0.0-0', '1.2.3-alpha' ],
+          :excludes => [ '1.2.3-alpha0', '1.2.3-alpha.0', '1.2.3-alpha'.next ],
+        },
+      }
+
+      expressions.each do |range, vs|
+        test_range(range, vs[:to_str], vs[:includes], vs[:excludes])
+      end
+    end
+
+    context '"reasonably close" expressions' do
+      expressions = {
+        [ '~ 1', '~1' ] => {
+          :to_str   => '1.x',
+          :includes => [ '1.0.0-0', '1.999.999' ],
+          :excludes => [ '0.999.999', '2.0.0-0' ],
+        },
+        [ '~ 1.2', '~1.2' ] => {
+          :to_str   => '1.2.x',
+          :includes => [ '1.2.0-0', '1.2.999' ],
+          :excludes => [ '1.1.999', '1.3.0-0' ],
+        },
+        [ '~ 1.2.3', '~1.2.3' ] => {
+          :to_str   => '1.2.3',
+          :includes => [ '1.2.3-0', '1.2.3' ],
+          :excludes => [ '1.2.2', '1.2.4-0' ],
+        },
+        [ '~ 1.2.3-alpha', '~1.2.3-alpha' ] => {
+          :to_str   => '>=1.2.3-alpha <1.2.4',
+          :includes => [ '1.2.3-alpha', '1.2.3' ],
+          :excludes => [ '1.2.3-alph', '1.2.4-0' ],
+        },
+      }
+
+      expressions.each do |range, vs|
+        test_range(range, vs[:to_str], vs[:includes], vs[:excludes])
+      end
+    end
+
+    context 'inclusive range expressions' do
+      expressions = {
+        '1.2.3 - 1.3.4' => {
+          :to_str   => '>=1.2.3 <1.3.5',
+          :includes => [ '1.2.3-0', '1.3.4' ],
+          :excludes => [ '1.2.2', '1.3.5-0' ],
+        },
+        '1.2.3 - 1.3.4-alpha' => {
+          :to_str   => '>=1.2.3 <=1.3.4-alpha',
+          :includes => [ '1.2.3-0', '1.3.4-alpha' ],
+          :excludes => [ '1.2.2', '1.3.4-alpha0', '1.3.5' ],
+        },
+
+        '1.2.3-alpha - 1.3.4' => {
+          :to_str   => '>=1.2.3-alpha <1.3.5',
+          :includes => [ '1.2.3-alpha', '1.3.4' ],
+          :excludes => [ '1.2.3-alph', '1.3.5-0' ],
+        },
+        '1.2.3-alpha - 1.3.4-alpha' => {
+          :to_str   => '>=1.2.3-alpha <=1.3.4-alpha',
+          :includes => [ '1.2.3-alpha', '1.3.4-alpha' ],
+          :excludes => [ '1.2.3-alph', '1.3.4-alpha0', '1.3.5' ],
+        },
+      }
+
+      expressions.each do |range, vs|
+        test_range(range, vs[:to_str], vs[:includes], vs[:excludes])
+      end
+    end
+
+    context 'unioned expressions' do
+      expressions = {
+        [ '1.2 <1.2.5' ] => {
+          :to_str   => '>=1.2.0 <1.2.5',
+          :includes => [ '1.2.0-0', '1.2.4' ],
+          :excludes => [ '1.1.999', '1.2.5-0', '1.9.0' ],
+        },
+        [ '1 <=1.2.5' ] => {
+          :to_str   => '>=1.0.0 <1.2.6',
+          :includes => [ '1.0.0-0', '1.2.5' ],
+          :excludes => [ '0.999.999', '1.2.6-0', '1.9.0' ],
+        },
+        [ '>1.0.0 >2.0.0 >=3.0.0 <5.0.0' ] => {
+          :to_str   => '>=3.0.0 <5.0.0',
+          :includes => [ '3.0.0-0', '4.999.999' ],
+          :excludes => [ '2.999.999', '5.0.0-0' ],
+        },
+        [ '<1.0.0 >2.0.0' ] => {
+          :to_str   => '<0.0.0',
+          :includes => [  ],
+          :excludes => [ '0.0.0-0' ],
+        },
+      }
+
+      expressions.each do |range, vs|
+        test_range(range, vs[:to_str], vs[:includes], vs[:excludes])
+      end
+    end
+
+    context 'invalid expressions' do
+      example 'raise an appropriate exception' do
+        ex = [ ArgumentError, 'Unparsable version range: "invalid"' ]
+        expect { Semantic::VersionRange.parse('invalid') }.to raise_error(*ex)
+      end
+    end
+  end
+
+  describe '#intersection' do
+    def self.v(num)
+      Semantic::Version.parse("#{num}.0.0")
+    end
+
+    def self.range(x, y, ex = false)
+      Semantic::VersionRange.new(v(x), v(y), ex)
+    end
+
+    EMPTY_RANGE = Semantic::VersionRange::EMPTY_RANGE
+
+    tests = {
+      # This falls entirely before the target range
+      range(1, 4) => [ EMPTY_RANGE ],
+
+      # This falls entirely after the target range
+      range(11, 15) => [ EMPTY_RANGE ],
+
+      # This overlaps the beginning of the target range
+      range(1, 6) => [ range(5, 6) ],
+
+      # This overlaps the end of the target range
+      range(9, 15) => [ range(9, 10), range(9, 10, true) ],
+
+      # This shares the first value of the target range
+      range(1, 5) => [ range(5, 5) ],
+
+      # This shares the last value of the target range
+      range(10, 15)  => [ range(10, 10), EMPTY_RANGE ],
+
+      # This shares both values with the target range
+      range(5, 10) => [ range(5, 10), range(5, 10, true) ],
+
+      # This is a superset of the target range
+      range(4, 11) => [ range(5, 10), range(5, 10, true) ],
+
+      # This is a subset of the target range
+      range(6, 9) => [ range(6, 9) ],
+
+      # This shares the first value of the target range, but excludes it
+      range(1, 5, true)   => [ EMPTY_RANGE ],
+
+      # This overlaps the beginning of the target range, with an excluded end
+      range(1, 7, true)   => [ range(5, 7, true) ],
+
+      # This shares both values with the target range, and excludes the end
+      range(5, 10, true)  => [ range(5, 10, true) ],
+    }
+
+    inclusive = range(5, 10)
+    context "between #{inclusive} &" do
+      tests.each do |subject, result|
+        result = result.first
+
+        example subject do
+          expect(inclusive & subject).to eql(result)
+        end
+      end
+    end
+
+    exclusive = range(5, 10, true)
+    context "between #{exclusive} &" do
+      tests.each do |subject, result|
+        result = result.last
+
+        example subject do
+          expect(exclusive & subject).to eql(result)
+        end
+      end
+    end
+
+    context 'is commutative' do
+      tests.each do |subject, _|
+        example "between #{inclusive} & #{subject}" do
+          expect(inclusive & subject).to eql(subject & inclusive)
+        end
+        example "between #{exclusive} & #{subject}" do
+          expect(exclusive & subject).to eql(subject & exclusive)
+        end
+      end
+    end
+
+    it 'cannot intersect with non-VersionRanges' do
+      msg = "value must be a Semantic::VersionRange"
+      expect { inclusive.intersection(1..2) }.to raise_error(msg)
+    end
+  end
+
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/version_spec.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/version_spec.rb
new file mode 100644
index 0000000..606c178
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/vendor/semantic/spec/unit/semantic/version_spec.rb
@@ -0,0 +1,608 @@
+require 'spec_helper'
+require 'semantic/version'
+
+describe Semantic::Version do
+
+  def subject(str)
+    Semantic::Version.parse(str)
+  end
+
+  describe '.parse' do
+
+    context 'Spec v2.0.0' do
+      context 'Section 2' do
+        # A normal version number MUST take the form X.Y.Z where X, Y, and Z are
+        # non-negative integers, and MUST NOT contain leading zeroes. X is the
+        # major version, Y is the minor version, and Z is the patch version.
+        # Each element MUST increase numerically.
+        # For instance: 1.9.0 -> 1.10.0 -> 1.11.0.
+
+        let(:must_begin_with_digits) do
+          'Version numbers MUST begin with three dot-separated numbers'
+        end
+
+        let(:no_leading_zeroes) do
+          'Version numbers MUST NOT contain leading zeroes'
+        end
+
+        it 'rejects versions that contain too few parts' do
+          expect { subject('1.2') }.to raise_error(must_begin_with_digits)
+        end
+
+        it 'rejects versions that contain too many parts' do
+          expect { subject('1.2.3.4') }.to raise_error(must_begin_with_digits)
+        end
+
+        it 'rejects versions that contain non-integers' do
+          expect { subject('x.2.3') }.to raise_error(must_begin_with_digits)
+          expect { subject('1.y.3') }.to raise_error(must_begin_with_digits)
+          expect { subject('1.2.z') }.to raise_error(must_begin_with_digits)
+        end
+
+        it 'rejects versions that contain negative integers' do
+          expect { subject('-1.2.3') }.to raise_error(must_begin_with_digits)
+          expect { subject('1.-2.3') }.to raise_error(must_begin_with_digits)
+          expect { subject('1.2.-3') }.to raise_error(must_begin_with_digits)
+        end
+
+        it 'rejects version numbers containing leading zeroes' do
+          expect { subject('01.2.3') }.to raise_error(no_leading_zeroes)
+          expect { subject('1.02.3') }.to raise_error(no_leading_zeroes)
+          expect { subject('1.2.03') }.to raise_error(no_leading_zeroes)
+        end
+
+        it 'permits zeroes in version number parts' do
+          expect { subject('0.2.3') }.to_not raise_error
+          expect { subject('1.0.3') }.to_not raise_error
+          expect { subject('1.2.0') }.to_not raise_error
+        end
+
+        context 'examples' do
+          example '1.9.0' do
+            version = subject('1.9.0')
+            expect(version.major).to eql 1
+            expect(version.minor).to eql 9
+            expect(version.patch).to eql 0
+          end
+
+          example '1.10.0' do
+            version = subject('1.10.0')
+            expect(version.major).to eql 1
+            expect(version.minor).to eql 10
+            expect(version.patch).to eql 0
+          end
+
+          example '1.11.0' do
+            version = subject('1.11.0')
+            expect(version.major).to eql 1
+            expect(version.minor).to eql 11
+            expect(version.patch).to eql 0
+          end
+        end
+      end
+
+      context 'Section 9' do
+        # A pre-release version MAY be denoted by appending a hyphen and a
+        # series of dot separated identifiers immediately following the patch
+        # version. Identifiers MUST comprise only ASCII alphanumerics and
+        # hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty. Numeric
+        # identifiers MUST NOT include leading zeroes. Pre-release versions
+        # have a lower precedence than the associated normal version. A
+        # pre-release version indicates that the version is unstable and
+        # might not satisfy the intended compatibility requirements as denoted
+        # by its associated normal version.
+        # Examples: 1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-0.3.7, 1.0.0-x.7.z.92.
+
+        let(:restricted_charset) do
+          'Prerelease identifiers MUST use only ASCII alphanumerics and hyphens'
+        end
+
+        let(:must_not_be_empty) do
+          'Prerelease identifiers MUST NOT be empty'
+        end
+
+        let(:no_leading_zeroes) do
+          'Prerelease identifiers MUST NOT contain leading zeroes'
+        end
+
+        it 'rejects prerelease identifiers with non-alphanumerics' do
+          expect { subject('1.2.3-$100') }.to raise_error(restricted_charset)
+          expect { subject('1.2.3-rc.1@me') }.to raise_error(restricted_charset)
+        end
+
+        it 'rejects empty prerelease versions' do
+          expect { subject('1.2.3-') }.to raise_error(must_not_be_empty)
+        end
+
+        it 'rejects empty prerelease version identifiers' do
+          expect { subject('1.2.3-.rc1') }.to raise_error(must_not_be_empty)
+          expect { subject('1.2.3-rc1.') }.to raise_error(must_not_be_empty)
+          expect { subject('1.2.3-rc..1') }.to raise_error(must_not_be_empty)
+        end
+
+        it 'rejects numeric prerelease identifiers with leading zeroes' do
+          expect { subject('1.2.3-01') }.to raise_error(no_leading_zeroes)
+          expect { subject('1.2.3-rc.01') }.to raise_error(no_leading_zeroes)
+        end
+
+        it 'permits numeric prerelease identifiers of zero' do
+          expect { subject('1.2.3-0') }.to_not raise_error
+          expect { subject('1.2.3-rc.0') }.to_not raise_error
+        end
+
+        it 'permits non-numeric prerelease identifiers with leading zeroes' do
+          expect { subject('1.2.3-0xDEADBEEF') }.to_not raise_error
+          expect { subject('1.2.3-rc.0x10c') }.to_not raise_error
+        end
+
+        context 'examples' do
+          example '1.0.0-alpha' do
+            version = subject('1.0.0-alpha')
+            expect(version.major).to eql 1
+            expect(version.minor).to eql 0
+            expect(version.patch).to eql 0
+            expect(version.prerelease).to eql 'alpha'
+          end
+
+          example '1.0.0-alpha.1' do
+            version = subject('1.0.0-alpha.1')
+            expect(version.major).to eql 1
+            expect(version.minor).to eql 0
+            expect(version.patch).to eql 0
+            expect(version.prerelease).to eql 'alpha.1'
+          end
+
+          example '1.0.0-0.3.7' do
+            version = subject('1.0.0-0.3.7')
+            expect(version.major).to eql 1
+            expect(version.minor).to eql 0
+            expect(version.patch).to eql 0
+            expect(version.prerelease).to eql '0.3.7'
+          end
+
+          example '1.0.0-x.7.z.92' do
+            version = subject('1.0.0-x.7.z.92')
+            expect(version.major).to eql 1
+            expect(version.minor).to eql 0
+            expect(version.patch).to eql 0
+            expect(version.prerelease).to eql 'x.7.z.92'
+          end
+        end
+      end
+
+      context 'Section 10' do
+        # Build metadata MAY be denoted by appending a plus sign and a series
+        # of dot separated identifiers immediately following the patch or
+        # pre-release version. Identifiers MUST comprise only ASCII
+        # alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty.
+        # Build metadata SHOULD be ignored when determining version precedence.
+        # Thus two versions that differ only in the build metadata, have the
+        # same precedence.
+        # Examples: 1.0.0-alpha+001, 1.0.0+20130313144700,
+        # 1.0.0-beta+exp.sha.5114f85.
+
+
+        let(:restricted_charset) do
+          'Build identifiers MUST use only ASCII alphanumerics and hyphens'
+        end
+
+        let(:must_not_be_empty) do
+          'Build identifiers MUST NOT be empty'
+        end
+
+        it 'rejects build identifiers with non-alphanumerics' do
+          expect { subject('1.2.3+$100') }.to raise_error(restricted_charset)
+          expect { subject('1.2.3+rc.1@me') }.to raise_error(restricted_charset)
+        end
+
+        it 'rejects empty build metadata' do
+          expect { subject('1.2.3+') }.to raise_error(must_not_be_empty)
+        end
+
+        it 'rejects empty build identifiers' do
+          expect { subject('1.2.3+.rc1') }.to raise_error(must_not_be_empty)
+          expect { subject('1.2.3+rc1.') }.to raise_error(must_not_be_empty)
+          expect { subject('1.2.3+rc..1') }.to raise_error(must_not_be_empty)
+        end
+
+        it 'permits numeric build identifiers with leading zeroes' do
+          expect { subject('1.2.3+01') }.to_not raise_error
+          expect { subject('1.2.3+rc.01') }.to_not raise_error
+        end
+
+        it 'permits numeric build identifiers of zero' do
+          expect { subject('1.2.3+0') }.to_not raise_error
+          expect { subject('1.2.3+rc.0') }.to_not raise_error
+        end
+
+        it 'permits non-numeric build identifiers with leading zeroes' do
+          expect { subject('1.2.3+0xDEADBEEF') }.to_not raise_error
+          expect { subject('1.2.3+rc.0x10c') }.to_not raise_error
+        end
+
+        context 'examples' do
+          example '1.0.0-alpha+001' do
+            version = subject('1.0.0-alpha+001')
+            expect(version.major).to eql 1
+            expect(version.minor).to eql 0
+            expect(version.patch).to eql 0
+            expect(version.prerelease).to eql 'alpha'
+            expect(version.build).to eql '001'
+          end
+
+          example '1.0.0+20130313144700' do
+            version = subject('1.0.0+20130313144700')
+            expect(version.major).to eql 1
+            expect(version.minor).to eql 0
+            expect(version.patch).to eql 0
+            expect(version.prerelease).to eql nil
+            expect(version.build).to eql '20130313144700'
+          end
+
+          example '1.0.0-beta+exp.sha.5114f85' do
+            version = subject('1.0.0-beta+exp.sha.5114f85')
+            expect(version.major).to eql 1
+            expect(version.minor).to eql 0
+            expect(version.patch).to eql 0
+            expect(version.prerelease).to eql 'beta'
+            expect(version.build).to eql 'exp.sha.5114f85'
+          end
+        end
+      end
+    end
+
+    context 'Spec v1.0.0' do
+      context 'Section 2' do
+        # A normal version number MUST take the form X.Y.Z where X, Y, and Z
+        # are integers. X is the major version, Y is the minor version, and Z
+        # is the patch version. Each element MUST increase numerically by
+        # increments of one.
+        # For instance: 1.9.0 -> 1.10.0 -> 1.11.0
+
+        let(:must_begin_with_digits) do
+          'Version numbers MUST begin with three dot-separated numbers'
+        end
+
+        let(:no_leading_zeroes) do
+          'Version numbers MUST NOT contain leading zeroes'
+        end
+
+        it 'rejects versions that contain too few parts' do
+          expect { subject('1.2') }.to raise_error(must_begin_with_digits)
+        end
+
+        it 'rejects versions that contain too many parts' do
+          expect { subject('1.2.3.4') }.to raise_error(must_begin_with_digits)
+        end
+
+        it 'rejects versions that contain non-integers' do
+          expect { subject('x.2.3') }.to raise_error(must_begin_with_digits)
+          expect { subject('1.y.3') }.to raise_error(must_begin_with_digits)
+          expect { subject('1.2.z') }.to raise_error(must_begin_with_digits)
+        end
+
+        it 'permits zeroes in version number parts' do
+          expect { subject('0.2.3') }.to_not raise_error
+          expect { subject('1.0.3') }.to_not raise_error
+          expect { subject('1.2.0') }.to_not raise_error
+        end
+
+        context 'examples' do
+          example '1.9.0' do
+            version = subject('1.9.0')
+            expect(version.major).to eql 1
+            expect(version.minor).to eql 9
+            expect(version.patch).to eql 0
+          end
+
+          example '1.10.0' do
+            version = subject('1.10.0')
+            expect(version.major).to eql 1
+            expect(version.minor).to eql 10
+            expect(version.patch).to eql 0
+          end
+
+          example '1.11.0' do
+            version = subject('1.11.0')
+            expect(version.major).to eql 1
+            expect(version.minor).to eql 11
+            expect(version.patch).to eql 0
+          end
+        end
+      end
+
+      context 'Section 4' do
+        # A pre-release version number MAY be denoted by appending an arbitrary
+        # string immediately following the patch version and a dash. The string
+        # MUST be comprised of only alphanumerics plus dash [0-9A-Za-z-].
+        # Pre-release versions satisfy but have a lower precedence than the
+        # associated normal version. Precedence SHOULD be determined by
+        # lexicographic ASCII sort order.
+        # For instance: 1.0.0-alpha1 < 1.0.0-beta1 < 1.0.0-beta2 < 1.0.0-rc1
+
+        let(:restricted_charset) do
+          'Prerelease identifiers MUST use only ASCII alphanumerics and hyphens'
+        end
+
+        let(:must_not_be_empty) do
+          'Prerelease identifiers MUST NOT be empty'
+        end
+
+        let(:no_leading_zeroes) do
+          'Prerelease identifiers MUST NOT contain leading zeroes'
+        end
+
+        it 'rejects prerelease identifiers with non-alphanumerics' do
+          expect { subject('1.2.3-$100') }.to raise_error(restricted_charset)
+          expect { subject('1.2.3-rc.1@me') }.to raise_error(restricted_charset)
+        end
+
+        it 'rejects empty prerelease versions' do
+          expect { subject('1.2.3-') }.to raise_error(must_not_be_empty)
+        end
+
+        pending 'permits numeric prerelease identifiers with leading zeroes' do
+          expect { subject('1.2.3-01') }.to raise_error(no_leading_zeroes)
+        end
+
+        it 'permits numeric prerelease identifiers of zero' do
+          expect { subject('1.2.3-0') }.to_not raise_error
+        end
+
+        it 'permits non-numeric prerelease identifiers with leading zeroes' do
+          expect { subject('1.2.3-0xDEADBEEF') }.to_not raise_error
+        end
+
+        context 'examples' do
+          example '1.0.0-alpha1' do
+            version = subject('1.0.0-alpha1')
+            expect(version.major).to eql 1
+            expect(version.minor).to eql 0
+            expect(version.patch).to eql 0
+            expect(version.prerelease).to eql 'alpha1'
+          end
+
+          example '1.0.0-beta1' do
+            version = subject('1.0.0-beta1')
+            expect(version.major).to eql 1
+            expect(version.minor).to eql 0
+            expect(version.patch).to eql 0
+            expect(version.prerelease).to eql 'beta1'
+          end
+
+          example '1.0.0-beta2' do
+            version = subject('1.0.0-beta2')
+            expect(version.major).to eql 1
+            expect(version.minor).to eql 0
+            expect(version.patch).to eql 0
+            expect(version.prerelease).to eql 'beta2'
+          end
+
+          example '1.0.0-rc1' do
+            version = subject('1.0.0-rc1')
+            expect(version.major).to eql 1
+            expect(version.minor).to eql 0
+            expect(version.patch).to eql 0
+            expect(version.prerelease).to eql 'rc1'
+          end
+        end
+      end
+    end
+
+  end
+
+  describe '#<=>' do
+    def parse(vstring)
+      Semantic::Version.parse(vstring)
+    end
+
+    context 'Spec v2.0.0' do
+      context 'Section 11' do
+        # Precedence refers to how versions are compared to each other when
+        # ordered. Precedence MUST be calculated by separating the version into
+        # major, minor, patch and pre-release identifiers in that order (Build
+        # metadata does not figure into precedence). Precedence is determined
+        # by the first difference when comparing each of these identifiers from
+        # left to right as follows: Major, minor, and patch versions are always
+        # compared numerically.
+        # Example: 1.0.0 < 2.0.0 < 2.1.0 < 2.1.1.
+        # When major, minor, and patch are equal, a pre-release version has
+        # lower precedence than a normal version.
+        # Example: 1.0.0-alpha < 1.0.0.
+        # Precedence for two pre-release versions with the same major, minor,
+        # and patch version MUST be determined by comparing each dot separated
+        # identifier from left to right until a difference is found as follows:
+        # identifiers consisting of only digits are compared numerically and
+        # identifiers with letters or hyphens are compared lexically in ASCII
+        # sort order. Numeric identifiers always have lower precedence than
+        # non-numeric identifiers. A larger set of pre-release fields has a
+        # higher precedence than a smaller set, if all of the preceding
+        # identifiers are equal.
+        # Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta
+        # < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0.
+
+        context 'comparisons without prereleases' do
+          subject do
+            %w[ 1.0.0 2.0.0 2.1.0 2.1.1 ].map { |v| parse(v) }.shuffle
+          end
+
+          example 'sorted order' do
+            sorted = subject.sort.map { |v| v.to_s }
+            expect(sorted).to eql(%w[ 1.0.0 2.0.0 2.1.0 2.1.1 ])
+          end
+        end
+
+        context 'comparisons against prereleases' do
+          let(:stable) { parse('1.0.0') }
+          let(:prerelease) { parse('1.0.0-alpha') }
+
+          example 'prereleases have lower precedence' do
+            expect(stable).to be > prerelease
+            expect(prerelease).to be < stable
+          end
+        end
+
+        context 'comparisions between prereleases' do
+          example 'identical prereleases are equal' do
+            expect(parse('1.0.0-rc1')).to eql parse('1.0.0-rc1')
+          end
+
+          example 'non-numeric identifiers sort ASCIIbetically' do
+            alpha, beta = parse('1.0.0-alpha'), parse('1.0.0-beta')
+            expect(alpha).to be < beta
+            expect(beta).to be > alpha
+          end
+
+          example 'numeric identifiers sort numerically' do
+            two, eleven = parse('1.0.0-2'), parse('1.0.0-11')
+            expect(two).to be < eleven
+            expect(eleven).to be > two
+          end
+
+          example 'non-numeric identifiers have a higher precendence' do
+            number, word = parse('1.0.0-1'), parse('1.0.0-one')
+            expect(number).to be < word
+            expect(word).to be > number
+          end
+
+          example 'identifiers are parsed left-to-right' do
+            a = parse('1.0.0-these.parts.are.the-same.but.not.waffles.123')
+            b = parse('1.0.0-these.parts.are.the-same.but.not.123.waffles')
+            expect(b).to be < a
+            expect(a).to be > b
+          end
+
+          example 'larger identifier sets have precendence' do
+            a = parse('1.0.0-alpha')
+            b = parse('1.0.0-alpha.1')
+            expect(a).to be < b
+            expect(b).to be > a
+          end
+
+          example 'build metadata does not figure into precendence' do
+            a = parse('1.0.0-alpha+SHA1')
+            b = parse('1.0.0-alpha+MD5')
+            expect(a).to eql b
+            expect(a.to_s).to_not eql b.to_s
+          end
+
+          example 'sorted order' do
+            list = %w[
+              1.0.0-alpha
+              1.0.0-alpha.1
+              1.0.0-alpha.beta
+              1.0.0-beta
+              1.0.0-beta.2
+              1.0.0-beta.11
+              1.0.0-rc.1
+              1.0.0
+            ].map { |v| parse(v) }.shuffle
+
+            sorted = list.sort.map { |v| v.to_s }
+            expect(sorted).to eql %w[
+              1.0.0-alpha
+              1.0.0-alpha.1
+              1.0.0-alpha.beta
+              1.0.0-beta
+              1.0.0-beta.2
+              1.0.0-beta.11
+              1.0.0-rc.1
+              1.0.0
+            ]
+          end
+        end
+      end
+    end
+
+    context 'Spec v1.0.0' do
+      context 'Section 4' do
+        # A pre-release version number MAY be denoted by appending an arbitrary
+        # string immediately following the patch version and a dash. The string
+        # MUST be comprised of only alphanumerics plus dash [0-9A-Za-z-].
+        # Pre-release versions satisfy but have a lower precedence than the
+        # associated normal version. Precedence SHOULD be determined by
+        # lexicographic ASCII sort order.
+        # For instance: 1.0.0-alpha1 < 1.0.0-beta1 < 1.0.0-beta2 < 1.0.0-rc1 <
+        # 1.0.0
+
+        example 'sorted order' do
+          list = %w[
+            1.0.0-alpha1
+            1.0.0-beta1
+            1.0.0-beta2
+            1.0.0-rc1
+            1.0.0
+          ].map { |v| parse(v) }.shuffle
+
+          sorted = list.sort.map { |v| v.to_s }
+          expect(sorted).to eql %w[
+            1.0.0-alpha1
+            1.0.0-beta1
+            1.0.0-beta2
+            1.0.0-rc1
+            1.0.0
+          ]
+        end
+      end
+    end
+
+  end
+
+  describe '#next' do
+    context 'with :major' do
+      it 'returns the next major version' do
+        expect(subject('1.0.0').next(:major)).to eql(subject('2.0.0'))
+      end
+
+      it 'does not modify the original version' do
+        v1 = subject('1.0.0')
+        v2 = v1.next(:major)
+        expect(v1).to_not eql(v2)
+      end
+
+      it 'resets the minor and patch versions to 0' do
+        expect(subject('1.1.1').next(:major)).to eql(subject('2.0.0'))
+      end
+
+      it 'removes any prerelease or build information' do
+        expect(subject('1.0.0-alpha+abc').next(:major)).to eql(subject('2.0.0'))
+      end
+    end
+
+    context 'with :minor' do
+      it 'returns the next minor version' do
+        expect(subject('1.0.0').next(:minor)).to eql(subject('1.1.0'))
+      end
+
+      it 'does not modify the original version' do
+        v1 = subject('1.0.0')
+        v2 = v1.next(:minor)
+        expect(v1).to_not eql(v2)
+      end
+
+      it 'resets the patch version to 0' do
+        expect(subject('1.1.1').next(:minor)).to eql(subject('1.2.0'))
+      end
+
+      it 'removes any prerelease or build information' do
+        expect(subject('1.1.0-alpha+abc').next(:minor)).to eql(subject('1.2.0'))
+      end
+    end
+
+    context 'with :patch' do
+      it 'returns the next patch version' do
+        expect(subject('1.1.1').next(:patch)).to eql(subject('1.1.2'))
+      end
+
+      it 'does not modify the original version' do
+        v1 = subject('1.0.0')
+        v2 = v1.next(:patch)
+        expect(v1).to_not eql(v2)
+      end
+
+      it 'removes any prerelease or build information' do
+        expect(subject('1.0.0-alpha+abc').next(:patch)).to eql(subject('1.0.1'))
+      end
+    end
+  end
+end
\ No newline at end of file
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/version.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/version.rb
new file mode 100644
index 0000000..140c62b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppet/version.rb
@@ -0,0 +1,89 @@
+# The version method and constant are isolated in puppet/version.rb so that a
+# simple `require 'puppet/version'` allows a rubygems gemspec or bundler
+# Gemfile to get the Puppet version of the gem install.
+#
+# The version is programatically settable because we want to allow the
+# Raketasks and such to set the version based on the output of `git describe`
+
+
+module Puppet
+  PUPPETVERSION = '3.8.5'
+
+  ##
+  # version is a public API method intended to always provide a fast and
+  # lightweight way to determine the version of Puppet.
+  #
+  # The intent is that software external to Puppet be able to determine the
+  # Puppet version with no side-effects.  The expected use is:
+  #
+  #     require 'puppet/version'
+  #     version = Puppet.version
+  #
+  # This function has the following ordering precedence.  This precedence list
+  # is designed to facilitate automated packaging tasks by simply writing to
+  # the VERSION file in the same directory as this source file.
+  #
+  #  1. If a version has been explicitly assigned using the Puppet.version=
+  #     method, return that version.
+  #  2. If there is a VERSION file, read the contents, trim any
+  #     trailing whitespace, and return that version string.
+  #  3. Return the value of the Puppet::PUPPETVERSION constant hard-coded into
+  #     the source code.
+  #
+  # If there is no VERSION file, the method must return the version string of
+  # the nearest parent version that is an officially released version.  That is
+  # to say, if a branch named 3.1.x contains 25 patches on top of the most
+  # recent official release of 3.1.1, then the version method must return the
+  # string "3.1.1" if no "VERSION" file is present.
+  #
+  # By design the version identifier is _not_ intended to vary during the life
+  # a process.  There is no guarantee provided that writing to the VERSION file
+  # while a Puppet process is running will cause the version string to be
+  # updated.  On the contrary, the contents of the VERSION are cached to reduce
+  # filesystem accesses.
+  #
+  # The VERSION file is intended to be used by package maintainers who may be
+  # applying patches or otherwise changing the software version in a manner
+  # that warrants a different software version identifier.  The VERSION file is
+  # intended to be managed and owned by the release process and packaging
+  # related tasks, and as such should not reside in version control.  The
+  # PUPPETVERSION constant is intended to be version controlled in history.
+  #
+  # Ideally, this behavior will allow package maintainers to precisely specify
+  # the version of the software they're packaging as in the following example:
+  #
+  #     $ git describe --match "3.0.*" > lib/puppet/VERSION
+  #     $ ruby -r puppet -e 'puts Puppet.version'
+  #     3.0.1-260-g9ca4e54
+  #
+  # @api public
+  #
+  # @return [String] containing the puppet version, e.g. "3.0.1"
+  def self.version
+    version_file = File.join(File.dirname(__FILE__), 'VERSION')
+    return @puppet_version if @puppet_version
+    if version = read_version_file(version_file)
+      @puppet_version = version
+    end
+    @puppet_version ||= PUPPETVERSION
+  end
+
+  def self.version=(version)
+    @puppet_version = version
+  end
+
+  ##
+  # read_version_file reads the content of the "VERSION" file that lives in the
+  # same directory as this source code file.
+  #
+  # @api private
+  #
+  # @return [String] for example: "1.6.14-6-gea42046" or nil if the VERSION
+  #   file does not exist.
+  def self.read_version_file(path)
+    if File.exist?(path)
+      File.read(path).chomp
+    end
+  end
+  private_class_method :read_version_file
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppetx.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppetx.rb
new file mode 100644
index 0000000..adba0fc
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppetx.rb
@@ -0,0 +1,89 @@
+# The Puppet Extensions Module.
+#
+# Submodules of this module should be named after the publisher (e.g. 'user' part of a Puppet Module name).
+# The submodule {Puppetx::Puppet} contains the puppet extension points.
+#
+# This module also contains constants that are used when defining extensions.
+#
+# @api public
+#
+module Puppetx
+
+  # The lookup **key** for the multibind containing syntax checkers used to syntax check embedded string in non
+  # puppet DSL syntax.
+  # @api public
+  SYNTAX_CHECKERS       = 'puppetx::puppet::syntaxcheckers'
+
+  # The lookup **type** for the multibind containing syntax checkers used to syntax check embedded string in non
+  # puppet DSL syntax.
+  # @api public
+  SYNTAX_CHECKERS_TYPE  = 'Puppetx::Puppet::SyntaxChecker'
+
+  # The lookup **key** for the multibind containing a map from scheme name to scheme handler class for bindings schemes.
+  # @api public
+  BINDINGS_SCHEMES      = 'puppetx::puppet::bindings::schemes'
+
+  # The lookup **type** for the multibind containing a map from scheme name to scheme handler class for bindings schemes.
+  # @api public
+  BINDINGS_SCHEMES_TYPE = 'Puppetx::Puppet::BindingsSchemeHandler'
+
+  # This module is the name space for extension points
+  # @api public
+  module Puppet
+
+    if ::Puppet[:binder] || ::Puppet.future_parser?
+        # Extension-points are registered here:
+        # - If in a Ruby submodule it is best to create it here
+        # - The class does not have to be required; it will be auto required when the binder
+        #   needs it.
+        # - If the extension is a multibind, it can be registered here; either with a required
+        #   class or a class reference in string form.
+
+        # Register extension points
+        # -------------------------
+        system_bindings = ::Puppet::Pops::Binder::SystemBindings
+        extensions = system_bindings.extensions()
+        extensions.multibind(SYNTAX_CHECKERS).name(SYNTAX_CHECKERS).hash_of(SYNTAX_CHECKERS_TYPE)
+        extensions.multibind(BINDINGS_SCHEMES).name(BINDINGS_SCHEMES).hash_of(BINDINGS_SCHEMES_TYPE)
+
+        # Register injector boot bindings
+        # -------------------------------
+        boot_bindings = system_bindings.injector_boot_bindings()
+
+        # Register the default bindings scheme handlers
+        require 'puppetx/puppet/bindings_scheme_handler'
+        { 'module'        => 'ModuleScheme', 
+          'confdir'       => 'ConfdirScheme',
+        }.each do |scheme, class_name|
+          boot_bindings.bind.name(scheme).instance_of(BINDINGS_SCHEMES_TYPE).in_multibind(BINDINGS_SCHEMES).
+            to_instance("Puppet::Pops::Binder::SchemeHandler::#{class_name}")
+        end
+      end
+  end
+
+  # Module with implementations of various extensions
+  # @api public
+  module Puppetlabs
+    # Default extensions delivered in Puppet Core are included here
+
+    # @api public
+    module SyntaxCheckers
+      if ::Puppet[:binder] || ::Puppet.future_parser?
+
+        # Classes in this name-space are lazily loaded as they may be overridden and/or never used
+        # (Lazy loading is done by binding to the name of a class instead of a Class instance).
+
+        # Register extensions
+        # -------------------
+        system_bindings = ::Puppet::Pops::Binder::SystemBindings
+        bindings = system_bindings.default_bindings()
+        bindings.bind do
+          name('json')
+          instance_of(SYNTAX_CHECKERS_TYPE)
+          in_multibind(SYNTAX_CHECKERS)
+          to_instance('Puppetx::Puppetlabs::SyntaxCheckers::Json')
+        end
+      end
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppetx/puppet/bindings_scheme_handler.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppetx/puppet/bindings_scheme_handler.rb
new file mode 100644
index 0000000..8ae66d3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppetx/puppet/bindings_scheme_handler.rb
@@ -0,0 +1,130 @@
+module Puppetx::Puppet
+  # BindingsSchemeHandler is a Puppet Extension Point for the purpose of extending Puppet with a
+  # handler of a URI scheme used in the Puppet Bindings / Injector system.
+  # The intended use is to create a class derived from this class and then register it with the
+  # Puppet Binder.
+  #
+  # Creating the Extension Class
+  # ----------------------------
+  # As an example, a class for getting LDAP data and transforming into bindings based on an LDAP URI scheme (such as RFC 2255, 4516)
+  # may be authored in say a puppet module called 'exampleorg/ldap'. The name of the class should start with `Puppetx::<user>::<module>`,
+  # e.g. 'Puppetx::Exampleorg::Ldap::LdapBindingsSchemeHandler" and
+  # be located in `lib/puppetx/exampleorg/Ldap/LdapBindingsSchemeHandler.rb`. (These rules are not enforced, but it make the class
+  # both auto-loadable, and guaranteed to not have a name that clashes with some other LdapBindingsSchemeHandler from some other
+  # author/organization.
+  #
+  # The Puppet Binder will auto-load the file when it
+  # has a binding to the class `Puppetx::Exampleorg::Ldap::LdapBindingsSchemeHandler'
+  # The Ruby Module `Puppetx` is created by Puppet, the remaining modules should be created by the loaded logic - e.g.:
+  #
+  # @example Defining an LdapBindingsSchemeHandler
+  #   module Puppetx::Exampleorg
+  #     module Ldap
+  #       class LdapBindingsSchemeHandler < Puppetx::Puppetlabs::BindingsSchemeHandler
+  #         # implement the methods
+  #       end
+  #     end
+  #   end
+  #
+  #
+  # The expand_included method
+  # --------------------------
+  # This method is given a URI (as entred by a user in a bindings configuration) and the handler's first task is to
+  # perform checking, transformation, and possible expansion into multiple URIs for loading. The result is always an array
+  # of URIs. This method allows users to enter wild-cards, or to represent something symbolic that is transformed into one or
+  # more "real URIs" to load. (It is allowed to change scheme!).
+  # If the "optional" feature is supported, the handler should not include the URI in the result unless it will be able to produce
+  # bindings for the given URI (as an option it may produce an empty set of bindings).
+  #
+  # The expand_excluded method
+  # ---------------------------
+  # This method is given an URI (as entered by the user in a bindings configuration), and it is the handler's second task
+  # to perform checking, transformation, and possible expansion into multiple URIs that should not be loaded. The result is always
+  # an array of URIs. The user may be allowed to enter wild-cards etc. The URIs produced by this method should have the same syntax
+  # as those produced by {#expand_included} since they are excluded by comparison.
+  #
+  # The contributed_bindings method
+  # -------------------------------
+  # As the last step, the handler is being called once per URI that was included, and not later excluded to produce the
+  # contributed bindings. It is given three arguments, uri (the uri to load), scope (to provide access to the rest of the
+  # environment), and an acceptor (of issues), on which issues can be recorded.
+  #
+  # Reporting Errors/Issues
+  # -----------------------
+  # Issues are reported by calling the given composer's acceptor, which takes a severity (e.g. `:error`,
+  # `:warning`, or `:ignore`), an {Puppet::Pops::Issues::Issue Issue} instance, and a {Puppet::Pops::Adapters::SourcePosAdapter
+  # SourcePosAdapter} (which describes details about linenumber, position, and length of the problem area). If the scheme is
+  # not based on file, line, pos - nil can be passed. The URI itself can be passed as file.
+  #
+  # @example Reporting an issue
+  #    # create an issue with a symbolic name (that can serve as a reference to more details about the problem),
+  #    # make the name unique
+  #    issue = Puppet::Pops::Issues::issue(:EXAMPLEORG_LDAP_ILLEGAL_URI) { "The URI is not a valid Ldap URI" }
+  #    source_pos = nil
+  #
+  #    # report it
+  #    composer.acceptor.accept(Puppet::Pops::Validation::Diagnostic.new(:error, issue, uri.to_s, source_pos, {}))
+  #
+  # Instead of reporting issues, an exception can be raised.
+  #
+  # @abstract
+  # @api public
+  #
+  class BindingsSchemeHandler
+
+    # Produces the bindings contributed to the binding system based on the given URI.
+    # @param uri [URI] the URI to load bindings from
+    # @param scope [Puppet::Pops::Parser::Scope] access to scope and the rest of the environment
+    # @param composer [Puppet::Pops::Binder::BindingsComposer] a composer giving access to modules by name, and a diagnostics acceptor
+    # @return [Puppet::Pops::Binder::Bindings::ContributedBindings] the bindings to contribute, most conveniently
+    #   created by calling {Puppet::Pops::Binder::BindingsFactory.contributed_bindings}.
+    # @api public
+    #
+    def contributed_bindings(uri, scope, composer)
+      raise NotImplementedError, "The BindingsProviderScheme for uri: '#{uri}' must implement 'contributed_bindings'"
+    end
+
+    # Expands the given URI for the purpose of including the bindings it refers to. The input may contain
+    # wild-cards (if supported by this handler), and it is this methods responsibility to transform such into
+    # real loadable URIs.
+    #
+    # A scheme handler that does not support optionality, or wildcards should simply return the given URI
+    # in an Array.
+    #
+    # @param uri [URI] the uri for which bindings are to be produced.
+    # @param composer [Puppet::Pops::Binder::BindingsComposer] a composer giving access to modules by name, and a diagnostics acceptor
+    # @return [Array<URI>] the transformed, and possibly expanded set of URIs to include.
+    # @api public
+    #
+    def expand_included(uri, composer)
+      [uri]
+    end
+
+    # Expands the given URI for the purpose of excluding the bindings it refers to. The input may contain
+    # wild-cards (if supported by this handler), and it is this methods responsibility to transform such into
+    # real loadable URIs (that match those produced by {#expand_included} that should be excluded from the result.
+    #
+    # A scheme handler that does not support optionality, or wildcards should simply return the given URI
+    # in an Array.
+    #
+    # @param uri [URI] the uri for which bindings are to be produced.
+    # @param composer [Puppet::Pops::Binder::BindingsComposer] a composer giving access to modules by name, and a diagnostics acceptor
+    # @return [Array<URI>] the transformed, and possibly expanded set of URIs to include-
+    # @api public
+    #
+    def expand_excluded(uri, composer)
+      [uri]
+    end
+
+    # Returns whether the uri is optional or not. A scheme handler does not have to use this method
+    # to determine optionality, but if it supports such a feature, and there is no technical problem in supporting
+    # it this way, it should be done the same (or at least similar) way across all scheme handlers.
+    #
+    # This method interprets a URI ending with `?` or has query that is '?optional' as optional.
+    #
+    # @return [Boolean] whether the uri is an optional reference or not.
+    def is_optional?(uri)
+      (query = uri.query) && query == '' || query == 'optional'
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppetx/puppet/syntax_checker.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppetx/puppet/syntax_checker.rb
new file mode 100644
index 0000000..d46ac8f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppetx/puppet/syntax_checker.rb
@@ -0,0 +1,91 @@
+module Puppetx::Puppet
+  # SyntaxChecker is a Puppet Extension Point for the purpose of extending Puppet with syntax checkers.
+  # The intended use is to create a class derived from this class and then register it with the
+  # Puppet Binder.
+  #
+  # Creating the Extension Class
+  # ----------------------------
+  # As an example, a class for checking custom xml (aware of some custom schemes) may be authored in
+  # say a puppet module called 'exampleorg/xmldata'. The name of the class should start with `Puppetx::<user>::<module>`,
+  # e.g. 'Puppetx::Exampleorg::XmlData::XmlChecker" and
+  # be located in `lib/puppetx/exampleorg/xml_data/xml_checker.rb`. The Puppet Binder will auto-load this file when it
+  # has a binding to the class `Puppetx::Exampleorg::XmlData::XmlChecker'
+  # The Ruby Module `Puppetx` is created by Puppet, the remaining modules should be created by the loaded logic - e.g.:
+  #
+  # @example Defining an XmlChecker
+  #   module Puppetx::Exampleorg
+  #     module XmlData
+  #       class XmlChecker < Puppetx::Puppetlabs::SyntaxCheckers::SyntaxChecker
+  #         def check(text, syntax_identifier, acceptor, location_hash)
+  #            # do the checking
+  #         end
+  #       end
+  #     end
+  #   end
+  #
+  # Implementing the check method
+  # -----------------------------
+  # The implementation of the {#check} method should naturally perform syntax checking of the given text/string and
+  # produce found issues on the given `acceptor`. These can be warnings or errors. The method should return `false` if
+  # any warnings or errors were produced (it is up to the caller to check for error/warning conditions and report them
+  # to the user).
+  #
+  # Issues are reported by calling the given `acceptor`, which takes a severity (e.g. `:error`,
+  # or `:warning), an {Puppet::Pops::Issues::Issue} instance, and a {Puppet::Pops::Adapters::SourcePosAdapter}
+  # (which describes details about linenumber, position, and length of the problem area). Note that the
+  # `location_info` given to the check method holds information about the location of the string in its *container*
+  # (e.g. the source position of a Heredoc); this information can be used if more detailed information is not
+  # available, or combined if there are more details (relative to the start of the checked string).
+  #
+  # @example Reporting an issue
+  #    # create an issue with a symbolic name (that can serve as a reference to more details about the problem),
+  #    # make the name unique
+  #    issue = Puppet::Pops::Issues::issue(:EXAMPLEORG_XMLDATA_ILLEGAL_XML) { "syntax error found in xml text" }
+  #    source_pos = Puppet::Pops::Adapters::SourcePosAdapter.new()
+  #    source_pos.line = info[:line] # use this if there is no detail from the used parser
+  #    source_pos.pos = info[:pos]   # use this pos if there is no detail from used parser
+  #
+  #    # report it
+  #    acceptor.accept(Puppet::Pops::Validation::Diagnostic.new(:error, issue, info[:file], source_pos, {}))
+  #
+  # There is usually a cap on the number of errors/warnings that are presented to the user, this is handled by the
+  # reporting logic, but care should be taken to not generate too many as the issues are kept in memory until
+  # the checker returns. The acceptor may set a limit and simply ignore issues past a certain (high) number of reported
+  # issues (this number is typically higher than the cap on issues reported to the user).
+  #
+  # The `syntax_identifier`
+  # -----------------------
+  # The extension makes use of a syntax identifier written in mime-style. This identifier can be something simple
+  # as 'xml', or 'json', but can also consist of several segments joined with '+' where the most specific syntax variant
+  # is placed first. When searching for a syntax checker; say for JSON having some special traits, say 'userdata', the
+  # author of the text may indicate this as the text having the syntax "userdata+json" - when a checker is looked up it is
+  # first checked if there is a checker for "userdata+json", if none is found, a lookup is made for "json" (since the text
+  # must at least be valid json). The given identifier is passed to the checker (to allow the same checker to check for
+  # several dialects/specializations).
+  #
+  # Use in Puppet DSL
+  # -----------------
+  # The Puppet DSL Heredoc support and Puppet Templates makes use of the syntax checker extension. A user of a
+  # heredoc can specify the syntax in the heredoc tag, e.g.`@(END:userdata+json)`.
+  #
+  #
+  # @abstract
+  #
+  class SyntaxChecker
+    # Checks the text for syntax issues and reports them to the given acceptor.
+    # This implementation is abstract, it raises {NotImplementedError} since a subclass should have implemented the
+    # method.
+    #
+    # @param text [String] The text to check
+    # @param syntax_identifier [String] The syntax identifier in mime style (e.g. 'json', 'json-patch+json', 'xml', 'myapp+xml'
+    # @option location_info [String] :file The filename where the string originates
+    # @option location_info [Integer] :line The line number identifying the location where the string is being used/checked
+    # @option location_info [Integer] :position The position on the line identifying the location where the string is being used/checked
+    # @return [Boolean] Whether the checked string had issues (warnings and/or errors) or not.
+    # @api public
+    #
+    def check(text, syntax_identifier, acceptor, location_info)
+      raise NotImplementedError, "The class #{self.class.name} should have implemented the method check()"
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppetx/puppetlabs/syntax_checkers/json.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppetx/puppetlabs/syntax_checkers/json.rb
new file mode 100644
index 0000000..c12e0e5
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/puppetx/puppetlabs/syntax_checkers/json.rb
@@ -0,0 +1,37 @@
+# A syntax checker for JSON.
+# @api public
+require 'puppetx/puppet/syntax_checker'
+class Puppetx::Puppetlabs::SyntaxCheckers::Json < Puppetx::Puppet::SyntaxChecker
+
+  # Checks the text for JSON syntax issues and reports them to the given acceptor.
+  # This implementation is abstract, it raises {NotImplementedError} since a subclass should have implemented the
+  # method.
+  #
+  # Error messages from the checker are capped at 100 chars from the source text.
+  #
+  # @param text [String] The text to check
+  # @param syntax [String] The syntax identifier in mime style (e.g. 'json', 'json-patch+json', 'xml', 'myapp+xml'
+  # @param acceptor [#accept] A Diagnostic acceptor
+  # @param source_pos [Puppet::Pops::Adapters::SourcePosAdapter] A source pos adapter with location information
+  # @api public
+  #
+  def check(text, syntax, acceptor, source_pos)
+    raise ArgumentError.new("Json syntax checker: the text to check must be a String.") unless text.is_a?(String)
+    raise ArgumentError.new("Json syntax checker: the syntax identifier must be a String, e.g. json, data+json") unless syntax.is_a?(String)
+    raise ArgumentError.new("Json syntax checker: invalid Acceptor, got: '#{acceptor.class.name}'.") unless acceptor.is_a?(Puppet::Pops::Validation::Acceptor)
+    #raise ArgumentError.new("Json syntax checker: location_info must be a Hash") unless location_info.is_a?(Hash)
+
+    begin
+      JSON.parse(text)
+    rescue => e
+      # Cap the message to 100 chars and replace newlines
+      msg = "JSON syntax checker: Cannot parse invalid JSON string. \"#{e.message().slice(0,100).gsub(/\r?\n/, "\\n")}\""
+
+      # TODO: improve the pops API to allow simpler diagnostic creation while still maintaining capabilities
+      # and the issue code. (In this case especially, where there is only a single error message being issued).
+      #
+      issue = Puppet::Pops::Issues::issue(:ILLEGAL_JSON) { msg }
+      acceptor.accept(Puppet::Pops::Validation::Diagnostic.new(:error, issue, source_pos.locator.file, source_pos, {}))
+    end
+  end
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/semver.rb b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/semver.rb
new file mode 100644
index 0000000..01ff1eb
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/ruby/vendor_ruby/semver.rb
@@ -0,0 +1,124 @@
+require 'puppet/util/monkey_patches'
+
+# We need to subclass Numeric to force range comparisons not to try to iterate over SemVer
+# and instead use numeric comparisons (eg >, <, >=, <=)
+# Ruby 1.8 already did this for all ranges, but Ruby 1.9 changed range include behavior
+class SemVer < Numeric
+  include Comparable
+
+  VERSION = /^v?(\d+)\.(\d+)\.(\d+)(-[0-9A-Za-z-]*|)$/
+  SIMPLE_RANGE = /^v?(\d+|[xX])(?:\.(\d+|[xX])(?:\.(\d+|[xX]))?)?$/
+
+  def self.valid?(ver)
+    VERSION =~ ver
+  end
+
+  def self.find_matching(pattern, versions)
+    versions.select { |v| v.matched_by?("#{pattern}") }.sort.last
+  end
+
+  def self.pre(vstring)
+    vstring =~ /-/ ? vstring : vstring + '-'
+  end
+
+  def self.[](range)
+    range.gsub(/([><=])\s+/, '\1').split(/\b\s+(?!-)/).map do |r|
+      case r
+      when SemVer::VERSION
+        SemVer.new(pre(r)) .. SemVer.new(r)
+      when SemVer::SIMPLE_RANGE
+        r += ".0" unless SemVer.valid?(r.gsub(/x/i, '0'))
+        SemVer.new(r.gsub(/x/i, '0'))...SemVer.new(r.gsub(/(\d+)\.x/i) { "#{$1.to_i + 1}.0" } + '-')
+      when /\s+-\s+/
+        a, b = r.split(/\s+-\s+/)
+        SemVer.new(pre(a)) .. SemVer.new(b)
+      when /^~/
+        ver = r.sub(/~/, '').split('.').map(&:to_i)
+        start = (ver + [0] * (3 - ver.length)).join('.')
+
+        ver.pop unless ver.length == 1
+        ver[-1] = ver.last + 1
+
+        finish = (ver + [0] * (3 - ver.length)).join('.')
+        SemVer.new(pre(start)) ... SemVer.new(pre(finish))
+      when /^>=/
+        ver = r.sub(/^>=/, '')
+        SemVer.new(pre(ver)) .. SemVer::MAX
+      when /^<=/
+        ver = r.sub(/^<=/, '')
+        SemVer::MIN .. SemVer.new(ver)
+      when /^>/
+        if r =~ /-/
+          ver = [r[1..-1]]
+        else
+          ver = r.sub(/^>/, '').split('.').map(&:to_i)
+          ver[2] = ver.last + 1
+        end
+        SemVer.new(ver.join('.') + '-') .. SemVer::MAX
+      when /^</
+        ver = r.sub(/^</, '')
+        SemVer::MIN ... SemVer.new(pre(ver))
+      else
+        (1..1)
+      end
+    end.inject { |a,e| a & e }
+  end
+
+  attr_reader :major, :minor, :tiny, :special
+
+  def initialize(ver)
+    unless SemVer.valid?(ver)
+      raise ArgumentError.new("Invalid version string '#{ver}'!")
+    end
+
+    @major, @minor, @tiny, @special = VERSION.match(ver).captures.map do |x|
+      # Because Kernel#Integer tries to interpret hex and octal strings, which
+      # we specifically do not want, and which cannot be overridden in 1.8.7.
+      Float(x).to_i rescue x
+    end
+  end
+
+  def <=>(other)
+    other = SemVer.new("#{other}") unless other.is_a? SemVer
+    return self.major <=> other.major unless self.major == other.major
+    return self.minor <=> other.minor unless self.minor == other.minor
+    return self.tiny  <=> other.tiny  unless self.tiny  == other.tiny
+
+    return 0  if self.special  == other.special
+    return 1  if self.special  == ''
+    return -1 if other.special == ''
+
+    return self.special <=> other.special
+  end
+
+  def matched_by?(pattern)
+    # For the time being, this is restricted to exact version matches and
+    # simple range patterns.  In the future, we should implement some or all of
+    # the comparison operators here:
+    # https://github.com/isaacs/node-semver/blob/d474801/semver.js#L340
+
+    case pattern
+    when SIMPLE_RANGE
+      pattern = SIMPLE_RANGE.match(pattern).captures
+      pattern[1] = @minor unless pattern[1] && pattern[1] !~ /x/i
+      pattern[2] = @tiny  unless pattern[2] && pattern[2] !~ /x/i
+      [@major, @minor, @tiny] == pattern.map { |x| x.to_i }
+    when VERSION
+      self == SemVer.new(pattern)
+    else
+      false
+    end
+  end
+
+  def inspect
+    @vstring || "v#{@major}.#{@minor}.#{@tiny}#{@special}"
+  end
+  alias :to_s :inspect
+
+  MIN = SemVer.new('0.0.0-')
+  MIN.instance_variable_set(:@vstring, 'vMIN')
+
+  MAX = SemVer.new('8.0.0')
+  MAX.instance_variable_set(:@major, Float::INFINITY) # => Infinity
+  MAX.instance_variable_set(:@vstring, 'vMAX')
+end
diff --git a/debian/stretch/puppet-linex-common/usr/lib/tmpfiles.d/puppet-common.conf b/debian/stretch/puppet-linex-common/usr/lib/tmpfiles.d/puppet-common.conf
new file mode 100644
index 0000000..baf6a4e
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/lib/tmpfiles.d/puppet-common.conf
@@ -0,0 +1 @@
+d /run/puppet 0755 puppet puppet - -
diff --git a/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/NEWS.Debian.gz b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/NEWS.Debian.gz
new file mode 100644
index 0000000..fca8768
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/NEWS.Debian.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/README.Debian b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/README.Debian
new file mode 100644
index 0000000..d23dc07
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/README.Debian
@@ -0,0 +1,26 @@
+puppet for Debian
+------------------
+
+To enable the puppet agent after installation, run
+
+ "puppet agent --enable"
+
+The default puppet configuration in Debian will automatically integrate with
+etckeeper if etckeeper is installed. puppet will automatically commit any
+changes made to files in /etc via etckeeper before and after its run.
+
+ -- Stig Sandbeck Mathisen <ssm@debian.org>, Mon,  5 Aug 2013 23:36:19 +0200
+
+Using stored configs
+--------------------
+
+Using the master's stored configs functionality with the ActiveRecord backend
+requires the ruby-activerecord (and, since Jessie,
+ruby-activerecord-deprecated-finders) packages to be installed. Furthermore a
+database adapter for the database of choice (e.g. ruby-mysql) must be
+installed.
+
+Note that ActiveRecord-based stored configs are deprecated and will be removed
+in Puppet 4 in favor of PuppetDB.
+
+ -- Apollon Oikonomopulos <apoikos@debian.org>  Thu, 12 Mar 2015 10:50:47 +0200
diff --git a/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/README.md b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/README.md
new file mode 100644
index 0000000..a0747d1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/README.md
@@ -0,0 +1,76 @@
+Puppet
+======
+
+[![Build Status](https://travis-ci.org/puppetlabs/puppet.png?branch=master)](https://travis-ci.org/puppetlabs/puppet)
+[![Inline docs](http://inch-ci.org/github/puppetlabs/puppet.png)](http://inch-ci.org/github/puppetlabs/puppet)
+
+Puppet, an automated administrative engine for your Linux, Unix, and Windows systems, performs
+administrative tasks (such as adding users, installing packages, and updating server
+configurations) based on a centralized specification.
+
+Documentation
+-------------
+
+Documentation for Puppet and related projects can be found online at the
+[Puppet Docs site](http://docs.puppetlabs.com).
+
+HTTP API
+--------
+[HTTP API Index](api/docs/http_api_index.md)
+
+Installation
+------------
+
+The best way to run Puppet is with [Puppet Enterprise](http://puppetlabs.com/puppet/puppet-enterprise),
+which also includes orchestration features, a web console, and professional support.
+[The PE documentation is available here.](http://docs.puppetlabs.com/pe/latest)
+
+To install an open source release of Puppet,
+[see the installation guide on the docs site.](http://docs.puppetlabs.com/guides/installation.html)
+
+If you need to run Puppet from source as a tester or developer,
+[see the running from source guide on the docs site.](http://docs.puppetlabs.com/guides/from_source.html)
+
+Developing and Contributing
+------
+
+We'd love to get contributions from you! For a quick guide to getting your
+system setup for developing take a look at our [Quickstart
+Guide](docs/quickstart.md). Once you are up and running, take a look at the
+[Contribution Documents](CONTRIBUTING.md) to see how to get your changes merged
+in.
+
+For more complete docs on developing with puppet you can take a look at the
+rest of the [developer documents](docs/index.md).
+
+License
+-------
+
+See [LICENSE](LICENSE) file.
+
+Support
+-------
+
+Please log tickets and issues at our [JIRA tracker](http://tickets.puppetlabs.com).  A [mailing
+list](https://groups.google.com/forum/?fromgroups#!forum/puppet-users) is
+available for asking questions and getting help from others. In addition there
+is an active #puppet channel on Freenode.
+
+We use semantic version numbers for our releases, and recommend that users stay
+as up-to-date as possible by upgrading to patch releases and minor releases as
+they become available.
+
+Bugfixes and ongoing development will occur in minor releases for the current
+major version. Security fixes will be backported to a previous major version on
+a best-effort basis, until the previous major version is no longer maintained.
+
+
+For example: If a security vulnerability is discovered in Puppet 4.1.1, we
+would fix it in the 4 series, most likely as 4.1.2. Maintainers would then make
+a best effort to backport that fix onto the latest Puppet 3 release.
+
+Long-term support, including security patches and bug fixes, is available for
+commercial customers. Please see the following page for more details:
+
+[Puppet Enterprise Support Lifecycle](http://puppetlabs.com/misc/puppet-enterprise-lifecycle)
+
diff --git a/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/changelog.Debian.gz b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/changelog.Debian.gz
new file mode 100644
index 0000000..79a12aa
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/changelog.Debian.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/copyright b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/copyright
new file mode 100644
index 0000000..b1c7e19
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/copyright
@@ -0,0 +1,472 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: Puppet
+Source: https://github.com/puppetlabs/puppet
+
+Files: *
+Copyright: 2004-2012 Puppet Labs Inc
+           2008 Google Inc.
+           2013, 2014 Adrien Thebo
+           2012, 2013, 2014 Andrew Parker
+           2013 Branan Purvine-Riley
+           2014 Brandon High
+           2014 Britt Gresham
+           2011 Bryan Kearney <bkearney@redhat.com>
+           2014 Charlie Sharpsteen
+           2014 Chris Price
+           2011, 2012 Daniel Pittman
+           2013 Dominic Cleal
+           2012, 2014 Eric Sorenson
+           2013 Erik Dalén
+           2014 Ethan J. Brown
+           2012 Hailee Kenney
+           2013, 2014 Henrik Lindberg
+           2011 Jacob Helwig
+           2008, 2009, 2010, 2011 James Turnbull
+           2012,2013 Jeff McCune <jeff.mccune@northstarlabs.net>
+           2012 Jeff Weiss
+           2005 Jesse Koontz
+           2010 Jesse Wolfe
+           2012, 2013, 2014 Josh Cooper
+           2013, 2014 Josh Partlow
+           2012, 2013 Justin Stoller
+           2012 Kelsey Hightower
+           2012 Ken Barber
+           2013, 2014 Kylo Ginsberg
+           2005, 2007, 2008, 2009, 2011 Luke Kanies
+           2009 Markus Roberts
+           2010 Mathias Gug
+           2010, 2011 Matt Robinson
+           2012 Matthaus Litteken
+           2012, 2013 Matthaus Owens
+           2012 Micah Anderson
+           2012 Michael Stahnke
+           2012, 2013 Moses Mendoza
+           2011,2013 Nick Fagerlund
+           2012, 2013 Patrick Carlisle
+           2010 Paul Berry
+           2012 R. Tyler Croy
+           2011 R.I.Pienaar
+           2010 Rein Henrichs
+           2008 Sean E. Millichamp
+           2012 Stig Sandbeck Mathisen
+           2013 Thomas Linkin
+           2006, 2007 lutter
+           2006 mpalmer
+License: Apache-2.0
+ Puppet - Automating Configuration Management.
+ .
+ Copyright (C) 2011 Puppet Labs Inc
+ .
+ Puppet Labs can be contacted at: info@puppetlabs.com
+ .
+ Licensed under the Apache License, Version 2.0 (the "License"); you
+ may not use this file except in compliance with the License. You may
+ obtain a copy of the License at
+ .
+ http://www.apache.org/licenses/LICENSE-2.0
+ .
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ permissions and limitations under the License.
+ .
+ For a local copy of the license, see /usr/share/common-licenses/Apache-2.0
+
+Files: ext/envpuppet
+Copyright: 2010, 2011 Jeff McCune <jeff@puppetlabs.com>
+           2012 Micah Anderson
+           2013 Patrick Carlisle
+           2012 rahul
+License: BSD-3-clause
+
+Files: debian/*
+Copyright: 2008-2012 Micah Anderson <micah@debian.org>,
+           2009-2014 Stig Sandbeck Mathisen <ssm@debian.org>,
+           2009,2010 Andrew Pollock <apollock@debian.org>,
+           2010 Mathias Gug <mathiaz@ubuntu.com>,
+           2009,2010 Nigel Kersten <nigel@explanatorygap.net>,
+           2007-2010 Thom May <thom@debian.org>,
+           2006,2007 Matthew Palmer <mpalmer@debian.org>,
+           2006,2007 Jamie Wilkinson <jaq@debian.org>,
+           2008 James Turnbull,
+           2007 Luke Kanies
+           2013 Micah Anderson
+License: GPL-2
+
+Files: install.rb
+Copyright: 2004 Austin Ziegler <ruby-install@halostatue.ca>
+           2011 Cameron Thomas
+           2011 Daniel Pittman
+           2014 Ethan J. Brown
+           2008, 2009, 2010, 2011 James Turnbull
+           2005 Jesse Koontz
+           2013 John Julien
+           2011, 2012 Josh Cooper
+           2005, 2007 Luke Kanies
+           2010 Markus Roberts
+           2010 Martin Englund
+           2011 Matt Robinson
+           2012 Matthaus Litteken
+           2012 Matthaus Owens
+           2012 Micah Anderson
+           2012, 2014 Moses Mendoza
+           2010, 2011 Nick Lewis
+           2008, 2009, 2010 Nigel Kersten
+           2013 Patrick Carlisle
+           2011, 2012 Stig Sandbeck Mathisen
+           2010, 2012 Todd Zullinger
+           2006, 2007 luke
+           2011 nfagerlund
+License: GPL-2+ or Ruby
+
+Files: conf/gentoo/init.d/puppet*
+Copyright: 1999-2008 Gentoo Foundation
+License: GPL-2
+
+Files: lib/puppet/util/rdoc/generators/template/puppet/puppet.rb
+Copyright: 2002, 2003 The FaerieMUD Consortium.
+           2008, 2009, 2013 Brice Figureau
+License: CC-BY-1.0
+
+Files: lib/puppet/external/nagios/parser.rb
+Copyright: 1999-2005 Minero Aoki
+           2012 Daniel Pittman
+           2014 Felix Frank
+           2013 Jeff McCune
+           2012, 2013 Ludovic LANGE
+           2007, 2009 Luke Kanies
+           2010 Markus Roberts
+           2011 Matt Robinson
+           2012 Micah Anderson
+License: Ruby with exception
+ This program is free software.
+ You can distribute/modify this program under the same terms of ruby.
+ .
+ As a special exception, when this code is copied by Racc
+ into a Racc output file, you may use that output file
+ without restriction.
+
+Files: lib/puppet/network/http_server/mongrel.rb
+Copyright: 2006 Manuel Holtgrewe, 2007 Luke Kanies
+License: MIT
+
+Files: examples/modules/sample-module/lib/puppet/parser/functions/hostname_to_dn.rb
+Copyright: David Schmitt <david@schmitt.edv-bus.at>
+License: BSD-3-clause
+
+License: MIT
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ .
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+ .
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+License: GPL-2
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation (version 2 of the License)
+ .
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ .
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston MA  02110-1301 USA
+ .
+ On Debian systems, the full text of the GNU General Public
+ License version 2 can be found in the file
+ "/usr/share/common-licenses/GPL-2".
+
+License: GPL-2+
+ This program is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation;
+ either version 2 of the License, or (at your option) any
+ later version.
+ .
+ This file is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty
+ of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+ .
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the Free
+ Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ .
+ On Debian systems, the full text of the GNU General Public
+ License version 2 can be found in the file
+ "/usr/share/common-licenses/GPL-2".
+
+License: CC-BY-1.0
+ THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE
+ COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY
+ COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
+ AUTHORIZED UNDER THIS LICENSE IS PROHIBITED.
+ .
+ BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE
+ BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS
+ CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND
+ CONDITIONS.
+ .
+ 1. Definitions
+ .
+ "Collective Work" means a work, such as a periodical issue, anthology or
+ encyclopedia, in which the Work in its entirety in unmodified form, along with
+ a number of other contributions, constituting separate and independent works in
+ themselves, are assembled into a collective whole. A work that constitutes a
+ Collective Work will not be considered a Derivative Work (as defined below) for
+ the purposes of this License.  "Derivative Work" means a work based upon the
+ Work or upon the Work and other pre-existing works, such as a translation,
+ musical arrangement, dramatization, fictionalization, motion picture version,
+ sound recording, art reproduction, abridgment, condensation, or any other form
+ in which the Work may be recast, transformed, or adapted, except that a work
+ that constitutes a Collective Work will not be considered a Derivative Work for
+ the purpose of this License.
+ .
+ "Licensor" means the individual or entity that offers the Work under the terms
+ of this License.  "Original Author" means the individual or entity who created
+ the Work.
+ .
+ "Work" means the copyrightable work of authorship offered under the terms of
+ this License.  "You" means an individual or entity exercising rights under this
+ License who has not previously violated the terms of this License with respect
+ to the Work, or who has received express permission from the Licensor to
+ exercise rights under this License despite a previous violation.
+ .
+ 2. Fair Use Rights. Nothing in this license is intended to reduce, limit, or
+ restrict any rights arising from fair use, first sale or other limitations on
+ the exclusive rights of the copyright owner under copyright law or other
+ applicable laws.
+ .
+ 3. License Grant. Subject to the terms and conditions of this License, Licensor
+ hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the
+ duration of the applicable copyright) license to exercise the rights in the
+ Work as stated below:
+ .
+ a. to reproduce the Work, to incorporate the Work into one or more Collective
+ Works, and to reproduce the Work as incorporated in the Collective Works;
+ .
+ b. to create and reproduce Derivative Works;
+ .
+ c. to distribute copies or phonorecords of, display publicly, perform publicly,
+ and perform publicly by means of a digital audio transmission the Work
+ including as incorporated in Collective Works;
+ .
+ d. to distribute copies or phonorecords of, display publicly, perform publicly,
+ and perform publicly by means of a digital audio transmission Derivative Works;
+ .
+ The above rights may be exercised in all media and formats whether now known or
+ hereafter devised. The above rights include the right to make such
+ modifications as are technically necessary to exercise the rights in other
+ media and formats. All rights not expressly granted by Licensor are hereby
+ reserved.
+ .
+ 4. Restrictions.
+ .
+ The license granted in Section 3 above is expressly made subject to and limited
+ by the following restrictions:
+ .
+ a. You may distribute, publicly display, publicly perform, or publicly
+ digitally perform the Work only under the terms of this License, and You must
+ include a copy of, or the Uniform Resource Identifier for, this License with
+ every copy or phonorecord of the Work You distribute, publicly display,
+ publicly perform, or publicly digitally perform. You may not offer or impose
+ any terms on the Work that alter or restrict the terms of this License or the
+ recipients' exercise of the rights granted hereunder. You may not sublicense
+ the Work. You must keep intact all notices that refer to this License and to
+ the disclaimer of warranties. You may not distribute, publicly display,
+ publicly perform, or publicly digitally perform the Work with any technological
+ measures that control access or use of the Work in a manner inconsistent with
+ the terms of this License Agreement. The above applies to the Work as
+ incorporated in a Collective Work, but this does not require the Collective
+ Work apart from the Work itself to be made subject to the terms of this
+ License. If You create a Collective Work, upon notice from any Licensor You
+ must, to the extent practicable, remove from the Collective Work any reference
+ to such Licensor or the Original Author, as requested. If You create a
+ Derivative Work, upon notice from any Licensor You must, to the extent
+ practicable, remove from the Derivative Work any reference to such Licensor or
+ the Original Author, as requested.
+ .
+ b. If you distribute, publicly display, publicly perform, or publicly digitally
+ perform the Work or any Derivative Works or Collective Works, You must keep
+ intact all copyright notices for the Work and give the Original Author credit
+ reasonable to the medium or means You are utilizing by conveying the name (or
+ pseudonym if applicable) of the Original Author if supplied; the title of the
+ Work if supplied; in the case of a Derivative Work, a credit identifying the
+ use of the Work in the Derivative Work (e.g., "French translation of the Work
+ by Original Author," or "Screenplay based on original Work by Original
+ Author"). Such credit may be implemented in any reasonable manner; provided,
+ however, that in the case of a Derivative Work or Collective Work, at a minimum
+ such credit will appear where any other comparable authorship credit appears
+ and in a manner at least as prominent as such other comparable authorship
+ credit.
+ .
+ 5. Representations, Warranties and Disclaimer
+ .
+ a. By offering the Work for public release under this License, Licensor
+ represents and warrants that, to the best of Licensor's knowledge after
+ reasonable inquiry:
+ .
+ i. Licensor has secured all rights in the Work necessary to grant the license
+ rights hereunder and to permit the lawful exercise of the rights granted
+ hereunder without You having any obligation to pay any royalties, compulsory
+ license fees, residuals or any other payments;
+ .
+ ii. The Work does not infringe the copyright, trademark, publicity rights, common
+ law rights or any other right of any third party or constitute defamation,
+ invasion of privacy or other tortious injury to any third party.
+ .
+ b. EXCEPT AS EXPRESSLY STATED IN THIS LICENSE OR OTHERWISE AGREED IN WRITING OR
+ REQUIRED BY APPLICABLE LAW, THE WORK IS LICENSED ON AN "AS IS" BASIS, WITHOUT
+ WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ LIMITATION, ANY WARRANTIES REGARDING THE CONTENTS OR ACCURACY OF THE WORK.
+ .
+ 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW,
+ AND EXCEPT FOR DAMAGES ARISING FROM LIABILITY TO A THIRD PARTY RESULTING FROM
+ BREACH OF THE WARRANTIES IN SECTION 5, IN NO EVENT WILL LICENSOR BE LIABLE TO
+ YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR
+ EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF
+ LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ .
+ 7. Termination
+ .
+ a. This License and the rights granted hereunder will terminate automatically
+ upon any breach by You of the terms of this License. Individuals or entities
+ who have received Derivative Works or Collective Works from You under this
+ License, however, will not have their licenses terminated provided such
+ individuals or entities remain in full compliance with those licenses. Sections
+ 1, 2, 5, 6, 7, and 8 will survive any termination of this License.
+ .
+ b. Subject to the above terms and conditions, the license granted here is
+ perpetual (for the duration of the applicable copyright in the Work).
+ Notwithstanding the above, Licensor reserves the right to release the Work
+ under different license terms or to stop distributing the Work at any time;
+ provided, however that any such election will not serve to withdraw this
+ License (or any other license that has been, or is required to be, granted
+ under the terms of this License), and this License will continue in full force
+ and effect unless terminated as stated above.
+ .
+ 8. Miscellaneous
+ .
+ Each time You distribute or publicly digitally perform the Work or a Collective
+ Work, the Licensor offers to the recipient a license to the Work on the same
+ terms and conditions as the license granted to You under this License.
+ .
+ Each time You distribute or publicly digitally perform a Derivative Work,
+ Licensor offers to the recipient a license to the original Work on the same
+ terms and conditions as the license granted to You under this License.
+ .
+ If any provision of this License is invalid or unenforceable under applicable
+ law, it shall not affect the validity or enforceability of the remainder of the
+ terms of this License, and without further action by the parties to this
+ agreement, such provision shall be reformed to the minimum extent necessary to
+ make such provision valid and enforceable.
+ .
+ No term or provision of this License shall be deemed waived and no breach
+ consented to unless such waiver or consent shall be in writing and signed by
+ the party to be charged with such waiver or consent.
+ .
+ This License constitutes the entire agreement between the parties with respect
+ to the Work licensed here. There are no understandings, agreements or
+ representations with respect to the Work not specified here. Licensor shall not
+ be bound by any additional provisions that may appear in any communication from
+ You. This License may not be modified without the mutual written agreement of
+ the Licensor and You.
+
+License: Ruby
+  1. You may make and give away verbatim copies of the source form of the
+     software without restriction, provided that you duplicate all of the
+     original copyright notices and associated disclaimers.
+ .
+  2. You may modify your copy of the software in any way, provided that
+     you do at least ONE of the following:
+ .
+       a) place your modifications in the Public Domain or otherwise
+          make them Freely Available, such as by posting said
+            modifications to Usenet or an equivalent medium, or by allowing
+              the author to include your modifications in the software.
+ .
+       b) use the modified software only within your corporation or
+          organization.
+ .
+       c) rename any non-standard executables so the names do not conflict
+         with standard executables, which must also be provided.
+ .
+       d) make other distribution arrangements with the author.
+ .
+  3. You may distribute the software in object code or executable
+     form, provided that you do at least ONE of the following:
+ .
+       a) distribute the executables and library files of the software,
+         together with instructions (in the manual page or equivalent)
+           on where to get the original distribution.
+ .
+       b) accompany the distribution with the machine-readable source of
+         the software.
+ .
+       c) give non-standard executables non-standard names, with
+          instructions on where to get the original software distribution.
+ .
+       d) make other distribution arrangements with the author.
+ .
+  4. You may modify and include the part of the software into any other
+     software (possibly commercial).  But some files in the distribution
+     are not written by the author, so that they are not under this terms.
+ .
+     They are gc.c(partly), utils.c(partly), regex.[ch], st.[ch] and some
+     files under the ./missing directory.  See each file for the copying
+     condition.
+ .
+  5. The scripts and library files supplied as input to or produced as
+     output from the software do not automatically fall under the
+     copyright of the software, but belong to whomever generated them,
+     and may be sold commercially, and may be aggregated with this
+     software.
+ .
+  6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+     IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+     PURPOSE.
+
+License: BSD-3-clause
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the University nor the names of its contributors
+    may be used to endorse or promote products derived from this software
+    without specific prior written permission.
+ .
+ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
diff --git a/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/README.md.gz b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/README.md.gz
new file mode 100644
index 0000000..cfaed1f
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/README.md.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/etc/hiera.yaml b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/etc/hiera.yaml
new file mode 100644
index 0000000..b2faa7c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/etc/hiera.yaml
@@ -0,0 +1,15 @@
+---
+:backends:
+  - yaml
+  - puppet
+
+:hierarchy:
+  - "%{location}"
+  - "%{environment}"
+  - common
+
+:yaml:
+  :datadir: etc/hieradb
+
+:puppet:
+  :datasource: data
diff --git a/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/etc/hieradb/common.yaml b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/etc/hieradb/common.yaml
new file mode 100644
index 0000000..71f545a
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/etc/hieradb/common.yaml
@@ -0,0 +1,3 @@
+classes:
+  - users::common
+  - ntp::config
diff --git a/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/etc/hieradb/dc1.yaml b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/etc/hieradb/dc1.yaml
new file mode 100644
index 0000000..232933c
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/etc/hieradb/dc1.yaml
@@ -0,0 +1,6 @@
+---
+ntpservers:
+  - ntp1.dc1.example.com
+  - ntp2.dc1.example.com
+classes:
+  - users::dc1
diff --git a/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/etc/hieradb/development.yaml b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/etc/hieradb/development.yaml
new file mode 100644
index 0000000..e4f4ad3
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/etc/hieradb/development.yaml
@@ -0,0 +1,2 @@
+---
+classes: users::development
diff --git a/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/etc/puppet.conf b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/etc/puppet.conf
new file mode 100644
index 0000000..0efb4e6
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/etc/puppet.conf
@@ -0,0 +1,3 @@
+[main]
+  modulepath = modules
+
diff --git a/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/modules/data/manifests/common.pp b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/modules/data/manifests/common.pp
new file mode 100644
index 0000000..9e0b532
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/modules/data/manifests/common.pp
@@ -0,0 +1,4 @@
+# sets the common (across all puppet conf) ntp servers.
+class data::common {
+  $ntpservers = ['ntp1.example.com', 'ntp2.example.com']
+}
diff --git a/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/modules/ntp/manifests/config.pp b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/modules/ntp/manifests/config.pp
new file mode 100644
index 0000000..0638ad1
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/modules/ntp/manifests/config.pp
@@ -0,0 +1,6 @@
+# lookup ntpservers from hiera, or allow user of class to provide other value
+class ntp::config($ntpservers = hiera('ntpservers')) {
+  file{'/tmp/ntp.conf':
+    content => template('ntp/ntp.conf.erb')
+  }
+}
diff --git a/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/modules/ntp/manifests/data.pp b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/modules/ntp/manifests/data.pp
new file mode 100644
index 0000000..b300c5f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/modules/ntp/manifests/data.pp
@@ -0,0 +1,4 @@
+# this class will be loaded using hiera's 'puppet' backend
+class ntp::data {
+  $ntpservers = ['1.pool.ntp.org', '2.pool.ntp.org']
+}
diff --git a/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/modules/ntp/templates/ntp.conf.erb b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/modules/ntp/templates/ntp.conf.erb
new file mode 100644
index 0000000..470bd86
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/modules/ntp/templates/ntp.conf.erb
@@ -0,0 +1,3 @@
+<% [ntpservers].flatten.each do |server| -%>
+server <%= server %>
+<% end -%>
diff --git a/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/modules/users/manifests/common.pp b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/modules/users/manifests/common.pp
new file mode 100644
index 0000000..18f7195
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/modules/users/manifests/common.pp
@@ -0,0 +1,4 @@
+# notifies
+class users::common {
+  notify{'Adding users::common': }
+}
diff --git a/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/modules/users/manifests/dc1.pp b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/modules/users/manifests/dc1.pp
new file mode 100644
index 0000000..c9f246f
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/modules/users/manifests/dc1.pp
@@ -0,0 +1,4 @@
+# notifies
+class users::dc1 {
+  notify{'Adding users::dc1': }
+}
diff --git a/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/modules/users/manifests/development.pp b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/modules/users/manifests/development.pp
new file mode 100644
index 0000000..93282e9
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/modules/users/manifests/development.pp
@@ -0,0 +1,4 @@
+# notifies
+class users::development {
+  notify{'Adding users::development': }
+}
diff --git a/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/site.pp b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/site.pp
new file mode 100644
index 0000000..beaa9be
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/share/doc/puppet-common/examples/hiera/site.pp
@@ -0,0 +1,3 @@
+node default {
+  hiera_include('classes')
+}
diff --git a/debian/stretch/puppet-linex-common/usr/share/lintian/overrides/puppet-common b/debian/stretch/puppet-linex-common/usr/share/lintian/overrides/puppet-common
new file mode 100644
index 0000000..e23047b
--- /dev/null
+++ b/debian/stretch/puppet-linex-common/usr/share/lintian/overrides/puppet-common
@@ -0,0 +1,5 @@
+# Man pages are automatically generated, not much to do here
+puppet-common binary: manpage-has-bad-whatis-entry
+
+# puppet manifests many use puppet as interpreter
+puppet-common binary: example-unusual-interpreter * #!puppet
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man1/extlookup2hiera.1.gz b/debian/stretch/puppet-linex-common/usr/share/man/man1/extlookup2hiera.1.gz
new file mode 100644
index 0000000..b5ea87d
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man1/extlookup2hiera.1.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man5/puppet.conf.5.gz b/debian/stretch/puppet-linex-common/usr/share/man/man5/puppet.conf.5.gz
new file mode 100644
index 0000000..a3fb4a9
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man5/puppet.conf.5.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-agent.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-agent.8.gz
new file mode 100644
index 0000000..dd2fbe0
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-agent.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-apply.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-apply.8.gz
new file mode 100644
index 0000000..1486146
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-apply.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-catalog.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-catalog.8.gz
new file mode 100644
index 0000000..11f9907
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-catalog.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-cert.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-cert.8.gz
new file mode 100644
index 0000000..d417d50
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-cert.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-certificate.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-certificate.8.gz
new file mode 100644
index 0000000..d810310
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-certificate.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-certificate_request.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-certificate_request.8.gz
new file mode 100644
index 0000000..bac96da
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-certificate_request.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-certificate_revocation_list.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-certificate_revocation_list.8.gz
new file mode 100644
index 0000000..0bb05ba
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-certificate_revocation_list.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-config.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-config.8.gz
new file mode 100644
index 0000000..203cc7e
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-config.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-describe.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-describe.8.gz
new file mode 100644
index 0000000..67e795e
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-describe.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-device.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-device.8.gz
new file mode 100644
index 0000000..33b0adb
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-device.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-doc.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-doc.8.gz
new file mode 100644
index 0000000..f99de65
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-doc.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-facts.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-facts.8.gz
new file mode 100644
index 0000000..395f7f9
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-facts.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-file.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-file.8.gz
new file mode 100644
index 0000000..c88163b
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-file.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-filebucket.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-filebucket.8.gz
new file mode 100644
index 0000000..37fb23c
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-filebucket.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-help.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-help.8.gz
new file mode 100644
index 0000000..878b8e2
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-help.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-inspect.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-inspect.8.gz
new file mode 100644
index 0000000..722d902
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-inspect.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-key.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-key.8.gz
new file mode 100644
index 0000000..debdf1f
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-key.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-kick.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-kick.8.gz
new file mode 100644
index 0000000..e5fb2e9
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-kick.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-man.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-man.8.gz
new file mode 100644
index 0000000..1c1b820
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-man.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-master.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-master.8.gz
new file mode 100644
index 0000000..cbfdb98
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-master.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-node.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-node.8.gz
new file mode 100644
index 0000000..90e6e46
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-node.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-parser.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-parser.8.gz
new file mode 100644
index 0000000..3cd7c44
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-parser.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-plugin.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-plugin.8.gz
new file mode 100644
index 0000000..dc192d5
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-plugin.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-queue.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-queue.8.gz
new file mode 100644
index 0000000..1f78ef6
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-queue.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-report.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-report.8.gz
new file mode 100644
index 0000000..3d10d2b
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-report.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-resource.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-resource.8.gz
new file mode 100644
index 0000000..85d246f
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-resource.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-resource_type.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-resource_type.8.gz
new file mode 100644
index 0000000..6077d8d
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-resource_type.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-secret_agent.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-secret_agent.8.gz
new file mode 100644
index 0000000..e7d43e3
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-secret_agent.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-status.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-status.8.gz
new file mode 100644
index 0000000..f30f383
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet-status.8.gz differ
diff --git a/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet.8.gz b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet.8.gz
new file mode 100644
index 0000000..02ca2ff
Binary files /dev/null and b/debian/stretch/puppet-linex-common/usr/share/man/man8/puppet.8.gz differ
diff --git a/debian/stretch/puppet-linex/debian/changelog b/debian/stretch/puppet-linex/debian/changelog
new file mode 100644
index 0000000..1a4d88a
--- /dev/null
+++ b/debian/stretch/puppet-linex/debian/changelog
@@ -0,0 +1,9 @@
+puppet-linex (3.8.5-2.1) linex; urgency=medium
+
+  [ root ]
+  * Initial release. 
+
+  [ Rafael J. García Perdigón ]
+  * Debianized sources.
+
+ -- Rafael J. García Perdigón <rafael.garciap@juntaex.es>  Wed, 21 Nov 2018 09:19:17 +0100
diff --git a/debian/stretch/puppet-linex/debian/conffiles b/debian/stretch/puppet-linex/debian/conffiles
new file mode 100644
index 0000000..92e0a06
--- /dev/null
+++ b/debian/stretch/puppet-linex/debian/conffiles
@@ -0,0 +1 @@
+/etc/init.d/puppet
diff --git a/debian/stretch/puppet-linex/debian/control b/debian/stretch/puppet-linex/debian/control
new file mode 100644
index 0000000..0ee001f
--- /dev/null
+++ b/debian/stretch/puppet-linex/debian/control
@@ -0,0 +1,22 @@
+Source: puppet-linex
+Section: admin
+Priority: optional
+Maintainer: Rafael Jesús García Perdigón <rafael.garciap@juntaex.es>
+Build-Depends: debhelper (>= 8.0.0)
+Standards-Version: 3.9.4
+
+Package: puppet-linex
+Architecture: all
+Depends: init-system-helpers (>= 1.18~), puppet-linex-common (= 3.8.5-2), ruby | ruby-interpreter
+Recommends: pciutils, dmidecode, virt-what
+Conflicts: puppet
+Suggests: puppet-el, vim-puppet, etckeeper
+Description: Configuration management system, agent.
+ Puppet is a server automation tool. It is composed of a declarative
+ language for expressing system configuration, a client and server for
+ distributing it, and a library for realizing the configuration.
+ .
+ The primary design goal of Puppet is to have an expressive enough
+ the puppet agent, and depend on the "puppet-linex-common" package which
+ contains the software.
+
diff --git a/debian/stretch/puppet-linex/debian/postinst b/debian/stretch/puppet-linex/debian/postinst
new file mode 100755
index 0000000..f36d23f
--- /dev/null
+++ b/debian/stretch/puppet-linex/debian/postinst
@@ -0,0 +1,36 @@
+#!/bin/sh
+set -e
+# Automatically added by dh_systemd_enable
+# This will only remove masks created by d-s-h on package removal.
+deb-systemd-helper unmask puppet.service >/dev/null || true
+
+# was-enabled defaults to true, so new installations run enable.
+if deb-systemd-helper --quiet was-enabled puppet.service; then
+	# Enables the unit on first installation, creates new
+	# symlinks on upgrades if the unit file has changed.
+	deb-systemd-helper enable puppet.service >/dev/null || true
+else
+	# Update the statefile to add new symlinks (if any), which need to be
+	# cleaned up on purge. Also remove old symlinks.
+	deb-systemd-helper update-state puppet.service >/dev/null || true
+fi
+# End automatically added section
+# Automatically added by dh_installinit
+if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ]; then
+	if [ -x "/etc/init.d/puppet" ]; then
+		update-rc.d puppet defaults 21 >/dev/null
+	fi
+	if [ -x "/etc/init.d/puppet" ] || [ -e "/etc/init/puppet.conf" ]; then
+		invoke-rc.d puppet start || true
+	fi
+fi
+# End automatically added section
+# Automatically added by dh_installdeb
+dpkg-maintscript-helper rm_conffile /etc/logrotate.d/puppet 2.6.4-2 -- "$@"
+# End automatically added section
+# Automatically added by dh_installdeb
+dpkg-maintscript-helper rm_conffile /etc/logcheck/ignore.d.server/puppet 2.6.4-2 -- "$@"
+# End automatically added section
+# Automatically added by dh_installdeb
+dpkg-maintscript-helper rm_conffile /etc/emacs/site-start.d/50puppet-mode-init.el 2.6.4-2 -- "$@"
+# End automatically added section
diff --git a/debian/stretch/puppet-linex/debian/postrm b/debian/stretch/puppet-linex/debian/postrm
new file mode 100755
index 0000000..8899876
--- /dev/null
+++ b/debian/stretch/puppet-linex/debian/postrm
@@ -0,0 +1,37 @@
+#!/bin/sh
+set -e
+# Automatically added by dh_installdeb
+dpkg-maintscript-helper rm_conffile /etc/emacs/site-start.d/50puppet-mode-init.el 2.6.4-2 -- "$@"
+# End automatically added section
+# Automatically added by dh_installdeb
+dpkg-maintscript-helper rm_conffile /etc/logcheck/ignore.d.server/puppet 2.6.4-2 -- "$@"
+# End automatically added section
+# Automatically added by dh_installdeb
+dpkg-maintscript-helper rm_conffile /etc/logrotate.d/puppet 2.6.4-2 -- "$@"
+# End automatically added section
+# Automatically added by dh_installinit
+if [ "$1" = "purge" ] ; then
+	update-rc.d puppet remove >/dev/null
+fi
+
+
+# In case this system is running systemd, we make systemd reload the unit files
+# to pick up changes.
+if [ -d /run/systemd/system ] ; then
+	systemctl --system daemon-reload >/dev/null || true
+fi
+# End automatically added section
+# Automatically added by dh_systemd_enable
+if [ "$1" = "remove" ]; then
+	if [ -x "/usr/bin/deb-systemd-helper" ]; then
+		deb-systemd-helper mask puppet.service >/dev/null
+	fi
+fi
+
+if [ "$1" = "purge" ]; then
+	if [ -x "/usr/bin/deb-systemd-helper" ]; then
+		deb-systemd-helper purge puppet.service >/dev/null
+		deb-systemd-helper unmask puppet.service >/dev/null
+	fi
+fi
+# End automatically added section
diff --git a/debian/stretch/puppet-linex/debian/preinst b/debian/stretch/puppet-linex/debian/preinst
new file mode 100755
index 0000000..97e82c1
--- /dev/null
+++ b/debian/stretch/puppet-linex/debian/preinst
@@ -0,0 +1,11 @@
+#!/bin/sh
+set -e
+# Automatically added by dh_installdeb
+dpkg-maintscript-helper rm_conffile /etc/logrotate.d/puppet 2.6.4-2 -- "$@"
+# End automatically added section
+# Automatically added by dh_installdeb
+dpkg-maintscript-helper rm_conffile /etc/logcheck/ignore.d.server/puppet 2.6.4-2 -- "$@"
+# End automatically added section
+# Automatically added by dh_installdeb
+dpkg-maintscript-helper rm_conffile /etc/emacs/site-start.d/50puppet-mode-init.el 2.6.4-2 -- "$@"
+# End automatically added section
diff --git a/debian/stretch/puppet-linex/debian/prerm b/debian/stretch/puppet-linex/debian/prerm
new file mode 100755
index 0000000..92a2d19
--- /dev/null
+++ b/debian/stretch/puppet-linex/debian/prerm
@@ -0,0 +1,16 @@
+#!/bin/sh
+set -e
+# Automatically added by dh_installdeb
+dpkg-maintscript-helper rm_conffile /etc/emacs/site-start.d/50puppet-mode-init.el 2.6.4-2 -- "$@"
+# End automatically added section
+# Automatically added by dh_installdeb
+dpkg-maintscript-helper rm_conffile /etc/logcheck/ignore.d.server/puppet 2.6.4-2 -- "$@"
+# End automatically added section
+# Automatically added by dh_installdeb
+dpkg-maintscript-helper rm_conffile /etc/logrotate.d/puppet 2.6.4-2 -- "$@"
+# End automatically added section
+# Automatically added by dh_installinit
+if [ -x "/etc/init.d/puppet" ] || [ -e "/etc/init/puppet.conf" ]; then
+	invoke-rc.d puppet stop || true
+fi
+# End automatically added section
diff --git a/debian/stretch/puppet-linex/etc/init.d/puppet b/debian/stretch/puppet-linex/etc/init.d/puppet
new file mode 100755
index 0000000..4b4406c
--- /dev/null
+++ b/debian/stretch/puppet-linex/etc/init.d/puppet
@@ -0,0 +1,73 @@
+#! /bin/sh
+### BEGIN INIT INFO
+# Provides:          puppet
+# Required-Start:    $network $named $remote_fs $syslog
+# Required-Stop:     $network $named $remote_fs $syslog
+# Should-Start:      puppetmaster apache2
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: puppet agent
+# Description:       The puppet agent connects to a puppet master, requests a
+#                    catalog of resources, and configures the local system.
+### END INIT INFO                                                                                                                                          
+
+PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+DAEMON=/usr/bin/puppet
+DAEMON_OPTS=""
+NAME="agent"
+DESC="puppet agent"
+PIDFILE="/run/puppet/${NAME}.pid"
+
+test -x $DAEMON || exit 0
+
+[ -r /etc/default/puppet ] && . /etc/default/puppet
+
+. /lib/lsb/init-functions
+
+reload_puppet_agent() {
+	start-stop-daemon --stop --quiet --signal HUP --pidfile $PIDFILE 
+}
+
+start_puppet_agent() {
+    start-stop-daemon --start --quiet --pidfile $PIDFILE \
+	--startas $DAEMON -- $NAME $DAEMON_OPTS
+}
+
+stop_puppet_agent() {
+	start-stop-daemon --stop --retry TERM/10/KILL/5 --quiet --oknodo --pidfile $PIDFILE
+}
+
+status_puppet_agent() {
+	status_of_proc -p "${PIDFILE}" "${DAEMON}" "${NAME}"
+}
+
+case "$1" in
+    start)
+	log_begin_msg "Starting $DESC"
+	start_puppet_agent
+	log_end_msg $?
+	;;
+    stop)
+	log_begin_msg "Stopping $DESC"
+	stop_puppet_agent
+	log_end_msg $?
+	;;
+    reload)
+    	log_begin_msg "Reloading $DESC"
+        reload_puppet_agent
+    	log_end_msg $?
+    	;;
+    status)
+        status_puppet_agent
+	;;
+    restart|force-reload)
+	log_begin_msg "Restarting $DESC"
+	stop_puppet_agent
+	start_puppet_agent
+	log_end_msg $?
+	;;
+  *)
+	echo "Usage: $0 {start|stop|status|restart|force-reload|reload}" >&2
+	exit 1
+	;;
+esac
diff --git a/debian/stretch/puppet-linex/lib/systemd/system/puppet.service b/debian/stretch/puppet-linex/lib/systemd/system/puppet.service
new file mode 100644
index 0000000..7d3217c
--- /dev/null
+++ b/debian/stretch/puppet-linex/lib/systemd/system/puppet.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Puppet agent
+
+[Service]
+Type=forking
+EnvironmentFile=-/etc/default/puppet
+PIDFile=/run/puppet/agent.pid
+ExecStart=/usr/bin/puppet agent $DAEMON_OPTS
+
+[Install]
+WantedBy=multi-user.target
diff --git a/debian/stretch/puppet-linex/usr/share/doc/puppet/NEWS.Debian.gz b/debian/stretch/puppet-linex/usr/share/doc/puppet/NEWS.Debian.gz
new file mode 100644
index 0000000..373fe27
Binary files /dev/null and b/debian/stretch/puppet-linex/usr/share/doc/puppet/NEWS.Debian.gz differ
diff --git a/debian/stretch/puppet-linex/usr/share/doc/puppet/copyright b/debian/stretch/puppet-linex/usr/share/doc/puppet/copyright
new file mode 100644
index 0000000..b1c7e19
--- /dev/null
+++ b/debian/stretch/puppet-linex/usr/share/doc/puppet/copyright
@@ -0,0 +1,472 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: Puppet
+Source: https://github.com/puppetlabs/puppet
+
+Files: *
+Copyright: 2004-2012 Puppet Labs Inc
+           2008 Google Inc.
+           2013, 2014 Adrien Thebo
+           2012, 2013, 2014 Andrew Parker
+           2013 Branan Purvine-Riley
+           2014 Brandon High
+           2014 Britt Gresham
+           2011 Bryan Kearney <bkearney@redhat.com>
+           2014 Charlie Sharpsteen
+           2014 Chris Price
+           2011, 2012 Daniel Pittman
+           2013 Dominic Cleal
+           2012, 2014 Eric Sorenson
+           2013 Erik Dalén
+           2014 Ethan J. Brown
+           2012 Hailee Kenney
+           2013, 2014 Henrik Lindberg
+           2011 Jacob Helwig
+           2008, 2009, 2010, 2011 James Turnbull
+           2012,2013 Jeff McCune <jeff.mccune@northstarlabs.net>
+           2012 Jeff Weiss
+           2005 Jesse Koontz
+           2010 Jesse Wolfe
+           2012, 2013, 2014 Josh Cooper
+           2013, 2014 Josh Partlow
+           2012, 2013 Justin Stoller
+           2012 Kelsey Hightower
+           2012 Ken Barber
+           2013, 2014 Kylo Ginsberg
+           2005, 2007, 2008, 2009, 2011 Luke Kanies
+           2009 Markus Roberts
+           2010 Mathias Gug
+           2010, 2011 Matt Robinson
+           2012 Matthaus Litteken
+           2012, 2013 Matthaus Owens
+           2012 Micah Anderson
+           2012 Michael Stahnke
+           2012, 2013 Moses Mendoza
+           2011,2013 Nick Fagerlund
+           2012, 2013 Patrick Carlisle
+           2010 Paul Berry
+           2012 R. Tyler Croy
+           2011 R.I.Pienaar
+           2010 Rein Henrichs
+           2008 Sean E. Millichamp
+           2012 Stig Sandbeck Mathisen
+           2013 Thomas Linkin
+           2006, 2007 lutter
+           2006 mpalmer
+License: Apache-2.0
+ Puppet - Automating Configuration Management.
+ .
+ Copyright (C) 2011 Puppet Labs Inc
+ .
+ Puppet Labs can be contacted at: info@puppetlabs.com
+ .
+ Licensed under the Apache License, Version 2.0 (the "License"); you
+ may not use this file except in compliance with the License. You may
+ obtain a copy of the License at
+ .
+ http://www.apache.org/licenses/LICENSE-2.0
+ .
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ permissions and limitations under the License.
+ .
+ For a local copy of the license, see /usr/share/common-licenses/Apache-2.0
+
+Files: ext/envpuppet
+Copyright: 2010, 2011 Jeff McCune <jeff@puppetlabs.com>
+           2012 Micah Anderson
+           2013 Patrick Carlisle
+           2012 rahul
+License: BSD-3-clause
+
+Files: debian/*
+Copyright: 2008-2012 Micah Anderson <micah@debian.org>,
+           2009-2014 Stig Sandbeck Mathisen <ssm@debian.org>,
+           2009,2010 Andrew Pollock <apollock@debian.org>,
+           2010 Mathias Gug <mathiaz@ubuntu.com>,
+           2009,2010 Nigel Kersten <nigel@explanatorygap.net>,
+           2007-2010 Thom May <thom@debian.org>,
+           2006,2007 Matthew Palmer <mpalmer@debian.org>,
+           2006,2007 Jamie Wilkinson <jaq@debian.org>,
+           2008 James Turnbull,
+           2007 Luke Kanies
+           2013 Micah Anderson
+License: GPL-2
+
+Files: install.rb
+Copyright: 2004 Austin Ziegler <ruby-install@halostatue.ca>
+           2011 Cameron Thomas
+           2011 Daniel Pittman
+           2014 Ethan J. Brown
+           2008, 2009, 2010, 2011 James Turnbull
+           2005 Jesse Koontz
+           2013 John Julien
+           2011, 2012 Josh Cooper
+           2005, 2007 Luke Kanies
+           2010 Markus Roberts
+           2010 Martin Englund
+           2011 Matt Robinson
+           2012 Matthaus Litteken
+           2012 Matthaus Owens
+           2012 Micah Anderson
+           2012, 2014 Moses Mendoza
+           2010, 2011 Nick Lewis
+           2008, 2009, 2010 Nigel Kersten
+           2013 Patrick Carlisle
+           2011, 2012 Stig Sandbeck Mathisen
+           2010, 2012 Todd Zullinger
+           2006, 2007 luke
+           2011 nfagerlund
+License: GPL-2+ or Ruby
+
+Files: conf/gentoo/init.d/puppet*
+Copyright: 1999-2008 Gentoo Foundation
+License: GPL-2
+
+Files: lib/puppet/util/rdoc/generators/template/puppet/puppet.rb
+Copyright: 2002, 2003 The FaerieMUD Consortium.
+           2008, 2009, 2013 Brice Figureau
+License: CC-BY-1.0
+
+Files: lib/puppet/external/nagios/parser.rb
+Copyright: 1999-2005 Minero Aoki
+           2012 Daniel Pittman
+           2014 Felix Frank
+           2013 Jeff McCune
+           2012, 2013 Ludovic LANGE
+           2007, 2009 Luke Kanies
+           2010 Markus Roberts
+           2011 Matt Robinson
+           2012 Micah Anderson
+License: Ruby with exception
+ This program is free software.
+ You can distribute/modify this program under the same terms of ruby.
+ .
+ As a special exception, when this code is copied by Racc
+ into a Racc output file, you may use that output file
+ without restriction.
+
+Files: lib/puppet/network/http_server/mongrel.rb
+Copyright: 2006 Manuel Holtgrewe, 2007 Luke Kanies
+License: MIT
+
+Files: examples/modules/sample-module/lib/puppet/parser/functions/hostname_to_dn.rb
+Copyright: David Schmitt <david@schmitt.edv-bus.at>
+License: BSD-3-clause
+
+License: MIT
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ .
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+ .
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+License: GPL-2
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation (version 2 of the License)
+ .
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ .
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston MA  02110-1301 USA
+ .
+ On Debian systems, the full text of the GNU General Public
+ License version 2 can be found in the file
+ "/usr/share/common-licenses/GPL-2".
+
+License: GPL-2+
+ This program is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation;
+ either version 2 of the License, or (at your option) any
+ later version.
+ .
+ This file is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty
+ of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+ .
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the Free
+ Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ .
+ On Debian systems, the full text of the GNU General Public
+ License version 2 can be found in the file
+ "/usr/share/common-licenses/GPL-2".
+
+License: CC-BY-1.0
+ THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE
+ COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY
+ COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
+ AUTHORIZED UNDER THIS LICENSE IS PROHIBITED.
+ .
+ BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE
+ BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS
+ CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND
+ CONDITIONS.
+ .
+ 1. Definitions
+ .
+ "Collective Work" means a work, such as a periodical issue, anthology or
+ encyclopedia, in which the Work in its entirety in unmodified form, along with
+ a number of other contributions, constituting separate and independent works in
+ themselves, are assembled into a collective whole. A work that constitutes a
+ Collective Work will not be considered a Derivative Work (as defined below) for
+ the purposes of this License.  "Derivative Work" means a work based upon the
+ Work or upon the Work and other pre-existing works, such as a translation,
+ musical arrangement, dramatization, fictionalization, motion picture version,
+ sound recording, art reproduction, abridgment, condensation, or any other form
+ in which the Work may be recast, transformed, or adapted, except that a work
+ that constitutes a Collective Work will not be considered a Derivative Work for
+ the purpose of this License.
+ .
+ "Licensor" means the individual or entity that offers the Work under the terms
+ of this License.  "Original Author" means the individual or entity who created
+ the Work.
+ .
+ "Work" means the copyrightable work of authorship offered under the terms of
+ this License.  "You" means an individual or entity exercising rights under this
+ License who has not previously violated the terms of this License with respect
+ to the Work, or who has received express permission from the Licensor to
+ exercise rights under this License despite a previous violation.
+ .
+ 2. Fair Use Rights. Nothing in this license is intended to reduce, limit, or
+ restrict any rights arising from fair use, first sale or other limitations on
+ the exclusive rights of the copyright owner under copyright law or other
+ applicable laws.
+ .
+ 3. License Grant. Subject to the terms and conditions of this License, Licensor
+ hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the
+ duration of the applicable copyright) license to exercise the rights in the
+ Work as stated below:
+ .
+ a. to reproduce the Work, to incorporate the Work into one or more Collective
+ Works, and to reproduce the Work as incorporated in the Collective Works;
+ .
+ b. to create and reproduce Derivative Works;
+ .
+ c. to distribute copies or phonorecords of, display publicly, perform publicly,
+ and perform publicly by means of a digital audio transmission the Work
+ including as incorporated in Collective Works;
+ .
+ d. to distribute copies or phonorecords of, display publicly, perform publicly,
+ and perform publicly by means of a digital audio transmission Derivative Works;
+ .
+ The above rights may be exercised in all media and formats whether now known or
+ hereafter devised. The above rights include the right to make such
+ modifications as are technically necessary to exercise the rights in other
+ media and formats. All rights not expressly granted by Licensor are hereby
+ reserved.
+ .
+ 4. Restrictions.
+ .
+ The license granted in Section 3 above is expressly made subject to and limited
+ by the following restrictions:
+ .
+ a. You may distribute, publicly display, publicly perform, or publicly
+ digitally perform the Work only under the terms of this License, and You must
+ include a copy of, or the Uniform Resource Identifier for, this License with
+ every copy or phonorecord of the Work You distribute, publicly display,
+ publicly perform, or publicly digitally perform. You may not offer or impose
+ any terms on the Work that alter or restrict the terms of this License or the
+ recipients' exercise of the rights granted hereunder. You may not sublicense
+ the Work. You must keep intact all notices that refer to this License and to
+ the disclaimer of warranties. You may not distribute, publicly display,
+ publicly perform, or publicly digitally perform the Work with any technological
+ measures that control access or use of the Work in a manner inconsistent with
+ the terms of this License Agreement. The above applies to the Work as
+ incorporated in a Collective Work, but this does not require the Collective
+ Work apart from the Work itself to be made subject to the terms of this
+ License. If You create a Collective Work, upon notice from any Licensor You
+ must, to the extent practicable, remove from the Collective Work any reference
+ to such Licensor or the Original Author, as requested. If You create a
+ Derivative Work, upon notice from any Licensor You must, to the extent
+ practicable, remove from the Derivative Work any reference to such Licensor or
+ the Original Author, as requested.
+ .
+ b. If you distribute, publicly display, publicly perform, or publicly digitally
+ perform the Work or any Derivative Works or Collective Works, You must keep
+ intact all copyright notices for the Work and give the Original Author credit
+ reasonable to the medium or means You are utilizing by conveying the name (or
+ pseudonym if applicable) of the Original Author if supplied; the title of the
+ Work if supplied; in the case of a Derivative Work, a credit identifying the
+ use of the Work in the Derivative Work (e.g., "French translation of the Work
+ by Original Author," or "Screenplay based on original Work by Original
+ Author"). Such credit may be implemented in any reasonable manner; provided,
+ however, that in the case of a Derivative Work or Collective Work, at a minimum
+ such credit will appear where any other comparable authorship credit appears
+ and in a manner at least as prominent as such other comparable authorship
+ credit.
+ .
+ 5. Representations, Warranties and Disclaimer
+ .
+ a. By offering the Work for public release under this License, Licensor
+ represents and warrants that, to the best of Licensor's knowledge after
+ reasonable inquiry:
+ .
+ i. Licensor has secured all rights in the Work necessary to grant the license
+ rights hereunder and to permit the lawful exercise of the rights granted
+ hereunder without You having any obligation to pay any royalties, compulsory
+ license fees, residuals or any other payments;
+ .
+ ii. The Work does not infringe the copyright, trademark, publicity rights, common
+ law rights or any other right of any third party or constitute defamation,
+ invasion of privacy or other tortious injury to any third party.
+ .
+ b. EXCEPT AS EXPRESSLY STATED IN THIS LICENSE OR OTHERWISE AGREED IN WRITING OR
+ REQUIRED BY APPLICABLE LAW, THE WORK IS LICENSED ON AN "AS IS" BASIS, WITHOUT
+ WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ LIMITATION, ANY WARRANTIES REGARDING THE CONTENTS OR ACCURACY OF THE WORK.
+ .
+ 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW,
+ AND EXCEPT FOR DAMAGES ARISING FROM LIABILITY TO A THIRD PARTY RESULTING FROM
+ BREACH OF THE WARRANTIES IN SECTION 5, IN NO EVENT WILL LICENSOR BE LIABLE TO
+ YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR
+ EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF
+ LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ .
+ 7. Termination
+ .
+ a. This License and the rights granted hereunder will terminate automatically
+ upon any breach by You of the terms of this License. Individuals or entities
+ who have received Derivative Works or Collective Works from You under this
+ License, however, will not have their licenses terminated provided such
+ individuals or entities remain in full compliance with those licenses. Sections
+ 1, 2, 5, 6, 7, and 8 will survive any termination of this License.
+ .
+ b. Subject to the above terms and conditions, the license granted here is
+ perpetual (for the duration of the applicable copyright in the Work).
+ Notwithstanding the above, Licensor reserves the right to release the Work
+ under different license terms or to stop distributing the Work at any time;
+ provided, however that any such election will not serve to withdraw this
+ License (or any other license that has been, or is required to be, granted
+ under the terms of this License), and this License will continue in full force
+ and effect unless terminated as stated above.
+ .
+ 8. Miscellaneous
+ .
+ Each time You distribute or publicly digitally perform the Work or a Collective
+ Work, the Licensor offers to the recipient a license to the Work on the same
+ terms and conditions as the license granted to You under this License.
+ .
+ Each time You distribute or publicly digitally perform a Derivative Work,
+ Licensor offers to the recipient a license to the original Work on the same
+ terms and conditions as the license granted to You under this License.
+ .
+ If any provision of this License is invalid or unenforceable under applicable
+ law, it shall not affect the validity or enforceability of the remainder of the
+ terms of this License, and without further action by the parties to this
+ agreement, such provision shall be reformed to the minimum extent necessary to
+ make such provision valid and enforceable.
+ .
+ No term or provision of this License shall be deemed waived and no breach
+ consented to unless such waiver or consent shall be in writing and signed by
+ the party to be charged with such waiver or consent.
+ .
+ This License constitutes the entire agreement between the parties with respect
+ to the Work licensed here. There are no understandings, agreements or
+ representations with respect to the Work not specified here. Licensor shall not
+ be bound by any additional provisions that may appear in any communication from
+ You. This License may not be modified without the mutual written agreement of
+ the Licensor and You.
+
+License: Ruby
+  1. You may make and give away verbatim copies of the source form of the
+     software without restriction, provided that you duplicate all of the
+     original copyright notices and associated disclaimers.
+ .
+  2. You may modify your copy of the software in any way, provided that
+     you do at least ONE of the following:
+ .
+       a) place your modifications in the Public Domain or otherwise
+          make them Freely Available, such as by posting said
+            modifications to Usenet or an equivalent medium, or by allowing
+              the author to include your modifications in the software.
+ .
+       b) use the modified software only within your corporation or
+          organization.
+ .
+       c) rename any non-standard executables so the names do not conflict
+         with standard executables, which must also be provided.
+ .
+       d) make other distribution arrangements with the author.
+ .
+  3. You may distribute the software in object code or executable
+     form, provided that you do at least ONE of the following:
+ .
+       a) distribute the executables and library files of the software,
+         together with instructions (in the manual page or equivalent)
+           on where to get the original distribution.
+ .
+       b) accompany the distribution with the machine-readable source of
+         the software.
+ .
+       c) give non-standard executables non-standard names, with
+          instructions on where to get the original software distribution.
+ .
+       d) make other distribution arrangements with the author.
+ .
+  4. You may modify and include the part of the software into any other
+     software (possibly commercial).  But some files in the distribution
+     are not written by the author, so that they are not under this terms.
+ .
+     They are gc.c(partly), utils.c(partly), regex.[ch], st.[ch] and some
+     files under the ./missing directory.  See each file for the copying
+     condition.
+ .
+  5. The scripts and library files supplied as input to or produced as
+     output from the software do not automatically fall under the
+     copyright of the software, but belong to whomever generated them,
+     and may be sold commercially, and may be aggregated with this
+     software.
+ .
+  6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+     IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+     PURPOSE.
+
+License: BSD-3-clause
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the University nor the names of its contributors
+    may be used to endorse or promote products derived from this software
+    without specific prior written permission.
+ .
+ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
