\FF\D8\FF\E0\00JFIF\00\00\00d\00d\00\00\FF\FE\00\border bs:0 bc:#000000 ps:0 pc:#ffffff es:0 ec:#000000 ck:feee6c715d26fd9f38b0ca4278c05026\FF\DB\00C\00P7<F<2PFAFZUP_xxnnx\F5\AF\B9\91\C8\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\DB\00CUZZxix‚\EB\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\C0\00\00b\00d\00\FF\C4\00\00\00\00\00\00\00\00\00\00\00\00\00\00\FF\C4\00\00\00\00\00\00\00\00\00\00\001A!Q\FF\C4\00\00\00\00\00\00\00\00\00\00\00\00\00\FF\C4\00\00\00\00\00\00\00\00\00\00!1AQ\FF\DA\00\00\00?\00\F6\00\00\00\00\00\00\00\00\00\00\A0\00\00\C5\CF\F8\E7Ó\FCjD~\B9^\AD\%\B3]\D8cs-\BBs,-\A0\00"\80\00%\B83rÏ^K~F\A4ea\00E\00\C6\EE=u\B1\9B\D1\00@\00r\BE8\F9:\FE5#.M\00\E7\CB\C9q\CBq\D6\F2\BE\B7\C7>\C9n5×\D6?\BDê\9Ds\EBp\9F[`8m\B7)o\B5\E8\E6I\99\FE3]]A2\BA\8Cw\D6E\93\\DEv\C8\009\F2\F1NI?uc\\F5\EA\96k\xN<~buv\EA\C8\D7	\8B\84\CEcxI\BBg\AE\9E=\D6+n\EC\80\C8A\8C\AE\EB\CF\D5\DA\E9"2\A4\B9j5\EB\F3W\B63\96\B30Yu\DA\FC8\ED\DF\E7Ms\FB\F1\8E\B3\FA\EA\E8\E6(\883zs\F2_\8DFk\8Bh
\00\8C\DCw\D3R\B5+6X\BA\B2\C4j\AB0\B4\FCMw\C2I\8E\9B\E3\A9~9u\FA\D3l\80\C8%p\EE\FDn2€
\00$\FEj\C4e\A9\DB\~\95\A7\A5\80EK\BB\8DDsP\00@@AD'k\CF\E8\DB\D2(\80\9AK\D3\85\D6lb\F2\BA\8C*\80\00)\95
59\A3R:\F3\CE"\B6\80\88\00\00i1u4ê\E9\F2á\A6\A2\FACM\93WMb*\E0*\00\00\00\00\00(\A8\80\00\00\80\00\00\00\00\00\00\00\00\00\FF\D9<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>C///</title>
</head>
#
# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Christopher Brown (<cb@chef.io>)
# Author:: Daniel DeLeo (<dan@chef.io>)
# Copyright:: Copyright (c) Chef Software Inc.
# License:: Apache License, Version 2.0
#
# 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 "forwardable" unless defined?(Forwardable)
require_relative "../../platform/query_helpers"
require_relative "generic_presenter"
require "tempfile" unless defined?(Tempfile)

