docs: public Object compact(Context activeCtx, String activeProperty, Object element,
              boolean compactArrays) throws JsonLdError {
          // 2)
          if (element instanceof List) {
              // 2.1)
              final List<Object> result = new ArrayList<Object>();
              // 2.2)
              for (final Object item : (List<Object>) element) {
                  // 2.2.1)
                  final Object compactedItem = compact(activeCtx, activeProperty, item,
                          compactArrays);
                  // 2.2.2)
                  if (compactedItem != null) {
                      result.add(compactedItem);
                  }
              }
              // 2.3)
              if (compactArrays && result.size() == 1
                      && activeCtx.getContainer(activeProperty) == null) {
                  return result.get(0);
              }
              // 2.4)
              return result;
          }
  
          // 3)
          if (element instanceof Map) {
              // access helper
              final Map<String, Object> elem = (Map<String, Object>) element;
  
              // 4
              if (elem.containsKey(JsonLdConsts.VALUE) || elem.containsKey(JsonLdConsts.ID)) {
                  final Object compactedValue = activeCtx.compactValue(activeProperty, elem);
                  if (!(compactedValue instanceof Map || compactedValue instanceof List)) {
                      return compactedValue;
                  }
              }
              // 5)
              final boolean insideReverse = (JsonLdConsts.REVERSE.equals(activeProperty));
  
              // 6)
              final Map<String, Object> result = newMap();
              // 7)
              final List<String> keys = new ArrayList<String>(elem.keySet());
              Collections.sort(keys);
              for (final String expandedProperty : keys) {
                  final Object expandedValue = elem.get(expandedProperty);
                  // 7.1)
                  if (JsonLdConsts.ID.equals(expandedProperty)
                          || JsonLdConsts.TYPE.equals(expandedProperty)) {
                      // TODO: Relabel these step numbers when spec changes
                      // 7.1.3)
                      final String alias = activeCtx.compactIri(expandedProperty, true);
                      Object compactedValue;
  
                      // 7.1.1)
                      if (expandedValue instanceof String) {
                          compactedValue = activeCtx.compactIri((String) expandedValue,
                                  JsonLdConsts.TYPE.equals(expandedProperty));
                      }
                      // 7.1.2)
                      else {
                          final List<String> types = new ArrayList<String>();
                          // 7.1.2.2)
                          for (final String expandedType : (List<String>) expandedValue) {
                              types.add(activeCtx.compactIri(expandedType, true));
                          }
                          // 7.1.2.3)
                          if (types.size() == 1//
                                  // see w3c/json-ld-syntax#74
                                  && (!opts.getAllowContainerSetOnType()
                                          || !(activeCtx.getContainer(alias) != null && activeCtx
                                                  .getContainer(alias).equals(JsonLdConsts.SET)))) {
                              compactedValue = types.get(0);
                          } else {
                              compactedValue = types;
                          }
                      }
                      // 7.1.4)
                      result.put(alias, compactedValue);
                      continue;
                      // TODO: old add value code, see if it's still relevant?
                      // addValue(rval, alias, compactedValue,
                      // isArray(compactedValue)
                      // && ((List<Object>) expandedValue).size() == 0);
                  }
  
                  // 7.2)
                  if (JsonLdConsts.REVERSE.equals(expandedProperty)) {
                      // 7.2.1)
                      final Map<String, Object> compactedValue = (Map<String, Object>) compact(
                              activeCtx, JsonLdConsts.REVERSE, expandedValue, compactArrays);
  
                      // 7.2.2)
                      // Note: Must create a new set to avoid modifying the set we
                      // are iterating over
                      for (final String property : new HashSet<String>(compactedValue.keySet())) {
                          final Object value = compactedValue.get(property);
                          // 7.2.2.1)
                          if (activeCtx.isReverseProperty(property)) {
                              // 7.2.2.1.1)
                              if ((JsonLdConsts.SET.equals(activeCtx.getContainer(property))
                                      || !compactArrays) && !(value instanceof List)) {
                                  final List<Object> tmp = new ArrayList<Object>();
                                  tmp.add(value);
                                  result.put(property, tmp);
                              }
                              // 7.2.2.1.2)
                              if (!result.containsKey(property)) {
                                  result.put(property, value);
                              }
                              // 7.2.2.1.3)
                              else {
                                  if (!(result.get(property) instanceof List)) {
                                      final List<Object> tmp = new ArrayList<Object>();
                                      tmp.add(result.put(property, tmp));
                                  }
                                  if (value instanceof List) {
                                      ((List<Object>) result.get(property))
                                              .addAll((List<Object>) value);
                                  } else {
                                      ((List<Object>) result.get(property)).add(value);
                                  }
                              }
                              // 7.2.2.1.4)
                              compactedValue.remove(property);
                          }
                      }
                      // 7.2.3)
                      if (!compactedValue.isEmpty()) {
                          // 7.2.3.1)
                          final String alias = activeCtx.compactIri(JsonLdConsts.REVERSE, true);
                          // 7.2.3.2)
                          result.put(alias, compactedValue);
                      }
                      // 7.2.4)
                      continue;
                  }
  
                  // 7.3)
                  if (JsonLdConsts.INDEX.equals(expandedProperty)
                          && JsonLdConsts.INDEX.equals(activeCtx.getContainer(activeProperty))) {
                      continue;
                  }
                  // 7.4)
                  else if (JsonLdConsts.INDEX.equals(expandedProperty)
                          || JsonLdConsts.VALUE.equals(expandedProperty)
                          || JsonLdConsts.LANGUAGE.equals(expandedProperty)) {
                      // 7.4.1)
                      final String alias = activeCtx.compactIri(expandedProperty, true);
                      // 7.4.2)
                      result.put(alias, expandedValue);
                      continue;
                  }
  
                  // NOTE: expanded value must be an array due to expansion
                  // algorithm.
  
                  // 7.5)
                  if (((List<Object>) expandedValue).size() == 0) {
                      // 7.5.1)
                      final String itemActiveProperty = activeCtx.compactIri(expandedProperty,
                              expandedValue, true, insideReverse);
                      // 7.5.2)
                      if (!result.containsKey(itemActiveProperty)) {
                          result.put(itemActiveProperty, new ArrayList<Object>());
                      } else {
                          final Object value = result.get(itemActiveProperty);
                          if (!(value instanceof List)) {
                              final List<Object> tmp = new ArrayList<Object>();
                              tmp.add(value);
                              result.put(itemActiveProperty, tmp);
                          }
                      }
                  }
  
                  // 7.6)
                  for (final Object expandedItem : (List<Object>) expandedValue) {
                      // 7.6.1)
                      final String itemActiveProperty = activeCtx.compactIri(expandedProperty,
                              expandedItem, true, insideReverse);
                      // 7.6.2)
                      final String container = activeCtx.getContainer(itemActiveProperty);
  
                      // get @list value if appropriate
                      final boolean isList = (expandedItem instanceof Map
                              && ((Map<String, Object>) expandedItem).containsKey(JsonLdConsts.LIST));
                      Object list = null;
                      if (isList) {
                          list = ((Map<String, Object>) expandedItem).get(JsonLdConsts.LIST);
                      }
  
                      // 7.6.3)
                      Object compactedItem = compact(activeCtx, itemActiveProperty,
                              isList ? list : expandedItem, compactArrays);
  
                      // 7.6.4)
                      if (isList) {
                          // 7.6.4.1)
                          if (!(compactedItem instanceof List)) {
                              final List<Object> tmp = new ArrayList<Object>();
                              tmp.add(compactedItem);
                              compactedItem = tmp;
                          }
                          // 7.6.4.2)
                          if (!JsonLdConsts.LIST.equals(container)) {
                              // 7.6.4.2.1)
                              final Map<String, Object> wrapper = newMap();
                              // TODO: SPEC: no mention of vocab = true
                              wrapper.put(activeCtx.compactIri(JsonLdConsts.LIST, true),
                                      compactedItem);
                              compactedItem = wrapper;
  
                              // 7.6.4.2.2)
                              if (((Map<String, Object>) expandedItem)
                                      .containsKey(JsonLdConsts.INDEX)) {
                                  ((Map<String, Object>) compactedItem).put(
                                          // TODO: SPEC: no mention of vocab =
                                          // true
                                          activeCtx.compactIri(JsonLdConsts.INDEX, true),
                                          ((Map<String, Object>) expandedItem)
                                                  .get(JsonLdConsts.INDEX));
                              }
                          }
                          // 7.6.4.3)
                          else if (result.containsKey(itemActiveProperty)) {
                              throw new JsonLdError(Error.COMPACTION_TO_LIST_OF_LISTS,
                                      "There cannot be two list objects associated with an active property that has a container mapping");
                          }
                      }
  
                      // 7.6.5)
                      if (JsonLdConsts.LANGUAGE.equals(container)
                              || JsonLdConsts.INDEX.equals(container)) {
                          // 7.6.5.1)
                          Map<String, Object> mapObject;
                          if (result.containsKey(itemActiveProperty)) {
                              mapObject = (Map<String, Object>) result.get(itemActiveProperty);
                          } else {
                              mapObject = newMap();
                              result.put(itemActiveProperty, mapObject);
                          }
  
                          // 7.6.5.2)
                          if (JsonLdConsts.LANGUAGE.equals(container) && (compactedItem instanceof Map
                                  && ((Map<String, Object>) compactedItem)
                                          .containsKey(JsonLdConsts.VALUE))) {
                              compactedItem = ((Map<String, Object>) compactedItem)
                                      .get(JsonLdConsts.VALUE);
                          }
  
                          // 7.6.5.3)
                          final String mapKey = (String) ((Map<String, Object>) expandedItem)
                                  .get(container);
                          // 7.6.5.4)
                          if (!mapObject.containsKey(mapKey)) {
                              mapObject.put(mapKey, compactedItem);
                          } else {
                              List<Object> tmp;
                              if (!(mapObject.get(mapKey) instanceof List)) {
                                  tmp = new ArrayList<Object>();
                                  tmp.add(mapObject.put(mapKey, tmp));
                              } else {
                                  tmp = (List<Object>) mapObject.get(mapKey);
                              }
                              tmp.add(compactedItem);
                          }
                      }
                      // 7.6.6)
                      else {
                          // 7.6.6.1)
                          final Boolean check = (!compactArrays || JsonLdConsts.SET.equals(container)
                                  || JsonLdConsts.LIST.equals(container)
                                  || JsonLdConsts.LIST.equals(expandedProperty)
                                  || JsonLdConsts.GRAPH.equals(expandedProperty))
                                  && (!(compactedItem instanceof List));
                          if (check) {
                              final List<Object> tmp = new ArrayList<Object>();
                              tmp.add(compactedItem);
                              compactedItem = tmp;
                          }
                          // 7.6.6.2)
                          if (!result.containsKey(itemActiveProperty)) {
                              result.put(itemActiveProperty, compactedItem);
                          } else {
                              if (!(result.get(itemActiveProperty) instanceof List)) {
                                  final List<Object> tmp = new ArrayList<Object>();
                                  tmp.add(result.put(itemActiveProperty, tmp));
                              }
                              if (compactedItem instanceof List) {
                                  ((List<Object>) result.get(itemActiveProperty))
                                          .addAll((List<Object>) compactedItem);
                              } else {
                                  ((List<Object>) result.get(itemActiveProperty)).add(compactedItem);
                              }
                          }
  
                      }
                  }
              }
              // 8)
              return result;
          }
  
          // 2)
          return element;
      }