// Path: json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonProvider.java
// public interface JsonProvider {
// 
//     static final Object UNDEFINED = new Object();
// 
//     /**
//      * Parse the given json string
//      * @param json json string to parse
//      * @return Object representation of json
//      * @throws InvalidJsonException
//      */
//     Object parse(String json) throws InvalidJsonException;
// 
//     /**
//      * Parse the given json bytes in UTF-8 encoding
//      * @param json json bytes to parse
//      * @return Object representation of json
//      * @throws InvalidJsonException
//      */
//     default Object parse(byte[] json) throws InvalidJsonException {
//         return parse(new String(json, StandardCharsets.UTF_8));
//     }
//     /**
//      * Parse the given json string
//      * @param jsonStream input stream to parse
//      * @param charset charset to use
//      * @return Object representation of json
//      * @throws InvalidJsonException
//      */
//     Object parse(InputStream jsonStream, String charset) throws InvalidJsonException;
// 
//     /**
//      * Convert given json object to a json string
//      * @param obj object to transform
//      * @return json representation of object
//      */
//     String toJson(Object obj);
// 
//     /**
//      * Creates a provider specific json array
//      * @return new array
//      */
//     Object createArray();
// 
//     /**
//      * Creates a provider specific json object
//      * @return new object
//      */
//     Object createMap();
// 
//     /**
//      * checks if object is an array
//      *
//      * @param obj object to check
//      * @return true if obj is an array
//      */
//     boolean isArray(Object obj);
// 
//     /**
//      * Get the length of an json array, json object or a json string
//      *
//      * @param obj an array or object or a string
//      * @return the number of entries in the array or object
//      */
//     int length(Object obj);
// 
//     /**
//      * Converts given array to an {@link Iterable}
//      *
//      * @param obj an array
//      * @return an Iterable that iterates over the entries of an array
//      */
//     Iterable<?> toIterable(Object obj);
// 
// 
//     /**
//      * Returns the keys from the given object
//      *
//      * @param obj an object
//      * @return the keys for an object
//      */
//     Collection<String> getPropertyKeys(Object obj);
// 
//     /**
//      * Extracts a value from an array anw unwraps provider specific data type
//      *
//      * @param obj an array
//      * @param idx index
//      * @return the entry at the given index
//      */
//     Object getArrayIndex(Object obj, int idx);
// 
//     /**
//      * Extracts a value from an array
//      *
//      * @param obj an array
//      * @param idx index
//      * @param unwrap should provider specific data type be unwrapped
//      * @return the entry at the given index
//      */
//     @Deprecated
//     Object getArrayIndex(Object obj, int idx, boolean unwrap);
// 
//     /**
//      * Sets a value in an array. If the array is too small, the provider is supposed to enlarge it.
//      *
//      * @param array an array
//      * @param idx index
//      * @param newValue the new value
//      */
//     void setArrayIndex(Object array, int idx, Object newValue);
// 
//     /**
//      * Extracts a value from an map
//      *
//      * @param obj a map
//      * @param key property key
//      * @return the map entry or {@link com.jayway.jsonpath.spi.json.JsonProvider#UNDEFINED} for missing properties
//      */
//     Object getMapValue(Object obj, String key);
// 
//     /**
//      * Sets a value in an object
//      *
//      * @param obj   an object
//      * @param key   a String key
//      * @param value the value to set
//      */
//     void setProperty(Object obj, Object key, Object value);
// 
//     /**
//      * Removes a value in an object or array
//      *
//      * @param obj   an array or an object
//      * @param key   a String key or a numerical index to remove
//      */
//     void removeProperty(Object obj, Object key);
// 
//     /**
//      * checks if object is a map (i.e. no array)
//      *
//      * @param obj object to check
//      * @return true if the object is a map
//      */
//     boolean isMap(Object obj);
// 
//     /**
//      * Extracts a value from a wrapper object. For JSON providers that to not wrap
//      * values, this will usually be the object itself.
//      *
//      * @param obj a value holder object
//      * @return the unwrapped value.
//      */
//     Object unwrap(Object obj);
// }