class Chef
  class Knife

    # The User Interaction class used by knife.
    class UI

      extend Forwardable

      attr_reader :stdout
      attr_reader :stderr
      attr_reader :stdin
      attr_reader :config

      attr_reader :presenter

      def_delegator :@presenter, :format_list_for_display
      def_delegator :@presenter, :format_for_display
      def_delegator :@presenter, :format_cookbook_list_for_display

      def initialize(stdout, stderr, stdin, config)
        @stdout, @stderr, @stdin, @config = stdout, stderr, stdin, config
        @presenter = Chef::Knife::Core::GenericPresenter.new(self, config)
      end

      # Creates a new +presenter_class+ object and uses it to format structured
      # data for display. By default, a Chef::Knife::Core::GenericPresenter
      # object is used.
      def use_presenter(presenter_class)
        @presenter = presenter_class.new(self, config)
      end

      def highline
        @highline ||= begin
          require "highline"
          HighLine.new
        end
      end

      # Creates a new object of class TTY::Prompt
      # with interrupt as exit so that it can be terminated with status code.
      def prompt
        @prompt ||= TTY::Prompt.new(interrupt: :exit)
      end

      # pastel.decorate is a lightweight replacement for highline.color
      def pastel
        @pastel ||= begin
          require "pastel"
          Pastel.new
        end
      end

      # Prints a message to stdout. Aliased as +info+ for compatibility with
      # the logger API.
      #
      # @param message [String] the text string
      def msg(message)
        stdout.puts message
      rescue Errno::EPIPE => e
        raise e if @config[:verbosity] >= 2

        exit 0
      end

      # Prints a msg to stderr. Used for info, warn, error, and fatal.
      #
      # @param message [String] the text string
      def log(message)
        lines = message.split("\n")
        first_line = lines.shift
        stderr.puts first_line
        # If the message is multiple lines,
        # indent subsequent lines to align with the
        # log type prefix ("ERROR: ", etc)
        unless lines.empty?
          prefix, = first_line.split(":", 2)
          return if prefix.nil?

          prefix_len = prefix.length
          prefix_len -= 9 if color? # prefix includes 9 bytes of color escape sequences
          prefix_len += 2 # include room to align to the ": " following PREFIX
          padding = " " * prefix_len
          lines.each do |line|
            stderr.puts "#{padding}#{line}"
          end
        end
      rescue Errno::EPIPE => e
        raise e if @config[:verbosity] >= 2

        exit 0
      end

      alias :info :log
      alias :err :log

      # Print a Debug
      #
      # @param message [String] the text string
      def debug(message)
        log("#{color("DEBUG:", :blue, :bold)} #{message}")
      end

      # Print a warning message
      #
      # @param message [String] the text string
      def warn(message)
        log("#{color("WARNING:", :yellow, :bold)} #{message}")
      end

      # Print an error message
      #
      # @param message [String] the text string
      def error(message)
        log("#{color("ERROR:", :red, :bold)} #{message}")
      end

      # Print a message describing a fatal error.
      #
      # @param message [String] the text string
      def fatal(message)
        log("#{color("FATAL:", :red, :bold)} #{message}")
      end

      # Print a message describing a fatal error and exit 1
      #
      # @param message [String] the text string
      def fatal!(message)
        fatal(message)
        exit 1
      end

      def color(string, *colors)
        if color?
          pastel.decorate(string, *colors)
        else
          string
        end
      end

      # Should colored output be used? For output to a terminal, this is
      # determined by the value of `config[:color]`. When output is not to a
      # terminal, colored output is never used
      def color?
        Chef::Config[:color] && stdout.tty?
      end

      def ask(*args, **options, &block)
        prompt.ask(*args, **options, &block)
      end

      def list(*args)
        highline.list(*args)
      end

      # Formats +data+ using the configured presenter and outputs the result
      # via +msg+. Formatting can be customized by configuring a different
      # presenter. See +use_presenter+
      def output(data)
        msg @presenter.format(data)
      end

      # Determines if the output format is a data interchange format, i.e.,
      # JSON or YAML
      def interchange?
        @presenter.interchange?
      end

      def ask_question(question, opts = {})
        question += "[#{opts[:default]}] " if opts[:default]

        if opts[:default] && config[:defaults]
          opts[:default]
        else
          stdout.print question
          a = stdin.readline.strip

          if opts[:default]
            a.empty? ? opts[:default] : a
          else
            a
          end
        end
      end

      def pretty_print(data)
        stdout.puts data
      rescue Errno::EPIPE => e
        raise e if @config[:verbosity] >= 2

        exit 0
      end

      # Hash -> Hash
      # Works the same as edit_data but
      # returns a hash rather than a JSON string/Fully inflated object
      def edit_hash(hash)
        raw = edit_data(hash, false)
        Chef::JSONCompat.parse(raw)
      end

      def edit_data(data, parse_output = true, object_class: nil)
        output = Chef::JSONCompat.to_json_pretty(data)
        unless config[:disable_editing]
          Tempfile.open([ "knife-edit-", ".json" ]) do |tf|
            tf.sync = true
            tf.puts output
            tf.close
            raise "Please set EDITOR environment variable. See https://docs.chef.io/knife_setup/ for details." unless system("#{config[:editor]} #{tf.path}")

            output = IO.read(tf.path)
          end
        end

        if parse_output
          if object_class.nil?
            raise ArgumentError, "Please pass in the object class to hydrate or use #edit_hash"
          else
            object_class.from_hash(Chef::JSONCompat.parse(output))
          end
        else
          output
        end
      end

      def edit_object(klass, name)
        object = klass.load(name)

        output = edit_data(object, object_class: klass)

        # Only make the save if the user changed the object.
        #
        # Output JSON for the original (object) and edited (output), then parse
        # them without reconstituting the objects into real classes
        # (create_additions=false). Then, compare the resulting simple objects,
        # which will be Array/Hash/String/etc.
        #
        # We wouldn't have to do these shenanigans if all the editable objects
        # implemented to_hash, or if to_json against a hash returned a string
        # with stable key order.
        object_parsed_again = Chef::JSONCompat.parse(Chef::JSONCompat.to_json(object))
        output_parsed_again = Chef::JSONCompat.parse(Chef::JSONCompat.to_json(output))
        if object_parsed_again != output_parsed_again
          output.save
          msg("Saved #{output}")
        else
          msg("Object unchanged, not saving")
        end
        output(format_for_display(object)) if config[:print_after]
      end

      def confirmation_instructions(default_choice)
        case default_choice
       