class RangeIndexSegment
            extends JSONPathSegment {
        final int begin;
        final int end;

        public RangeIndexSegment(int begin, int end) {
            this.begin = begin;
            this.end = end;
        }

        @Override
        public void eval(JSONPath.Context context) {
            Object object = context.parent == null
                    ? context.root
                    : context.parent.value;

            List result = new JSONArray();

            if (object instanceof List) {
                List list = (List) object;
                for (int i = 0, size = list.size(); i < size; i++) {
                    int index = begin >= 0 ? i : i - size;
                    if (index >= begin && index < end) {
                        result.add(list.get(i));
                    }
                }
                context.value = result;
                context.eval = true;
                return;
            }

            if (object instanceof Object[]) {
                Object[] array = (Object[]) object;
                for (int i = 0; i < array.length; i++) {
                    boolean match = i >= begin && i <= end
                            || i - array.length > begin && i - array.length <= end;
                    if (match) {
                        result.add(array[i]);
                    }
                }
                context.value = result;
                context.eval = true;
                return;
            }

            throw new JSONException("TODO");
        }

        @Override
        public void accept(JSONReader jsonReader, JSONPath.Context context) {
            if (context.parent != null
                    && (context.parent.eval
                    || (context.parent.current instanceof CycleNameSegment && context.next == null))
            ) {
                eval(context);
                return;
            }

            if (jsonReader.jsonb) {
                JSONArray array = new JSONArray();

                {
                    int itemCnt = jsonReader.startArray();
                    for (int i = 0; i < itemCnt; i++) {
                        boolean match = begin < 0 || i >= begin && i < end;

                        if (!match) {
                            jsonReader.skipValue();
                            continue;
                        }

                        array.add(
                                jsonReader.readAny());
                    }
                }

                if (begin < 0) {
                    for (int size = array.size(), i = size - 1; i >= 0; i--) {
                        int ni = i - size;
                        if (ni < begin || ni >= end) {
                            array.remove(i);
                        }
                    }
                }

                context.value = array;
                context.eval = true;
                return;
            }

            JSONArray array = new JSONArray();
            jsonReader.next();
            for (int i = 0; jsonReader.ch != EOI; ++i) {
                if (jsonReader.ch == ']') {
                    jsonReader.next();
                    break;
                }

                boolean match = begin < 0 || i >= begin && i < end;

                if (!match) {
                    jsonReader.skipValue();
                    if (jsonReader.ch == ',') {
                        jsonReader.next();
                    }
                    continue;
                }

                Object val;
                switch (jsonReader.ch) {
                    case '-':
                    case '+':
                    case '0':
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9':
                    case '.':
                        jsonReader.readNumber0();
                        val = jsonReader.getNumber();
                        break;
                    case '[':
                        val = jsonReader.readArray();
                        break;
                    case '{':
                        val = jsonReader.readObject();
                        break;
                    case '"':
                    case '\'':
                        val = jsonReader.readString();
                        break;
                    case 't':
                    case 'f':
                        val = jsonReader.readBoolValue();
                        break;
                    case 'n':
                        jsonReader.readNull();
                        val = null;
                        break;
                    default:
                        throw new JSONException("TODO : " + jsonReader.ch);
                }

                array.add(val);
            }

            if (begin < 0) {
                for (int size = array.size(), i = size - 1; i >= 0; i--) {
                    int ni = i - size;
                    if (ni < begin || ni >= end) {
                        array.remove(i);
                    }
                }
            }
            context.value = array;
            context.eval = true;
        }

        @Override
        public void set(JSONPath.Context context, Object value) {
            Object object = context.parent == null
                    ? context.root
                    : context.parent.value;

            if (object instanceof List) {
                List list = (List) object;
                for (int i = 0, size = list.size(); i < size; i++) {
                    int index = begin >= 0 ? i : i - size;
                    if (index >= begin && index < end) {
                        list.set(i, value);
                    }
                }
                return;
            }

            if (object != null) {
                Class objectClass = object.getClass();
                if (objectClass.isArray()) {
                    int size = Array.getLength(object);
                    for (int i = 0; i < size; i++) {
                        int index = begin >= 0 ? i : i - size;
                        if (index >= begin && index < end) {
                            Array.set(object, i, value);
                        }
                    }
                    return;
                }
            }

            throw new JSONException("UnsupportedOperation " + getClass());
        }

        public void setCallback(JSONPath.Context context, BiFunction callback) {
            Object object = context.parent == null
                    ? context.root
                    : context.parent.value;

            if (object instanceof List) {
                List list = (List) object;
                for (int i = 0, size = list.size(); i < size; i++) {
                    int index = begin >= 0 ? i : i - size;
                    if (index >= begin && index < end) {
                        Object item = list.get(i);
                        item = callback.apply(list, item);
                        list.set(index, item);
                    }
                }
                return;
            }

            if (object != null) {
                Class objectClass = object.getClass();
                if (objectClass.isArray()) {
                    int size = Array.getLength(object);
                    for (int i = 0; i < size; i++) {
                        int index = begin >= 0 ? i : i - size;
                        if (index >= begin && index < end) {
                            Object item = Array.get(object, i);
                            item = callback.apply(object, item);
                            Array.set(object, i, item);
                        }
                    }
                    return;
                }
            }

            throw new JSONException("UnsupportedOperation " + getClass());
        }

        @Override
        public boolean remove(JSONPath.Context context) {<FILL_FUNCTION_BODY>}
    }

            Object object = context.parent == null
                    ? context.root
                    : context.parent.value;

            if (object instanceof List) {
                List list = (List) object;
                int removeCount = 0;
                for (int size = list.size(), i = size - 1; i >= 0; i--) {
                    int index = begin >= 0 ? i : i - size;
                    if (index >= begin && index < end) {
                        list.remove(i);
                        removeCount++;
                    }
                }
                return removeCount > 0;
            }

            throw new JSONException("UnsupportedOperation " + getClass());
        
<no_super_class>