import com.jayway.jsonpath.Option;
import com.jayway.jsonpath.internal.PathRef;
import com.jayway.jsonpath.spi.json.JsonProvider;
import java.util.Collection;
                Iterable<?> models = ctx.jsonProvider().toIterable(model);
                int idx = 0;
                for (Object evalModel : models) {
                    String evalPath = currentPath + "[" + idx + "]";
                    next.setUpstreamArrayIndex(idx);
                    next.evaluate(evalPath, parent, evalModel, ctx);
                    idx++;
                }
            }
        }

        Iterable<?> models = ctx.jsonProvider().toIterable(model);
        int idx = 0;
        for (Object evalModel : models) {
            String evalPath = currentPath + "[" + idx + "]";
            walk(pt, evalPath, PathRef.create(model, idx), evalModel, ctx, predicate);
            idx++;
        }
    }

    public static void walkObject(PathToken pt, String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx, Predicate predicate) {

        if (predicate.matches(model)) {
            pt.evaluate(currentPath, parent, model, ctx);
        }
        Collection<String> properties = ctx.jsonProvider().getPropertyKeys(model);

        for (String property : properties) {
            String evalPath = currentPath + "['" + property + "']";
            Object propertyModel = ctx.jsonProvider().getMapValue(model, property);
// Path: json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonProvider.java
// public interface JsonProvider {
// 
//     static final Object UNDEFINED = new Object();
// 
//     /**
//      * Parse the given json string
//      * @param json json string to parse
//      * @return Object representation of json
//      * @throws InvalidJsonException
//      */
//     Object parse(String json) throws InvalidJsonException;
// 
//     /**
//      * Parse the given json bytes in UTF-8 encoding
//      * @param json json bytes to parse
//      * @return Object representation of json
//      * @throws InvalidJsonException
//      */
//     default Object parse(byte[] json) throws InvalidJsonException {
//         return parse(new String(json, StandardCharsets.UTF_8));
//     }
//     /**
//      * Parse the given json string
//      * @param jsonStream input stream to parse
//      * @param charset charset to use
//      * @return Object representation of json
//      * @throws InvalidJsonException
//      */
//     Object parse(InputStream jsonStream, String charset) throws InvalidJsonException;
// 
//     /**
//      * Convert given json object to a json string
//      * @param obj object to transform
//      * @return json representation of object
//      */
//     String toJson(Object obj);
// 
//     /**
//      * Creates a provider specific json array
//      * @return new array
//      */
//     Object createArray();
// 
//     /**
//      * Creates a provider specific json object
//      * @return new object
//      */
//     Object createMap();
// 
//     /**
//      * checks if object is an array
//      *
//      * @param obj object to check
//      * @return true if obj is an array
//      */
//     boolean isArray(Object obj);
// 
//     /**
//      * Get the length of an json array, json object or a json string
//      *
//      * @param obj an array or object or a string
//      * @return the number of entries in the array or object
//      */
//     int length(Object obj);
// 
//     /**
//      * Converts given array to an {@link Iterable}
//      *
//      * @param obj an array
//      * @return an Iterable that iterates over the entries of an array
//      */
//     Iterable<?> toIterable(Object obj);
// 
// 
//     /**
//      * Returns the keys from the given object
//      *
//      * @param obj an object
//      * @return the keys for an object
//      */
//     Collection<String> getPropertyKeys(Object obj);
// 
//     /**
//      * Extracts a value from an array anw unwraps provider specific data type
//      *
//      * @param obj an array
//      * @param idx index
//      * @return the entry at the given index
//      */
//     Object getArrayIndex(Object obj, int idx);
// 
//     /**
//      * Extracts a value from an array
//      *
//      * @param obj an array
//      * @param idx index
//      * @param unwrap should provider specific data type be unwrapped
//      * @return the entry at the given index
//      */
//     @Deprecated
//     Object getArrayIndex(Object obj, int idx, boolean unwrap);
// 
//     /**
//      * Sets a value in an array. If the array is too small, the provider is supposed to enlarge it.
//      *
//      * @param array an array
//      * @param idx index
//      * @param newValue the new value
//      */
//     void setArrayIndex(Object array, int idx, Object newValue);
// 
//     /**
//      * Extracts a value from an map
//      *
//      * @param obj a map
//      * @param key property key
//      * @return the map entry or {@link com.jayway.jsonpath.spi.json.JsonProvider#UNDEFINED} for missing properties
//      */
//     Object getMapValue(Object obj, String key);
// 
//     /**
//      * Sets a value in an object
//      *
//      * @param obj   an object
//      * @param key   a String key
//      * @param value the value to set
//      */
//     void setProperty(Object obj, Object key, Object value);
// 
//     /**
//      * Removes a value in an object or array
//      *
//      * @param obj   an array or an object
//      * @param key   a String key or a numerical index to remove
//      */
//     void removeProperty(Object obj, Object key);
// 
//     /**
//      * checks if object is a map (i.e. no array)
//      *
//      * @param obj object to check
//      * @return true if the object is a map
//      */
//     boolean isMap(Object obj);
// 
//     /**
//      * Extracts a value from a wrapper object. For JSON providers that to not wrap
//      * values, this will usually be the object itself.
//      *
//      * @param obj a value holder object
//      * @return the unwrapped value.
//      */
//     Object unwrap(Object obj);
// }


// Path: json-path/src/main/java/com/jayway/jsonpath/internal/path/ScanPathToken.java
import com.jayway.jsonpath.Option;
import com.jayway.jsonpath.internal.PathRef;
import com.jayway.jsonpath.spi.json.JsonProvider;
import java.util.Collection;

                Iterable<?> models = ctx.jsonProvider().toIterable(model);
                int idx = 0;
                for (Object evalModel : models) {
                    String evalPath = currentPath + "[" + idx + "]";
                    next.setUpstreamArrayIndex(idx);
                    next.evaluate(evalPath, parent, evalModel, ctx);
                    idx++;
                }
            }
        }

        Iterable<?> models = ctx.jsonProvider().toIterable(model);
        int idx = 0;
        for (Object evalModel : models) {
            String evalPath = currentPath + "[" + idx + "]";
            walk(pt, evalPath, PathRef.create(model, idx), evalModel, ctx, predicate);
            idx++;
        }
    }

    public static void walkObject(PathToken pt, String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx, Predicate predicate) {

        if (predicate.matches(model)) {
            pt.evaluate(currentPath, parent, model, ctx);
        }
        Collection<String> properties = ctx.jsonProvider().getPropertyKeys(model);

        for (String property : properties) {
            String evalPath = currentPath + "['" + property + "']";
            Object propertyModel = ctx.jsonProvider().getMapValue(model, property);
            if (propertyModel != JsonProvider.UNDEFINED) {