/**
  * Creates a child context.
  *
  * @param parent The parent context. Required.
  * @param model The target value. Resolved as '.' or 'this' inside templates. Required.
  * @return A child context.
  */
 private static Context child(final Context parent, final Object model) {
   notNull(parent, "A parent context is required.");
   Context child = new Context(model);
   child.extendedContext = new Context(new HashMap<String, Object>());
   child.parent = parent;
   child.data = parent.data;
   return child;
 }
 /**
  * Creates a root context.
  *
  * @param model The target value. Resolved as '.' or 'this' inside templates. Required.
  * @return A root context.
  */
 private static Context root(final Object model) {
   Context root = new Context(model);
   root.extendedContext = new Context(new HashMap<String, Object>());
   root.parent = null;
   root.data = new HashMap<String, Object>();
   root.data.put(PARTIALS, new HashMap<String, Template>());
   root.data.put(INVOCATION_STACK, new LinkedList<TemplateSource>());
   return root;
 }
 /**
  * Lookup the given key inside the context stack.
  *
  * <ul>
  *   <li>Objects and hashes should be pushed onto the context stack.
  *   <li>All elements on the context stack should be accessible.
  *   <li>Multiple sections per template should be permitted.
  *   <li>Failed context lookups should be considered falsey.
  *   <li>Dotted names should be valid for Section tags.
  *   <li>Dotted names that cannot be resolved should be considered falsey.
  *   <li>Dotted Names - Context Precedence: Dotted names should be resolved against former
  *       resolutions.
  * </ul>
  *
  * @param key The object key.
  * @return The value associated to the given key or <code>null</code> if no value is found.
  */
 public Object get(final String key) {
   // '.' or 'this'
   if (MUSTACHE_THIS.equals(key) || THIS.equals(key)) {
     return model;
   }
   // '..'
   if (key.equals(PARENT)) {
     return parent == null ? null : parent.model;
   }
   // '../'
   if (key.startsWith(PARENT_ATTR)) {
     return parent == null ? null : parent.get(key.substring(PARENT_ATTR.length()));
   }
   String[] path = toPath(key);
   Object value = get(path);
   if (value == null) {
     // No luck, check the extended context.
     value = get(extendedContext, key);
     // No luck, check the data context.
     if (value == null && data != null) {
       String dataKey = key.charAt(0) == '@' ? key.substring(1) : key;
       // simple data keys will be resolved immediately, complex keys need to go down and using a
       // new context.
       value = data.get(dataKey);
       if (value == null && path.length > 1) {
         // for complex keys, a new data context need to be created per invocation,
         // bc data might changes per execution.
         Context dataContext =
             Context.newBuilder(data).resolver(MapValueResolver.INSTANCE).build();
         // don't extend the lookup further.
         dataContext.data = null;
         value = dataContext.get(dataKey);
         // destroy it!
         dataContext.destroy();
       }
     }
     // No luck, but before checking at the parent scope we need to check for
     // the 'this' qualifier. If present, no look up will be done.
     if (value == null && !path[0].equals(THIS)) {
       value = get(parent, key);
     }
   }
   return value == NULL ? null : value;
 }