private CharSequence iterableContext(Iterable<?> context, Options options) throws IOException {
    if (options.isFalsy(context)) {
      return options.inverse();
    }

    StringBuilder buffer = new StringBuilder();

    Iterator<?> iterator = reverse(context);
    int index = 0;
    Context parent = options.context;
    while (iterator.hasNext()) {
      Object element = iterator.next();

      boolean first = index == 0;
      boolean even = index % 2 == 0;
      boolean last = !iterator.hasNext();

      Context current =
          Context.newContext(parent, element)
              .data("index", index)
              .data("first", first ? "first" : "")
              .data("last", last ? "last" : "")
              .data("odd", even ? "" : "odd")
              .data("even", even ? "even" : "");
      buffer.append(options.fn(current));

      index++;
    }

    return buffer;
  }
  private CharSequence hashContext(Object context, Options options) throws IOException {
    StringBuilder buffer = new StringBuilder();

    Context parent = options.context;
    Iterator<Map.Entry<String, Object>> iterator = reverse(options.propertySet(context));
    while (iterator.hasNext()) {
      Map.Entry<String, Object> entry = iterator.next();
      Context current = Context.newContext(parent, entry.getValue()).data("key", entry.getKey());
      buffer.append(options.fn(current));
    }

    return buffer;
  }