Snapshot of commit 84dc01e773388c2c72a1fc437f313dd5747e7809

from branch master of git://git.jetbrains.org/idea/community.git
diff --git a/xml/dom-impl/dom-impl.iml b/xml/dom-impl/dom-impl.iml
index cc3900c..8b2feb0 100644
--- a/xml/dom-impl/dom-impl.iml
+++ b/xml/dom-impl/dom-impl.iml
@@ -9,8 +9,7 @@
     <orderEntry type="sourceFolder" forTests="false" />
     <orderEntry type="module" module-name="dom-openapi" exported="" />
     <orderEntry type="library" name="asm" level="project" />
-    <orderEntry type="library" name="CGLIB" level="project" />
-    <orderEntry type="module" module-name="resources" />
+    <orderEntry type="library" exported="" name="CGLIB" level="project" />
     <orderEntry type="library" name="Xerces" level="project" />
     <orderEntry type="module" module-name="xml" />
     <orderEntry type="module" module-name="util" />
@@ -20,6 +19,7 @@
     <orderEntry type="module" module-name="lang-impl" />
     <orderEntry type="module" module-name="xml-openapi" />
     <orderEntry type="library" name="DTDParser" level="project" />
+    <orderEntry type="module" module-name="platform-resources" />
   </component>
   <component name="copyright">
     <Base>
diff --git a/xml/dom-impl/src/META-INF/DomPlugin.xml b/xml/dom-impl/src/META-INF/DomPlugin.xml
index 71ce3f7..3b2e0ff 100644
--- a/xml/dom-impl/src/META-INF/DomPlugin.xml
+++ b/xml/dom-impl/src/META-INF/DomPlugin.xml
@@ -17,6 +17,8 @@
 
     <extensionPoint name="dom.uiControlsProvider"
                     interface="com.intellij.util.Consumer"/>
+
+    <extensionPoint name="moduleContextProvider" interface="com.intellij.util.xml.ModuleContextProvider"/>
   </extensionPoints>
 
   <extensions defaultExtensionNs="com.intellij">
diff --git a/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementAnnotationHolderImpl.java b/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementAnnotationHolderImpl.java
index f381140..55b140a 100644
--- a/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementAnnotationHolderImpl.java
+++ b/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementAnnotationHolderImpl.java
@@ -27,7 +27,7 @@
 import com.intellij.util.SmartList;
 import com.intellij.util.containers.ContainerUtil;
 import com.intellij.util.xml.*;
-import com.intellij.util.xml.impl.ConvertContextImpl;
+import com.intellij.util.xml.impl.ConvertContextFactory;
 import com.intellij.util.xml.impl.DomManagerImpl;
 import com.intellij.util.xml.reflect.DomCollectionChildDescription;
 import org.jetbrains.annotations.NotNull;
@@ -122,7 +122,7 @@
     if (converter instanceof ResolvingConverter) {
       final ResolvingConverter resolvingConverter = (ResolvingConverter)converter;
       ContainerUtil
-        .addAll(result, resolvingConverter.getQuickFixes(new ConvertContextImpl(DomManagerImpl.getDomInvocationHandler(element))));
+        .addAll(result, resolvingConverter.getQuickFixes(ConvertContextFactory.createConvertContext(DomManagerImpl.getDomInvocationHandler(element))));
     }
     if (reference instanceof LocalQuickFixProvider) {
       final LocalQuickFix[] localQuickFixes = ((LocalQuickFixProvider)reference).getQuickFixes();
diff --git a/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomHighlightingHelperImpl.java b/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomHighlightingHelperImpl.java
index 5e8614d..31935b7 100644
--- a/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomHighlightingHelperImpl.java
+++ b/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomHighlightingHelperImpl.java
@@ -132,7 +132,7 @@
                                      hasBadResolve(domReference = new GenericDomValueReference(element)))) {
           hasBadResolve = true;
           final String errorMessage = converter
-            .getErrorMessage(element.getStringValue(), new ConvertContextImpl(DomManagerImpl.getDomInvocationHandler(element)));
+            .getErrorMessage(element.getStringValue(), ConvertContextFactory.createConvertContext(DomManagerImpl.getDomInvocationHandler(element)));
           if (errorMessage != null && XmlHighlightVisitor.getErrorDescription(domReference) != null) {
             list.add(holder.createResolveProblem(element, domReference));
           }
@@ -140,7 +140,7 @@
       }
       if (!hasBadResolve && psiReferences.length == 0 && element.getValue() == null && !PsiTreeUtil.hasErrorElements(valueElement)) {
         final String errorMessage = converter
-          .getErrorMessage(element.getStringValue(), new ConvertContextImpl(DomManagerImpl.getDomInvocationHandler(element)));
+          .getErrorMessage(element.getStringValue(), ConvertContextFactory.createConvertContext(DomManagerImpl.getDomInvocationHandler(element)));
         if (errorMessage != null) {
           list.add(holder.createProblem(element, errorMessage));
         }
diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/ConvertContextFactory.java b/xml/dom-impl/src/com/intellij/util/xml/impl/ConvertContextFactory.java
new file mode 100644
index 0000000..2ed9b0e
--- /dev/null
+++ b/xml/dom-impl/src/com/intellij/util/xml/impl/ConvertContextFactory.java
@@ -0,0 +1,18 @@
+package com.intellij.util.xml.impl;
+
+import com.intellij.util.xml.ConvertContext;
+import com.intellij.util.xml.DomElement;
+
+public class ConvertContextFactory {
+   public static ConvertContext createConvertContext(final DomElement element) {
+      return new ConvertContextImpl(DomManagerImpl.getDomInvocationHandler(element)) {
+        public DomElement getInvocationElement() {
+           return element;
+        }
+      };
+   }
+
+   public static ConvertContext createConvertContext(final DomInvocationHandler element) {
+     return new ConvertContextImpl(element);
+   }
+}
diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/ConvertContextImpl.java b/xml/dom-impl/src/com/intellij/util/xml/impl/ConvertContextImpl.java
index 2fd958e..d776073 100644
--- a/xml/dom-impl/src/com/intellij/util/xml/impl/ConvertContextImpl.java
+++ b/xml/dom-impl/src/com/intellij/util/xml/impl/ConvertContextImpl.java
@@ -21,7 +21,7 @@
   }
 
   @NotNull
-  public final DomElement getInvocationElement() {
+  public DomElement getInvocationElement() {
     return myHandler.getProxy();
   }
 
diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomApplicationComponent.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomApplicationComponent.java
index 8df0195..058ce38 100644
--- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomApplicationComponent.java
+++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomApplicationComponent.java
@@ -18,6 +18,7 @@
 import com.intellij.openapi.Disposable;
 import com.intellij.openapi.components.ServiceManager;
 import com.intellij.openapi.extensions.Extensions;
+import com.intellij.util.NotNullFunction;
 import com.intellij.util.ReflectionAssignabilityCache;
 import com.intellij.util.containers.ConcurrentFactoryMap;
 import com.intellij.util.containers.FactoryMap;
@@ -60,18 +61,20 @@
     }
   };
 
-  private final ConcurrentFactoryMap<Type, StaticGenericInfo> myGenericInfos = new ConcurrentFactoryMap<Type, StaticGenericInfo>() {
+  private final SofterCache<Type, StaticGenericInfo> myGenericInfos = SofterCache.create(new NotNullFunction<Type, StaticGenericInfo>() {
     @NotNull
-    protected StaticGenericInfo create(final Type type) {
+    @Override
+    public StaticGenericInfo fun(Type type) {
       return new StaticGenericInfo(type);
     }
-  };
-  private final ConcurrentFactoryMap<Class, InvocationCache> myInvocationCaches = new ConcurrentFactoryMap<Class, InvocationCache>() {
+  });
+  private final SofterCache<Class, InvocationCache> myInvocationCaches = SofterCache.create(new NotNullFunction<Class, InvocationCache>() {
     @NotNull
-    protected InvocationCache create(final Class key) {
+    @Override
+    public InvocationCache fun(Class key) {
       return new InvocationCache(key);
     }
-  };
+  });
   private final ConcurrentFactoryMap<Class<? extends DomElementVisitor>, VisitorDescription> myVisitorDescriptions =
     new ConcurrentFactoryMap<Class<? extends DomElementVisitor>, VisitorDescription>() {
       @NotNull
@@ -161,21 +164,15 @@
   }
 
   public final StaticGenericInfo getStaticGenericInfo(final Type type) {
-    return myGenericInfos.get(type);
+    return myGenericInfos.getCachedValue(type);
   }
 
   final InvocationCache getInvocationCache(final Class type) {
-    return myInvocationCaches.get(type);
+    return myInvocationCaches.getCachedValue(type);
   }
 
   public final VisitorDescription getVisitorDescription(Class<? extends DomElementVisitor> aClass) {
     return myVisitorDescriptions.get(aClass);
   }
 
-  @TestOnly
-  public void clearCachesInTests() {
-    myInvocationCaches.clear();
-    myGenericInfos.clear();
-    myCachedImplementationClasses.clear();
-  }
 }
diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomCompletionContributor.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomCompletionContributor.java
index 7d8b2cc..e0478c9 100644
--- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomCompletionContributor.java
+++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomCompletionContributor.java
@@ -18,6 +18,7 @@
 import com.intellij.codeInsight.completion.*;
 import com.intellij.psi.PsiElement;
 import com.intellij.psi.PsiReference;
+import com.intellij.psi.filters.getters.XmlAttributeValueGetter;
 import com.intellij.psi.util.PsiTreeUtil;
 import com.intellij.psi.xml.XmlAttribute;
 import com.intellij.psi.xml.XmlAttributeValue;
@@ -75,7 +76,17 @@
       final PsiElement parent = element.getParent();
       if (parent instanceof XmlAttribute) {
         final XmlAttributeDescriptor descriptor = ((XmlAttribute)parent).getDescriptor();
-        if (descriptor != null && descriptor.isEnumerated()) return true;
+        if (descriptor != null && descriptor.isEnumerated()) {
+          return true;
+        }
+
+        String[] enumeratedValues = XmlAttributeValueGetter.getEnumeratedValues((XmlAttribute)parent);
+        if (enumeratedValues != null && enumeratedValues.length > 0) {
+          String value = descriptor == null ? null : descriptor.getDefaultValue();
+          if (value == null || enumeratedValues.length != 1 || !value.equals(enumeratedValues[0])) {
+            return true;
+          }
+        }
       }
     }
     return false;
diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomReferenceContributor.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomReferenceContributor.java
index 8dbfe5f..9c1d04b 100644
--- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomReferenceContributor.java
+++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomReferenceContributor.java
@@ -24,7 +24,9 @@
  */
 public class DomReferenceContributor extends PsiReferenceContributor{
   public void registerReferenceProviders(final PsiReferenceRegistrar registrar) {
-    registrar.registerReferenceProvider(XmlPatterns.xmlTag(), new GenericValueReferenceProvider());
-    registrar.registerReferenceProvider(XmlPatterns.xmlAttributeValue(), new GenericValueReferenceProvider());
+    GenericValueReferenceProvider provider = new GenericValueReferenceProvider();
+
+    registrar.registerReferenceProvider(XmlPatterns.xmlTag(), provider);
+    registrar.registerReferenceProvider(XmlPatterns.xmlAttributeValue(), provider);
   }
 }
diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DynamicGenericInfo.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DynamicGenericInfo.java
index a95cbe5..ffcc033 100644
--- a/xml/dom-impl/src/com/intellij/util/xml/impl/DynamicGenericInfo.java
+++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DynamicGenericInfo.java
@@ -23,10 +23,11 @@
 import com.intellij.openapi.util.RecursionManager;
 import com.intellij.psi.xml.XmlElement;
 import com.intellij.psi.xml.XmlFile;
+import com.intellij.reference.SoftReference;
 import com.intellij.util.ArrayUtil;
 import com.intellij.util.Function;
 import com.intellij.util.Processor;
-import com.intellij.util.containers.ConcurrentWeakHashMap;
+import com.intellij.util.containers.ConcurrentHashMap;
 import com.intellij.util.containers.ContainerUtil;
 import com.intellij.util.xml.DomElement;
 import com.intellij.util.xml.GenericDomValue;
@@ -46,7 +47,7 @@
  * @author peter
  */
 public class DynamicGenericInfo extends DomGenericInfoEx {
-  private static final Key<ConcurrentWeakHashMap<ChildrenDescriptionsHolder, ChildrenDescriptionsHolder>> HOLDERS_CACHE = Key.create("DOM_CHILDREN_HOLDERS_CACHE");
+  private static final Key<SoftReference<ConcurrentHashMap<ChildrenDescriptionsHolder, ChildrenDescriptionsHolder>>> HOLDERS_CACHE = Key.create("DOM_CHILDREN_HOLDERS_CACHE");
   private static final RecursionGuard ourGuard = RecursionManager.createGuard("dynamicGenericInfo");
   private final StaticGenericInfo myStaticGenericInfo;
   @NotNull private final DomInvocationHandler myInvocationHandler;
@@ -136,9 +137,11 @@
   }
 
   private static <T extends DomChildDescriptionImpl> ChildrenDescriptionsHolder<T> internChildrenHolder(XmlFile file, ChildrenDescriptionsHolder<T> holder) {
-    ConcurrentWeakHashMap<ChildrenDescriptionsHolder, ChildrenDescriptionsHolder> cache = file.getUserData(HOLDERS_CACHE);
+    SoftReference<ConcurrentHashMap<ChildrenDescriptionsHolder, ChildrenDescriptionsHolder>> ref = file.getUserData(HOLDERS_CACHE);
+    ConcurrentHashMap<ChildrenDescriptionsHolder, ChildrenDescriptionsHolder> cache = ref == null ? null : ref.get();
     if (cache == null) {
-      file.putUserData(HOLDERS_CACHE, cache = new ConcurrentWeakHashMap<ChildrenDescriptionsHolder, ChildrenDescriptionsHolder>());
+      cache = new ConcurrentHashMap<ChildrenDescriptionsHolder, ChildrenDescriptionsHolder>();
+      file.putUserData(HOLDERS_CACHE, new SoftReference<ConcurrentHashMap<ChildrenDescriptionsHolder, ChildrenDescriptionsHolder>>(cache));
     }
     ChildrenDescriptionsHolder existing = cache.get(holder);
     if (existing != null) {
diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/GenericDomValueReference.java b/xml/dom-impl/src/com/intellij/util/xml/impl/GenericDomValueReference.java
index b934fe3..06a47b9 100644
--- a/xml/dom-impl/src/com/intellij/util/xml/impl/GenericDomValueReference.java
+++ b/xml/dom-impl/src/com/intellij/util/xml/impl/GenericDomValueReference.java
@@ -143,12 +143,12 @@
   }
 
   public String getUnresolvedMessagePattern() {
-    final ConvertContextImpl context = getConvertContext();
+    final ConvertContext context = getConvertContext();
     return getConverter().getErrorMessage(getStringValue(), context);
   }
 
-  public final ConvertContextImpl getConvertContext() {
-    return new ConvertContextImpl(DomManagerImpl.getDomInvocationHandler(myGenericValue));
+  public final ConvertContext getConvertContext() {
+    return ConvertContextFactory.createConvertContext(DomManagerImpl.getDomInvocationHandler(myGenericValue));
   }
 
   public PsiElement handleElementRename(final String newElementName) throws IncorrectOperationException {
diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/GenericValueReferenceProvider.java b/xml/dom-impl/src/com/intellij/util/xml/impl/GenericValueReferenceProvider.java
index 4040ade..b457c9d 100644
--- a/xml/dom-impl/src/com/intellij/util/xml/impl/GenericValueReferenceProvider.java
+++ b/xml/dom-impl/src/com/intellij/util/xml/impl/GenericValueReferenceProvider.java
@@ -89,17 +89,8 @@
     return references;
   }
 
-  private static AbstractConvertContext createConvertContext(final PsiElement psiElement, final GenericDomValue domValue) {
-    return new AbstractConvertContext() {
-      @NotNull
-      public DomElement getInvocationElement() {
-        return domValue;
-      }
-
-      public PsiManager getPsiManager() {
-        return psiElement.getManager();
-      }
-    };
+  private static ConvertContext createConvertContext(final PsiElement psiElement, final GenericDomValue domValue) {
+    return ConvertContextFactory.createConvertContext(domValue);
   }
 
   @Nullable
@@ -108,7 +99,7 @@
   }
 
   private PsiReference[] createReferences(final GenericDomValue domValue, final XmlElement psiElement, final Object converter) {
-    AbstractConvertContext context = createConvertContext(psiElement, domValue);
+    ConvertContext context = createConvertContext(psiElement, domValue);
 
     List<PsiReference> result = new ArrayList<PsiReference>();
     String unresolvedText = ElementManipulators.getValueText(psiElement);
diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/GetInvocation.java b/xml/dom-impl/src/com/intellij/util/xml/impl/GetInvocation.java
index 41e85a9..c2642f1 100644
--- a/xml/dom-impl/src/com/intellij/util/xml/impl/GetInvocation.java
+++ b/xml/dom-impl/src/com/intellij/util/xml/impl/GetInvocation.java
@@ -9,10 +9,7 @@
 import com.intellij.psi.util.CachedValuesManager;
 import com.intellij.psi.util.PsiModificationTracker;
 import com.intellij.util.containers.ContainerUtil;
-import com.intellij.util.xml.Converter;
-import com.intellij.util.xml.DomReferenceInjector;
-import com.intellij.util.xml.DomUtil;
-import com.intellij.util.xml.SubTag;
+import com.intellij.util.xml.*;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.List;
@@ -43,8 +40,9 @@
       handler.putUserData(DOM_VALUE_KEY, value = cachedValuesManager.createCachedValue(new CachedValueProvider<List<Pair<Converter,Object>>>() {
         @Override
         public Result<List<Pair<Converter,Object>>> compute() {
-          List<Pair<Converter, Object>> list = ContainerUtil.createEmptyCOWList();
-          return Result.create(list, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT, domManager, ProjectRootManager.getInstance(project));
+          List<Pair<Converter, Object>> list = ContainerUtil.createLockFreeCopyOnWriteList();
+          return Result
+            .create(list, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT, domManager, ProjectRootManager.getInstance(project));
         }
       }, false));
     }
@@ -80,7 +78,7 @@
     }
 
     String tagValue = handler.getValue();
-    ConvertContextImpl context = new ConvertContextImpl(handler);
+    ConvertContext context = ConvertContextFactory.createConvertContext(handler);
 
     for (DomReferenceInjector each : DomUtil.getFileElement(handler).getFileDescription().getReferenceInjectors()) {
       tagValue = each.resolveString(tagValue, context);
diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/ImplementationClassCache.java b/xml/dom-impl/src/com/intellij/util/xml/impl/ImplementationClassCache.java
index 57625e8..463c06d 100644
--- a/xml/dom-impl/src/com/intellij/util/xml/impl/ImplementationClassCache.java
+++ b/xml/dom-impl/src/com/intellij/util/xml/impl/ImplementationClassCache.java
@@ -18,17 +18,22 @@
 import com.intellij.openapi.Disposable;
 import com.intellij.openapi.extensions.ExtensionPointName;
 import com.intellij.openapi.util.Disposer;
+import com.intellij.util.NotNullFunction;
 import com.intellij.util.ReflectionCache;
+import com.intellij.util.SofterReference;
 import com.intellij.util.containers.ConcurrentFactoryMap;
+import com.intellij.util.containers.ConcurrentHashMap;
 import com.intellij.util.containers.MultiMap;
 import com.intellij.util.xml.DomReflectionUtil;
 import com.intellij.util.xml.Implementation;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.SortedSet;
 import java.util.TreeSet;
+import java.util.concurrent.ConcurrentMap;
 
 /**
  * @author peter
@@ -45,18 +50,13 @@
 
 
   private final MultiMap<String, DomImplementationClassEP> myImplementationClasses = new MultiMap<String, DomImplementationClassEP>();
-  private final ConcurrentFactoryMap<Class, Class> myCache = new ConcurrentFactoryMap<Class, Class>() {
-      @Nullable
-        protected Class create(final Class concreteInterface) {
-          final TreeSet<Class> set = new TreeSet<Class>(CLASS_COMPARATOR);
-          findImplementationClassDFS(concreteInterface, set);
-          if (!set.isEmpty()) {
-            return set.first();
-          }
-          final Implementation implementation = DomReflectionUtil.findAnnotationDFS(concreteInterface, Implementation.class);
-          return implementation == null ? null : implementation.value();
-        }
-    };
+  private final SofterCache<Class, Class> myCache = SofterCache.create(new NotNullFunction<Class, Class>() {
+    @NotNull
+    @Override
+    public Class fun(Class dom) {
+      return calcImplementationClass(dom);
+    }
+  });
 
   ImplementationClassCache(ExtensionPointName<DomImplementationClassEP> epName) {
     for (DomImplementationClassEP ep : epName.getExtensions()) {
@@ -64,6 +64,16 @@
     }
   }
 
+  private Class calcImplementationClass(Class concreteInterface) {
+    final TreeSet<Class> set = new TreeSet<Class>(CLASS_COMPARATOR);
+    findImplementationClassDFS(concreteInterface, set);
+    if (!set.isEmpty()) {
+      return set.first();
+    }
+    final Implementation implementation = DomReflectionUtil.findAnnotationDFS(concreteInterface, Implementation.class);
+    return implementation == null ? concreteInterface : implementation.value();
+  }
+
   private void findImplementationClassDFS(final Class concreteInterface, SortedSet<Class> results) {
     final Collection<DomImplementationClassEP> values = myImplementationClasses.get(concreteInterface.getName());
     for (DomImplementationClassEP value : values) {
@@ -98,15 +108,13 @@
         }
       });
     }
-    myCache.clear();
+    myCache.clearCache();
   }
 
   public Class get(Class key) {
-    return myCache.get(key);
+    Class impl = myCache.getCachedValue(key);
+    return impl == key ? null : impl;
   }
 
-  public void clear() {
-    myCache.clear();
-  }
 
 }
diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/SofterCache.java b/xml/dom-impl/src/com/intellij/util/xml/impl/SofterCache.java
new file mode 100644
index 0000000..1e03744
--- /dev/null
+++ b/xml/dom-impl/src/com/intellij/util/xml/impl/SofterCache.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.util.xml.impl;
+
+import com.intellij.util.NotNullFunction;
+import com.intellij.util.SofterReference;
+import com.intellij.util.containers.ConcurrentHashMap;
+
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * @author peter
+ */
+public class SofterCache<T,V> {
+  private final NotNullFunction<T,V> myValueProvider;
+  private SofterReference<ConcurrentMap<T, V>> myCache;
+
+  public SofterCache(NotNullFunction<T, V> valueProvider) {
+    myValueProvider = valueProvider;
+  }
+
+  public static <T, V> SofterCache<T, V> create(NotNullFunction<T, V> valueProvider) {
+    return new SofterCache<T, V>(valueProvider);
+  }
+
+  public void clearCache() {
+    myCache = null;
+  }
+
+  public V getCachedValue(T key) {
+    SofterReference<ConcurrentMap<T, V>> ref = myCache;
+    ConcurrentMap<T, V> map = ref == null ? null : ref.get();
+    if (map == null) {
+      myCache = new SofterReference<ConcurrentMap<T, V>>(map = new ConcurrentHashMap<T, V>());
+    }
+    V value = map.get(key);
+    if (value == null) {
+      map.put(key, value = myValueProvider.fun(key));
+    }
+    return value;
+  }
+
+
+}
diff --git a/xml/dom-impl/src/com/intellij/util/xml/ui/TextControl.java b/xml/dom-impl/src/com/intellij/util/xml/ui/TextControl.java
index 89cf4db..c6dec44 100644
--- a/xml/dom-impl/src/com/intellij/util/xml/ui/TextControl.java
+++ b/xml/dom-impl/src/com/intellij/util/xml/ui/TextControl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2013 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -99,7 +99,7 @@
           DialogBuilder builder = new DialogBuilder(project);
           builder.setDimensionServiceKey("TextControl");
           builder.setCenterPanel(textArea);
-          builder.setPreferedFocusComponent(textArea);
+          builder.setPreferredFocusComponent(textArea);
           builder.setTitle(UIBundle.message("big.text.control.window.title"));
           builder.addCloseButton();
           builder.show();
diff --git a/xml/dom-openapi/dom-openapi.iml b/xml/dom-openapi/dom-openapi.iml
index da874a7..f94d712 100644
--- a/xml/dom-openapi/dom-openapi.iml
+++ b/xml/dom-openapi/dom-openapi.iml
@@ -7,13 +7,13 @@
     </content>
     <orderEntry type="inheritedJdk" />
     <orderEntry type="sourceFolder" forTests="false" />
-    <orderEntry type="module" module-name="resources" />
     <orderEntry type="module" module-name="xml-openapi" />
     <orderEntry type="module" module-name="lang-api" />
     <orderEntry type="module" module-name="platform-api" />
     <orderEntry type="module" module-name="extensions" />
     <orderEntry type="module" module-name="util" />
     <orderEntry type="module" module-name="lang-impl" />
+    <orderEntry type="module" module-name="platform-resources" />
   </component>
   <component name="copyright">
     <Base>
diff --git a/xml/dom-openapi/src/com/intellij/util/xml/AbstractConvertContext.java b/xml/dom-openapi/src/com/intellij/util/xml/AbstractConvertContext.java
index dd2c03f..b3580d6 100644
--- a/xml/dom-openapi/src/com/intellij/util/xml/AbstractConvertContext.java
+++ b/xml/dom-openapi/src/com/intellij/util/xml/AbstractConvertContext.java
@@ -17,7 +17,12 @@
 
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.module.ModuleUtil;
+import com.intellij.openapi.roots.ProjectFileIndex;
+import com.intellij.openapi.roots.ProjectRootManager;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
 import com.intellij.psi.PsiManager;
+import com.intellij.psi.search.GlobalSearchScope;
 import com.intellij.psi.xml.XmlElement;
 import com.intellij.psi.xml.XmlFile;
 import com.intellij.psi.xml.XmlTag;
@@ -29,15 +34,6 @@
  */
 public abstract class AbstractConvertContext extends ConvertContext {
 
-  public static ConvertContext createConvertContext(final DomElement domElement) {
-    return new AbstractConvertContext() {
-      @NotNull
-      public DomElement getInvocationElement() {
-        return domElement;
-      }
-    };
-  }
-
   public final XmlTag getTag() {
     return getInvocationElement().getXmlTag();
   }
@@ -56,7 +52,7 @@
     final DomFileElement<DomElement> fileElement = DomUtil.getFileElement(getInvocationElement());
     if (fileElement == null) {
       final XmlElement xmlElement = getInvocationElement().getXmlElement();
-      return xmlElement == null? null : ModuleUtil.findModuleForPsiElement(xmlElement);
+      return xmlElement == null ? null : ModuleUtil.findModuleForPsiElement(xmlElement);
     }
     return fileElement.getRootElement().getModule();
   }
@@ -65,4 +61,66 @@
     return getFile().getManager();
   }
 
+  @Nullable
+  public GlobalSearchScope getSearchScope() {
+    GlobalSearchScope scope = null;
+
+    Module[] modules = getConvertContextModules(this);
+    if (modules.length != 0) {
+
+      PsiFile file = getFile();
+      file = file.getOriginalFile();
+      VirtualFile virtualFile = file.getVirtualFile();
+      if (virtualFile != null) {
+        ProjectFileIndex fileIndex = ProjectRootManager.getInstance(file.getProject()).getFileIndex();
+        boolean tests = fileIndex.isInTestSourceContent(virtualFile);
+
+        for (Module module : modules) {
+          if (scope == null) {
+            scope = module.getModuleRuntimeScope(tests);
+          }
+          else {
+            scope.union(module.getModuleRuntimeScope(tests));
+          }
+        }
+      }
+    }
+    return scope; // ??? scope == null ? GlobalSearchScope.allScope(getProject()) : scope; ???
+  }
+
+  public static GlobalSearchScope getSearchScope(@NotNull ConvertContext context) {
+    Module[] modules = getConvertContextModules(context);
+    if (modules.length == 0) return null;
+
+    PsiFile file = context.getFile();
+    file = file.getOriginalFile();
+    VirtualFile virtualFile = file.getVirtualFile();
+    if (virtualFile == null) return null;
+    ProjectFileIndex fileIndex = ProjectRootManager.getInstance(file.getProject()).getFileIndex();
+    boolean tests = fileIndex.isInTestSourceContent(virtualFile);
+
+
+    GlobalSearchScope scope = null;
+    for (Module module : modules) {
+      if (scope == null) {
+        scope = module.getModuleRuntimeScope(tests);
+      }
+      else {
+        scope.union(module.getModuleRuntimeScope(tests));
+      }
+    }
+    return scope;
+  }
+
+
+  @NotNull
+  private static Module[] getConvertContextModules(@NotNull ConvertContext context) {
+    Module[] modules = ModuleContextProvider.getModules(context.getFile());
+    if (modules.length > 0) return modules;
+
+    final Module module = context.getModule();
+    if (module != null) return new Module[]{module};
+
+    return new Module[0];
+  }
 }
diff --git a/xml/dom-openapi/src/com/intellij/util/xml/ConvertContext.java b/xml/dom-openapi/src/com/intellij/util/xml/ConvertContext.java
index 2ee1b01..00550b0 100644
--- a/xml/dom-openapi/src/com/intellij/util/xml/ConvertContext.java
+++ b/xml/dom-openapi/src/com/intellij/util/xml/ConvertContext.java
@@ -18,6 +18,7 @@
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.project.Project;
 import com.intellij.psi.PsiManager;
+import com.intellij.psi.search.GlobalSearchScope;
 import com.intellij.psi.xml.XmlAttribute;
 import com.intellij.psi.xml.XmlElement;
 import com.intellij.psi.xml.XmlFile;
@@ -56,6 +57,9 @@
 
   @Nullable
   public abstract Module getModule();
+
+  @Nullable
+  public abstract GlobalSearchScope getSearchScope();
   
   public abstract PsiManager getPsiManager();
 
diff --git a/xml/dom-openapi/src/com/intellij/util/xml/DomUtil.java b/xml/dom-openapi/src/com/intellij/util/xml/DomUtil.java
index 5803c6c..9a6de09 100644
--- a/xml/dom-openapi/src/com/intellij/util/xml/DomUtil.java
+++ b/xml/dom-openapi/src/com/intellij/util/xml/DomUtil.java
@@ -221,7 +221,6 @@
         }
       });
       return result;
-
     }
 
     ProgressManager.checkCanceled();
@@ -241,21 +240,25 @@
       if (attributes) {
         for (final XmlAttribute attribute : tag.getAttributes()) {
           if (!attribute.isValid()) {
-            throw new AssertionError("Invalid attr: parent.valid=" + tag.isValid());
+            LOG.error("Invalid attr: parent.valid=" + tag.isValid());
+            continue;
           }
           GenericAttributeValue element = domManager.getDomElement(attribute);
-          checkHasXml(attribute, element);
-          ContainerUtil.addIfNotNull(element, result);
+          if (checkHasXml(attribute, element)) {
+            ContainerUtil.addIfNotNull(element, result);
+          }
         }
       }
       if (tags) {
         for (final XmlTag subTag : tag.getSubTags()) {
           if (!subTag.isValid()) {
-            throw new AssertionError("Invalid subtag: parent.valid=" + tag.isValid());
+            LOG.error("Invalid subtag: parent.valid=" + tag.isValid());
+            continue;
           }
           DomElement element = domManager.getDomElement(subTag);
-          checkHasXml(subTag, element);
-          ContainerUtil.addIfNotNull(element, result);
+          if (checkHasXml(subTag, element)) {
+            ContainerUtil.addIfNotNull(element, result);
+          }
         }
       }
       return result;
@@ -263,10 +266,12 @@
     return Collections.emptyList();
   }
 
-  private static void checkHasXml(XmlElement psi, DomElement dom) {
+  private static boolean checkHasXml(XmlElement psi, DomElement dom) {
     if (dom != null && dom.getXmlElement() == null) {
-      throw new AssertionError("No xml for dom " + dom + "; attr=" + psi + ", physical=" + psi.isPhysical());
+      LOG.error("No xml for dom " + dom + "; attr=" + psi + ", physical=" + psi.isPhysical());
+      return false;
     }
+    return true;
   }
 
   public static <T> List<T> getDefinedChildrenOfType(@NotNull final DomElement parent, final Class<T> type, boolean tags, boolean attributes) {
diff --git a/xml/dom-openapi/src/com/intellij/util/xml/ModuleContextProvider.java b/xml/dom-openapi/src/com/intellij/util/xml/ModuleContextProvider.java
new file mode 100644
index 0000000..7cf5525
--- /dev/null
+++ b/xml/dom-openapi/src/com/intellij/util/xml/ModuleContextProvider.java
@@ -0,0 +1,33 @@
+package com.intellij.util.xml;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleUtilCore;
+import com.intellij.psi.PsiFile;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.HashSet;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Set;
+
+public abstract class ModuleContextProvider {
+  public static final ExtensionPointName<ModuleContextProvider> EP_NAME = ExtensionPointName.create("com.intellij.moduleContextProvider");
+
+  @NotNull
+  public abstract Module[] getContextModules(@NotNull PsiFile context);
+
+  public static Module[] getModules(@Nullable PsiFile context) {
+    if (context == null) return Module.EMPTY_ARRAY;
+
+    final Set<Module> modules = new HashSet<Module>();
+    for (ModuleContextProvider moduleContextProvider : Extensions.getExtensions(EP_NAME)) {
+      ContainerUtil.addAllNotNull(modules, moduleContextProvider.getContextModules(context));
+    }
+    Module module = ModuleUtilCore.findModuleForPsiElement(context);
+    if (module != null) modules.add(module);
+
+    return modules.toArray(new Module[modules.size()]);
+  }
+}
diff --git a/xml/dom-openapi/src/com/intellij/util/xml/converters/DelimitedListConverter.java b/xml/dom-openapi/src/com/intellij/util/xml/converters/DelimitedListConverter.java
index e8b12e6..2e5c825 100644
--- a/xml/dom-openapi/src/com/intellij/util/xml/converters/DelimitedListConverter.java
+++ b/xml/dom-openapi/src/com/intellij/util/xml/converters/DelimitedListConverter.java
@@ -107,7 +107,7 @@
   }
 
   public String toString(final List<T> ts, final ConvertContext context) {
-    final StringBuffer buffer = new StringBuffer();
+    final StringBuilder buffer = new StringBuilder();
     final char delimiter = getDefaultDelimiter();
     for (T t : ts) {
       final String s = toString(t);
@@ -151,6 +151,11 @@
     return new MyPsiReference(element, new TextRange(start, end), context, genericDomValue, delimitersOnly);
   }
 
+  @Override
+  public String toString() {
+    return super.toString() + " delimiters: " + myDelimiters;
+  }
+
   protected class MyPsiReference extends PsiReferenceBase<PsiElement> implements EmptyResolveMessageProvider {
     protected final ConvertContext myContext;
     protected final GenericDomValue<List<T>> myGenericDomValue;
@@ -212,6 +217,11 @@
       return bindElement;
     }
 
+    @Override
+    public String toString() {
+      return super.toString() + " converter: " + DelimitedListConverter.this;
+    }
+
     private Function<PsiElement, PsiElement> getSuperBindToElementFunction(final Ref<IncorrectOperationException> ref) {
       return new Function<PsiElement, PsiElement>() {
         public PsiElement fun(final PsiElement s) {
diff --git a/xml/dom-openapi/src/com/intellij/util/xml/converters/PathReferenceConverter.java b/xml/dom-openapi/src/com/intellij/util/xml/converters/PathReferenceConverter.java
index c533e58..2d578a1 100644
--- a/xml/dom-openapi/src/com/intellij/util/xml/converters/PathReferenceConverter.java
+++ b/xml/dom-openapi/src/com/intellij/util/xml/converters/PathReferenceConverter.java
@@ -36,9 +36,8 @@
   public final static Converter<PathReference> INSTANCE = new PathReferenceConverter();
 
   public PathReference fromString(@Nullable final String s, final ConvertContext context) {
-    Module module = context.getModule();
     final XmlElement element = context.getXmlElement();
-    return s == null || module == null || element == null ? null : PathReferenceManager.getInstance().getPathReference(s, module, element);
+    return s == null || element == null ? null : PathReferenceManager.getInstance().getPathReference(s, element);
   }
 
   public String toString(final PathReference t, final ConvertContext context) {
diff --git a/xml/dom-openapi/src/com/intellij/util/xml/ui/CaptionComponent.java b/xml/dom-openapi/src/com/intellij/util/xml/ui/CaptionComponent.java
index 4743fc9..ed30d6b 100644
--- a/xml/dom-openapi/src/com/intellij/util/xml/ui/CaptionComponent.java
+++ b/xml/dom-openapi/src/com/intellij/util/xml/ui/CaptionComponent.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2013 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
 package com.intellij.util.xml.ui;
 
 import com.intellij.openapi.util.Disposer;
+import com.intellij.ui.JBColor;
 import com.intellij.util.xml.DomElement;
 
 import javax.swing.*;
@@ -46,6 +47,7 @@
   public CaptionComponent(String text, Icon icon) {
     super(new BorderLayout());
     updateBorder();
+    myRootPanel.setBackground(new JBColor(new Color(243, 244, 229), new Color(42, 55, 62)));
     add(myRootPanel, BorderLayout.CENTER);
 
     setText(text);
@@ -54,7 +56,7 @@
 
   private void updateBorder() {
     if (myBordered) {
-      myRootPanel.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.LIGHT_GRAY));
+      myRootPanel.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, JBColor.LIGHT_GRAY));
     }
     else {
       myRootPanel.setBorder(BorderFactory.createEmptyBorder());
diff --git a/xml/dom-openapi/src/com/intellij/util/xml/ui/ComboControl.java b/xml/dom-openapi/src/com/intellij/util/xml/ui/ComboControl.java
index db9c5ed..3984d19 100644
--- a/xml/dom-openapi/src/com/intellij/util/xml/ui/ComboControl.java
+++ b/xml/dom-openapi/src/com/intellij/util/xml/ui/ComboControl.java
@@ -112,24 +112,6 @@
     };
   }
 
-  public static Factory<Collection<? extends Object>> createVariantsGetter(final GenericDomValue<?> reference) {
-    return new Factory<Collection<? extends Object>>() {
-      public Collection<? extends Object> create() {
-        final Converter converter = reference.getConverter();
-        if (converter instanceof ResolvingConverter) {
-          return ((ResolvingConverter)converter).getVariants(new AbstractConvertContext() {
-            @NotNull
-            public DomElement getInvocationElement() {
-              return reference;
-            }
-          });
-
-        }
-        return Collections.emptyList();
-      }
-    };
-  }
-
   public static Factory<List<Pair<String, Icon>>> createPresentationFunction(final Factory<Collection<? extends Object>> variantFactory) {
     return new Factory<List<Pair<String, Icon>>>() {
       public List<Pair<String, Icon>> create() {
diff --git a/xml/dom-openapi/src/com/intellij/util/xml/ui/actions/generate/CreateDomElementAction.java b/xml/dom-openapi/src/com/intellij/util/xml/ui/actions/generate/CreateDomElementAction.java
index 2d3d1ed..198016b 100644
--- a/xml/dom-openapi/src/com/intellij/util/xml/ui/actions/generate/CreateDomElementAction.java
+++ b/xml/dom-openapi/src/com/intellij/util/xml/ui/actions/generate/CreateDomElementAction.java
@@ -49,7 +49,7 @@
   protected abstract DomElement createElement(T context, Editor editor, PsiFile file, Project project);
 
   @Override
-  protected boolean isValidForFile(Project project, Editor editor, PsiFile file) {
+  protected boolean isValidForFile(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
     return getContextElement(editor) != null;
   }
 
diff --git a/xml/dom-openapi/src/com/intellij/util/xml/ui/actions/generate/GenerateDomElementAction.java b/xml/dom-openapi/src/com/intellij/util/xml/ui/actions/generate/GenerateDomElementAction.java
index dad9336..dd6f1c0 100644
--- a/xml/dom-openapi/src/com/intellij/util/xml/ui/actions/generate/GenerateDomElementAction.java
+++ b/xml/dom-openapi/src/com/intellij/util/xml/ui/actions/generate/GenerateDomElementAction.java
@@ -50,6 +50,7 @@
       this(generateProvider, null);
   }
 
+  @NotNull
   protected CodeInsightActionHandler getHandler() {
     return new CodeInsightActionHandler() {
       public void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile file) {
@@ -82,7 +83,7 @@
     return true;
   }
 
-  protected boolean isValidForFile(final Project project, final Editor editor, final PsiFile file) {
+  protected boolean isValidForFile(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile file) {
     final DomElement element = DomUtil.getContextElement(editor);
     return element != null && myProvider.isAvailableForElement(element);
   }
diff --git a/xml/dom-tests/tests/com/intellij/util/xml/DomConcurrencyStressTest.java b/xml/dom-tests/tests/com/intellij/util/xml/DomConcurrencyStressTest.java
index c38cd10..e0aa679 100644
--- a/xml/dom-tests/tests/com/intellij/util/xml/DomConcurrencyStressTest.java
+++ b/xml/dom-tests/tests/com/intellij/util/xml/DomConcurrencyStressTest.java
@@ -97,27 +97,30 @@
   }
 
   private static void runThreads(int threadCount, final Runnable runnable) throws Throwable {
-    final Ref<Throwable> exc = Ref.create(null);
+    for (int i=0; i<threadCount/8 + 1; i++) {
+      final Ref<Throwable> exc = Ref.create(null);
 
-    final CountDownLatch reads = new CountDownLatch(threadCount);
-    for (int j = 0; j < threadCount; j++) {
-      new Thread(){
-        @Override
-        public void run() {
-          try {
-            runnable.run();
+      final CountDownLatch reads = new CountDownLatch(8);
+      for (int j = 0; j < 8; j++) {
+        new Thread(){
+          @Override
+          public void run() {
+            try {
+              runnable.run();
+            }
+            catch (Throwable e) {
+              exc.set(e);
+            }
+            finally {
+              reads.countDown();
+            }
           }
-          catch (Throwable e) {
-            exc.set(e);
-          } finally {
-            reads.countDown();
-          }
-        }
-      }.start();
-    }
-    reads.await();
-    if (!exc.isNull()) {
-      throw exc.get();
+        }.start();
+      }
+      reads.await();
+      if (!exc.isNull()) {
+        throw exc.get();
+      }
     }
   }
 
diff --git a/xml/dom-tests/tests/com/intellij/util/xml/DomHardCoreTestCase.java b/xml/dom-tests/tests/com/intellij/util/xml/DomHardCoreTestCase.java
index dc092fc..934bf29 100644
--- a/xml/dom-tests/tests/com/intellij/util/xml/DomHardCoreTestCase.java
+++ b/xml/dom-tests/tests/com/intellij/util/xml/DomHardCoreTestCase.java
@@ -35,12 +35,6 @@
     }, myProject);
   }
 
-  @Override
-  protected void tearDown() throws Exception {
-    DomApplicationComponent.getInstance().clearCachesInTests();
-    super.tearDown();
-  }
-
   protected DomManagerImpl getDomManager() {
     return DomManagerImpl.getDomManager(getProject());
   }
diff --git a/xml/dom-tests/tests/com/intellij/util/xml/DomIncludesTest.java b/xml/dom-tests/tests/com/intellij/util/xml/DomIncludesTest.java
index 20e19b8..16d2b6f 100644
--- a/xml/dom-tests/tests/com/intellij/util/xml/DomIncludesTest.java
+++ b/xml/dom-tests/tests/com/intellij/util/xml/DomIncludesTest.java
@@ -5,6 +5,7 @@
 package com.intellij.util.xml;
 
 import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction;
+import com.intellij.concurrency.JobLauncher;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.vfs.VfsUtil;
 import com.intellij.openapi.vfs.VirtualFile;
@@ -90,51 +91,51 @@
                             "<xi:include href=\"b.xml\" xpointer=\"xpointer(/xxx/*)\"/>" +
                             "</root>");
 
-    final PsiFile fileB = createFile("b.xml",
-                                    "<xxx><boy/><xi:include href=\"c.xml\" xpointer=\"xpointer(/xxx/*)\"/><child/><xi:include href=\"c.xml\" xpointer=\"xpointer(/xxx/*)\"/></xxx>");
-    final PsiFile fileC = createFile("c.xml",
-                                    "<xxx><child/><xi:include href=\"d.xml\" xpointer=\"xpointer(/xxx/*)\"/><boy/><xi:include href=\"d.xml\" xpointer=\"xpointer(/xxx/*)\"/></xxx>");
-    final PsiFile fileD = createFile("d.xml",
-                                    "<xxx><boy/><xi:include href=\"e.xml\" xpointer=\"xpointer(/xxx/*)\"/><child/><xi:include href=\"e.xml\" xpointer=\"xpointer(/xxx/*)\"/></xxx>");
-    final PsiFile fileE = createFile("e.xml",
-                                    "<xxx><boy/><child/><boy/><child/><boy/><child/><boy/><child/><boy/><child/><boy/><child/></xxx>");
+    final String textB =
+      "<xxx><boy/><xi:include href=\"c.xml\" xpointer=\"xpointer(/xxx/*)\"/><child/><xi:include href=\"c.xml\" xpointer=\"xpointer(/xxx/*)\"/></xxx>";
+    final PsiFile fileB = createFile("b.xml", textB);
+    final String textC =
+      "<xxx><child/><xi:include href=\"d.xml\" xpointer=\"xpointer(/xxx/*)\"/><boy/><xi:include href=\"d.xml\" xpointer=\"xpointer(/xxx/*)\"/></xxx>";
+    final PsiFile fileC = createFile("c.xml", textC);
+    final String textD =
+      "<xxx><boy/><xi:include href=\"e.xml\" xpointer=\"xpointer(/xxx/*)\"/><child/><xi:include href=\"e.xml\" xpointer=\"xpointer(/xxx/*)\"/></xxx>";
+    final PsiFile fileD = createFile("d.xml", textD);
+    final String textE = "<xxx><boy/><child/><boy/><child/><boy/><child/><boy/><child/><boy/><child/><boy/><child/></xxx>";
+    final PsiFile fileE = createFile("e.xml", textE);
     final int threadCount = 100;
-    final int iterationCount = Timings.adjustAccordingToMySpeed(800, true);
+    final int iterationCount = Timings.adjustAccordingToMySpeed(100, true);
     System.out.println("iterationCount = " + iterationCount);
 
     final CountDownLatch finished = new CountDownLatch(threadCount);
     final AtomicReference<Exception> ex = new AtomicReference<Exception>();
 
-    Thread[] threads = new Thread[threadCount];
     for (int j = 0; j < threadCount; j++) {
-      Thread thread = new Thread() {
+      JobLauncher.getInstance().submitToJobThread(0, new Runnable() {
         @Override
         public void run() {
+          try {
           for (int k = 0; k < iterationCount; k++) {
             ApplicationManager.getApplication().runReadAction(new Runnable() {
               public void run() {
-                try {
                   final List<Boy> boys = rootElement.getBoys();
                   Thread.yield();
                   final List<Child> children = rootElement.getChildren();
                   Thread.yield();
                   assertEquals(boys, rootElement.getBoys());
                   assertEquals(children, rootElement.getChildren());
-                }
-                catch (Exception e) {
-                  ex.set(e);
-                }
-                finally {
-                  finished.countDown();
-                }
               }
             });
             Thread.yield();
           }
+          }
+          catch (Exception e) {
+            ex.set(e);
+          }
+          finally {
+            finished.countDown();
+          }
         }
-      };
-      threads[j] = thread;
-      thread.start();
+      });
     }
 
     for (int i = 0; i < iterationCount; i++) {
@@ -154,12 +155,18 @@
         }
       });
       Thread.sleep(10);
+      ApplicationManager.getApplication().runWriteAction(new Runnable() {
+        public void run() {
+          fileB.getViewProvider().getDocument().setText(textB);
+          fileC.getViewProvider().getDocument().setText(textC);
+          fileD.getViewProvider().getDocument().setText(textD);
+          fileE.getViewProvider().getDocument().setText(textE);
+          PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); //clear xinclude caches
+        }
+      });
     }
 
     finished.await();
-    for (Thread thread : threads) {
-      thread.join();
-    }
     final Exception exception = ex.get();
     if (exception != null) {
       throw exception;
diff --git a/xml/dom-tests/tests/com/intellij/util/xml/DomPerformanceTest.java b/xml/dom-tests/tests/com/intellij/util/xml/DomPerformanceTest.java
index 6e6b15b..054a32a 100644
--- a/xml/dom-tests/tests/com/intellij/util/xml/DomPerformanceTest.java
+++ b/xml/dom-tests/tests/com/intellij/util/xml/DomPerformanceTest.java
@@ -52,7 +52,7 @@
 
     final MyElement newElement = createElement(DomUtil.getFile(element).getText(), MyElement.class);
 
-    PlatformTestUtil.startPerformanceTest(getTestName(false), 200, new ThrowableRunnable() {
+    PlatformTestUtil.startPerformanceTest(getTestName(false), 300, new ThrowableRunnable() {
       @Override
       public void run() throws Exception {
         newElement.acceptChildren(new DomElementVisitor() {
diff --git a/xml/dom-tests/tests/com/intellij/util/xml/DomTestCase.java b/xml/dom-tests/tests/com/intellij/util/xml/DomTestCase.java
index ce036c1..7531e48 100644
--- a/xml/dom-tests/tests/com/intellij/util/xml/DomTestCase.java
+++ b/xml/dom-tests/tests/com/intellij/util/xml/DomTestCase.java
@@ -39,12 +39,6 @@
     getDomManager().addDomEventListener(myListener, myTestRootDisposable);
   }
 
-  @Override
-  protected void tearDown() throws Exception {
-    DomApplicationComponent.getInstance().clearCachesInTests();
-    super.tearDown();
-  }
-
   protected void assertCached(final DomElement element, final XmlElement xmlElement) {
     assertNotNull(xmlElement);
     assertSame(element.getXmlTag(), xmlElement);
diff --git a/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubTest.java b/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubTest.java
index 2f0b09a..73b975d 100644
--- a/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubTest.java
+++ b/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubTest.java
@@ -58,12 +58,6 @@
   }
 
   @Override
-  protected void tearDown() throws Exception {
-    DomApplicationComponent.getInstance().clearCachesInTests();
-    super.tearDown();
-  }
-
-  @Override
   protected String getBasePath() {
     return "/xml/dom-tests/testData/stubs";
   }
diff --git a/xml/impl/resources/liveTemplates/zen_html.xml b/xml/impl/resources/liveTemplates/zen_html.xml
index 43025dc..7f537b5 100644
--- a/xml/impl/resources/liveTemplates/zen_html.xml
+++ b/xml/impl/resources/liveTemplates/zen_html.xml
@@ -12,6 +12,12 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
+  <template description="" name="c" toReformat="true" toShortenFQNames="true" value="&lt;!-- $VAR0$ --&gt;$END$">
+    <variable alwaysStopAt="true" defaultValue="" expression="" name="VAR0"/>
+    <context>
+      <option name="HTML_TEXT" value="true"/>
+    </context>
+  </template>
   <template description="" name="cc:ie6" toReformat="true" toShortenFQNames="true" value="&lt;!--[if lte IE 6]&gt;&#10;  $END$&#10;&lt;![endif]--&gt;">
     <context>
       <option name="HTML_TEXT" value="true"/>
@@ -28,7 +34,13 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="" name="html:5" toReformat="true" toShortenFQNames="true" value="&lt;!DOCTYPE HTML&gt;&#10;&lt;html lang=&quot;$ENV_LOCALE$&quot;&gt;&#10;&lt;head&gt;&#10;  &lt;meta charset=&quot;UTF-8&quot;&gt;&#10;  &lt;title&gt;&lt;/title&gt;&#10;&lt;/head&gt;&#10;&lt;body&gt;&#10;  $END$&#10;&lt;/body&gt;&#10;&lt;/html&gt;">
+  <template description="" name="html:5" toReformat="true" toShortenFQNames="true" value="&lt;!doctype html&gt;&#10;&lt;html lang=&quot;$ENV_LOCALE$&quot;&gt;&#10;&lt;head&gt;&#10;  &lt;meta charset=&quot;UTF-8&quot;&gt;&#10;  &lt;title&gt;&lt;/title&gt;&#10;&lt;/head&gt;&#10;&lt;body&gt;&#10;  $END$&#10;&lt;/body&gt;&#10;&lt;/html&gt;">
+    <variable alwaysStopAt="true" defaultValue="&quot;en-US&quot;" expression="" name="ENV_LOCALE"/>
+    <context>
+      <option name="HTML_TEXT" value="true"/>
+    </context>
+  </template>
+  <template description="" name="!" toReformat="true" toShortenFQNames="true" value="&lt;!doctype html&gt;&#10;&lt;html lang=&quot;$ENV_LOCALE$&quot;&gt;&#10;&lt;head&gt;&#10;  &lt;meta charset=&quot;UTF-8&quot;&gt;&#10;  &lt;title&gt;&lt;/title&gt;&#10;&lt;/head&gt;&#10;&lt;body&gt;&#10;  $END$&#10;&lt;/body&gt;&#10;&lt;/html&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;en-US&quot;" expression="" name="ENV_LOCALE"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
@@ -57,14 +69,14 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;datetime-local&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:datetime-local" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;datetime-local&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;datetime-local&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:datetime-local" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;datetime-local&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;reset&quot; value=&quot;...&quot;&gt;" name="input:reset" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;reset&quot; value=&quot;$VAR0$&quot;&gt;">
+  <template description="&lt;input type=&quot;reset&quot; value=&quot;...&quot;/&gt;" name="input:reset" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;reset&quot; value=&quot;$VAR0$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
@@ -85,7 +97,7 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;img src=&quot;...&quot; alt=&quot;...&quot;&gt;" name="img" toReformat="true" toShortenFQNames="true" value="&lt;img src=&quot;$VAR0$&quot; alt=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;img src=&quot;...&quot; alt=&quot;...&quot;&gt;" name="img" toReformat="true" toShortenFQNames="true" value="&lt;img src=&quot;$VAR0$&quot; alt=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
@@ -97,7 +109,7 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;param name=&quot;...&quot; value=&quot;...&quot;&gt;" name="param" toReformat="true" toShortenFQNames="true" value="&lt;param name=&quot;$VAR0$&quot; value=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;param name=&quot;...&quot; value=&quot;...&quot;&gt;" name="param" toReformat="true" toShortenFQNames="true" value="&lt;param name=&quot;$VAR0$&quot; value=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
@@ -125,51 +137,52 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;radio&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:radio" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;radio&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;radio&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:radio" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;radio&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;...print.css&quot; media=&quot;print&quot;&gt;" name="link:print" toReformat="true" toShortenFQNames="true" value="&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;$END$print.css&quot; media=&quot;print&quot;&gt;">
+  <template description="&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;...print.css&quot; media=&quot;print&quot;&gt;" name="link:print" toReformat="true" toShortenFQNames="true" value="&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;$END$print.css&quot; media=&quot;print&quot;/&gt;">
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;option&gt;...&lt;/option&gt;" name="opt" toReformat="true" toShortenFQNames="true" value="&lt;option&gt;$END$&lt;/option&gt;">
+  <template description="&lt;option value=&quot;...&quot;&gt;...&lt;/option&gt;" name="opt" toReformat="true" toShortenFQNames="true" value="&lt;option value=&quot;$VAR0$&quot;&gt;$END$&lt;/option&gt;">
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;image&quot; src=&quot;...&quot; alt=&quot;...&quot;&gt;" name="input:i" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;image&quot; src=&quot;$VAR0$&quot; alt=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;image&quot; src=&quot;...&quot; alt=&quot;...&quot;/&gt;" name="input:i" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;image&quot; src=&quot;$VAR0$&quot; alt=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;hidden&quot; name=&quot;...&quot;&gt;" name="input:h" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;hidden&quot; name=&quot;$VAR0$&quot;&gt;">
+  <template description="&lt;input type=&quot;hidden&quot; name=&quot;...&quot;/&gt;" name="input:h" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;hidden&quot; name=&quot;$VAR0$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;file&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:f" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;file&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;file&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:f" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;file&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;checkbox&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:c" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;checkbox&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;checkbox&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:c" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;checkbox&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;button&quot; value=&quot;...&quot;&gt;" name="input:b" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;button&quot; value=&quot;$VAR0$&quot;&gt;">
+  <template description="&lt;input type=&quot;button&quot; value=&quot;...&quot;/&gt;" name="input:b" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;button&quot; value=&quot;$VAR0$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
@@ -181,39 +194,42 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;text&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:t" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;text&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;text&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:t" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;text&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;password&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:p" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;password&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;password&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:p" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;password&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;submit&quot; value=&quot;...&quot;&gt;" name="input:s" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;submit&quot; value=&quot;$VAR0$&quot;&gt;">
+  <template description="&lt;input type=&quot;submit&quot; value=&quot;...&quot;/&gt;" name="input:s" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;submit&quot; value=&quot;$VAR0$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;radio&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:r" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;radio&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;radio&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:r" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;radio&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;iframe&gt;...&lt;/iframe&gt;" name="ifr" toReformat="true" toShortenFQNames="true" value="&lt;iframe&gt;$END$&lt;/iframe&gt;">
+  <template description="&lt;iframe src=&quot;...&quot; frameborder=&quot;0&quot;&gt;...&lt;/iframe&gt;" name="ifr" toReformat="true" toShortenFQNames="true" value="&lt;iframe src=&quot;$VAR0$&quot; frameborder=&quot;0&quot;&gt;$END$&lt;/iframe&gt;">
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;embed&gt;" name="emb" toReformat="true" toShortenFQNames="true" value="&lt;embed&gt;">
+  <template description="&lt;embed src=&quot;...&quot; type=&quot;...&quot;/&gt;" name="emb" toReformat="true" toShortenFQNames="true" value="&lt;embed src=&quot;$VAR0$&quot; type=&quot;$VAR1$&quot;/&gt;">
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
@@ -229,7 +245,7 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;link rel=&quot;alternate&quot; type=&quot;application/atom+xml&quot; title=&quot;Atom&quot; href=&quot;atom.xml&quot;&gt;" name="link:atom" toReformat="true" toShortenFQNames="true" value="&lt;link rel=&quot;alternate&quot; type=&quot;application/atom+xml&quot; title=&quot;Atom&quot; href=&quot;atom.xml&quot;&gt;">
+  <template description="&lt;link rel=&quot;alternate&quot; type=&quot;application/atom+xml&quot; title=&quot;Atom&quot; href=&quot;atom.xml&quot;&gt;" name="link:atom" toReformat="true" toShortenFQNames="true" value="&lt;link rel=&quot;alternate&quot; type=&quot;application/atom+xml&quot; title=&quot;Atom&quot; href=&quot;atom.xml&quot;/&gt;">
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
@@ -244,14 +260,14 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;search&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:search" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;search&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;search&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:search" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;search&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;area shape=&quot;rect&quot; coords=&quot;...&quot; href=&quot;...&quot; alt=&quot;...&quot;&gt;" name="area:r" toReformat="true" toShortenFQNames="true" value="&lt;area shape=&quot;rect&quot; coords=&quot;$VAR0$&quot; href=&quot;$VAR1$&quot; alt=&quot;$VAR2$&quot;&gt;">
+  <template description="&lt;area shape=&quot;rect&quot; coords=&quot;...&quot; href=&quot;...&quot; alt=&quot;...&quot;&gt;" name="area:r" toReformat="true" toShortenFQNames="true" value="&lt;area shape=&quot;rect&quot; coords=&quot;$VAR0$&quot; href=&quot;$VAR1$&quot; alt=&quot;$VAR2$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR2"/>
@@ -259,7 +275,7 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;area shape=&quot;poly&quot; coords=&quot;...&quot; href=&quot;...&quot; alt=&quot;...&quot;&gt;" name="area:p" toReformat="true" toShortenFQNames="true" value="&lt;area shape=&quot;poly&quot; coords=&quot;$VAR0$&quot; href=&quot;$VAR1$&quot; alt=&quot;$VAR2$&quot;&gt;">
+  <template description="&lt;area shape=&quot;poly&quot; coords=&quot;...&quot; href=&quot;...&quot; alt=&quot;...&quot;&gt;" name="area:p" toReformat="true" toShortenFQNames="true" value="&lt;area shape=&quot;poly&quot; coords=&quot;$VAR0$&quot; href=&quot;$VAR1$&quot; alt=&quot;$VAR2$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR2"/>
@@ -267,7 +283,7 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;date&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:date" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;date&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;date&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:date" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;date&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
@@ -280,20 +296,20 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;button&quot; value=&quot;...&quot;&gt;" name="input:button" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;button&quot; value=&quot;$VAR0$&quot;&gt;">
+  <template description="&lt;input type=&quot;button&quot; value=&quot;...&quot;/&gt;" name="input:button" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;button&quot; value=&quot;$VAR0$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;area shape=&quot;default&quot; href=&quot;...&quot; alt=&quot;...&quot;&gt;" name="area:d" toReformat="true" toShortenFQNames="true" value="&lt;area shape=&quot;default&quot; href=&quot;$VAR0$&quot; alt=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;area shape=&quot;default&quot; href=&quot;...&quot; alt=&quot;...&quot;&gt;" name="area:d" toReformat="true" toShortenFQNames="true" value="&lt;area shape=&quot;default&quot; href=&quot;$VAR0$&quot; alt=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;area shape=&quot;circle&quot; coords=&quot;...&quot; href=&quot;...&quot; alt=&quot;...&quot;&gt;" name="area:c" toReformat="true" toShortenFQNames="true" value="&lt;area shape=&quot;circle&quot; coords=&quot;$VAR0$&quot; href=&quot;$VAR1$&quot; alt=&quot;$VAR2$&quot;&gt;">
+  <template description="&lt;area shape=&quot;circle&quot; coords=&quot;...&quot; href=&quot;...&quot; alt=&quot;...&quot;&gt;" name="area:c" toReformat="true" toShortenFQNames="true" value="&lt;area shape=&quot;circle&quot; coords=&quot;$VAR0$&quot; href=&quot;$VAR1$&quot; alt=&quot;$VAR2$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR2"/>
@@ -328,7 +344,7 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html;charset=UTF-8&quot;&gt;" name="meta:utf" toReformat="true" toShortenFQNames="true" value="&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html;charset=UTF-8&quot;&gt;">
+  <template description="&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html;charset=UTF-8&quot;&gt;" name="meta:utf" toReformat="true" toShortenFQNames="true" value="&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html;charset=UTF-8&quot;/&gt;">
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
@@ -339,14 +355,14 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;time&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:time" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;time&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;time&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:time" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;time&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;link rel=&quot;shortcut icon&quot; type=&quot;image/x-icon&quot; href=&quot;...favicon.ico&quot;&gt;" name="link:favicon" toReformat="true" toShortenFQNames="true" value="&lt;link rel=&quot;shortcut icon&quot; type=&quot;image/x-icon&quot; href=&quot;$END$favicon.ico&quot;&gt;">
+  <template description="&lt;link rel=&quot;shortcut icon&quot; type=&quot;image/x-icon&quot; href=&quot;...favicon.ico&quot;&gt;" name="link:favicon" toReformat="true" toShortenFQNames="true" value="&lt;link rel=&quot;shortcut icon&quot; type=&quot;image/x-icon&quot; href=&quot;$END$favicon.ico&quot;/&gt;">
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
@@ -361,7 +377,7 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;email&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:email" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;email&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;email&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:email" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;email&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
@@ -405,7 +421,7 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;base href=&quot;...&quot;&gt;" name="base" toReformat="true" toShortenFQNames="true" value="&lt;base href=&quot;$VAR0$&quot;&gt;">
+  <template description="&lt;base href=&quot;...&quot;&gt;" name="base" toReformat="true" toShortenFQNames="true" value="&lt;base href=&quot;$VAR0$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
@@ -421,7 +437,9 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;object&gt;...&lt;/object&gt;" name="obj" toReformat="true" toShortenFQNames="true" value="&lt;object&gt;$END$&lt;/object&gt;">
+  <template description="&lt;object data=&quot;...&quot; type=&quot;...&quot;&gt;...&lt;/object&gt;" name="obj" toReformat="true" toShortenFQNames="true" value="&lt;object data=&quot;$VAR0$&quot; type=&quot;$VAR1$&quot;&gt;$END$&lt;/object&gt;">
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
@@ -437,26 +455,29 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;acronym&gt;...&lt;/acronym&gt;" name="acr" toReformat="true" toShortenFQNames="true" value="&lt;acronym&gt;$END$&lt;/acronym&gt;">
+  <template description="&lt;acronym title=&quot;...&quot;&gt;...&lt;/acronym&gt;" name="acr" toReformat="true" toShortenFQNames="true" value="&lt;acronym title=&quot;$VAR0$&quot;&gt;$END$&lt;/acronym&gt;">
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;password&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:password" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;password&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;password&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:password" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;password&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;file&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:file" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;file&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;file&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:file" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;file&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;textarea&gt;...&lt;/textarea&gt;" name="tarea" toReformat="true" toShortenFQNames="true" value="&lt;textarea&gt;$END$&lt;/textarea&gt;">
+  <template description="&lt;textarea name=&quot;...&quot; id=&quot;...&quot; cols=&quot;30&quot; rows=&quot;10&quot;&gt;...&lt;/textarea&gt;" name="tarea" toReformat="true" toShortenFQNames="true" value="&lt;textarea name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot; cols=&quot;30&quot; rows=&quot;10&quot;&gt;$END$&lt;/textarea&gt;">
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
@@ -468,21 +489,21 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;number&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:number" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;number&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;number&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:number" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;number&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;range&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:range" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;range&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;range&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:range" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;range&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;area shape=&quot;...&quot; coords=&quot;...&quot; href=&quot;...&quot; alt=&quot;...&quot;&gt;" name="area" toReformat="true" toShortenFQNames="true" value="&lt;area shape=&quot;$VAR0$&quot; coords=&quot;$VAR1$&quot; href=&quot;$VAR2$&quot; alt=&quot;$VAR3$&quot;&gt;">
+  <template description="&lt;area shape=&quot;...&quot; coords=&quot;...&quot; href=&quot;...&quot; alt=&quot;...&quot;&gt;" name="area" toReformat="true" toShortenFQNames="true" value="&lt;area shape=&quot;$VAR0$&quot; coords=&quot;$VAR1$&quot; href=&quot;$VAR2$&quot; alt=&quot;$VAR3$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR2"/>
@@ -491,7 +512,7 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;image&quot; src=&quot;...&quot; alt=&quot;...&quot;&gt;" name="input:image" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;image&quot; src=&quot;$VAR0$&quot; alt=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;image&quot; src=&quot;...&quot; alt=&quot;...&quot;/&gt;" name="input:image" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;image&quot; src=&quot;$VAR0$&quot; alt=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
@@ -503,7 +524,7 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;month&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:month" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;month&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;month&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:month" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;month&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
@@ -515,7 +536,7 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html;charset=Win-1251&quot;&gt;" name="meta:win" toReformat="true" toShortenFQNames="true" value="&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html;charset=Win-1251&quot;&gt;">
+  <template description="&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html;charset=Win-1251&quot;&gt;" name="meta:win" toReformat="true" toShortenFQNames="true" value="&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html;charset=windows-1251&quot;/&gt;">
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
@@ -536,19 +557,19 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;link rel=&quot;stylesheet&quot; href=&quot;...&quot;&gt;" name="link" toReformat="true" toShortenFQNames="true" value="&lt;link rel=&quot;stylesheet&quot; href=&quot;$VAR0$&quot;&gt;">
+  <template description="&lt;link rel=&quot;stylesheet&quot; href=&quot;...&quot;&gt;" name="link" toReformat="true" toShortenFQNames="true" value="&lt;link rel=&quot;stylesheet&quot; href=&quot;$VAR0$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;...&quot;&gt;" name="input" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;$VAR0$&quot;&gt;">
+  <template description="&lt;input type=&quot;...&quot;/&gt;" name="input" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;$VAR0$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;link rel=&quot;alternate&quot; type=&quot;application/rss+xml&quot; title=&quot;RSS&quot; href=&quot;...rss.xml&quot;&gt;" name="link:rss" toReformat="true" toShortenFQNames="true" value="&lt;link rel=&quot;alternate&quot; type=&quot;application/rss+xml&quot; title=&quot;RSS&quot; href=&quot;$END$rss.xml&quot;&gt;">
+  <template description="&lt;link rel=&quot;alternate&quot; type=&quot;application/rss+xml&quot; title=&quot;RSS&quot; href=&quot;...rss.xml&quot;&gt;" name="link:rss" toReformat="true" toShortenFQNames="true" value="&lt;link rel=&quot;alternate&quot; type=&quot;application/rss+xml&quot; title=&quot;RSS&quot; href=&quot;$END$rss.xml&quot;/&gt;">
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
@@ -576,7 +597,7 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;link rel=&quot;apple-touch-icon&quot; href=&quot;...favicon.png&quot;&gt;" name="link:touch" toReformat="true" toShortenFQNames="true" value="&lt;link rel=&quot;apple-touch-icon&quot; href=&quot;$END$favicon.png&quot;&gt;">
+  <template description="&lt;link rel=&quot;apple-touch-icon&quot; href=&quot;...favicon.png&quot;&gt;" name="link:touch" toReformat="true" toShortenFQNames="true" value="&lt;link rel=&quot;apple-touch-icon&quot; href=&quot;$END$favicon.png&quot;/&gt;">
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
@@ -587,19 +608,19 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;....css&quot; media=&quot;all&quot;&gt;" name="link:css" toReformat="true" toShortenFQNames="true" value="&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;$END$.css&quot; media=&quot;all&quot;&gt;">
+  <template description="&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;....css&quot; media=&quot;all&quot;&gt;" name="link:css" toReformat="true" toShortenFQNames="true" value="&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;$END$.css&quot; media=&quot;all&quot;/&gt;">
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;week&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:week" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;week&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;week&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:week" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;week&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;embed src=&quot;...&quot; type=&quot;...&quot;&gt;" name="embed" toReformat="true" toShortenFQNames="true" value="&lt;embed src=&quot;$VAR0$&quot; type=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;embed src=&quot;...&quot; type=&quot;...&quot;/&gt;" name="embed" toReformat="true" toShortenFQNames="true" value="&lt;embed src=&quot;$VAR0$&quot; type=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
@@ -611,7 +632,7 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;datetime&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:datetime" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;datetime&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;datetime&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:datetime" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;datetime&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
@@ -634,7 +655,7 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;url&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:url" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;url&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;url&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:url" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;url&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
@@ -657,19 +678,20 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;color&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:color" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;color&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;color&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:color" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;color&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=7&quot;&gt;" name="meta:compat" toReformat="true" toShortenFQNames="true" value="&lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=7&quot;&gt;">
+  <template description="&lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=7&quot;/&gt;" name="meta:compat" toReformat="true" toShortenFQNames="true" value="&lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;$VAR0$&quot;/&gt;">
+    <variable alwaysStopAt="true" defaultValue="&quot;IE=7&quot;" expression="" name="VAR0"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;hidden&quot; name=&quot;...&quot;&gt;" name="input:hidden" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;hidden&quot; name=&quot;$VAR0$&quot;&gt;">
+  <template description="&lt;input type=&quot;hidden&quot; name=&quot;...&quot;/&gt;" name="input:hidden" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;hidden&quot; name=&quot;$VAR0$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
@@ -711,7 +733,7 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="" name="map+" toReformat="true" toShortenFQNames="true" value="&lt;map name=&quot;$VAR0$&quot;&gt;&#10;  &lt;area shape=&quot;$VAR1$&quot; coords=&quot;$VAR2$&quot; href=&quot;$VAR3$&quot; alt=&quot;$VAR4$&quot;&gt;&#10;&lt;/map&gt;">
+  <template description="" name="map+" toReformat="true" toShortenFQNames="true" value="&lt;map name=&quot;$VAR0$&quot;&gt;&#10;  &lt;area shape=&quot;$VAR1$&quot; coords=&quot;$VAR2$&quot; href=&quot;$VAR3$&quot; alt=&quot;$VAR4$&quot;/&gt;&#10;&lt;/map&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR2"/>
@@ -721,20 +743,20 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;submit&quot; value=&quot;...&quot;&gt;" name="input:submit" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;submit&quot; value=&quot;$VAR0$&quot;&gt;">
+  <template description="&lt;input type=&quot;submit&quot; value=&quot;...&quot;/&gt;" name="input:submit" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;submit&quot; value=&quot;$VAR0$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;text&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:text" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;text&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;text&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:text" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;text&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;input type=&quot;checkbox&quot; name=&quot;...&quot; id=&quot;...&quot;&gt;" name="input:checkbox" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;checkbox&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;&gt;">
+  <template description="&lt;input type=&quot;checkbox&quot; name=&quot;...&quot; id=&quot;...&quot;/&gt;" name="input:checkbox" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;checkbox&quot; name=&quot;$VAR0$&quot; id=&quot;$VAR1$&quot;/&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
@@ -763,4 +785,9 @@
       <option name="HTML_TEXT" value="true"/>
     </context>
   </template>
+  <template description="&lt;figcaption&gt;...&lt;/figcaption&gt;" name="figc" toReformat="true" toShortenFQNames="true" value="&lt;figcaption&gt;$END$&lt;/figcaption&gt;">
+    <context>
+      <option name="HTML_TEXT" value="true"/>
+    </context>
+  </template>
 </templateSet>
diff --git a/xml/impl/resources/liveTemplates/zen_xsl.xml b/xml/impl/resources/liveTemplates/zen_xsl.xml
index dbd599b..39fb4fd 100644
--- a/xml/impl/resources/liveTemplates/zen_xsl.xml
+++ b/xml/impl/resources/liveTemplates/zen_xsl.xml
@@ -7,7 +7,13 @@
       <option name="XSL_TEXT" value="true"/>
     </context>
   </template>
-  <template description="&lt;xsl:param name=&quot;...&quot; select=&quot;...&quot; /&gt;" name="par" toReformat="true" toShortenFQNames="true" value="&lt;xsl:param name=&quot;$VAR0$&quot; select=&quot;$VAR1$&quot; /&gt;">
+  <template description="&lt;xsl:param name=&quot;...&quot;&gt;...&lt;/xsl:param&gt;" name="par" toReformat="true" toShortenFQNames="true" value="&lt;xsl:param name=&quot;$VAR0$&quot; &gt;$END$&lt;/xsl:param&gt;">
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
+    <context>
+      <option name="XSL_TEXT" value="true"/>
+    </context>
+  </template>
+  <template description="&lt;xsl:param name=&quot;...&quot; select=&quot;...&quot; /&gt;" name="pare" toReformat="true" toShortenFQNames="true" value="&lt;xsl:param name=&quot;$VAR0$&quot; select=&quot;$VAR1$&quot; /&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
     <context>
@@ -82,6 +88,11 @@
       <option name="XSL_TEXT" value="true"/>
     </context>
   </template>
+  <template description="&lt;xsl:choose&gt;...&lt;/xsl:choose&gt;" name="ch" toReformat="true" toShortenFQNames="true" value="&lt;xsl:choose&gt;$END$&lt;/xsl:choose&gt;">
+    <context>
+      <option name="XSL_TEXT" value="true"/>
+    </context>
+  </template>
   <template description="" name="choose+" toReformat="true" toShortenFQNames="true" value="&lt;xsl:choose&gt;&#10;  &lt;xsl:when test=&quot;$VAR0$&quot;&gt;$VAR1$&lt;/xsl:when&gt;&#10;  &lt;xsl:otherwise&gt;$END$&lt;/xsl:otherwise&gt;&#10;&lt;/xsl:choose&gt;">
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
     <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
@@ -115,4 +126,112 @@
       <option name="XSL_TEXT" value="true"/>
     </context>
   </template>
+  <template description="&lt;xsl:sort select=&quot;...&quot; order=&quot;...&quot; /&gt;" name="sort" toReformat="true" toShortenFQNames="true" value="&lt;xsl:sort select=&quot;$VAR0$&quot; order=&quot;$VAR1$&quot; /&gt;">
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
+    <context>
+      <option name="XSL_TEXT" value="true"/>
+    </context>
+  </template>
+  <template description="&lt;xsl:processing-instruction name=&quot;...&quot;&gt;...&lt;/xsl:processing-instruction&gt;" name="proc" toReformat="true" toShortenFQNames="true" value="&lt;xsl:processing-instruction name=&quot;$VAR0$&quot;&gt;$END$&lt;/xsl:processing-instruction&gt;">
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
+    <context>
+      <option name="XSL_TEXT" value="true"/>
+    </context>
+  </template>
+  <template description="&lt;xsl:for-each select=&quot;...&quot;&gt;...&lt;/xsl:for-each&gt;" name="for" toReformat="true" toShortenFQNames="true" value="&lt;xsl:for-each select=&quot;$VAR0$&quot;&gt;$END$&lt;/xsl:for-each&gt;">
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
+    <context>
+      <option name="XSL_TEXT" value="true"/>
+    </context>
+  </template>
+  <template description="&lt;xsl:strip-space elements=&quot;...&quot; /&gt;>" name="strip" toReformat="true" toShortenFQNames="true" value="&lt;xsl:strip-space elements=&quot;$END$&quot; /&gt;">
+    <context>
+      <option name="XSL_TEXT" value="true"/>
+    </context>
+  </template>
+  <template description="&lt;xsl:preserve-space elements=&quot;...&quot; /&gt;" name="pres" toReformat="true" toShortenFQNames="true" value="&lt;xsl:preserve-space elements=&quot;$END$&quot; /&gt;">
+    <context>
+      <option name="XSL_TEXT" value="true"/>
+    </context>
+  </template>
+  <template description="&lt;namespace-alias stylesheet-prefix=&quot;...&quot; result-prefix=&quot;...&quot; /&gt;" name="nam" toReformat="true" toShortenFQNames="true" value="&lt;namespace-alias stylesheet-prefix=&quot;$VAR0$&quot; result-prefix=&quot;$END$&quot; /&gt;">
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
+    <context>
+      <option name="XSL_TEXT" value="true"/>
+    </context>
+  </template>
+  <template description="&lt;xsl:number value=&quot;...&quot; /&gt;" name="num" toReformat="true" toShortenFQNames="true" value="&lt;xsl:number value=&quot;$END$&quot; /&gt;">
+    <context>
+      <option name="XSL_TEXT" value="true"/>
+    </context>
+  </template>
+  <template description="&lt;xsl:fallback&gt;...&lt;/xsl:fallback&gt;" name="fall" toReformat="true" toShortenFQNames="true" value="&lt;xsl:fallback&gt;$END$&lt;/xsl:fallback&gt;">
+    <context>
+      <option name="XSL_TEXT" value="true"/>
+    </context>
+  </template>
+  <template description="&lt;xsl:message terminate=&quot;no&quot;&gt;...&lt;/xsl:message&gt;" name="msg" toReformat="true" toShortenFQNames="true" value="&lt;xsl:message terminate=&quot;no&quot;&gt;$END$&lt;/xsl:message&gt;">
+    <context>
+      <option name="XSL_TEXT" value="true"/>
+    </context>
+  </template>
+  <template description="&lt;xsl:comment&gt;...&lt;/xsl:comment&gt;" name="com" toReformat="true" toShortenFQNames="true" value="&lt;xsl:comment&gt;$END$&lt;/xsl:comment&gt;">
+    <context>
+      <option name="XSL_TEXT" value="true"/>
+    </context>
+  </template>
+  <template description="&lt;xsl:otherwise&gt;&lt;/xsl:otherwise&gt;" name="ot" toReformat="true" toShortenFQNames="true" value="&lt;xsl:otherwise&gt;$END$&lt;/xsl:otherwise&gt;">
+    <context>
+      <option name="XSL_TEXT" value="true"/>
+    </context>
+  </template>
+  <template description="&lt;xsl:text&gt;&lt;/xsl:text&gt;" name="tex" toReformat="true" toShortenFQNames="true" value="&lt;xsl:text&gt;$END$&lt;/xsl:text&gt;">
+    <context>
+      <option name="XSL_TEXT" value="true"/>
+    </context>
+  </template>
+  <template description="&lt;xsl:apply-imports/&gt;" name="api" toReformat="true" toShortenFQNames="true" value="&lt;xsl:apply-imports/&gt;">
+    <context>
+      <option name="XSL_TEXT" value="true"/>
+    </context>
+  </template>
+  <template description="&lt;xsl:copy select=&quot;...&quot;/&gt;" name="cp" toReformat="true" toShortenFQNames="true" value="&lt;xsl:copy select=&quot;$VAR0$&quot;/&gt;">
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
+    <context>
+      <option name="XSL_TEXT" value="true"/>
+    </context>
+  </template>
+  <template description="&lt;xsl:attribute-set name=&quot;...&quot;&gt;...&lt;/xsl:attribute-set&gt;" name="attrs" toReformat="true" toShortenFQNames="true" value="&lt;xsl:attribute-set name=&quot;$VAR0$&quot;&gt;$END$&lt;/xsl:attribute-set&gt;">
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
+    <context>
+      <option name="XSL_TEXT" value="true"/>
+    </context>
+  </template>
+  <template description="&lt;xsl:element name=&quot;...&quot;&gt;...&lt;/xsl:element&gt;" name="elem" toReformat="true" toShortenFQNames="true" value="&lt;xsl:element name=&quot;$VAR0$&quot;&gt;$END$&lt;/xsl:element&gt;">
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
+    <context>
+      <option name="XSL_TEXT" value="true"/>
+    </context>
+  </template>
+  <template description="&lt;xsl:include href=&quot;...&quot;/&gt;" name="inc" toReformat="true" toShortenFQNames="true" value="&lt;xsl:include href=&quot;$VAR0$&quot;/&gt;">
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
+    <context>
+      <option name="XSL_TEXT" value="true"/>
+    </context>
+  </template>
+  <template description="&lt;xsl:import href=&quot;...&quot;/&gt;" name="imp" toReformat="true" toShortenFQNames="true" value="&lt;xsl:import href=&quot;$VAR0$&quot;/&gt;">
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
+    <context>
+      <option name="XSL_TEXT" value="true"/>
+    </context>
+  </template>
+  <template description="&lt;xsl:key name=&quot;...&quot; match=&quot;...&quot; use=&quot;...&quot; /&gt;" name="key" toReformat="true" toShortenFQNames="true" value="&lt;xsl:key name=&quot;$VAR0$&quot; match=&quot;$VAR1$&quot; use=&quot;$VAR2$&quot; /&gt;">
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR1"/>
+    <variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR2"/>
+    <context>
+      <option name="XSL_TEXT" value="true"/>
+    </context>
+  </template>
 </templateSet>
diff --git a/xml/impl/src/com/intellij/codeInsight/actions/GenerateDTDAction.java b/xml/impl/src/com/intellij/codeInsight/actions/GenerateDTDAction.java
index 1aa5ae4..027bb15 100644
--- a/xml/impl/src/com/intellij/codeInsight/actions/GenerateDTDAction.java
+++ b/xml/impl/src/com/intellij/codeInsight/actions/GenerateDTDAction.java
@@ -42,6 +42,7 @@
  */
 public class GenerateDTDAction extends BaseCodeInsightAction{
   private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.actions.GenerateDTDAction");
+  @NotNull
   protected CodeInsightActionHandler getHandler(){
     return new CodeInsightActionHandler(){
       public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
@@ -115,7 +116,7 @@
     }
   }
 
-  protected boolean isValidForFile(Project project, Editor editor, PsiFile file){
+  protected boolean isValidForFile(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file){
     return file instanceof XmlFile;
   }
 }
diff --git a/xml/impl/src/com/intellij/codeInsight/completion/XmlSmartEnterProcessor.java b/xml/impl/src/com/intellij/codeInsight/completion/XmlSmartEnterProcessor.java
index e01a7e4..001f339 100644
--- a/xml/impl/src/com/intellij/codeInsight/completion/XmlSmartEnterProcessor.java
+++ b/xml/impl/src/com/intellij/codeInsight/completion/XmlSmartEnterProcessor.java
@@ -38,10 +38,6 @@
   private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.XmlSmartEnterProcessor");
 
   public boolean process(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile psiFile) {
-    /*if (!completeEndTag(project, editor, psiFile)) {
-      return XmlZenCodingTemplate.startZenCoding(editor, psiFile, null);
-    }
-    return true;*/
     return completeEndTag(project, editor, psiFile);
   }
 
diff --git a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/XmlHighlightVisitor.java b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/XmlHighlightVisitor.java
index 96b111a..f97208d 100644
--- a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/XmlHighlightVisitor.java
+++ b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/XmlHighlightVisitor.java
@@ -157,6 +157,8 @@
           }
         }
       }
+    } else if (tokenType == XmlTokenType.XML_TAG_CHARACTERS && token.getParent() instanceof XmlProcessingInstruction) {
+      checkReferences(token);
     }
   }
 
diff --git a/xml/impl/src/com/intellij/codeInsight/intentions/XmlChooseColorIntentionAction.java b/xml/impl/src/com/intellij/codeInsight/intentions/XmlChooseColorIntentionAction.java
index 5bfdb3b..e92d59b 100644
--- a/xml/impl/src/com/intellij/codeInsight/intentions/XmlChooseColorIntentionAction.java
+++ b/xml/impl/src/com/intellij/codeInsight/intentions/XmlChooseColorIntentionAction.java
@@ -18,6 +18,8 @@
 import com.intellij.codeInsight.CodeInsightBundle;
 import com.intellij.codeInsight.CodeInsightUtilBase;
 import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
+import com.intellij.openapi.application.Result;
+import com.intellij.openapi.command.WriteCommandAction;
 import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.Comparing;
@@ -56,12 +58,11 @@
 
   @Override
   public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
-    if (!CodeInsightUtilBase.preparePsiElementForWrite(element)) return;
-    invokeForLiteral(editor.getComponent(), element);
+    chooseColor(editor.getComponent(), element, getText(), false);
   }
 
-  private void invokeForLiteral(JComponent editorComponent, PsiElement element) {
-    final XmlAttributeValue literal = PsiTreeUtil.getParentOfType(element, XmlAttributeValue.class);
+  public static void chooseColor(JComponent editorComponent, PsiElement element, String caption, boolean startInWriteAction) {
+    final XmlAttributeValue literal = PsiTreeUtil.getParentOfType(element, XmlAttributeValue.class, false);
     if (literal == null) return;
     final String text = StringUtil.unquoteString(literal.getValue());
     final String hexPrefix = text.startsWith("#") ? "#" : "";
@@ -73,13 +74,28 @@
     catch (NumberFormatException e) {
       oldColor = Color.GRAY;
     }
-    Color color = ColorChooser.chooseColor(editorComponent, getText(), oldColor, true);
+    Color color = ColorChooser.chooseColor(editorComponent, caption, oldColor, true);
     if (color == null) return;
     if (!Comparing.equal(color, oldColor)) {
+      if (!CodeInsightUtilBase.preparePsiElementForWrite(element)) return;
       final String newText =  hexPrefix + ColorUtil.toHex(color);
       final PsiManager manager = literal.getManager();
       final XmlAttribute newAttribute = XmlElementFactory.getInstance(manager.getProject()).createXmlAttribute("name", newText);
-      literal.replace(newAttribute.getValueElement());
+      final Runnable replaceRunnable = new Runnable() {
+        public void run() {
+          literal.replace(newAttribute.getValueElement());
+        }
+      };
+      if (startInWriteAction) {
+        new WriteCommandAction(element.getProject(), caption) {
+          @Override
+          protected void run(Result result) throws Throwable {
+            replaceRunnable.run();
+          }
+        }.execute();
+      } else {
+        replaceRunnable.run();
+      }
     }
   }
 }
diff --git a/xml/impl/src/com/intellij/codeInsight/template/HtmlTextContextType.java b/xml/impl/src/com/intellij/codeInsight/template/HtmlTextContextType.java
index 5a61b4e..63b9593 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/HtmlTextContextType.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/HtmlTextContextType.java
@@ -29,7 +29,7 @@
  * @author Eugene.Kudelevsky
  */
 public class HtmlTextContextType extends TemplateContextType {
-  protected HtmlTextContextType() {
+  public HtmlTextContextType() {
     super("HTML_TEXT", CodeInsightBundle.message("dialog.edit.template.checkbox.html.text"), HtmlContextType.class);
   }
 
diff --git a/xml/impl/src/com/intellij/codeInsight/template/XslTextContextType.java b/xml/impl/src/com/intellij/codeInsight/template/XslTextContextType.java
index 7f22c59..b9d0ba3 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/XslTextContextType.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/XslTextContextType.java
@@ -14,7 +14,7 @@
 
 import com.intellij.codeInsight.CodeInsightBundle;
 import com.intellij.openapi.fileTypes.StdFileTypes;
-import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.io.FileUtilRt;
 import com.intellij.psi.PsiElement;
 import com.intellij.psi.PsiFile;
 import org.jetbrains.annotations.NotNull;
@@ -23,13 +23,13 @@
  * @author Eugene.Kudelevsky
  */
 public class XslTextContextType extends TemplateContextType {
-  protected XslTextContextType() {
+  public XslTextContextType() {
     super("XSL_TEXT", CodeInsightBundle.message("dialog.edit.template.checkbox.xsl.text"), XmlContextType.class);
   }
 
   @Override
   public boolean isInContext(@NotNull PsiFile file, int offset) {
-    if (file.getFileType() == StdFileTypes.XML && FileUtil.getExtension(file.getName()).equals("xsl")) {
+    if (file.getFileType() == StdFileTypes.XML && FileUtilRt.extensionEquals(file.getName(), "xsl")) {
       PsiElement element = file.findElementAt(offset);
       return element == null || HtmlTextContextType.isInContext(element);
     }
diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/EmmetLexer.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/EmmetLexer.java
new file mode 100644
index 0000000..66aed8d
--- /dev/null
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/EmmetLexer.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.template.emmet;
+
+import com.intellij.codeInsight.template.emmet.tokens.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * User: zolotov
+ * Date: 1/25/13
+ */
+public class EmmetLexer {
+  private static final String DELIMS = ">^+*|()[]{}.#,='\" \0";
+
+  @Nullable
+  public List<ZenCodingToken> lex(@NotNull String text) {
+    text += ZenCodingTemplate.MARKER;
+    final List<ZenCodingToken> result = new ArrayList<ZenCodingToken>();
+
+    boolean inQuotes = false;
+    boolean inApostrophes = false;
+    int bracesStack = 0;
+
+    StringBuilder builder = new StringBuilder();
+    for (int i = 0; i < text.length(); i++) {
+      final char c = text.charAt(i);
+
+      if (inQuotes) {
+        builder.append(c);
+        if (c == '"') {
+          inQuotes = false;
+          result.add(new StringLiteralToken(builder.toString()));
+          builder = new StringBuilder();
+        }
+        continue;
+      }
+
+      if (inApostrophes) {
+        builder.append(c);
+        if (c == '\'') {
+          inApostrophes = false;
+          result.add(new StringLiteralToken(builder.toString()));
+          builder = new StringBuilder();
+        }
+        continue;
+      }
+
+      if (bracesStack > 0) {
+        builder.append(c);
+        if (c == '}') {
+          bracesStack--;
+          if (bracesStack == 0) {
+            result.add(new TextToken(builder.toString()));
+            builder = new StringBuilder();
+          }
+        }
+        else if (c == '{') {
+          bracesStack++;
+        }
+        continue;
+      }
+
+      if (DELIMS.indexOf(c) < 0) {
+        builder.append(c);
+      }
+      else {
+        // handle special case: ul+ template
+        if (c == '+' && (i == text.length() - 2 || text.charAt(i + 1) == ')')) {
+          builder.append(c);
+          continue;
+        }
+
+        if (builder.length() > 0) {
+          final String tokenText = builder.toString();
+          final int n = ZenCodingUtil.parseNonNegativeInt(tokenText);
+          if (n >= 0) {
+            result.add(new NumberToken(n));
+          }
+          else {
+            result.add(new IdentifierToken(tokenText));
+          }
+          builder = new StringBuilder();
+        }
+        if (c == '"') {
+          inQuotes = true;
+          builder.append(c);
+        }
+        else if (c == '\'') {
+          inApostrophes = true;
+          builder.append(c);
+        }
+        else if (c == '{') {
+          bracesStack = 1;
+          builder.append(c);
+        }
+        else if (c == '(') {
+          result.add(ZenCodingTokens.OPENING_R_BRACKET);
+        }
+        else if (c == ')') {
+          result.add(ZenCodingTokens.CLOSING_R_BRACKET);
+        }
+        else if (c == '[') {
+          result.add(ZenCodingTokens.OPENING_SQ_BRACKET);
+        }
+        else if (c == ']') {
+          result.add(ZenCodingTokens.CLOSING_SQ_BRACKET);
+        }
+        else if (c == '=') {
+          result.add(ZenCodingTokens.EQ);
+        }
+        else if (c == '.') {
+          result.add(ZenCodingTokens.DOT);
+        }
+        else if (c == '#') {
+          result.add(ZenCodingTokens.SHARP);
+        }
+        else if (c == ',') {
+          result.add(ZenCodingTokens.COMMA);
+        }
+        else if (c == ' ') {
+          result.add(ZenCodingTokens.SPACE);
+        }
+        else if (c == '|') {
+          result.add(ZenCodingTokens.PIPE);
+        }
+        else if (c != ZenCodingTemplate.MARKER) {
+          result.add(new OperationToken(c));
+        }
+      }
+    }
+    if (bracesStack != 0 || inQuotes || inApostrophes) {
+      return null;
+    }
+    return result;
+  }
+}
diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/EmmetParser.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/EmmetParser.java
new file mode 100644
index 0000000..337818e
--- /dev/null
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/EmmetParser.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.template.emmet;
+
+import com.intellij.codeInsight.template.CustomTemplateCallback;
+import com.intellij.codeInsight.template.emmet.generators.ZenCodingGenerator;
+import com.intellij.codeInsight.template.emmet.nodes.*;
+import com.intellij.codeInsight.template.emmet.tokens.*;
+import com.intellij.codeInsight.template.impl.TemplateImpl;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+/**
+ * User: zolotov
+ * Date: 1/25/13
+ */
+public abstract class EmmetParser {
+  private final List<ZenCodingToken> myTokens;
+  protected final CustomTemplateCallback myCallback;
+  private final ZenCodingGenerator myGenerator;
+
+  private int myIndex = 0;
+
+  EmmetParser(List<ZenCodingToken> tokens, CustomTemplateCallback callback, ZenCodingGenerator generator) {
+    myTokens = tokens;
+    myCallback = callback;
+    myGenerator = generator;
+  }
+
+  public int getIndex() {
+    return myIndex;
+  }
+
+  @Nullable
+  public ZenCodingNode parse() {
+    ZenCodingNode add = parseAddOrMore();
+    if (add == null) {
+      return null;
+    }
+
+    ZenCodingNode result = add;
+
+    while (true) {
+      ZenCodingToken token = getToken();
+      if (token != ZenCodingTokens.PIPE) {
+        return result;
+      }
+
+      advance();
+      token = getToken();
+      if (!(token instanceof IdentifierToken)) {
+        return null;
+      }
+
+      final String filterSuffix = ((IdentifierToken)token).getText();
+      if (!ZenCodingUtil.checkFilterSuffix(filterSuffix)) {
+        return null;
+      }
+
+      advance();
+      result = new FilterNode(result, filterSuffix);
+    }
+  }
+
+  @Nullable
+  protected ZenCodingNode parseAddOrMore() {
+    ZenCodingNode mul = parseMul();
+
+    ZenCodingToken operationToken = getToken();
+    if (!(operationToken instanceof OperationToken)) {
+      return mul;
+    }
+    char sign = ((OperationToken)operationToken).getSign();
+
+    if (sign == '^') {
+      return parseClimbUpOperation(mul);
+    }
+    if (mul == null) {
+      return null;
+    }
+    if (sign == '+') {
+      advance();
+      ZenCodingNode add2 = parseAddOrMore();
+      if (add2 == null) {
+        return null;
+      }
+      return new AddOperationNode(mul, add2);
+    }
+    else if (sign == '>') {
+      return parseMoreOperation(mul);
+    }
+    return null;
+  }
+
+  protected ZenCodingNode parseClimbUpOperation(@Nullable ZenCodingNode leftPart) {
+    advance();
+    leftPart = leftPart != null ? leftPart : ZenEmptyNode.INSTANCE;
+    ZenCodingNode rigthPart = parseAddOrMore();
+    if (rigthPart == null) {
+      return null;
+    }
+    return new ClimbUpOperationNode(leftPart, rigthPart);
+  }
+
+  protected ZenCodingNode parseMoreOperation(@NotNull ZenCodingNode leftPart) {
+    advance();
+    ZenCodingNode rightPart = parseAddOrMore();
+    if (rightPart == null) {
+      return null;
+    }
+    return new MoreOperationNode(leftPart, rightPart);
+  }
+
+  protected int advance() {
+    return myIndex++;
+  }
+
+  @Nullable
+  private ZenCodingNode parseMul() {
+    ZenCodingNode exp = parseExpressionInBraces();
+    if (exp == null) {
+      return null;
+    }
+    ZenCodingToken operationToken = getToken();
+    if (!(operationToken instanceof OperationToken)) {
+      return exp;
+    }
+    if (((OperationToken)operationToken).getSign() != '*') {
+      return exp;
+    }
+    advance();
+    ZenCodingToken numberToken = getToken();
+    if (numberToken instanceof NumberToken) {
+      advance();
+      return new MulOperationNode(exp, ((NumberToken)numberToken).getNumber());
+    }
+    return new UnaryMulOperationNode(exp);
+  }
+
+  @Nullable
+  private ZenCodingNode parseExpressionInBraces() {
+    ZenCodingToken token = getToken();
+    if (token == ZenCodingTokens.OPENING_R_BRACKET) {
+      advance();
+      ZenCodingNode add = parseAddOrMore();
+      if (add == null) {
+        return null;
+      }
+      ZenCodingToken closingBrace = getToken();
+      if (closingBrace != ZenCodingTokens.CLOSING_R_BRACKET) {
+        return null;
+      }
+      advance();
+      return add;
+    }
+    else if (token instanceof TextToken) {
+      advance();
+      return new TextNode((TextToken)token);
+    }
+
+    final ZenCodingNode templateNode = parseTemplate();
+    if (templateNode == null) {
+      return null;
+    }
+
+    token = getToken();
+    if (token instanceof TextToken) {
+      advance();
+      return new MoreOperationNode(templateNode, new TextNode((TextToken)token));
+    }
+    return templateNode;
+  }
+
+  @Nullable
+  protected ZenCodingNode parseTemplate() {
+    ZenCodingToken token = getToken();
+    if (!(token instanceof IdentifierToken)) {
+      return null;
+    }
+    String templateKey = ((IdentifierToken)token).getText();
+    advance();
+
+    TemplateImpl template = myCallback.findApplicableTemplate(templateKey);
+    if (template == null && !ZenCodingUtil.isXML11ValidQName(templateKey)) {
+      return null;
+    }
+
+    final TemplateToken templateToken = new TemplateToken(templateKey);
+    if (!setTemplate(templateToken, template)) {
+      return null;
+    }
+    return new TemplateNode(templateToken);
+  }
+
+  @Nullable
+  protected String getDefaultTemplateKey() {
+    return null;
+  }
+
+  protected boolean setTemplate(final TemplateToken token, TemplateImpl template) {
+    if (template == null) {
+      template = myGenerator.createTemplateByKey(token.getKey());
+    }
+    if (template == null) {
+      return false;
+    }
+    return ZenCodingTemplate.doSetTemplate(token, template, myCallback);
+  }
+
+  @Nullable
+  protected ZenCodingToken getToken() {
+    if (myIndex < myTokens.size()) {
+      return myTokens.get(myIndex);
+    }
+    return null;
+  }
+}
diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/XmlEmmetParser.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/XmlEmmetParser.java
new file mode 100644
index 0000000..e0935b7
--- /dev/null
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/XmlEmmetParser.java
@@ -0,0 +1,369 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.template.emmet;
+
+import com.google.common.base.Strings;
+import com.intellij.codeInsight.template.CustomTemplateCallback;
+import com.intellij.codeInsight.template.emmet.generators.ZenCodingGenerator;
+import com.intellij.codeInsight.template.emmet.nodes.*;
+import com.intellij.codeInsight.template.emmet.tokens.*;
+import com.intellij.codeInsight.template.impl.TemplateImpl;
+import com.intellij.openapi.util.Pair;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.xml.XmlTag;
+import com.intellij.util.containers.Stack;
+import com.intellij.xml.util.HtmlUtil;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static com.intellij.openapi.util.text.StringUtil.startsWithIgnoreCase;
+
+/**
+ * User: zolotov
+ * Date: 2/7/13
+ */
+public class XmlEmmetParser extends EmmetParser {
+  private static final String DEFAULT_TAG = "div";
+  private static final int DEFAULT_LOREM_LENGTH = 30;
+  private static final Pattern LOREM_PATTERN = Pattern.compile("(lorem|lipsum)(\\d*)");
+  @NonNls private static final String DEFAULT_INLINE_TAG = "span";
+  @NonNls private static final String LOREM_KEYWORD = "lorem";
+  @NonNls private static final String LIPSUM_KEYWORD = "lipsum";
+  private static final String ID = "id";
+  private static final String CLASS = "class";
+
+  private boolean hasTagContext = false;
+  private final Stack<String> tagLevel = new Stack<String>();
+
+  private static Map<String, String> parentChildTagMapping = new HashMap<String, String>() {{
+    put("p", "span");
+    put("ul", "li");
+    put("ol", "li");
+    put("table", "tr");
+    put("tr", "td");
+    put("tbody", "tr");
+    put("thead", "tr");
+    put("tfoot", "tr");
+    put("colgroup", "col");
+    put("select", "option");
+    put("optgroup", "option");
+    put("audio", "source");
+    put("video", "source");
+    put("object", "param");
+    put("map", "area");
+  }};
+
+  public XmlEmmetParser(List<ZenCodingToken> tokens,
+                        CustomTemplateCallback callback,
+                        ZenCodingGenerator generator) {
+    super(tokens, callback, generator);
+    PsiElement context = callback.getContext();
+    XmlTag parentTag = PsiTreeUtil.getParentOfType(context, XmlTag.class);
+    if (parentTag != null) {
+      hasTagContext = true;
+      tagLevel.push(parentTag.getName());
+    }
+  }
+
+  @NotNull
+  private static String getAttributeValueByToken(@Nullable ZenCodingToken token) {
+    if (token == null) {
+      return "";
+    }
+    if (token instanceof StringLiteralToken) {
+      final String text = ((StringLiteralToken)token).getText();
+      return text.substring(1, text.length() - 1);
+    }
+    else if (token instanceof IdentifierToken) {
+      return ((IdentifierToken)token).getText();
+    }
+    else if (token instanceof NumberToken) {
+      return Integer.toString(((NumberToken)token).getNumber());
+    }
+    else if (token == ZenCodingTokens.DOT || token == ZenCodingTokens.SHARP) {
+      return token.toString();
+    }
+    return "";
+  }
+
+  @Nullable
+  @Override
+  protected ZenCodingNode parseTemplate() {
+    ZenCodingToken token = getToken();
+    String templateKey = getDefaultTemplateKey();
+    boolean mustHaveSelector = true;
+
+    if (token instanceof IdentifierToken) {
+      templateKey = ((IdentifierToken)token).getText();
+      advance();
+      if (startsWithIgnoreCase(templateKey, LOREM_KEYWORD) || startsWithIgnoreCase(templateKey, LIPSUM_KEYWORD)) {
+        return parseLorem(templateKey);
+      }
+      mustHaveSelector = false;
+    }
+
+    if (templateKey == null) {
+      return null;
+    }
+
+    TemplateImpl template = myCallback.findApplicableTemplate(templateKey);
+    if (template == null && !ZenCodingUtil.isXML11ValidQName(templateKey)) {
+      return null;
+    }
+
+    final List<Pair<String, String>> attrList = parseSelectors();
+    if (mustHaveSelector && attrList.size() == 0) {
+      return null;
+    }
+
+    final TemplateToken templateToken = new TemplateToken(templateKey, attrList);
+    if (!setTemplate(templateToken, template)) {
+      return null;
+    }
+    return new TemplateNode(templateToken);
+  }
+
+  @Override
+  protected ZenCodingNode parseClimbUpOperation(@Nullable ZenCodingNode leftPart) {
+    popTagLevel();
+    return super.parseClimbUpOperation(leftPart);
+  }
+
+  @Override
+  protected ZenCodingNode parseMoreOperation(@NotNull ZenCodingNode leftPart) {
+    String parentTag = getParentTag(leftPart);
+    boolean hasParent = false;
+    if (!Strings.isNullOrEmpty(parentTag)) {
+      hasParent = true;
+      tagLevel.push(parentTag);
+    }
+    ZenCodingNode result = super.parseMoreOperation(leftPart);
+    if (result == null) {
+      return null;
+    }
+    if (hasParent) {
+      popTagLevel();
+    }
+    return result;
+  }
+
+  @Nullable
+  @Override
+  protected String getDefaultTemplateKey() {
+    return ZenCodingUtil.isHtml(myCallback) ? suggestTagName() : null;
+  }
+
+  @Nullable
+  private static String getParentTag(ZenCodingNode node) {
+    if (node instanceof TemplateNode) {
+      return ((TemplateNode)node).getTemplateToken().getKey();
+    }
+    else if (node instanceof MulOperationNode) {
+      ZenCodingNode leftOperand = ((MulOperationNode)node).getLeftOperand();
+      if (leftOperand instanceof TemplateNode) {
+        return ((TemplateNode)leftOperand).getTemplateToken().getKey();
+      }
+    }
+    return null;
+  }
+
+  @Nullable
+  private ZenCodingNode parseLorem(String templateKey) {
+    Matcher matcher = LOREM_PATTERN.matcher(templateKey);
+    if (matcher.matches()) {
+      int loremWordsCount = DEFAULT_LOREM_LENGTH;
+      if (matcher.groupCount() > 1) {
+        String group = matcher.group(2);
+        loremWordsCount = group.isEmpty() ? DEFAULT_LOREM_LENGTH : Integer.parseInt(group);
+      }
+
+      final List<Pair<String, String>> attrList = parseSelectors();
+      ZenCodingToken token = getToken();
+      boolean isRepeating = token instanceof OperationToken && ((OperationToken)token).getSign() == '*';
+      if (!attrList.isEmpty() || isRepeating) {
+        String wrapTag = suggestTagName();
+        TemplateImpl template = myCallback.findApplicableTemplate(templateKey);
+        if (template == null && !ZenCodingUtil.isXML11ValidQName(templateKey)) {
+          return null;
+        }
+        final TemplateToken templateToken = new TemplateToken(wrapTag, attrList);
+        if (!setTemplate(templateToken, template)) {
+          return null;
+        }
+        return new MoreOperationNode(new TemplateNode(templateToken), new LoremNode(loremWordsCount));
+      }
+      else {
+        return new LoremNode(loremWordsCount);
+      }
+    }
+    else {
+      return null;
+    }
+  }
+
+  private String suggestTagName() {
+    if (!tagLevel.empty()) {
+      String parentTag = tagLevel.peek();
+      if (parentChildTagMapping.containsKey(parentTag)) {
+        return parentChildTagMapping.get(parentTag);
+      }
+      if (HtmlUtil.isPossiblyInlineTag(parentTag)) {
+        return DEFAULT_INLINE_TAG;
+      }
+    }
+    return DEFAULT_TAG;
+  }
+
+  private void popTagLevel() {
+    if (tagLevel.size() > (hasTagContext ? 1 : 0)) {
+      tagLevel.pop();
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  @NotNull
+  private List<Pair<String, String>> parseSelectors() {
+    final List<Pair<String, String>> result = new ArrayList<Pair<String, String>>();
+
+    int classAttrPosition = -1;
+    int idAttrPosition = -1;
+
+    final StringBuilder classAttrBuilder = new StringBuilder();
+    final StringBuilder idAttrBuilder = new StringBuilder();
+
+    while (true) {
+      final List<Pair<String, String>> attrList = parseSelector();
+      if (attrList == null) {
+        if (classAttrPosition != -1) {
+          result.set(classAttrPosition, new Pair<String, String>(CLASS, classAttrBuilder.toString()));
+        }
+        if (idAttrPosition != -1) {
+          result.set(idAttrPosition, new Pair<String, String>(ID, idAttrBuilder.toString()));
+        }
+        return result;
+      }
+
+      for (Pair<String, String> attr : attrList) {
+        if (CLASS.equals(attr.first)) {
+          if (classAttrBuilder.length() > 0) {
+            classAttrBuilder.append(' ');
+          }
+          classAttrBuilder.append(attr.second);
+          if (classAttrPosition == -1) {
+            classAttrPosition = result.size();
+            result.add(attr);
+          }
+        }
+        else if (ID.equals(attr.first)) {
+          if (idAttrBuilder.length() > 0) {
+            idAttrBuilder.append(' ');
+          }
+          idAttrBuilder.append(attr.second);
+          if (idAttrPosition == -1) {
+            idAttrPosition = result.size();
+            result.add(attr);
+          }
+        }
+        else {
+          result.add(attr);
+        }
+      }
+    }
+  }
+
+  @Nullable
+  private List<Pair<String, String>> parseSelector() {
+    ZenCodingToken token = getToken();
+    if (token == ZenCodingTokens.OPENING_SQ_BRACKET) {
+      advance();
+      final List<Pair<String, String>> attrList = parseAttributeList();
+      if (attrList == null || getToken() != ZenCodingTokens.CLOSING_SQ_BRACKET) {
+        return null;
+      }
+      advance();
+      return attrList;
+    }
+
+    if (token == ZenCodingTokens.DOT || token == ZenCodingTokens.SHARP) {
+      final String name = token == ZenCodingTokens.DOT ? CLASS : ID;
+      advance();
+      token = getToken();
+      final String value = getAttributeValueByToken(token);
+      if (!value.isEmpty()) {
+        advance();
+      }
+      return Collections.singletonList(new Pair<String, String>(name, value));
+    }
+
+    return null;
+  }
+
+  @Nullable
+  private List<Pair<String, String>> parseAttributeList() {
+    final List<Pair<String, String>> result = new ArrayList<Pair<String, String>>();
+    while (true) {
+      final Pair<String, String> attribute = parseAttribute();
+      if (attribute == null) {
+        return result;
+      }
+      result.add(attribute);
+
+      final ZenCodingToken token = getToken();
+      if (token != ZenCodingTokens.COMMA && token != ZenCodingTokens.SPACE) {
+        return result;
+      }
+      advance();
+    }
+  }
+
+  @Nullable
+  private Pair<String, String> parseAttribute() {
+    ZenCodingToken token = getToken();
+    if (!(token instanceof IdentifierToken)) {
+      return null;
+    }
+
+    final String name = ((IdentifierToken)token).getText();
+
+    advance();
+    token = getToken();
+    if (token != ZenCodingTokens.EQ) {
+      return new Pair<String, String>(name, "");
+    }
+
+    advance();
+    final StringBuilder attrValueBuilder = new StringBuilder();
+    String value;
+    do {
+      token = getToken();
+      value = getAttributeValueByToken(token);
+      attrValueBuilder.append(value);
+      if (token != null && token != ZenCodingTokens.CLOSING_SQ_BRACKET
+          && token != ZenCodingTokens.SPACE && token != ZenCodingTokens.COMMA) {
+        advance();
+      }
+    }
+    while (token != null && token != ZenCodingTokens.CLOSING_SQ_BRACKET
+           && token != ZenCodingTokens.SPACE && token != ZenCodingTokens.COMMA);
+    return new Pair<String, String>(name, attrValueBuilder.toString());
+  }
+}
diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/ZenCodingTemplate.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/ZenCodingTemplate.java
new file mode 100644
index 0000000..f98078d
--- /dev/null
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/ZenCodingTemplate.java
@@ -0,0 +1,410 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.template.emmet;
+
+import com.intellij.application.options.editor.WebEditorOptions;
+import com.intellij.codeInsight.CodeInsightBundle;
+import com.intellij.codeInsight.template.*;
+import com.intellij.codeInsight.template.emmet.filters.SingleLineEmmetFilter;
+import com.intellij.codeInsight.template.emmet.filters.ZenCodingFilter;
+import com.intellij.codeInsight.template.emmet.generators.XmlZenCodingGenerator;
+import com.intellij.codeInsight.template.emmet.generators.ZenCodingGenerator;
+import com.intellij.codeInsight.template.emmet.nodes.*;
+import com.intellij.codeInsight.template.emmet.tokens.TemplateToken;
+import com.intellij.codeInsight.template.emmet.tokens.TextToken;
+import com.intellij.codeInsight.template.emmet.tokens.ZenCodingToken;
+import com.intellij.codeInsight.template.impl.TemplateImpl;
+import com.intellij.codeInsight.template.impl.TemplateState;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.command.CommandProcessor;
+import com.intellij.openapi.command.undo.UndoConstants;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.EditorModificationUtil;
+import com.intellij.openapi.editor.ScrollType;
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.openapi.ui.InputValidatorEx;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.*;
+import com.intellij.psi.xml.XmlAttribute;
+import com.intellij.psi.xml.XmlDocument;
+import com.intellij.psi.xml.XmlFile;
+import com.intellij.psi.xml.XmlTag;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.LocalTimeCounter;
+import com.intellij.xml.XmlBundle;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+
+/**
+ * @author Eugene.Kudelevsky
+ */
+public class ZenCodingTemplate implements CustomLiveTemplate {
+  public static final char MARKER = '\0';
+  public static final String ATTRS = "ATTRS";
+
+  private static void addMissingAttributes(XmlTag tag, List<Pair<String, String>> value) {
+    List<Pair<String, String>> attr2value = new ArrayList<Pair<String, String>>(value);
+    for (Iterator<Pair<String, String>> iterator = attr2value.iterator(); iterator.hasNext(); ) {
+      Pair<String, String> pair = iterator.next();
+      if (tag.getAttribute(pair.first) != null) {
+        iterator.remove();
+      }
+    }
+    addAttributesBefore(tag, attr2value);
+  }
+
+  private static void addAttributesBefore(XmlTag tag, List<Pair<String, String>> attr2value) {
+    XmlAttribute firstAttribute = ArrayUtil.getFirstElement(tag.getAttributes());
+    XmlElementFactory factory = XmlElementFactory.getInstance(tag.getProject());
+    for (Pair<String, String> pair : attr2value) {
+      XmlAttribute xmlAttribute = factory.createXmlAttribute(pair.first, "");
+      if (firstAttribute != null) {
+        tag.addBefore(xmlAttribute, firstAttribute);
+      }
+      else {
+        tag.add(xmlAttribute);
+      }
+    }
+  }
+
+  @Nullable
+  public static ZenCodingGenerator findApplicableDefaultGenerator(@NotNull PsiElement context, boolean wrapping) {
+    for (ZenCodingGenerator generator : ZenCodingGenerator.getInstances()) {
+      if (generator.isMyContext(context, wrapping) && generator.isAppliedByDefault(context)) {
+        return generator;
+      }
+    }
+    return null;
+  }
+
+  @NotNull
+  private static XmlFile parseXmlFileInTemplate(String templateString, CustomTemplateCallback callback, boolean createPhysicalFile) {
+    XmlFile xmlFile = (XmlFile)PsiFileFactory.getInstance(callback.getProject())
+      .createFileFromText("dummy.xml", StdFileTypes.XML, templateString, LocalTimeCounter.currentTime(), createPhysicalFile);
+    VirtualFile vFile = xmlFile.getVirtualFile();
+    if (vFile != null) {
+      vFile.putUserData(UndoConstants.DONT_RECORD_UNDO, Boolean.TRUE);
+    }
+    return xmlFile;
+  }
+
+  @Nullable
+  private static ZenCodingNode parse(@NotNull String text, @NotNull CustomTemplateCallback callback, @NotNull ZenCodingGenerator generator) {
+    List<ZenCodingToken> tokens = new EmmetLexer().lex(text);
+    if (tokens == null) {
+      return null;
+    }
+    if (!validate(tokens, generator)) {
+      return null;
+    }
+    EmmetParser parser = generator.createParser(tokens, callback, generator);
+    ZenCodingNode node = parser.parse();
+    if (parser.getIndex() != tokens.size() || node instanceof TextNode) {
+      return null;
+    }
+    return node;
+  }
+
+  private static boolean validate(@NotNull List<ZenCodingToken> tokens, @NotNull ZenCodingGenerator generator) {
+    for (ZenCodingToken token : tokens) {
+      if (token instanceof TextToken && !(generator instanceof XmlZenCodingGenerator)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  public static boolean checkTemplateKey(@NotNull String key, CustomTemplateCallback callback, @NotNull ZenCodingGenerator generator) {
+    return parse(key, callback, generator) != null;
+  }
+
+  public void expand(String key, @NotNull CustomTemplateCallback callback) {
+    ZenCodingGenerator defaultGenerator = findApplicableDefaultGenerator(callback.getContext(), false);
+    assert defaultGenerator != null;
+    expand(key, callback, null, defaultGenerator);
+  }
+
+  @Nullable
+  private static ZenCodingGenerator findApplicableGenerator(ZenCodingNode node, PsiElement context, boolean wrapping) {
+    ZenCodingGenerator defaultGenerator = null;
+    List<ZenCodingGenerator> generators = ZenCodingGenerator.getInstances();
+    for (ZenCodingGenerator generator : generators) {
+      if (defaultGenerator == null && generator.isMyContext(context, wrapping) && generator.isAppliedByDefault(context)) {
+        defaultGenerator = generator;
+      }
+    }
+    while (node instanceof FilterNode) {
+      FilterNode filterNode = (FilterNode)node;
+      String suffix = filterNode.getFilter();
+      for (ZenCodingGenerator generator : generators) {
+        if (generator.isMyContext(context, wrapping)) {
+          if (suffix != null && suffix.equals(generator.getSuffix())) {
+            return generator;
+          }
+        }
+      }
+      node = filterNode.getNode();
+    }
+    return defaultGenerator;
+  }
+
+  private static List<ZenCodingFilter> getFilters(ZenCodingNode node, PsiElement context) {
+    List<ZenCodingFilter> result = new ArrayList<ZenCodingFilter>();
+
+    while (node instanceof FilterNode) {
+      FilterNode filterNode = (FilterNode)node;
+      String filterSuffix = filterNode.getFilter();
+      boolean filterFound = false;
+      for (ZenCodingFilter filter : ZenCodingFilter.getInstances()) {
+        if (filter.isMyContext(context) && filter.getSuffix().equals(filterSuffix)) {
+          filterFound = true;
+          result.add(filter);
+        }
+      }
+      assert filterFound;
+      node = filterNode.getNode();
+    }
+
+    for (ZenCodingFilter filter : ZenCodingFilter.getInstances()) {
+      if (filter.isMyContext(context) && filter.isAppliedByDefault(context)) {
+        result.add(filter);
+      }
+    }
+
+    Collections.reverse(result);
+    return result;
+  }
+
+
+  private static void expand(String key,
+                             @NotNull CustomTemplateCallback callback,
+                             String surroundedText,
+                             @NotNull ZenCodingGenerator defaultGenerator) {
+    ZenCodingNode node = parse(key, callback, defaultGenerator);
+    assert node != null;
+    if (surroundedText == null) {
+      if (node instanceof TemplateNode) {
+        if (key.equals(((TemplateNode)node).getTemplateToken().getKey()) &&
+            callback.findApplicableTemplates(key).size() > 1) {
+          callback.startTemplate();
+          return;
+        }
+      }
+      callback.deleteTemplateKey(key);
+    }
+
+    PsiElement context = callback.getContext();
+    ZenCodingGenerator generator = findApplicableGenerator(node, context, false);
+    List<ZenCodingFilter> filters = getFilters(node, context);
+
+    expand(node, generator, filters, surroundedText, callback);
+  }
+
+  private static void expand(ZenCodingNode node,
+                             ZenCodingGenerator generator,
+                             List<ZenCodingFilter> filters,
+                             String surroundedText,
+                             CustomTemplateCallback callback) {
+    if (surroundedText != null) {
+      surroundedText = surroundedText.trim();
+    }
+
+    GenerationNode fakeParentNode = new GenerationNode(TemplateToken.EMPTY_TEMPLATE_TOKEN, -1, 1, surroundedText, true, null);
+    node.expand(-1, 1, surroundedText, callback, true, fakeParentNode);
+
+    List<GenerationNode> genNodes = fakeParentNode.getChildren();
+    LiveTemplateBuilder builder = new LiveTemplateBuilder();
+    int end = -1;
+    for (int i = 0, genNodesSize = genNodes.size(); i < genNodesSize; i++) {
+      GenerationNode genNode = genNodes.get(i);
+      TemplateImpl template = genNode.generate(callback, generator, filters, true);
+      int e = builder.insertTemplate(builder.length(), template, null);
+      if (end == -1 && end < builder.length()) {
+        end = e;
+      }
+    }
+    for (ZenCodingFilter filter : filters) {
+      if(filter instanceof SingleLineEmmetFilter) {
+        builder.setIsToReformat(false);
+        break;
+      }
+    }
+
+    callback.startTemplate(builder.buildTemplate(), null, new TemplateEditingAdapter() {
+      private TextRange myEndVarRange;
+      private Editor myEditor;
+
+      @Override
+      public void beforeTemplateFinished(TemplateState state, Template template) {
+        int variableNumber = state.getCurrentVariableNumber();
+        if (variableNumber >= 0 && template instanceof TemplateImpl) {
+          TemplateImpl t = (TemplateImpl)template;
+          while (variableNumber < t.getVariableCount()) {
+            String varName = t.getVariableNameAt(variableNumber);
+            if (LiveTemplateBuilder.isEndVariable(varName)) {
+              myEndVarRange = state.getVariableRange(varName);
+              myEditor = state.getEditor();
+              break;
+            }
+            variableNumber++;
+          }
+        }
+      }
+
+      @Override
+      public void templateFinished(Template template, boolean brokenOff) {
+        if (brokenOff && myEndVarRange != null && myEditor != null) {
+          int offset = myEndVarRange.getStartOffset();
+          if (offset >= 0 && offset != myEditor.getCaretModel().getOffset()) {
+            myEditor.getCaretModel().moveToOffset(offset);
+            myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
+          }
+        }
+      }
+    });
+  }
+
+  public void wrap(final String selection,
+                   @NotNull final CustomTemplateCallback callback
+  ) {
+    InputValidatorEx validator = new InputValidatorEx() {
+      public String getErrorText(String inputString) {
+        if (!checkTemplateKey(inputString, callback)) {
+          return XmlBundle.message("zen.coding.incorrect.abbreviation.error");
+        }
+        return null;
+      }
+
+      public boolean checkInput(String inputString) {
+        return getErrorText(inputString) == null;
+      }
+
+      public boolean canClose(String inputString) {
+        return checkInput(inputString);
+      }
+    };
+    final String abbreviation = Messages
+      .showInputDialog(callback.getProject(), XmlBundle.message("zen.coding.enter.abbreviation.dialog.label"),
+                       XmlBundle.message("zen.coding.title"), Messages.getQuestionIcon(), "", validator);
+    if (abbreviation != null) {
+      doWrap(selection, abbreviation, callback);
+    }
+  }
+
+  public static boolean checkTemplateKey(String inputString, CustomTemplateCallback callback) {
+    ZenCodingGenerator generator = findApplicableDefaultGenerator(callback.getContext(), true);
+    assert generator != null;
+    return checkTemplateKey(inputString, callback, generator);
+  }
+
+  public boolean isApplicable(PsiFile file, int offset, boolean wrapping) {
+    WebEditorOptions webEditorOptions = WebEditorOptions.getInstance();
+    if (!webEditorOptions.isZenCodingEnabled()) {
+      return false;
+    }
+    if (file == null) {
+      return false;
+    }
+    PsiDocumentManager.getInstance(file.getProject()).commitAllDocuments();
+    PsiElement element = CustomTemplateCallback.getContext(file, offset);
+    return findApplicableDefaultGenerator(element, wrapping) != null;
+  }
+
+  public static void doWrap(final String selection,
+                               final String abbreviation,
+                               final CustomTemplateCallback callback) {
+    final ZenCodingGenerator defaultGenerator = findApplicableDefaultGenerator(callback.getContext(), true);
+    assert defaultGenerator != null;
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      public void run() {
+        CommandProcessor.getInstance().executeCommand(callback.getProject(), new Runnable() {
+          public void run() {
+            callback.fixInitialState(true);
+            ZenCodingNode node = parse(abbreviation, callback, defaultGenerator);
+            assert node != null;
+            PsiElement context = callback.getContext();
+            ZenCodingGenerator generator = findApplicableGenerator(node, context, true);
+            List<ZenCodingFilter> filters = getFilters(node, context);
+
+            EditorModificationUtil.deleteSelectedText(callback.getEditor());
+            PsiDocumentManager.getInstance(callback.getProject()).commitAllDocuments();
+
+            expand(node, generator, filters, selection, callback);
+          }
+        }, CodeInsightBundle.message("insert.code.template.command"), null);
+      }
+    });
+  }
+
+  @NotNull
+  public String getTitle() {
+    return XmlBundle.message("zen.coding.title");
+  }
+
+  public char getShortcut() {
+    return (char)WebEditorOptions.getInstance().getZenCodingExpandShortcut();
+  }
+
+  protected static boolean containsAttrsVar(TemplateImpl template) {
+    for (int i = 0; i < template.getVariableCount(); i++) {
+      String varName = template.getVariableNameAt(i);
+      if (ATTRS.equals(varName)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  public String computeTemplateKey(@NotNull CustomTemplateCallback callback) {
+    ZenCodingGenerator generator = findApplicableDefaultGenerator(callback.getContext(), false);
+    if (generator == null) return null;
+    return generator.computeTemplateKey(callback);
+  }
+
+  public boolean supportsWrapping() {
+    return true;
+  }
+
+  public static boolean doSetTemplate(final TemplateToken token, TemplateImpl template, CustomTemplateCallback callback) {
+    token.setTemplate(template);
+    final XmlFile xmlFile = parseXmlFileInTemplate(template.getString(), callback, true);
+    token.setFile(xmlFile);
+    XmlDocument document = xmlFile.getDocument();
+    final XmlTag tag = document != null ? document.getRootTag() : null;
+    if (token.getAttribute2Value().size() > 0 && tag == null) {
+      return false;
+    }
+    if (tag != null) {
+      if (!containsAttrsVar(template) && token.getAttribute2Value().size() > 0) {
+        ApplicationManager.getApplication().runWriteAction(new Runnable() {
+          public void run() {
+            addMissingAttributes(tag, token.getAttribute2Value());
+          }
+        });
+      }
+    }
+    return true;
+  }
+}
diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/ZenCodingUtil.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/ZenCodingUtil.java
new file mode 100644
index 0000000..9b81e47
--- /dev/null
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/ZenCodingUtil.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.template.emmet;
+
+import com.intellij.codeInsight.template.CustomTemplateCallback;
+import com.intellij.codeInsight.template.emmet.filters.ZenCodingFilter;
+import com.intellij.codeInsight.template.emmet.generators.ZenCodingGenerator;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import org.apache.xerces.util.XML11Char;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Eugene.Kudelevsky
+ */
+public class ZenCodingUtil {
+  private static final char NUMBER_IN_ITERATION_PLACE_HOLDER = '$';
+  private static final String SURROUNDED_TEXT_MARKER = "$#";
+
+  private ZenCodingUtil() {
+  }
+
+  public static boolean containsSurroundedTextMarker(@NotNull String s) {
+    return s.contains(SURROUNDED_TEXT_MARKER);
+  }
+
+  public static String replaceMarkers(String s, int numberInIteration, int totalIterations, @Nullable String surroundedText) {
+    String by = Integer.toString(numberInIteration + 1);
+    StringBuilder builder = new StringBuilder(s.length());
+    int markerStartIndex = -1;
+    int i = 0;
+    int n = s.length();
+    while (i <= n) {
+      char c = i < n ? s.charAt(i) : 0;
+      if (c == NUMBER_IN_ITERATION_PLACE_HOLDER && (i == n - 1 || s.charAt(i + 1) != '#')) {
+        if (markerStartIndex == -1) {
+          markerStartIndex = i;
+        }
+      }
+      else {
+        int markersCount = i - markerStartIndex;
+        if (markerStartIndex != -1) {
+          // counter base
+          boolean decrement = false;
+          if(i < n && s.charAt(i) == '@') {
+            i++;
+            if (i < n && s.charAt(i) == '-') {
+              decrement = true;
+              i++;
+            }
+            StringBuilder base = new StringBuilder();
+            while (i < n && Character.isDigit(s.charAt(i))) {
+              base.append(s.charAt(i));
+              i++;
+            }
+            int baseInt = parseNonNegativeInt(base.toString()) - 1;
+            baseInt = baseInt >= 0 ? baseInt : 0;
+            if(baseInt >= 0) {
+              int byInt = decrement
+                          ? totalIterations - numberInIteration
+                          : numberInIteration + 1;
+              byInt += baseInt;
+              by = Integer.toString(byInt);
+            }
+          }
+          for (int k = 0, m = markersCount - by.length(); k < m; k++) {
+            builder.append('0');
+          }
+          builder.append(by);
+          markerStartIndex = -1;
+          c = i < n ? s.charAt(i) : 0;
+        }
+        if (i < n) {
+          if (c == NUMBER_IN_ITERATION_PLACE_HOLDER && surroundedText != null) {
+            builder.append(surroundedText);
+            i++;
+          }
+          else {
+            builder.append(c);
+          }
+        }
+      }
+      i++;
+    }
+    return builder.toString();
+  }
+
+  public static String getValue(String value, int numberInIteration, int totalIterations, String surroundedText) {
+    String s = replaceMarkers(value, numberInIteration, totalIterations, surroundedText);
+    return s.replace("\"", "&quot;");
+  }
+
+  public static int parseNonNegativeInt(@NotNull String s) {
+    try {
+      return Integer.parseInt(s);
+    }
+    catch (Throwable ignored) {
+    }
+    return -1;
+  }
+
+  public static boolean isXML11ValidQName(String str) {
+    final int colon = str.indexOf(':');
+    if (colon == 0 || colon == str.length() - 1) {
+      return false;
+    }
+    if (colon > 0) {
+      final String prefix = str.substring(0, colon);
+      final String localPart = str.substring(colon + 1);
+      return XML11Char.isXML11ValidNCName(prefix) && XML11Char.isXML11ValidNCName(localPart);
+    }
+    return XML11Char.isXML11ValidNCName(str);
+  }
+
+  public static boolean isHtml(CustomTemplateCallback callback) {
+    FileType type = callback.getFileType();
+    return type == StdFileTypes.HTML || type == StdFileTypes.XHTML;
+  }
+
+  public static boolean checkFilterSuffix(@NotNull String suffix) {
+    for (ZenCodingGenerator generator : ZenCodingGenerator.getInstances()) {
+      if (suffix.equals(generator.getSuffix())) {
+        return true;
+      }
+    }
+    for (ZenCodingFilter filter : ZenCodingFilter.getInstances()) {
+      if (suffix.equals(filter.getSuffix())) {
+        return true;
+      }
+    }
+    return false;
+  }
+}
diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/filters/BemEmmetFilter.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/filters/BemEmmetFilter.java
new file mode 100644
index 0000000..f226864
--- /dev/null
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/filters/BemEmmetFilter.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.template.emmet.filters;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableSet;
+import com.intellij.codeInsight.template.emmet.nodes.GenerationNode;
+import com.intellij.lang.xml.XMLLanguage;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.Pair;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static com.google.common.base.Strings.nullToEmpty;
+import static com.google.common.collect.Iterables.*;
+import static com.google.common.collect.Lists.newLinkedList;
+
+/**
+ * User: zolotov
+ * Date: 2/4/13
+ * <p/>
+ * Bem filter for emmet support.
+ * See the original source code here: https://github.com/emmetio/emmet/blob/master/javascript/filters/bem.js
+ * And documentation here: http://docs.emmet.io/filters/bem/
+ */
+public class BemEmmetFilter extends ZenCodingFilter {
+  private static final Key<BemState> BEM_STATE = Key.create("BEM_STATE");
+
+  private static final String ELEMENT_SEPARATOR = "__";
+  private static final String MODIFIER_SEPARATOR = "_";
+  private static final String SHORT_ELEMENT_PREFIX = "-";
+
+  private static final Splitter ELEMENTS_SPLITTER = Splitter.on(ELEMENT_SEPARATOR);
+  private static final Splitter MODIFIERS_SPLITTER = Splitter.on(MODIFIER_SEPARATOR).limit(2);
+  private static final Splitter CLASS_NAME_SPLITTER = Splitter.on(' ').trimResults().omitEmptyStrings();
+  private static final Joiner CLASS_NAME_JOINER = Joiner.on(' ');
+
+  private static final Function<String, String> CLASS_NAME_NORMALIZER = new Function<String, String>() {
+    @Override
+    public String apply(@NotNull String input) {
+      if(!input.startsWith(SHORT_ELEMENT_PREFIX)) {
+        return input;
+      }
+
+      StringBuilder result = new StringBuilder();
+      while (input.startsWith(SHORT_ELEMENT_PREFIX)) {
+        input = input.substring(SHORT_ELEMENT_PREFIX.length());
+        result.append(ELEMENT_SEPARATOR);
+      }
+      return result.append(input).toString();
+    }
+  };
+
+  private static final Predicate<String> BLOCK_NAME_PREDICATE = new Predicate<String>() {
+    @Override
+    public boolean apply(String className) {
+      return Pattern.compile("^[A-z]-").matcher(className).matches();
+    }
+  };
+  private static final Predicate<String> STARTS_WITH_LETTER = new Predicate<String>() {
+    @Override
+    public boolean apply(@Nullable String input) {
+      return input != null && input.length() > 0 && Character.isLetter(input.charAt(0));
+    }
+  };
+
+  @NotNull
+  @Override
+  public String getSuffix() {
+    return "bem";
+  }
+
+  @Override
+  public boolean isAppliedByDefault(@NotNull PsiElement context) {
+    return false; //todo: add setting for enabling this filter by default
+  }
+
+  @Override
+  public boolean isMyContext(@NotNull PsiElement context) {
+    return context.getLanguage() instanceof XMLLanguage;
+  }
+
+  @NotNull
+  @Override
+  public GenerationNode filterNode(@NotNull final GenerationNode node) {
+    final List<Pair<String, String>> attribute2Value = node.getTemplateToken().getAttribute2Value();
+    Pair<String, String> classNamePair = getClassPair(attribute2Value);
+    if (classNamePair != null) {
+      Iterable<String> classNames = extractClasses(classNamePair.second);
+      BEM_STATE.set(node, new BemState(suggestBlockName(classNames), null, null));
+      final Set<String> newClassNames = ImmutableSet.copyOf(concat(transform(classNames, new Function<String, Iterable<String>>() {
+        @Override
+        public Iterable<String> apply(String className) {
+          return processClassName(className, node);
+        }
+      })));
+      attribute2Value.add(Pair.create("class", CLASS_NAME_JOINER.join(newClassNames)));
+    }
+    return node;
+  }
+
+  private static Iterable<String> processClassName(String className, GenerationNode node) {
+    className = fillWithBemElements(className, node);
+    className = fillWithBemModifiers(className, node);
+
+    BemState nodeBemState = BEM_STATE.get(node);
+    BemState bemState = extractBemStateFromClassName(className);
+    List<String> result = newLinkedList();
+    if (!bemState.isEmpty()) {
+      String block = bemState.getBlock();
+      if (isNullOrEmpty(block)) {
+        block = nullToEmpty(nodeBemState != null ? nodeBemState.getBlock() : null);
+        bemState.setBlock(block);
+      }
+      String prefix = block;
+      String element = bemState.getElement();
+      if (!isNullOrEmpty(element)) {
+        prefix += ELEMENT_SEPARATOR + element;
+      }
+      result.add(prefix);
+      String modifier = bemState.getModifier();
+      if (!isNullOrEmpty(modifier)) {
+        result.add(prefix + MODIFIER_SEPARATOR + modifier);
+      }
+      BEM_STATE.set(node, bemState.copy());
+    }
+    else {
+      result.add(className);
+    }
+    return result;
+  }
+
+  @NotNull
+  private static BemState extractBemStateFromClassName(@NotNull String className) {
+    BemState result = new BemState();
+    if (className.contains(ELEMENT_SEPARATOR)) {
+      List<String> blockElements = newLinkedList(ELEMENTS_SPLITTER.split(className));
+      result.setBlock(getFirst(blockElements, ""));
+      if (blockElements.size() > 1) {
+        List<String> elementModifiers = newLinkedList(MODIFIERS_SPLITTER.split(blockElements.get(1)));
+        result.setElement(getFirst(elementModifiers, ""));
+        if (elementModifiers.size() > 1) {
+          result.setModifier(getLast(elementModifiers, ""));
+        }
+      }
+    }
+    else if (className.contains(MODIFIER_SEPARATOR)) {
+      Iterable<String> blockModifiers = MODIFIERS_SPLITTER.split(className);
+      result.setBlock(getFirst(blockModifiers, ""));
+      result.setModifier(getLast(blockModifiers, ""));
+    }
+    return result;
+  }
+
+  @NotNull
+  private static String fillWithBemElements(@NotNull String className, @NotNull GenerationNode node) {
+    return transformClassNameToBemFormat(className, ELEMENT_SEPARATOR, node);
+  }
+
+  @NotNull
+  private static String fillWithBemModifiers(@NotNull String className, @NotNull GenerationNode node) {
+    return transformClassNameToBemFormat(className, MODIFIER_SEPARATOR, node);
+  }
+
+  /**
+   * Adduction className to BEM format according to tags structure.
+   *
+   * @param className
+   * @param separator handling separator
+   * @param node      current node
+   * @return class name in BEM format
+   */
+  @NotNull
+  private static String transformClassNameToBemFormat(@NotNull String className, @NotNull String separator, @NotNull GenerationNode node) {
+    Pair<String, Integer> cleanStringAndDepth = getCleanStringAndDepth(className, separator);
+    Integer depth = cleanStringAndDepth.second;
+    if (depth > 0) {
+      GenerationNode donor = node;
+      while (donor.getParent() != null && depth > 0) {
+        donor = donor.getParent();
+        depth--;
+      }
+
+      BemState bemState = BEM_STATE.get(donor);
+      if (bemState != null) {
+        String prefix = bemState.getBlock();
+        if (!isNullOrEmpty(prefix)) {
+          String element = bemState.getElement();
+          if (MODIFIER_SEPARATOR.equals(separator) && !isNullOrEmpty(element)) {
+            prefix = prefix + separator + element;
+          }
+          return prefix + separator + cleanStringAndDepth.first;
+        }
+      }
+    }
+    return className;
+  }
+
+  /**
+   * Counts separators at the start of className and retrieve className without these separators.
+   *
+   * @param name
+   * @param separator
+   * @return pair like <name_without_separator_at_the_start, count_of_separators_at_the_start_of_string>
+   */
+  @NotNull
+  private static Pair<String, Integer> getCleanStringAndDepth(@NotNull String name, @NotNull String separator) {
+    int result = 0;
+    while (name.startsWith(separator)) {
+      result++;
+      name = name.substring(separator.length());
+    }
+    return Pair.create(name, result);
+  }
+
+  /**
+   * Extract all normalized class names from class attribute value
+   *
+   * @param classAttributeValue
+   * @return collection of normalized class names
+   */
+  @NotNull
+  private static Iterable<String> extractClasses(String classAttributeValue) {
+    return transform(CLASS_NAME_SPLITTER.split(classAttributeValue), CLASS_NAME_NORMALIZER);
+  }
+
+  /**
+   * Suggest block name by class names.
+   * Returns first class started with pattern [a-z]-
+   * or first class started with letter.
+   *
+   * @param classNames
+   * @return suggested block name for given classes. Empty string if name can't be suggested.
+   */
+  @NotNull
+  private static String suggestBlockName(Iterable<String> classNames) {
+    return find(classNames, BLOCK_NAME_PREDICATE, find(classNames, STARTS_WITH_LETTER, ""));
+  }
+
+  /**
+   * Retrieve pair "class" => classAttributeValue from node attributeList
+   *
+   * @param attribute2Value node's attributes
+   * @return pointer to pair
+   */
+  @Nullable
+  private static Pair<String, String> getClassPair(@NotNull List<Pair<String, String>> attribute2Value) {
+    for (int i = 0; i < attribute2Value.size(); i++) {
+      Pair<String, String> pair = attribute2Value.get(i);
+      if ("class".equals(pair.first) && !isNullOrEmpty(pair.second)) {
+        return attribute2Value.remove(i);
+      }
+    }
+    return null;
+  }
+
+  private static class BemState {
+    @Nullable private String block;
+    @Nullable private String element;
+    @Nullable private String modifier;
+
+    private BemState() {
+    }
+
+    private BemState(@Nullable String block, @Nullable String element, @Nullable String modifier) {
+      this.block = block;
+      this.element = element;
+      this.modifier = modifier;
+    }
+
+    public void setModifier(@Nullable String modifier) {
+      this.modifier = modifier;
+    }
+
+    public void setElement(@Nullable String element) {
+      this.element = element;
+    }
+
+    public void setBlock(@Nullable String block) {
+      this.block = block;
+    }
+
+    @Nullable
+    public String getBlock() {
+      return block;
+    }
+
+    @Nullable
+    public String getElement() {
+      return element;
+    }
+
+    @Nullable
+    public String getModifier() {
+      return modifier;
+    }
+
+    public boolean isEmpty() {
+      return isNullOrEmpty(block) && isNullOrEmpty(element) && isNullOrEmpty(modifier);
+    }
+
+    public BemState copy() {
+      return new BemState(block, element, modifier);
+    }
+  }
+}
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/filters/CommentZenCodingFilter.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/filters/CommentZenCodingFilter.java
similarity index 83%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/filters/CommentZenCodingFilter.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/filters/CommentZenCodingFilter.java
index 612487f..82b6235 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/filters/CommentZenCodingFilter.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/filters/CommentZenCodingFilter.java
@@ -13,9 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.template.zencoding.filters;
+package com.intellij.codeInsight.template.emmet.filters;
 
-import com.intellij.codeInsight.template.zencoding.tokens.TemplateToken;
+import com.intellij.codeInsight.template.emmet.tokens.TemplateToken;
 import com.intellij.lang.xml.XMLLanguage;
 import com.intellij.psi.PsiElement;
 import com.intellij.psi.xml.XmlDocument;
@@ -23,16 +23,18 @@
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
+import static com.google.common.base.Strings.isNullOrEmpty;
+
 /**
  * @author Eugene.Kudelevsky
  */
 public class CommentZenCodingFilter extends ZenCodingFilter {
   private static String buildCommentString(@Nullable String classAttr, @Nullable String idAttr) {
     StringBuilder builder = new StringBuilder();
-    if (idAttr != null) {
+    if (!isNullOrEmpty(idAttr)) {
       builder.append('#').append(idAttr);
     }
-    if (classAttr != null) {
+    if (!isNullOrEmpty(classAttr)) {
       builder.append('.').append(classAttr);
     }
     return builder.toString();
@@ -47,9 +49,9 @@
       if (tag != null) {
         String classAttr = tag.getAttributeValue("class");
         String idAttr = tag.getAttributeValue("id");
-        if (classAttr != null || idAttr != null) {
+        if (!isNullOrEmpty(classAttr) || !isNullOrEmpty(idAttr)) {
           String commentString = buildCommentString(classAttr, idAttr);
-          return "<!-- " + commentString + " -->\n" + text + "\n<!-- /" + commentString + " -->";
+          return text + "\n<!-- /" + commentString + " -->";
         }
       }
     }
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/filters/EscapeZenCodingFilter.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/filters/EscapeZenCodingFilter.java
similarity index 90%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/filters/EscapeZenCodingFilter.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/filters/EscapeZenCodingFilter.java
index 8c3abe8..3249b5a 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/filters/EscapeZenCodingFilter.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/filters/EscapeZenCodingFilter.java
@@ -13,9 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.template.zencoding.filters;
+package com.intellij.codeInsight.template.emmet.filters;
 
-import com.intellij.codeInsight.template.zencoding.tokens.TemplateToken;
+import com.intellij.codeInsight.template.emmet.tokens.TemplateToken;
 import com.intellij.lang.xml.XMLLanguage;
 import com.intellij.psi.PsiElement;
 import org.jetbrains.annotations.NotNull;
diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/filters/SingleLineEmmetFilter.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/filters/SingleLineEmmetFilter.java
new file mode 100644
index 0000000..c355644
--- /dev/null
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/filters/SingleLineEmmetFilter.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.template.emmet.filters;
+
+import com.intellij.codeInsight.template.emmet.nodes.GenerationNode;
+import com.intellij.codeInsight.template.impl.TemplateImpl;
+import com.intellij.lang.xml.XMLLanguage;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * User: zolotov
+ * Date: 2/4/13
+ */
+public class SingleLineEmmetFilter extends ZenCodingFilter {
+  @NotNull
+  @Override
+  public String getSuffix() {
+    return "s";
+  }
+
+  @NotNull
+  @Override
+  public GenerationNode filterNode(@NotNull GenerationNode node) {
+    TemplateImpl template = node.getTemplateToken().getTemplate();
+    if (template != null) {
+      template.setToReformat(false);
+    }
+    for (GenerationNode generationNode : node.getChildren()) {
+      filterNode(generationNode);
+    }
+    return node;
+  }
+
+  @Override
+  public boolean isMyContext(@NotNull PsiElement context) {
+    return context.getLanguage() instanceof XMLLanguage;
+  }
+}
diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/filters/TrimZenCodingFilter.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/filters/TrimZenCodingFilter.java
new file mode 100644
index 0000000..1c63692
--- /dev/null
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/filters/TrimZenCodingFilter.java
@@ -0,0 +1,74 @@
+package com.intellij.codeInsight.template.emmet.filters;
+
+import com.intellij.codeInsight.template.emmet.nodes.GenerationNode;
+import com.intellij.codeInsight.template.emmet.tokens.TemplateToken;
+import com.intellij.lang.xml.XMLLanguage;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.XmlElementVisitor;
+import com.intellij.psi.xml.XmlDocument;
+import com.intellij.psi.xml.XmlTag;
+import com.intellij.psi.xml.XmlTagValue;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.regex.Pattern;
+
+/**
+ * @author Eugene.Kudelevsky
+ */
+public class TrimZenCodingFilter extends ZenCodingFilter {
+  private static final Pattern PATTERN = Pattern.compile("^([\\s|\u00a0])?[\\d|#|\\-|\\*|\u2022]+\\.?\\s*");
+
+  @NotNull
+  @Override
+  public String getSuffix() {
+    return "t";
+  }
+
+  @Override
+  public boolean isMyContext(@NotNull PsiElement context) {
+    return context.getLanguage() instanceof XMLLanguage;
+  }
+
+  @NotNull
+  @Override
+  public String filterText(@NotNull String text, @NotNull TemplateToken token) {
+    XmlDocument document = token.getFile().getDocument();
+    if (document != null) {
+      XmlTag tag = document.getRootTag();
+      if (tag != null && !tag.getText().isEmpty()) {
+        new XmlElementVisitor() {
+          @Override
+          public void visitXmlTag(XmlTag tag) {
+            if(!tag.isEmpty()) {
+              XmlTagValue tagValue = tag.getValue();
+              tagValue.setText(PATTERN.matcher(tagValue.getText()).replaceAll(""));
+            }
+            tag.acceptChildren(this);
+          }
+        }.visitXmlTag(tag);
+        return tag.getText();
+      } else {
+        return PATTERN.matcher(document.getText()).replaceAll("");
+      }
+    }
+    return text;
+  }
+
+  @NotNull
+  @Override
+  public GenerationNode filterNode(@NotNull GenerationNode node) {
+    doFilter(node);
+    return node;
+  }
+
+  private static void doFilter(GenerationNode node) {
+    final String surroundedText = node.getSurroundedText();
+    if (surroundedText != null) {
+      node.setSurroundedText(PATTERN.matcher(surroundedText).replaceAll(""));
+    } else if(node.getTemplateToken() == TemplateToken.EMPTY_TEMPLATE_TOKEN) {
+    }
+    for (GenerationNode child : node.getChildren()) {
+      doFilter(child);
+    }
+  }
+}
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/filters/XslZenCodingFilter.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/filters/XslZenCodingFilter.java
similarity index 83%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/filters/XslZenCodingFilter.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/filters/XslZenCodingFilter.java
index 3a05ca2..086fa7d 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/filters/XslZenCodingFilter.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/filters/XslZenCodingFilter.java
@@ -13,12 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.template.zencoding.filters;
+package com.intellij.codeInsight.template.emmet.filters;
 
-import com.intellij.codeInsight.template.zencoding.generators.XmlZenCodingGenerator;
-import com.intellij.codeInsight.template.zencoding.generators.XmlZenCodingGeneratorImpl;
-import com.intellij.codeInsight.template.zencoding.nodes.GenerationNode;
-import com.intellij.codeInsight.template.zencoding.tokens.TemplateToken;
+import com.intellij.codeInsight.template.emmet.generators.XmlZenCodingGenerator;
+import com.intellij.codeInsight.template.emmet.generators.XmlZenCodingGeneratorImpl;
+import com.intellij.codeInsight.template.emmet.nodes.GenerationNode;
+import com.intellij.codeInsight.template.emmet.tokens.TemplateToken;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.util.Pair;
 import com.intellij.openapi.vfs.VirtualFile;
@@ -41,12 +41,11 @@
   public GenerationNode filterNode(@NotNull final GenerationNode node) {
     TemplateToken token = node.getTemplateToken();
     if (token != null) {
-      TemplateToken xmlToken = token;
-      XmlDocument document = xmlToken.getFile().getDocument();
+      XmlDocument document = token.getFile().getDocument();
       if (document != null) {
         final XmlTag tag = document.getRootTag();
         if (tag != null) {
-          for (Pair<String, String> pair : xmlToken.getAttribute2Value()) {
+          for (Pair<String, String> pair : token.getAttribute2Value()) {
             if (SELECT_ATTR_NAME.equals(pair.first)) {
               return node;
             }
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/filters/ZenCodingFilter.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/filters/ZenCodingFilter.java
similarity index 88%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/filters/ZenCodingFilter.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/filters/ZenCodingFilter.java
index 5ab6ada..f5057f3 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/filters/ZenCodingFilter.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/filters/ZenCodingFilter.java
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.template.zencoding.filters;
+package com.intellij.codeInsight.template.emmet.filters;
 
-import com.intellij.codeInsight.template.zencoding.nodes.GenerationNode;
-import com.intellij.codeInsight.template.zencoding.tokens.TemplateToken;
+import com.intellij.codeInsight.template.emmet.nodes.GenerationNode;
+import com.intellij.codeInsight.template.emmet.tokens.TemplateToken;
 import com.intellij.openapi.extensions.ExtensionPointName;
 import com.intellij.psi.PsiElement;
 import org.jetbrains.annotations.NotNull;
@@ -36,6 +36,8 @@
     new XslZenCodingFilter(),
     new CommentZenCodingFilter(),
     new EscapeZenCodingFilter(),
+    new SingleLineEmmetFilter(),
+    new BemEmmetFilter(),
     new TrimZenCodingFilter()
   };
 
diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/generators/LoremGenerator.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/generators/LoremGenerator.java
new file mode 100644
index 0000000..a5f4aee
--- /dev/null
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/generators/LoremGenerator.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.template.emmet.generators;
+
+import com.intellij.openapi.util.text.StringUtil;
+
+import java.util.*;
+
+/**
+ * User: zolotov
+ * Date: 1/31/13
+ */
+public class LoremGenerator {
+  static final String[] COMMON_P = "lorem ipsum dolor sit amet consectetur adipisicing elit".split(" ");
+  private static final String[] WORDS = new String[]{"exercitationem", "perferendis", "perspiciatis", "laborum", "eveniet",
+    "sunt", "iure", "nam", "nobis", "eum", "cum", "officiis", "excepturi",
+    "odio", "consectetur", "quasi", "aut", "quisquam", "vel", "eligendi",
+    "itaque", "non", "odit", "tempore", "quaerat", "dignissimos",
+    "facilis", "neque", "nihil", "expedita", "vitae", "vero", "ipsum",
+    "nisi", "animi", "cumque", "pariatur", "velit", "modi", "natus",
+    "iusto", "eaque", "sequi", "illo", "sed", "ex", "et", "voluptatibus",
+    "tempora", "veritatis", "ratione", "assumenda", "incidunt", "nostrum",
+    "placeat", "aliquid", "fuga", "provident", "praesentium", "rem",
+    "necessitatibus", "suscipit", "adipisci", "quidem", "possimus",
+    "voluptas", "debitis", "sint", "accusantium", "unde", "sapiente",
+    "voluptate", "qui", "aspernatur", "laudantium", "soluta", "amet",
+    "quo", "aliquam", "saepe", "culpa", "libero", "ipsa", "dicta",
+    "reiciendis", "nesciunt", "doloribus", "autem", "impedit", "minima",
+    "maiores", "repudiandae", "ipsam", "obcaecati", "ullam", "enim",
+    "totam", "delectus", "ducimus", "quis", "voluptates", "dolores",
+    "molestiae", "harum", "dolorem", "quia", "voluptatem", "molestias",
+    "magni", "distinctio", "omnis", "illum", "dolorum", "voluptatum", "ea",
+    "quas", "quam", "corporis", "quae", "blanditiis", "atque", "deserunt",
+    "laboriosam", "earum", "consequuntur", "hic", "cupiditate",
+    "quibusdam", "accusamus", "ut", "rerum", "error", "minus", "eius",
+    "ab", "ad", "nemo", "fugit", "officia", "at", "in", "id", "quos",
+    "reprehenderit", "numquam", "iste", "fugiat", "sit", "inventore",
+    "beatae", "repellendus", "magnam", "recusandae", "quod", "explicabo",
+    "doloremque", "aperiam", "consequatur", "asperiores", "commodi",
+    "optio", "dolor", "labore", "temporibus", "repellat", "veniam",
+    "architecto", "est", "esse", "mollitia", "nulla", "a", "similique",
+    "eos", "alias", "dolore", "tenetur", "deleniti", "porro", "facere",
+    "maxime", "corrupti"};
+
+  private final Random random;
+
+  public LoremGenerator() {
+    random = new Random();
+  }
+
+  /**
+   * Generate a paragraph of Lorem ipsum
+   *
+   * @param wordsCount      words count in paragraph
+   * @param startWithCommon should paragraph start with common {@link this#COMMON_P}
+   * @return generated paragraph
+   */
+  public String generate(int wordsCount, boolean startWithCommon) {
+    Collection<String> sentences = new LinkedList<String>();
+    int totalWords = 0;
+    String[] words;
+
+    if (startWithCommon) {
+      words = Arrays.copyOfRange(COMMON_P, 0, Math.min(wordsCount, COMMON_P.length));
+      if (words.length > 5) {
+        words[4] += ',';
+      }
+      totalWords += words.length;
+      sentences.add(sentence(words, '.'));
+    }
+
+    while (totalWords < wordsCount) {
+      words = sample(WORDS, Math.min(rand(3, 12) * rand(1, 5), wordsCount - totalWords));
+      totalWords += words.length;
+      insertCommas(words);
+      sentences.add(sentence(words));
+    }
+
+    return StringUtil.join(sentences, " ");
+  }
+
+  private void insertCommas(String[] words) {
+    if (words.length <= 1) {
+      return;
+    }
+
+    int len = words.length;
+    int totalCommas;
+
+    if (len > 3 && len <= 6) {
+      totalCommas = rand(0, 1);
+    }
+    else if (len > 6 && len <= 12) {
+      totalCommas = rand(0, 2);
+    }
+    else {
+      totalCommas = rand(1, 4);
+    }
+
+    while (totalCommas > 0) {
+      int i = rand(0, words.length - 1);
+      String word = words[i];
+      if (!StringUtil.endsWithChar(word, ',')) {
+        words[i] = word + ",";
+      }
+      totalCommas--;
+    }
+  }
+
+  private String sentence(String[] words) {
+    return sentence(words, choice("?!..."));
+  }
+
+  private static String sentence(String[] words, char endChar) {
+    if (words.length > 0) {
+      words[0] = StringUtil.capitalize(words[0]);
+    }
+
+    return StringUtil.join(words, " ") + endChar;
+  }
+
+  private int rand(int from, int to) {
+    return random.nextInt(to - from) + from;
+  }
+
+  private String[] sample(String[] words, int wordsCount) {
+    int len = words.length;
+    int iterations = Math.min(len, wordsCount);
+    Set<String> result = new TreeSet<String>();
+    while (result.size() < iterations) {
+      int i = rand(0, len - 1);
+      result.add(words[i]);
+    }
+
+    return result.toArray(new String[result.size()]);
+  }
+
+  private char choice(String values) {
+    return values.charAt(rand(0, values.length() - 1));
+  }
+}
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/generators/XmlZenCodingGenerator.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/generators/XmlZenCodingGenerator.java
similarity index 92%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/generators/XmlZenCodingGenerator.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/generators/XmlZenCodingGenerator.java
index 07f22e5..4febf21 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/generators/XmlZenCodingGenerator.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/generators/XmlZenCodingGenerator.java
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.template.zencoding.generators;
+package com.intellij.codeInsight.template.emmet.generators;
 
+import com.intellij.codeInsight.template.emmet.tokens.TemplateToken;
 import com.intellij.codeInsight.template.impl.TemplateImpl;
-import com.intellij.codeInsight.template.zencoding.tokens.TemplateToken;
 import com.intellij.openapi.util.Pair;
 import com.intellij.psi.PsiElement;
 import com.intellij.psi.xml.XmlDocument;
@@ -73,7 +73,7 @@
   public abstract String buildAttributesString(@NotNull List<Pair<String, String>> attribute2value,
                                                boolean hasChildren,
                                                int numberInIteration,
-                                               @Nullable String surroundedText);
+                                               int totalIterations, @Nullable String surroundedText);
 
   public abstract boolean isMyContext(@NotNull PsiElement context, boolean wrapping);
 }
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/generators/XmlZenCodingGeneratorImpl.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/generators/XmlZenCodingGeneratorImpl.java
similarity index 95%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/generators/XmlZenCodingGeneratorImpl.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/generators/XmlZenCodingGeneratorImpl.java
index b9ee262..2fbfc13 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/generators/XmlZenCodingGeneratorImpl.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/generators/XmlZenCodingGeneratorImpl.java
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.template.zencoding.generators;
+package com.intellij.codeInsight.template.emmet.generators;
 
 import com.intellij.codeInsight.template.HtmlTextContextType;
-import com.intellij.codeInsight.template.zencoding.ZenCodingUtil;
+import com.intellij.codeInsight.template.emmet.ZenCodingUtil;
 import com.intellij.lang.ASTNode;
 import com.intellij.lang.Language;
 import com.intellij.lang.xml.XMLLanguage;
@@ -64,12 +64,12 @@
   public String buildAttributesString(@NotNull List<Pair<String, String>> attribute2value,
                                       boolean hasChildren,
                                       int numberInIteration,
-                                      @Nullable String surroundedText) {
+                                      int totalIterations, @Nullable String surroundedText) {
     StringBuilder result = new StringBuilder();
     for (Iterator<Pair<String, String>> it = attribute2value.iterator(); it.hasNext();) {
       Pair<String, String> pair = it.next();
       String name = pair.first;
-      String value = ZenCodingUtil.getValue(pair.second, numberInIteration, surroundedText);
+      String value = ZenCodingUtil.getValue(pair.second, numberInIteration, totalIterations, surroundedText);
       result.append(getAttributeString(name, value));
       if (it.hasNext()) {
         result.append(' ');
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/generators/ZenCodingGenerator.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/generators/ZenCodingGenerator.java
similarity index 89%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/generators/ZenCodingGenerator.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/generators/ZenCodingGenerator.java
index abd3926..f4a53d7 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/generators/ZenCodingGenerator.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/generators/ZenCodingGenerator.java
@@ -13,12 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.template.zencoding.generators;
+package com.intellij.codeInsight.template.emmet.generators;
 
 import com.intellij.codeInsight.template.CustomTemplateCallback;
+import com.intellij.codeInsight.template.emmet.EmmetParser;
+import com.intellij.codeInsight.template.emmet.XmlEmmetParser;
+import com.intellij.codeInsight.template.emmet.ZenCodingTemplate;
+import com.intellij.codeInsight.template.emmet.tokens.TemplateToken;
+import com.intellij.codeInsight.template.emmet.tokens.ZenCodingToken;
 import com.intellij.codeInsight.template.impl.TemplateImpl;
-import com.intellij.codeInsight.template.zencoding.ZenCodingTemplate;
-import com.intellij.codeInsight.template.zencoding.tokens.TemplateToken;
 import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.extensions.ExtensionPointName;
 import com.intellij.psi.PsiElement;
@@ -154,4 +157,9 @@
     }
     return key;
   }
+
+  @NotNull
+  public EmmetParser createParser(List<ZenCodingToken> tokens, CustomTemplateCallback callback, ZenCodingGenerator generator) {
+    return new XmlEmmetParser(tokens, callback, generator);
+  }
 }
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/AddOperationNode.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/AddOperationNode.java
similarity index 71%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/AddOperationNode.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/AddOperationNode.java
index 1894ae7..60ab7cf 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/AddOperationNode.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/AddOperationNode.java
@@ -13,9 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.template.zencoding.nodes;
+package com.intellij.codeInsight.template.emmet.nodes;
 
 import com.intellij.codeInsight.template.CustomTemplateCallback;
+import com.intellij.util.containers.ContainerUtil;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.ArrayList;
@@ -43,14 +44,25 @@
 
   @NotNull
   @Override
+  public List<ZenCodingNode> getChildren() {
+    return ContainerUtil.newLinkedList(myLeftOperand, myRightOperand);
+  }
+
+  @NotNull
+  @Override
   public List<GenerationNode> expand(int numberInIteration,
-                                     String surroundedText,
+                                     int totalIterations, String surroundedText,
                                      CustomTemplateCallback callback,
-                                     boolean insertSurroundedTextAtTheEnd) {
+                                     boolean insertSurroundedTextAtTheEnd, GenerationNode parent) {
     List<GenerationNode> result = new ArrayList<GenerationNode>();
-    List<GenerationNode> leftNodes = myLeftOperand.expand(numberInIteration, surroundedText, callback, false);
+    List<GenerationNode> leftNodes = myLeftOperand.expand(numberInIteration, totalIterations, surroundedText, callback, false, parent);
     result.addAll(leftNodes);
-    result.addAll(myRightOperand.expand(numberInIteration, surroundedText, callback, insertSurroundedTextAtTheEnd));
+    result.addAll(myRightOperand.expand(numberInIteration, totalIterations, surroundedText, callback, insertSurroundedTextAtTheEnd, parent));
     return result;
   }
+
+  @Override
+  public String toString() {
+    return "+";
+  }
 }
diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/ClimbUpOperationNode.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/ClimbUpOperationNode.java
new file mode 100644
index 0000000..1648a36
--- /dev/null
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/ClimbUpOperationNode.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.template.emmet.nodes;
+
+import com.intellij.codeInsight.template.CustomTemplateCallback;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+import static com.intellij.util.containers.ContainerUtil.newArrayList;
+
+/**
+ * @author zolotov
+ */
+public class ClimbUpOperationNode extends ZenCodingNode {
+  private final ZenCodingNode myLeftOperand;
+  private final ZenCodingNode myRightOperand;
+
+  public ClimbUpOperationNode(ZenCodingNode leftOperand, ZenCodingNode rightOperand) {
+    myLeftOperand = leftOperand;
+    myRightOperand = rightOperand;
+  }
+
+  public ZenCodingNode getLeftOperand() {
+    return myLeftOperand;
+  }
+
+  public ZenCodingNode getRightOperand() {
+    return myRightOperand;
+  }
+
+  @NotNull
+  @Override
+  public List<GenerationNode> expand(int numberInIteration,
+                                     int totalIterations, String surroundedText,
+                                     CustomTemplateCallback callback,
+                                     boolean insertSurroundedTextAtTheEnd, GenerationNode parent) {
+    List<GenerationNode> result = newArrayList();
+    result.addAll(myLeftOperand.expand(numberInIteration, totalIterations, surroundedText, callback, insertSurroundedTextAtTheEnd, parent));
+    GenerationNode grandParent = parent != null ? parent.getParent() : null;
+    if (grandParent != null) {
+      myRightOperand.expand(numberInIteration, totalIterations, surroundedText, callback, insertSurroundedTextAtTheEnd, grandParent);
+    }
+    else {
+      result.addAll(myRightOperand.expand(numberInIteration, totalIterations, surroundedText, callback, insertSurroundedTextAtTheEnd, parent));
+    }
+    return result;
+  }
+
+  @NotNull
+  @Override
+  public List<ZenCodingNode> getChildren() {
+    return ContainerUtil.newLinkedList(myLeftOperand, myRightOperand);
+  }
+
+  @Override
+  public String toString() {
+    return "^";
+  }
+}
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/FilterNode.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/FilterNode.java
similarity index 77%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/FilterNode.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/FilterNode.java
index 7ff67f1..2de1c99 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/FilterNode.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/FilterNode.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.template.zencoding.nodes;
+package com.intellij.codeInsight.template.emmet.nodes;
 
 import com.intellij.codeInsight.template.CustomTemplateCallback;
 import org.jetbrains.annotations.NotNull;
@@ -43,9 +43,14 @@
   @NotNull
   @Override
   public List<GenerationNode> expand(int numberInIteration,
-                                     String surroundedText,
+                                     int totalIterations, String surroundedText,
                                      CustomTemplateCallback callback,
-                                     boolean insertSurroundedTextAtTheEnd) {
-    return myNode.expand(numberInIteration, surroundedText, callback, insertSurroundedTextAtTheEnd);
+                                     boolean insertSurroundedTextAtTheEnd, GenerationNode parent) {
+    return myNode.expand(numberInIteration, totalIterations, surroundedText, callback, insertSurroundedTextAtTheEnd, parent);
+  }
+
+  @Override
+  public String toString() {
+    return "Filter(" + myFilter + ")";
   }
 }
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/GenerationNode.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/GenerationNode.java
similarity index 79%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/GenerationNode.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/GenerationNode.java
index a07b521..771f1a8 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/GenerationNode.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/GenerationNode.java
@@ -13,23 +13,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.template.zencoding.nodes;
+package com.intellij.codeInsight.template.emmet.nodes;
 
+import com.google.common.base.Strings;
 import com.intellij.codeInsight.template.CustomTemplateCallback;
 import com.intellij.codeInsight.template.LiveTemplateBuilder;
+import com.intellij.codeInsight.template.emmet.ZenCodingTemplate;
+import com.intellij.codeInsight.template.emmet.ZenCodingUtil;
+import com.intellij.codeInsight.template.emmet.filters.SingleLineEmmetFilter;
+import com.intellij.codeInsight.template.emmet.filters.ZenCodingFilter;
+import com.intellij.codeInsight.template.emmet.generators.XmlZenCodingGenerator;
+import com.intellij.codeInsight.template.emmet.generators.XmlZenCodingGeneratorImpl;
+import com.intellij.codeInsight.template.emmet.generators.ZenCodingGenerator;
+import com.intellij.codeInsight.template.emmet.tokens.TemplateToken;
 import com.intellij.codeInsight.template.impl.TemplateImpl;
-import com.intellij.codeInsight.template.zencoding.ZenCodingTemplate;
-import com.intellij.codeInsight.template.zencoding.ZenCodingUtil;
-import com.intellij.codeInsight.template.zencoding.generators.XmlZenCodingGenerator;
-import com.intellij.codeInsight.template.zencoding.generators.XmlZenCodingGeneratorImpl;
-import com.intellij.codeInsight.template.zencoding.filters.ZenCodingFilter;
-import com.intellij.codeInsight.template.zencoding.generators.ZenCodingGenerator;
-import com.intellij.codeInsight.template.zencoding.tokens.TemplateToken;
 import com.intellij.lang.xml.XMLLanguage;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.fileTypes.StdFileTypes;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.UserDataHolderBase;
 import com.intellij.psi.PsiElement;
 import com.intellij.psi.PsiFile;
 import com.intellij.psi.PsiFileFactory;
@@ -41,43 +44,55 @@
 import com.intellij.util.LocalTimeCounter;
 import com.intellij.util.containers.HashMap;
 import com.intellij.util.containers.HashSet;
-import com.intellij.util.containers.IntArrayList;
 import com.intellij.xml.util.HtmlUtil;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.*;
 
+import static com.google.common.collect.Lists.newArrayList;
+
 /**
  * @author Eugene.Kudelevsky
  */
-public class GenerationNode {
+public class GenerationNode extends UserDataHolderBase {
   private final TemplateToken myTemplateToken;
-  private final List<GenerationNode> myChildren;
+  private final List<GenerationNode> myChildren = newArrayList();
   private final int myNumberInIteration;
+  private final int myTotalIterations;
   private String mySurroundedText;
   private final boolean myInsertSurroundedTextAtTheEnd;
+  private GenerationNode myParent;
 
   private boolean myContainsSurroundedTextMarker = false;
 
   public GenerationNode(TemplateToken templateToken,
-                        List<GenerationNode> children,
                         int numberInIteration,
-                        String surroundedText,
-                        boolean insertSurroundedTextAtTheEnd) {
+                        int totalIterations, String surroundedText,
+                        boolean insertSurroundedTextAtTheEnd, GenerationNode parent) {
     myTemplateToken = templateToken;
-    myChildren = children;
     myNumberInIteration = numberInIteration;
+    myTotalIterations = totalIterations;
     mySurroundedText = surroundedText;
     myInsertSurroundedTextAtTheEnd = insertSurroundedTextAtTheEnd;
+    if(parent != null) {
+      parent.addChild(this);
+    }
   }
 
   public List<GenerationNode> getChildren() {
     return myChildren;
   }
 
-  public void addChildren(Collection<GenerationNode> child) {
-    myChildren.addAll(child);
+  public void addChild(GenerationNode child) {
+    child.setParent(this);
+    myChildren.add(child);
+  }
+
+  public void addChildren(Collection<GenerationNode> children) {
+    for (GenerationNode child : children) {
+      addChild(child);
+    }
   }
 
   public boolean isLeaf() {
@@ -105,9 +120,14 @@
                                 boolean insertSurroundedText) {
     myContainsSurroundedTextMarker = !(insertSurroundedText && myInsertSurroundedTextAtTheEnd);
 
+    boolean singleLineFilterEnabled = false;
+
     GenerationNode generationNode = this;
     for (ZenCodingFilter filter : filters) {
       generationNode = filter.filterNode(generationNode);
+      if(filter instanceof SingleLineEmmetFilter) {
+        singleLineFilterEnabled = true;
+      }
     }
 
     if (generationNode != this) {
@@ -125,8 +145,7 @@
       TemplateToken xmlTemplateToken = myTemplateToken;
       List<Pair<String, String>> attr2value = new ArrayList<Pair<String, String>>(xmlTemplateToken.getAttribute2Value());
       parentTemplate = invokeXmlTemplate(xmlTemplateToken, callback, generator, hasChildren, attr2value);
-      predefinedValues =
-        buildPredefinedValues(attr2value, (XmlZenCodingGenerator)generator, hasChildren);
+      predefinedValues = buildPredefinedValues(attr2value, (XmlZenCodingGenerator)generator, hasChildren);
     }
     else {
       parentTemplate = invokeTemplate(myTemplateToken, hasChildren, callback, generator);
@@ -155,12 +174,12 @@
     LiveTemplateBuilder.Marker marker = offset < builder.length() ? builder.createMarker(offset) : null;
 
     CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(callback.getProject());
-    String tabStr;
+    String indentStr;
     if (callback.isInInjectedFragment()) {
-      tabStr = "";
+      indentStr = "";
     }
     else if (settings.useTabCharacter(callback.getFileType())) {
-      tabStr = "\t";
+      indentStr = "\t";
     }
     else {
       StringBuilder tab = new StringBuilder();
@@ -168,7 +187,7 @@
       while (tabSize-- > 0) {
         tab.append(' ');
       }
-      tabStr = tab.toString();
+      indentStr = tab.toString();
     }
 
     for (int i = 0, myChildrenSize = myChildren.size(); i < myChildrenSize; i++) {
@@ -177,17 +196,17 @@
 
       boolean blockTag = child.isBlockTag();
 
-      if (blockTag && !isNewLineBefore(builder.getText(), offset)) {
-        builder.insertText(offset, "\n" + tabStr, false);
-        offset += tabStr.length() + 1;
+      if (!singleLineFilterEnabled && blockTag && !isNewLineBefore(builder.getText(), offset)) {
+        builder.insertText(offset, "\n" + indentStr, false);
+        offset += indentStr.length() + 1;
       }
 
       int e = builder.insertTemplate(offset, childTemplate, null);
       offset = marker != null ? marker.getEndOffset() : builder.length();
 
-      if (blockTag && !isNewLineAfter(builder.getText(), offset)) {
-        builder.insertText(offset, "\n" + tabStr, false);
-        offset += tabStr.length() + 1;
+      if (!singleLineFilterEnabled && blockTag && !isNewLineAfter(builder.getText(), offset)) {
+        builder.insertText(offset, "\n" + indentStr, false);
+        offset += indentStr.length() + 1;
       }
 
       if (end == -1 && e < offset) {
@@ -197,6 +216,9 @@
     /*if (end != -1) {
       builder.insertVariableSegment(end, TemplateImpl.END);
     }*/
+    if(singleLineFilterEnabled) {
+      builder.setIsToReformat(false);
+    }
     return builder.buildTemplate();
   }
 
@@ -229,6 +251,11 @@
     XmlDocument document = xmlFile.getDocument();
     if (document != null) {
       final XmlTag tag = document.getRootTag();
+      for (Pair<String, String> pair : attr2value) {
+        if (Strings.isNullOrEmpty(pair.second)) {
+          template.addVariable(pair.first, "", "", true);
+        }
+      }
       if (tag != null) {
         ApplicationManager.getApplication().runWriteAction(new Runnable() {
           public void run() {
@@ -239,8 +266,8 @@
         });
       }
     }
-    template =
-      (generator != null ? generator : XmlZenCodingGeneratorImpl.INSTANCE).generateTemplate(token, hasChildren, callback.getContext());
+    ZenCodingGenerator zenCodingGenerator = generator != null ? generator : XmlZenCodingGeneratorImpl.INSTANCE;
+    template = zenCodingGenerator.generateTemplate(token, hasChildren, callback.getContext());
     removeVariablesWhichHasNoSegment(template);
     return template;
   }
@@ -315,16 +342,14 @@
     for (int i = 0; i < template.getSegmentsCount(); i++) {
       segments.add(template.getSegmentName(i));
     }
-    IntArrayList varsToRemove = new IntArrayList();
-    for (int i = 0; i < template.getVariableCount(); i++) {
+    for (int i = template.getVariableCount() - 1; i >= 0; i--) {
       String varName = template.getVariableNameAt(i);
       if (!segments.contains(varName)) {
-        varsToRemove.add(i);
+        template.removeVariable(i);
+      } else {
+        segments.remove(varName);
       }
     }
-    for (int i = 0; i < varsToRemove.size(); i++) {
-      template.removeVariable(varsToRemove.get(i));
-    }
   }
 
   @Nullable
@@ -342,7 +367,7 @@
       }
     }
 
-    String attributes = generator.buildAttributesString(attribute2value, hasChildren, myNumberInIteration, mySurroundedText);
+    String attributes = generator.buildAttributesString(attribute2value, hasChildren, myNumberInIteration, myTotalIterations, mySurroundedText);
     attributes = attributes.length() > 0 ? ' ' + attributes : null;
     Map<String, String> predefinedValues = null;
     if (attributes != null) {
@@ -359,7 +384,10 @@
         if (ZenCodingUtil.containsSurroundedTextMarker(pair.second)) {
           myContainsSurroundedTextMarker = true;
         }
-        tag.setAttribute(pair.first, ZenCodingUtil.getValue(pair.second, myNumberInIteration, mySurroundedText));
+        tag.setAttribute(pair.first,
+                         Strings.isNullOrEmpty(pair.second)
+                         ? "$" + pair.first + "$"
+                         : ZenCodingUtil.getValue(pair.second, myNumberInIteration, myTotalIterations, mySurroundedText));
         iterator.remove();
       }
     }
@@ -398,4 +426,12 @@
   public void setSurroundedText(String surroundedText) {
     mySurroundedText = surroundedText;
   }
+
+  public GenerationNode getParent() {
+    return myParent;
+  }
+
+  public void setParent(GenerationNode parent) {
+    myParent = parent;
+  }
 }
diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/LoremNode.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/LoremNode.java
new file mode 100644
index 0000000..c116390
--- /dev/null
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/LoremNode.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.template.emmet.nodes;
+
+import com.intellij.codeInsight.template.CustomTemplateCallback;
+import com.intellij.codeInsight.template.emmet.ZenCodingTemplate;
+import com.intellij.codeInsight.template.emmet.generators.LoremGenerator;
+import com.intellij.codeInsight.template.emmet.tokens.TemplateToken;
+import com.intellij.codeInsight.template.impl.TemplateImpl;
+import com.intellij.openapi.util.Pair;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author Eugene.Kudelevsky
+ */
+public class LoremNode extends ZenCodingNode {
+  private final int myWordsCount;
+  private final LoremGenerator myLoremGenerator;
+
+  public LoremNode(int wordsCount) {
+    myLoremGenerator = new LoremGenerator();
+    myWordsCount = wordsCount;
+  }
+
+  @NotNull
+  @Override
+  public List<GenerationNode> expand(int numberInIteration,
+                                     int totalIterations, String surroundedText,
+                                     CustomTemplateCallback callback,
+                                     boolean insertSurroundedTextAtTheEnd, GenerationNode parent) {
+
+
+    final TemplateToken templateToken = new TemplateToken("", Collections.<Pair<String, String>>emptyList());
+    final TemplateImpl template = new TemplateImpl("", myLoremGenerator.generate(myWordsCount, numberInIteration <= 0), "");
+    ZenCodingTemplate.doSetTemplate(templateToken, template, callback);
+
+    final GenerationNode node = new GenerationNode(templateToken, numberInIteration,
+                                                   totalIterations, surroundedText, insertSurroundedTextAtTheEnd, parent);
+    return Collections.singletonList(node);
+  }
+
+  @Override
+  public String toString() {
+    return "Lorem(" + myWordsCount + ")";
+  }
+}
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/MoreOperationNode.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/MoreOperationNode.java
similarity index 69%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/MoreOperationNode.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/MoreOperationNode.java
index 8e32e50..fa80215 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/MoreOperationNode.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/MoreOperationNode.java
@@ -13,14 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.template.zencoding.nodes;
+package com.intellij.codeInsight.template.emmet.nodes;
 
 import com.intellij.codeInsight.template.CustomTemplateCallback;
 import com.intellij.openapi.util.text.LineTokenizer;
+import com.intellij.util.containers.ContainerUtil;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 
 /**
@@ -43,32 +43,27 @@
     return myRightOperand;
   }
 
-  private static void addChildrenToAllLeafs(GenerationNode root, Collection<GenerationNode> children) {
-    if (root.isLeaf()) {
-      root.addChildren(children);
-    }
-    else {
-      for (GenerationNode child : root.getChildren()) {
-        addChildrenToAllLeafs(child, children);
-      }
-    }
+  @NotNull
+  @Override
+  public List<ZenCodingNode> getChildren() {
+    return ContainerUtil.newLinkedList(myLeftOperand, myRightOperand);
   }
 
   @NotNull
   @Override
   public List<GenerationNode> expand(int numberInIteration,
-                                     String surroundedText,
+                                     int totalIterations, String surroundedText,
                                      CustomTemplateCallback callback,
-                                     boolean insertSurroundedTextAtTheEnd) {
+                                     boolean insertSurroundedTextAtTheEnd, GenerationNode parent) {
     if (myLeftOperand instanceof MulOperationNode || (myLeftOperand instanceof UnaryMulOperationNode && surroundedText != null)) {
       List<GenerationNode> result = new ArrayList<GenerationNode>();
       if (myLeftOperand instanceof MulOperationNode) {
         MulOperationNode mul = (MulOperationNode)myLeftOperand;
         for (int i = 0; i < mul.getRightOperand(); i++) {
-          List<GenerationNode> parentNodes = mul.getLeftOperand().expand(i, surroundedText, callback, insertSurroundedTextAtTheEnd);
-          List<GenerationNode> innerNodes = myRightOperand.expand(i, surroundedText, callback, insertSurroundedTextAtTheEnd);
+          List<GenerationNode> parentNodes = mul.getLeftOperand().expand(i, totalIterations, surroundedText, callback, insertSurroundedTextAtTheEnd,
+                                                                         parent);
           for (GenerationNode parentNode : parentNodes) {
-            addChildrenToAllLeafs(parentNode, innerNodes);
+            myRightOperand.expand(i, totalIterations, surroundedText, callback, insertSurroundedTextAtTheEnd, parentNode);
           }
           result.addAll(parentNodes);
         }
@@ -78,21 +73,25 @@
         String[] lines = LineTokenizer.tokenize(surroundedText, false);
         for (int i = 0; i < lines.length; i++) {
           String line = lines[i].trim();
-          List<GenerationNode> parentNodes = unaryMul.getOperand().expand(i, line, callback, insertSurroundedTextAtTheEnd);
-          List<GenerationNode> innerNodes = myRightOperand.expand(i, line, callback, insertSurroundedTextAtTheEnd);
+          List<GenerationNode> parentNodes = unaryMul.getOperand().expand(i, totalIterations, line, callback, insertSurroundedTextAtTheEnd, parent);
           for (GenerationNode parentNode : parentNodes) {
-            addChildrenToAllLeafs(parentNode, innerNodes);
+            myRightOperand.expand(i, totalIterations, line, callback, insertSurroundedTextAtTheEnd, parentNode);
           }
           result.addAll(parentNodes);
         }
       }
       return result;
     }
-    List<GenerationNode> leftGenNodes = myLeftOperand.expand(numberInIteration, surroundedText, callback, insertSurroundedTextAtTheEnd);
+    List<GenerationNode> leftGenNodes = myLeftOperand.expand(numberInIteration, totalIterations, surroundedText, callback, insertSurroundedTextAtTheEnd,
+                                                             parent);
     for (GenerationNode leftGenNode : leftGenNodes) {
-      List<GenerationNode> rightGenNodes = myRightOperand.expand(numberInIteration, surroundedText, callback, insertSurroundedTextAtTheEnd);
-      addChildrenToAllLeafs(leftGenNode, rightGenNodes);
+      myRightOperand.expand(numberInIteration,totalIterations , surroundedText, callback, insertSurroundedTextAtTheEnd, leftGenNode);
     }
     return leftGenNodes;
   }
+
+  @Override
+  public String toString() {
+    return ">";
+  }
 }
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/MulOperationNode.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/MulOperationNode.java
similarity index 81%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/MulOperationNode.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/MulOperationNode.java
index bb5b324..ec9eee1 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/MulOperationNode.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/MulOperationNode.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.template.zencoding.nodes;
+package com.intellij.codeInsight.template.emmet.nodes;
 
 import com.intellij.codeInsight.template.CustomTemplateCallback;
 import org.jetbrains.annotations.NotNull;
@@ -44,13 +44,18 @@
   @NotNull
   @Override
   public List<GenerationNode> expand(int numberInIteration,
-                                     String surroundedText,
+                                     int totalIterations, String surroundedText,
                                      CustomTemplateCallback callback,
-                                     boolean insertSurroundedTextAtTheEnd) {
+                                     boolean insertSurroundedTextAtTheEnd, GenerationNode parent) {
     List<GenerationNode> result = new ArrayList<GenerationNode>();
     for (int i = 0; i < myRightOperand; i++) {
-      result.addAll(myLeftOperand.expand(i, surroundedText, callback, insertSurroundedTextAtTheEnd));
+      result.addAll(myLeftOperand.expand(i, myRightOperand, surroundedText, callback, insertSurroundedTextAtTheEnd, parent));
     }
     return result;
   }
+
+  @Override
+  public String toString() {
+    return "*";
+  }
 }
diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/TemplateNode.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/TemplateNode.java
new file mode 100644
index 0000000..317459e
--- /dev/null
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/TemplateNode.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.template.emmet.nodes;
+
+import com.google.common.base.Joiner;
+import com.intellij.codeInsight.template.CustomTemplateCallback;
+import com.intellij.codeInsight.template.emmet.tokens.TemplateToken;
+import com.intellij.openapi.util.Pair;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Eugene.Kudelevsky
+ */
+public class TemplateNode extends ZenCodingNode {
+  private static final Joiner JOINER = Joiner.on(",");
+  private final TemplateToken myTemplateToken;
+
+  public TemplateNode(TemplateToken templateToken) {
+    myTemplateToken = templateToken;
+  }
+
+  public TemplateToken getTemplateToken() {
+    return myTemplateToken;
+  }
+
+  @NotNull
+  @Override
+  public List<GenerationNode> expand(int numberInIteration,
+                                     int totalIterations, String surroundedText,
+                                     CustomTemplateCallback callback,
+                                     boolean insertSurroundedTextAtTheEnd, GenerationNode parent) {
+    GenerationNode node = new GenerationNode(myTemplateToken, numberInIteration, totalIterations,
+                                             surroundedText, insertSurroundedTextAtTheEnd, parent);
+    return Arrays.asList(node);
+  }
+
+  @Override
+  public String toString() {
+    String result = myTemplateToken.getKey();
+    List<Pair<String, String>> attributes = myTemplateToken.getAttribute2Value();
+    if (!attributes.isEmpty()) {
+      result += "[" + JOINER.join(myTemplateToken.getAttribute2Value()) + "]";
+    }
+    return "Template(" + result + ")";
+  }
+}
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/TextNode.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/TextNode.java
similarity index 65%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/TextNode.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/TextNode.java
index 8e7eba7..f715aec 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/TextNode.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/TextNode.java
@@ -1,15 +1,14 @@
-package com.intellij.codeInsight.template.zencoding.nodes;
+package com.intellij.codeInsight.template.emmet.nodes;
 
 import com.intellij.codeInsight.template.CustomTemplateCallback;
+import com.intellij.codeInsight.template.emmet.ZenCodingTemplate;
+import com.intellij.codeInsight.template.emmet.ZenCodingUtil;
+import com.intellij.codeInsight.template.emmet.tokens.TemplateToken;
+import com.intellij.codeInsight.template.emmet.tokens.TextToken;
 import com.intellij.codeInsight.template.impl.TemplateImpl;
-import com.intellij.codeInsight.template.zencoding.ZenCodingTemplate;
-import com.intellij.codeInsight.template.zencoding.ZenCodingUtil;
-import com.intellij.codeInsight.template.zencoding.tokens.TemplateToken;
-import com.intellij.codeInsight.template.zencoding.tokens.TextToken;
 import com.intellij.openapi.util.Pair;
 import org.jetbrains.annotations.NotNull;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
@@ -31,18 +30,24 @@
   @NotNull
   @Override
   public List<GenerationNode> expand(int numberInIteration,
-                                     String surroundedText,
+                                     int totalIterations, String surroundedText,
                                      CustomTemplateCallback callback,
-                                     boolean insertSurroundedTextAtTheEnd) {
+                                     boolean insertSurroundedTextAtTheEnd, GenerationNode parent) {
     final TemplateToken templateToken = new TemplateToken("", Collections.<Pair<String, String>>emptyList());
     final boolean containsSurroundedTextMarker = ZenCodingUtil.containsSurroundedTextMarker(myText);
 
-    final String text = ZenCodingUtil.replaceMarkers(myText.replace("${nl}", "\n"), numberInIteration, surroundedText);
+    final String text = ZenCodingUtil.replaceMarkers(myText.replace("${nl}", "\n"), numberInIteration, totalIterations, surroundedText);
     final TemplateImpl template = new TemplateImpl("", text, "");
     ZenCodingTemplate.doSetTemplate(templateToken, template, callback);
 
-    final GenerationNode node = new GenerationNode(templateToken, new ArrayList<GenerationNode>(), numberInIteration,
-                                                   containsSurroundedTextMarker ? null : surroundedText, insertSurroundedTextAtTheEnd);
+    final GenerationNode node = new GenerationNode(templateToken, numberInIteration, totalIterations,
+                                                   containsSurroundedTextMarker ? null : surroundedText,
+                                                   insertSurroundedTextAtTheEnd, parent);
     return Collections.singletonList(node);
   }
+
+  @Override
+  public String toString() {
+    return "Text(" + myText + ")";
+  }
 }
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/UnaryMulOperationNode.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/UnaryMulOperationNode.java
similarity index 76%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/UnaryMulOperationNode.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/UnaryMulOperationNode.java
index 7efb182..78eb446 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/UnaryMulOperationNode.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/UnaryMulOperationNode.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.template.zencoding.nodes;
+package com.intellij.codeInsight.template.emmet.nodes;
 
 import com.intellij.codeInsight.template.CustomTemplateCallback;
 import com.intellij.openapi.util.text.LineTokenizer;
@@ -39,17 +39,22 @@
   @NotNull
   @Override
   public List<GenerationNode> expand(int numberInIteration,
-                                     String surroundedText,
+                                     int totalIterations, String surroundedText,
                                      CustomTemplateCallback callback,
-                                     boolean insertSurroundedTextAtTheEnd) {
+                                     boolean insertSurroundedTextAtTheEnd, GenerationNode parent) {
     if (surroundedText == null) {
-      return myOperand.expand(numberInIteration, surroundedText, callback, insertSurroundedTextAtTheEnd);
+      return myOperand.expand(numberInIteration, totalIterations, surroundedText, callback, insertSurroundedTextAtTheEnd, parent);
     }
     String[] lines = LineTokenizer.tokenize(surroundedText, false);
     List<GenerationNode> result = new ArrayList<GenerationNode>();
     for (int i = 0; i < lines.length; i++) {
-      result.addAll(myOperand.expand(i, lines[i].trim(), callback, insertSurroundedTextAtTheEnd));
+      result.addAll(myOperand.expand(i, lines.length, lines[i].trim(), callback, insertSurroundedTextAtTheEnd, parent));
     }
     return result;
   }
+
+  @Override
+  public String toString() {
+    return "*";
+  }
 }
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/ZenCodingNode.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/ZenCodingNode.java
similarity index 76%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/ZenCodingNode.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/ZenCodingNode.java
index f1993ad..550d05d 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/ZenCodingNode.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/ZenCodingNode.java
@@ -13,11 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.template.zencoding.nodes;
+package com.intellij.codeInsight.template.emmet.nodes;
 
 import com.intellij.codeInsight.template.CustomTemplateCallback;
 import org.jetbrains.annotations.NotNull;
 
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -26,7 +27,12 @@
 public abstract class ZenCodingNode {
   @NotNull
   public abstract List<GenerationNode> expand(int numberInIteration,
-                                              String surroundedText,
+                                              int totalIterations, String surroundedText,
                                               CustomTemplateCallback callback,
-                                              boolean insertSurroundedTextAtTheEnd);
+                                              boolean insertSurroundedTextAtTheEnd, GenerationNode parent);
+
+  @NotNull
+  public List<ZenCodingNode> getChildren() {
+    return Collections.emptyList();
+  }
 }
diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/ZenEmptyNode.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/ZenEmptyNode.java
new file mode 100644
index 0000000..9b92681
--- /dev/null
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/ZenEmptyNode.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.template.emmet.nodes;
+
+import com.intellij.codeInsight.template.CustomTemplateCallback;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * User: zolotov
+ * Date: 1/31/13
+ */
+public class ZenEmptyNode extends ZenCodingNode {
+  public static final ZenCodingNode INSTANCE = new ZenEmptyNode();
+
+  @NotNull
+  @Override
+  public List<GenerationNode> expand(int numberInIteration,
+                                     int totalIterations, String surroundedText,
+                                     CustomTemplateCallback callback,
+                                     boolean insertSurroundedTextAtTheEnd,
+                                     GenerationNode parent) {
+    return Collections.emptyList();
+  }
+
+  @Override
+  public String toString() {
+    return "EMPTY_NODE";
+  }
+}
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/ZenCodingToken.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/processors/EmmetPreprocessor.java
similarity index 76%
copy from xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/ZenCodingToken.java
copy to xml/impl/src/com/intellij/codeInsight/template/emmet/processors/EmmetPreprocessor.java
index b38c98e..1dbfee0 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/ZenCodingToken.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/processors/EmmetPreprocessor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2010 JetBrains s.r.o.
+ * Copyright 2000-2013 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,10 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.template.zencoding.tokens;
+package com.intellij.codeInsight.template.emmet.processors;
 
 /**
- * @author Eugene.Kudelevsky
+ * User: zolotov
+ * Date: 1/31/13
  */
-public abstract class ZenCodingToken {
+public interface EmmetPreprocessor {
+
 }
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/ZenCodingToken.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/processors/LoremProcessor.java
similarity index 74%
copy from xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/ZenCodingToken.java
copy to xml/impl/src/com/intellij/codeInsight/template/emmet/processors/LoremProcessor.java
index b38c98e..d7eecfc 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/ZenCodingToken.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/processors/LoremProcessor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2010 JetBrains s.r.o.
+ * Copyright 2000-2013 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,10 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.template.zencoding.tokens;
+package com.intellij.codeInsight.template.emmet.processors;
 
 /**
- * @author Eugene.Kudelevsky
+ * User: zolotov
+ * Date: 1/31/13
  */
-public abstract class ZenCodingToken {
+public class LoremProcessor implements EmmetPreprocessor {
+
 }
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/FilterToken.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/FilterToken.java
similarity index 93%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/FilterToken.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/FilterToken.java
index 739c9b6..0001590 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/FilterToken.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/FilterToken.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.template.zencoding.tokens;
+package com.intellij.codeInsight.template.emmet.tokens;
 
 /**
  * @author Eugene.Kudelevsky
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/IdentifierToken.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/IdentifierToken.java
similarity index 85%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/IdentifierToken.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/IdentifierToken.java
index 2c42ebb..399eb51 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/IdentifierToken.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/IdentifierToken.java
@@ -1,4 +1,4 @@
-package com.intellij.codeInsight.template.zencoding.tokens;
+package com.intellij.codeInsight.template.emmet.tokens;
 
 import org.jetbrains.annotations.NotNull;
 
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/NumberToken.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/NumberToken.java
similarity index 93%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/NumberToken.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/NumberToken.java
index 5d4ae7c..fd85596 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/NumberToken.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/NumberToken.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.template.zencoding.tokens;
+package com.intellij.codeInsight.template.emmet.tokens;
 
 /**
  * @author Eugene.Kudelevsky
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/OperationToken.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/OperationToken.java
similarity index 93%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/OperationToken.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/OperationToken.java
index 5c7c843..eee51cd 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/OperationToken.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/OperationToken.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.template.zencoding.tokens;
+package com.intellij.codeInsight.template.emmet.tokens;
 
 /**
  * @author Eugene.Kudelevsky
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/StringLiteralToken.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/StringLiteralToken.java
similarity index 83%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/StringLiteralToken.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/StringLiteralToken.java
index 1c8428a..c853640 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/StringLiteralToken.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/StringLiteralToken.java
@@ -1,4 +1,4 @@
-package com.intellij.codeInsight.template.zencoding.tokens;
+package com.intellij.codeInsight.template.emmet.tokens;
 
 /**
  * @author Eugene.Kudelevsky
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/TemplateToken.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/TemplateToken.java
similarity index 81%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/TemplateToken.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/TemplateToken.java
index 3bd3e5f..dac15a9 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/TemplateToken.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/TemplateToken.java
@@ -13,23 +13,31 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.template.zencoding.tokens;
+package com.intellij.codeInsight.template.emmet.tokens;
 
 import com.intellij.codeInsight.template.impl.TemplateImpl;
 import com.intellij.openapi.util.Pair;
 import com.intellij.psi.xml.XmlFile;
+import org.jetbrains.annotations.Nullable;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
  * @author Eugene.Kudelevsky
  */
 public class TemplateToken extends ZenCodingToken {
+  public final static TemplateToken EMPTY_TEMPLATE_TOKEN = new TemplateToken("", new ArrayList<Pair<String, String>>());
+
   private final String myKey;
   private TemplateImpl myTemplate;
   private final List<Pair<String, String>> myAttribute2Value;
   private XmlFile myFile;
 
+  public TemplateToken(String key) {
+    this(key, new ArrayList<Pair<String, String>>());
+  }
+
   public TemplateToken(String key, List<Pair<String, String>> attribute2value) {
     myKey = key;
     myAttribute2Value = attribute2value;
@@ -55,6 +63,7 @@
     myTemplate = template;
   }
 
+  @Nullable
   public TemplateImpl getTemplate() {
     return myTemplate;
   }
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/TextToken.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/TextToken.java
similarity index 82%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/TextToken.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/TextToken.java
index e216302..a458d3b 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/TextToken.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/TextToken.java
@@ -1,4 +1,4 @@
-package com.intellij.codeInsight.template.zencoding.tokens;
+package com.intellij.codeInsight.template.emmet.tokens;
 
 /**
  * @author Eugene.Kudelevsky
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/ZenCodingToken.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/ZenCodingToken.java
similarity index 91%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/ZenCodingToken.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/ZenCodingToken.java
index b38c98e..d2da772 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/ZenCodingToken.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/ZenCodingToken.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.codeInsight.template.zencoding.tokens;
+package com.intellij.codeInsight.template.emmet.tokens;
 
 /**
  * @author Eugene.Kudelevsky
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/ZenCodingTokenImpl.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/ZenCodingTokenImpl.java
similarity index 81%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/ZenCodingTokenImpl.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/ZenCodingTokenImpl.java
index 749279c..ae9cf1b 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/ZenCodingTokenImpl.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/ZenCodingTokenImpl.java
@@ -1,4 +1,4 @@
-package com.intellij.codeInsight.template.zencoding.tokens;
+package com.intellij.codeInsight.template.emmet.tokens;
 
 /**
  * @author Eugene.Kudelevsky
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/ZenCodingTokens.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/ZenCodingTokens.java
similarity index 93%
rename from xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/ZenCodingTokens.java
rename to xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/ZenCodingTokens.java
index 8911153..9db2d50 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/tokens/ZenCodingTokens.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/tokens/ZenCodingTokens.java
@@ -1,4 +1,4 @@
-package com.intellij.codeInsight.template.zencoding.tokens;
+package com.intellij.codeInsight.template.emmet.tokens;
 
 /**
  * @author Eugene.Kudelevsky
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/ZenCodingTemplate.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/ZenCodingTemplate.java
deleted file mode 100644
index 29bac40..0000000
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/ZenCodingTemplate.java
+++ /dev/null
@@ -1,890 +0,0 @@
-/*
- * Copyright 2000-2010 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.intellij.codeInsight.template.zencoding;
-
-import com.intellij.application.options.editor.WebEditorOptions;
-import com.intellij.codeInsight.CodeInsightBundle;
-import com.intellij.codeInsight.template.*;
-import com.intellij.codeInsight.template.impl.TemplateImpl;
-import com.intellij.codeInsight.template.impl.TemplateState;
-import com.intellij.codeInsight.template.zencoding.filters.ZenCodingFilter;
-import com.intellij.codeInsight.template.zencoding.generators.XmlZenCodingGenerator;
-import com.intellij.codeInsight.template.zencoding.generators.ZenCodingGenerator;
-import com.intellij.codeInsight.template.zencoding.nodes.*;
-import com.intellij.codeInsight.template.zencoding.tokens.*;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.command.CommandProcessor;
-import com.intellij.openapi.command.undo.UndoConstants;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.editor.EditorModificationUtil;
-import com.intellij.openapi.editor.ScrollType;
-import com.intellij.openapi.fileTypes.FileType;
-import com.intellij.openapi.fileTypes.StdFileTypes;
-import com.intellij.openapi.ui.InputValidatorEx;
-import com.intellij.openapi.ui.Messages;
-import com.intellij.openapi.util.Pair;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.*;
-import com.intellij.psi.xml.XmlAttribute;
-import com.intellij.psi.xml.XmlDocument;
-import com.intellij.psi.xml.XmlFile;
-import com.intellij.psi.xml.XmlTag;
-import com.intellij.util.ArrayUtil;
-import com.intellij.util.LocalTimeCounter;
-import com.intellij.xml.XmlBundle;
-import org.apache.xerces.util.XML11Char;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-
-/**
- * @author Eugene.Kudelevsky
- */
-public class ZenCodingTemplate implements CustomLiveTemplate {
-  public static final char MARKER = '\0';
-  private static final String DELIMS = ">+*|()[]{}.#,='\" \0";
-  public static final String ATTRS = "ATTRS";
-  private static final String ID = "id";
-  private static final String CLASS = "class";
-  private static final String DEFAULT_TAG = "div";
-
-  private static int parseNonNegativeInt(@NotNull String s) {
-    try {
-      return Integer.parseInt(s);
-    }
-    catch (Throwable ignored) {
-    }
-    return -1;
-  }
-
-  private static boolean isXML11ValidQName(String str) {
-    final int colon = str.indexOf(':');
-    if (colon == 0 || colon == str.length() - 1) {
-      return false;
-    }
-    if (colon > 0) {
-      final String prefix = str.substring(0, colon);
-      final String localPart = str.substring(colon + 1);
-      return XML11Char.isXML11ValidNCName(prefix) && XML11Char.isXML11ValidNCName(localPart);
-    }
-    return XML11Char.isXML11ValidNCName(str);
-  }
-
-  private static boolean isHtml(CustomTemplateCallback callback) {
-    FileType type = callback.getFileType();
-    return type == StdFileTypes.HTML || type == StdFileTypes.XHTML;
-  }
-
-  private static void addMissingAttributes(XmlTag tag, List<Pair<String, String>> value) {
-    List<Pair<String, String>> attr2value = new ArrayList<Pair<String, String>>(value);
-    for (Iterator<Pair<String, String>> iterator = attr2value.iterator(); iterator.hasNext();) {
-      Pair<String, String> pair = iterator.next();
-      if (tag.getAttribute(pair.first) != null) {
-        iterator.remove();
-      }
-    }
-    addAttributesBefore(tag, attr2value);
-  }
-
-  private static void addAttributesBefore(XmlTag tag, List<Pair<String, String>> attr2value) {
-    XmlAttribute firstAttribute = ArrayUtil.getFirstElement(tag.getAttributes());
-    XmlElementFactory factory = XmlElementFactory.getInstance(tag.getProject());
-    for (Pair<String, String> pair : attr2value) {
-      XmlAttribute xmlAttribute = factory.createXmlAttribute(pair.first, "");
-      if (firstAttribute != null) {
-        tag.addBefore(xmlAttribute, firstAttribute);
-      }
-      else {
-        tag.add(xmlAttribute);
-      }
-    }
-  }
-
-  @Nullable
-  private static ZenCodingGenerator findApplicableDefaultGenerator(@NotNull PsiElement context, boolean wrapping) {
-    for (ZenCodingGenerator generator : ZenCodingGenerator.getInstances()) {
-      if (generator.isMyContext(context, wrapping) && generator.isAppliedByDefault(context)) {
-        return generator;
-      }
-    }
-    return null;
-  }
-
-  @NotNull
-  private static XmlFile parseXmlFileInTemplate(String templateString, CustomTemplateCallback callback, boolean createPhysicalFile) {
-    XmlFile xmlFile = (XmlFile)PsiFileFactory.getInstance(callback.getProject())
-      .createFileFromText("dummy.xml", StdFileTypes.XML, templateString, LocalTimeCounter.currentTime(), createPhysicalFile);
-    VirtualFile vFile = xmlFile.getVirtualFile();
-    if (vFile != null) {
-      vFile.putUserData(UndoConstants.DONT_RECORD_UNDO, Boolean.TRUE);
-    }
-    return xmlFile;
-  }
-
-  @Nullable
-  private static ZenCodingNode parse(@NotNull String text, @NotNull CustomTemplateCallback callback, ZenCodingGenerator generator) {
-    List<ZenCodingToken> tokens = lex(text);
-    if (tokens == null) {
-      return null;
-    }
-    if (generator != null && !validate(tokens, generator)) {
-      return null;
-    }
-    MyParser parser = new MyParser(tokens, callback, generator);
-    ZenCodingNode node = parser.parse();
-    if (parser.myIndex != tokens.size() || node instanceof TextNode) {
-      return null;
-    }
-    return node;
-  }
-  
-  private static boolean validate(@NotNull List<ZenCodingToken> tokens, @NotNull ZenCodingGenerator generator) {
-    for (ZenCodingToken token : tokens) {
-      if (token instanceof TextToken && !(generator instanceof XmlZenCodingGenerator)) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  @Nullable
-  private static List<ZenCodingToken> lex(@NotNull String text) {
-    text += MARKER;
-    final List<ZenCodingToken> result = new ArrayList<ZenCodingToken>();
-
-    boolean inQuotes = false;
-    boolean inApostrophes = false;
-    int bracesStack = 0;
-
-    StringBuilder builder = new StringBuilder();
-    for (int i = 0; i < text.length(); i++) {
-      final char c = text.charAt(i);
-
-      if (inQuotes) {
-        builder.append(c);
-        if (c == '"') {
-          inQuotes = false;
-          result.add(new StringLiteralToken(builder.toString()));
-          builder = new StringBuilder();
-        }
-        continue;
-      }
-
-      if (inApostrophes) {
-        builder.append(c);
-        if (c == '\'') {
-          inApostrophes = false;
-          result.add(new StringLiteralToken(builder.toString()));
-          builder = new StringBuilder();
-        }
-        continue;
-      }
-
-      if (bracesStack > 0) {
-        builder.append(c);
-        if (c == '}') {
-          bracesStack--;
-          if (bracesStack == 0) {
-            result.add(new TextToken(builder.toString()));
-            builder = new StringBuilder();
-          }
-        }
-        else if (c == '{') {
-          bracesStack++;
-        }
-        continue;
-      }
-
-      if (DELIMS.indexOf(c) < 0) {
-        builder.append(c);
-      }
-      else {
-        // handle special case: ul+ template
-        if (c == '+' && (i == text.length() - 2 || text.charAt(i + 1) == ')')) {
-          builder.append(c);
-          continue;
-        }
-
-        if (builder.length() > 0) {
-          final String tokenText = builder.toString();
-          final int n = parseNonNegativeInt(tokenText);
-          if (n >= 0) {
-            result.add(new NumberToken(n));
-          }
-          else {
-            result.add(new IdentifierToken(tokenText));
-          }
-          builder = new StringBuilder();
-        }
-        if (c == '"') {
-          inQuotes = true;
-          builder.append(c);
-        }
-        else if (c == '\'') {
-          inApostrophes = true;
-          builder.append(c);
-        }
-        else if (c == '{') {
-          bracesStack = 1;
-          builder.append(c);
-        }
-        else if (c == '(') {
-          result.add(ZenCodingTokens.OPENING_R_BRACKET);
-        }
-        else if (c == ')') {
-          result.add(ZenCodingTokens.CLOSING_R_BRACKET);
-        }
-        else if (c == '[') {
-          result.add(ZenCodingTokens.OPENING_SQ_BRACKET);
-        }
-        else if (c == ']') {
-          result.add(ZenCodingTokens.CLOSING_SQ_BRACKET);
-        }
-        else if (c == '=') {
-          result.add(ZenCodingTokens.EQ);
-        }
-        else if (c == '.') {
-          result.add(ZenCodingTokens.DOT);
-        }
-        else if (c == '#') {
-          result.add(ZenCodingTokens.SHARP);
-        }
-        else if (c == ',') {
-          result.add(ZenCodingTokens.COMMA);
-        }
-        else if (c == ' ') {
-          result.add(ZenCodingTokens.SPACE);
-        }
-        else if (c == '|') {
-          result.add(ZenCodingTokens.PIPE);
-        }
-        else if (c != MARKER) {
-          result.add(new OperationToken(c));
-        }
-      }
-    }
-    if (bracesStack != 0 || inQuotes || inApostrophes) {
-      return null;
-    }
-    return result;
-  }
-
-
-  public static boolean checkTemplateKey(@NotNull String key, CustomTemplateCallback callback, ZenCodingGenerator generator) {
-    return parse(key, callback, generator) != null;
-  }
-
-  public void expand(String key, @NotNull CustomTemplateCallback callback) {
-    ZenCodingGenerator defaultGenerator = findApplicableDefaultGenerator(callback.getContext(), false);
-    assert defaultGenerator != null;
-    expand(key, callback, null, defaultGenerator);
-  }
-
-  @Nullable
-  private static ZenCodingGenerator findApplicableGenerator(ZenCodingNode node, PsiElement context, boolean wrapping) {
-    ZenCodingGenerator defaultGenerator = null;
-    List<ZenCodingGenerator> generators = ZenCodingGenerator.getInstances();
-    for (ZenCodingGenerator generator : generators) {
-      if (defaultGenerator == null && generator.isMyContext(context, wrapping) && generator.isAppliedByDefault(context)) {
-        defaultGenerator = generator;
-      }
-    }
-    while (node instanceof FilterNode) {
-      FilterNode filterNode = (FilterNode)node;
-      String suffix = filterNode.getFilter();
-      for (ZenCodingGenerator generator : generators) {
-        if (generator.isMyContext(context, wrapping)) {
-          if (suffix != null && suffix.equals(generator.getSuffix())) {
-            return generator;
-          }
-        }
-      }
-      node = filterNode.getNode();
-    }
-    return defaultGenerator;
-  }
-
-  private static List<ZenCodingFilter> getFilters(ZenCodingNode node, PsiElement context) {
-    List<ZenCodingFilter> result = new ArrayList<ZenCodingFilter>();
-
-    while (node instanceof FilterNode) {
-      FilterNode filterNode = (FilterNode)node;
-      String filterSuffix = filterNode.getFilter();
-      boolean filterFound = false;
-      for (ZenCodingFilter filter : ZenCodingFilter.getInstances()) {
-        if (filter.isMyContext(context) && filter.getSuffix().equals(filterSuffix)) {
-          filterFound = true;
-          result.add(filter);
-        }
-      }
-      assert filterFound;
-      node = filterNode.getNode();
-    }
-
-    for (ZenCodingFilter filter : ZenCodingFilter.getInstances()) {
-      if (filter.isMyContext(context) && filter.isAppliedByDefault(context)) {
-        result.add(filter);
-      }
-    }
-
-    Collections.reverse(result);
-    return result;
-  }
-
-
-  private static void expand(String key,
-                             @NotNull CustomTemplateCallback callback,
-                             String surroundedText,
-                             @NotNull ZenCodingGenerator defaultGenerator) {
-    ZenCodingNode node = parse(key, callback, defaultGenerator);
-    assert node != null;
-    if (surroundedText == null) {
-      if (node instanceof TemplateNode) {
-        if (key.equals(((TemplateNode)node).getTemplateToken().getKey()) &&
-            callback.findApplicableTemplates(key).size() > 1) {
-          callback.startTemplate();
-          return;
-        }
-      }
-      callback.deleteTemplateKey(key);
-    }
-
-    PsiElement context = callback.getContext();
-    ZenCodingGenerator generator = findApplicableGenerator(node, context, false);
-    List<ZenCodingFilter> filters = getFilters(node, context);
-
-    expand(node, generator, filters, surroundedText, callback);
-  }
-
-  private static void expand(ZenCodingNode node,
-                             ZenCodingGenerator generator,
-                             List<ZenCodingFilter> filters,
-                             String surroundedText,
-                             CustomTemplateCallback callback) {
-    if (surroundedText != null) {
-      surroundedText = surroundedText.trim();
-    }
-    List<GenerationNode> genNodes = node.expand(-1, surroundedText, callback, true);
-    LiveTemplateBuilder builder = new LiveTemplateBuilder();
-    int end = -1;
-    for (int i = 0, genNodesSize = genNodes.size(); i < genNodesSize; i++) {
-      GenerationNode genNode = genNodes.get(i);
-      TemplateImpl template = genNode.generate(callback, generator, filters, true);
-      int e = builder.insertTemplate(builder.length(), template, null);
-      if (end == -1 && end < builder.length()) {
-        end = e;
-      }
-    }
-
-    callback.startTemplate(builder.buildTemplate(), null, new TemplateEditingAdapter() {
-      private TextRange myEndVarRange;
-      private Editor myEditor;
-
-      @Override
-      public void beforeTemplateFinished(TemplateState state, Template template) {
-        int variableNumber = state.getCurrentVariableNumber();
-        if (variableNumber >= 0 && template instanceof TemplateImpl) {
-          TemplateImpl t = (TemplateImpl)template;
-          while (variableNumber < t.getVariableCount()) {
-            String varName = t.getVariableNameAt(variableNumber);
-            if (LiveTemplateBuilder.isEndVariable(varName)) {
-              myEndVarRange = state.getVariableRange(varName);
-              myEditor = state.getEditor();
-              break;
-            }
-            variableNumber++;
-          }
-        }
-      }
-
-      @Override
-      public void templateFinished(Template template, boolean brokenOff) {
-        if (brokenOff && myEndVarRange != null && myEditor != null) {
-          int offset = myEndVarRange.getStartOffset();
-          if (offset >= 0 && offset != myEditor.getCaretModel().getOffset()) {
-            myEditor.getCaretModel().moveToOffset(offset);
-            myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
-          }
-        }
-      }
-    });
-  }
-
-  public void wrap(final String selection,
-                   @NotNull final CustomTemplateCallback callback
-  ) {
-    InputValidatorEx validator = new InputValidatorEx() {
-      public String getErrorText(String inputString) {
-        if (!checkTemplateKey(inputString, callback)) {
-          return XmlBundle.message("zen.coding.incorrect.abbreviation.error");
-        }
-        return null;
-      }
-
-      public boolean checkInput(String inputString) {
-        return getErrorText(inputString) == null;
-      }
-
-      public boolean canClose(String inputString) {
-        return checkInput(inputString);
-      }
-    };
-    final String abbreviation = Messages
-      .showInputDialog(callback.getProject(), XmlBundle.message("zen.coding.enter.abbreviation.dialog.label"),
-                       XmlBundle.message("zen.coding.title"), Messages.getQuestionIcon(), "", validator);
-    if (abbreviation != null) {
-      doWrap(selection, abbreviation, callback);
-    }
-  }
-
-  public static boolean checkTemplateKey(String inputString, CustomTemplateCallback callback) {
-    ZenCodingGenerator generator = findApplicableDefaultGenerator(callback.getContext(), true);
-    assert generator != null;
-    return checkTemplateKey(inputString, callback, generator);
-  }
-
-  public boolean isApplicable(PsiFile file, int offset, boolean wrapping) {
-    WebEditorOptions webEditorOptions = WebEditorOptions.getInstance();
-    if (!webEditorOptions.isZenCodingEnabled()) {
-      return false;
-    }
-    if (file == null) {
-      return false;
-    }
-    PsiDocumentManager.getInstance(file.getProject()).commitAllDocuments();
-    PsiElement element = CustomTemplateCallback.getContext(file, offset);
-    return findApplicableDefaultGenerator(element, wrapping) != null;
-  }
-
-  protected static void doWrap(final String selection,
-                               final String abbreviation,
-                               final CustomTemplateCallback callback) {
-    final ZenCodingGenerator defaultGenerator = findApplicableDefaultGenerator(callback.getContext(), true);
-    assert defaultGenerator != null;
-    ApplicationManager.getApplication().runWriteAction(new Runnable() {
-      public void run() {
-        CommandProcessor.getInstance().executeCommand(callback.getProject(), new Runnable() {
-          public void run() {
-            callback.fixInitialState(true);
-            ZenCodingNode node = parse(abbreviation, callback, defaultGenerator);
-            assert node != null;
-            PsiElement context = callback.getContext();
-            ZenCodingGenerator generator = findApplicableGenerator(node, context, true);
-            List<ZenCodingFilter> filters = getFilters(node, context);
-
-            EditorModificationUtil.deleteSelectedText(callback.getEditor());
-            PsiDocumentManager.getInstance(callback.getProject()).commitAllDocuments();
-
-            expand(node, generator, filters, selection, callback);
-          }
-        }, CodeInsightBundle.message("insert.code.template.command"), null);
-      }
-    });
-  }
-
-  @NotNull
-  public String getTitle() {
-    return XmlBundle.message("zen.coding.title");
-  }
-
-  public char getShortcut() {
-    return (char)WebEditorOptions.getInstance().getZenCodingExpandShortcut();
-  }
-
-  protected static boolean containsAttrsVar(TemplateImpl template) {
-    for (int i = 0; i < template.getVariableCount(); i++) {
-      String varName = template.getVariableNameAt(i);
-      if (ATTRS.equals(varName)) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  public String computeTemplateKey(@NotNull CustomTemplateCallback callback) {
-    ZenCodingGenerator generator = findApplicableDefaultGenerator(callback.getContext(), false);
-    if (generator == null) return null;
-    return generator.computeTemplateKey(callback);
-  }
-
-  public boolean supportsWrapping() {
-    return true;
-  }
-
-  public static boolean checkFilterSuffix(@NotNull String suffix) {
-    for (ZenCodingGenerator generator : ZenCodingGenerator.getInstances()) {
-      if (suffix.equals(generator.getSuffix())) {
-        return true;
-      }
-    }
-    for (ZenCodingFilter filter : ZenCodingFilter.getInstances()) {
-      if (suffix.equals(filter.getSuffix())) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  public static boolean doSetTemplate(final TemplateToken token, TemplateImpl template, CustomTemplateCallback callback) {
-    token.setTemplate(template);
-    final XmlFile xmlFile = parseXmlFileInTemplate(template.getString(), callback, true);
-    token.setFile(xmlFile);
-    XmlDocument document = xmlFile.getDocument();
-    final XmlTag tag = document != null ? document.getRootTag() : null;
-    if (token.getAttribute2Value().size() > 0 && tag == null) {
-      return false;
-    }
-    if (tag != null) {
-      if (!containsAttrsVar(template) && token.getAttribute2Value().size() > 0) {
-        ApplicationManager.getApplication().runWriteAction(new Runnable() {
-          public void run() {
-            addMissingAttributes(tag, token.getAttribute2Value());
-          }
-        });
-      }
-    }
-    return true;
-  }
-
-  private static class MyParser {
-    private final List<ZenCodingToken> myTokens;
-    private final CustomTemplateCallback myCallback;
-    private final ZenCodingGenerator myGenerator;
-    private int myIndex = 0;
-
-    private MyParser(List<ZenCodingToken> tokens, CustomTemplateCallback callback, ZenCodingGenerator generator) {
-      myTokens = tokens;
-      myCallback = callback;
-      myGenerator = generator;
-    }
-
-    @Nullable
-    private ZenCodingNode parse() {
-      ZenCodingNode add = parseAddOrMore();
-      if (add == null) {
-        return null;
-      }
-
-      ZenCodingNode result = add;
-
-      while (true) {
-        ZenCodingToken token = nextToken();
-        if (token != ZenCodingTokens.PIPE) {
-          return result;
-        }
-
-        myIndex++;
-        token = nextToken();
-        if (!(token instanceof IdentifierToken)) {
-          return null;
-        }
-
-        final String filterSuffix = ((IdentifierToken)token).getText();
-        if (!checkFilterSuffix(filterSuffix)) {
-          return null;
-        }
-
-        myIndex++;
-        result = new FilterNode(result, filterSuffix);
-      }
-    }
-
-    @Nullable
-    private ZenCodingNode parseAddOrMore() {
-      ZenCodingNode mul = parseMul();
-      if (mul == null) {
-        return null;
-      }
-      ZenCodingToken operationToken = nextToken();
-      if (!(operationToken instanceof OperationToken)) {
-        return mul;
-      }
-      char sign = ((OperationToken)operationToken).getSign();
-      if (sign == '+') {
-        myIndex++;
-        ZenCodingNode add2 = parseAddOrMore();
-        if (add2 == null) {
-          return null;
-        }
-        return new AddOperationNode(mul, add2);
-      }
-      else if (sign == '>') {
-        myIndex++;
-        ZenCodingNode more2 = parseAddOrMore();
-        if (more2 == null) {
-          return null;
-        }
-        return new MoreOperationNode(mul, more2);
-      }
-      return null;
-    }
-
-    @Nullable
-    private ZenCodingNode parseMul() {
-      ZenCodingNode exp = parseExpressionInBraces();
-      if (exp == null) {
-        return null;
-      }
-      ZenCodingToken operationToken = nextToken();
-      if (!(operationToken instanceof OperationToken)) {
-        return exp;
-      }
-      if (((OperationToken)operationToken).getSign() != '*') {
-        return exp;
-      }
-      myIndex++;
-      ZenCodingToken numberToken = nextToken();
-      if (numberToken instanceof NumberToken) {
-        myIndex++;
-        return new MulOperationNode(exp, ((NumberToken)numberToken).getNumber());
-      }
-      return new UnaryMulOperationNode(exp);
-    }
-
-    @Nullable
-    private ZenCodingNode parseExpressionInBraces() {
-      ZenCodingToken token = nextToken();
-      if (token == ZenCodingTokens.OPENING_R_BRACKET) {
-        myIndex++;
-        ZenCodingNode add = parseAddOrMore();
-        if (add == null) {
-          return null;
-        }
-        ZenCodingToken closingBrace = nextToken();
-        if (closingBrace != ZenCodingTokens.CLOSING_R_BRACKET) {
-          return null;
-        }
-        myIndex++;
-        return add;
-      }
-      else if (token instanceof TextToken) {
-        myIndex++;
-        return new TextNode((TextToken)token);
-
-      }
-
-      final ZenCodingNode templateNode = parseTemplate();
-      if (templateNode == null) {
-        return null;
-      }
-
-      token = nextToken();
-      if (token instanceof TextToken) {
-        myIndex++;
-        return new MoreOperationNode(templateNode, new TextNode((TextToken)token));
-      }
-      return templateNode;
-    }
-
-    @Nullable
-    private ZenCodingNode parseTemplate() {
-      final ZenCodingToken token = nextToken();
-      String templateKey = isHtml(myCallback) ? DEFAULT_TAG : null;
-      boolean mustHaveSelector = true;
-
-      if (token instanceof IdentifierToken) {
-        templateKey = ((IdentifierToken)token).getText();
-        mustHaveSelector = false;
-        myIndex++;
-      }
-
-      if (templateKey == null) {
-        return null;
-      }
-
-      final TemplateImpl template = myCallback.findApplicableTemplate(templateKey);
-      if (template == null && !isXML11ValidQName(templateKey)) {
-        return null;
-      }
-
-      final List<Pair<String, String>> attrList = parseSelectors();
-      if (mustHaveSelector && attrList.size() == 0) {
-        return null;
-      }
-
-      final TemplateToken templateToken = new TemplateToken(templateKey, attrList);
-
-      if (!setTemplate(templateToken, template)) {
-        return null;
-      }
-      return new TemplateNode(templateToken);
-    }
-
-    @SuppressWarnings("unchecked")
-    @NotNull
-    private List<Pair<String, String>> parseSelectors() {
-      final List<Pair<String, String>> result = new ArrayList<Pair<String, String>>();
-
-      int classAttrPosition = -1;
-      int idAttrPosition = -1;
-
-      final StringBuilder classAttrBuilder = new StringBuilder();
-      final StringBuilder idAttrBuilder = new StringBuilder();
-
-      while (true) {
-        final List<Pair<String, String>> attrList = parseSelector();
-        if (attrList == null) {
-          if (classAttrPosition != -1) {
-            result.set(classAttrPosition, new Pair<String, String>(CLASS, classAttrBuilder.toString()));
-          }
-          if (idAttrPosition != -1) {
-            result.set(idAttrPosition, new Pair<String, String>(ID, idAttrBuilder.toString()));
-          }
-          return result;
-        }
-
-        for (Pair<String, String> attr : attrList) {
-          if (CLASS.equals(attr.first)) {
-            if (classAttrBuilder.length() > 0) {
-              classAttrBuilder.append(' ');
-            }
-            classAttrBuilder.append(attr.second);
-            if (classAttrPosition == -1) {
-              classAttrPosition = result.size();
-              result.add(attr);
-            }
-          }
-          else if (ID.equals(attr.first)) {
-            if (idAttrBuilder.length() > 0) {
-              idAttrBuilder.append(' ');
-            }
-            idAttrBuilder.append(attr.second);
-            if (idAttrPosition == -1) {
-              idAttrPosition = result.size();
-              result.add(attr);
-            }
-          }
-          else {
-            result.add(attr);
-          }
-        }
-      }
-    }
-
-    @Nullable
-    private List<Pair<String, String>> parseSelector() {
-      ZenCodingToken token = nextToken();
-      if (token == ZenCodingTokens.OPENING_SQ_BRACKET) {
-        myIndex++;
-        final List<Pair<String, String>> attrList = parseAttributeList();
-        if (attrList == null || nextToken() != ZenCodingTokens.CLOSING_SQ_BRACKET) {
-          return null;
-        }
-        myIndex++;
-        return attrList;
-      }
-
-      if (token == ZenCodingTokens.DOT || token == ZenCodingTokens.SHARP) {
-        final String name = token == ZenCodingTokens.DOT ? CLASS : ID;
-        myIndex++;
-        token = nextToken();
-        final String value = getAttributeValueByToken(token);
-        myIndex++;
-        return value != null ? Collections.singletonList(new Pair<String, String>(name, value)) : null;
-      }
-
-      return null;
-    }
-
-    private boolean setTemplate(final TemplateToken token, TemplateImpl template) {
-      if (template == null) {
-        template = myGenerator.createTemplateByKey(token.getKey());
-      }
-      if (template == null) {
-        return false;
-      }
-      return doSetTemplate(token, template, myCallback);
-    }
-
-    @Nullable
-    private List<Pair<String, String>> parseAttributeList() {
-      final List<Pair<String, String>> result = new ArrayList<Pair<String, String>>();
-      while (true) {
-        final Pair<String, String> attribute = parseAttribute();
-        if (attribute == null) {
-          return result;
-        }
-        result.add(attribute);
-
-        final ZenCodingToken token = nextToken();
-        if (token != ZenCodingTokens.COMMA && token != ZenCodingTokens.SPACE) {
-          return result;
-        }
-        myIndex++;
-      }
-    }
-
-    @Nullable
-    private Pair<String, String> parseAttribute() {
-      ZenCodingToken token = nextToken();
-      if (!(token instanceof IdentifierToken)) {
-        return null;
-      }
-
-      final String name = ((IdentifierToken)token).getText();
-
-      myIndex++;
-      token = nextToken();
-      if (token != ZenCodingTokens.EQ) {
-        return new Pair<String, String>(name, "");
-      }
-
-      myIndex++;
-      final StringBuilder attrValueBuilder = new StringBuilder();
-      String value;
-      do {
-        token = nextToken();
-        value = token != null && token == ZenCodingTokens.SHARP ? token.toString() : getAttributeValueByToken(token);
-        if (value != null) {
-          attrValueBuilder.append(value);
-          myIndex++;
-        }
-      }
-      while (value != null);
-      return new Pair<String, String>(name, attrValueBuilder.toString());
-    }
-
-    @Nullable
-    private static String getAttributeValueByToken(ZenCodingToken token) {
-      if (token instanceof StringLiteralToken) {
-        final String text = ((StringLiteralToken)token).getText();
-        return text.substring(1, text.length() - 1);
-      }
-      else if (token instanceof IdentifierToken) {
-        return ((IdentifierToken)token).getText();
-      }
-      else if (token instanceof NumberToken) {
-        return Integer.toString(((NumberToken)token).getNumber());
-      }
-      return null;
-    }
-
-    @Nullable
-    private ZenCodingToken nextToken() {
-      if (myIndex < myTokens.size()) {
-        return myTokens.get(myIndex);
-      }
-      return null;
-    }
-
-  }
-}
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/ZenCodingUtil.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/ZenCodingUtil.java
deleted file mode 100644
index a72a2ed..0000000
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/ZenCodingUtil.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2000-2010 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.intellij.codeInsight.template.zencoding;
-
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * @author Eugene.Kudelevsky
- */
-public class ZenCodingUtil {
-  private static final char NUMBER_IN_ITERATION_PLACE_HOLDER = '$';
-  private static final String SURROUNDED_TEXT_MARKER = "$#";
-
-  private ZenCodingUtil() {
-  }
-
-  public static boolean containsSurroundedTextMarker(@NotNull String s) {
-    return s.contains(SURROUNDED_TEXT_MARKER);
-  }
-
-  public static String replaceMarkers(String s, int numberInIteration, @Nullable String surroundedText) {
-    final String by = Integer.toString(numberInIteration + 1);
-    StringBuilder builder = new StringBuilder(s.length());
-    int j = -1;
-    int i = 0;
-    int n = s.length();
-    while (i <= n) {
-      char c = i < n ? s.charAt(i) : 0;
-      if (c == NUMBER_IN_ITERATION_PLACE_HOLDER && (i == n - 1 || s.charAt(i + 1) != '#')) {
-        if (j == -1) {
-          j = i;
-        }
-      }
-      else {
-        if (j != -1) {
-          for (int k = 0, m = i - j - by.length(); k < m; k++) {
-            builder.append('0');
-          }
-          builder.append(by);
-          j = -1;
-        }
-        if (i < n) {
-          if (c == NUMBER_IN_ITERATION_PLACE_HOLDER && surroundedText != null) {
-            builder.append(surroundedText);
-            i++;
-          }
-          else {
-            builder.append(c);
-          }
-        }
-      }
-      i++;
-    }
-    return builder.toString();
-  }
-
-  public static String getValue(String value, int numberInIteration, String surroundedText) {
-    String s = replaceMarkers(value, numberInIteration, surroundedText);
-    return s.replace("\"", "&quot;");
-  }
-}
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/filters/TrimZenCodingFilter.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/filters/TrimZenCodingFilter.java
deleted file mode 100644
index f6c26f1..0000000
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/filters/TrimZenCodingFilter.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.intellij.codeInsight.template.zencoding.filters;
-
-import com.intellij.codeInsight.template.zencoding.nodes.GenerationNode;
-import com.intellij.lang.xml.XMLLanguage;
-import com.intellij.psi.PsiElement;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.regex.Pattern;
-
-/**
- * @author Eugene.Kudelevsky
- */
-public class TrimZenCodingFilter extends ZenCodingFilter {
-  private static final Pattern PATTERN = Pattern.compile("^([\\s|\u00a0])?[\\d|#|\\-|\\*|\u2022]+\\.?\\s*");
-
-  @NotNull
-  @Override
-  public String getSuffix() {
-    return "t";
-  }
-
-  @Override
-  public boolean isMyContext(@NotNull PsiElement context) {
-    return context.getLanguage() instanceof XMLLanguage;
-  }
-
-  @NotNull
-  @Override
-  public GenerationNode filterNode(@NotNull GenerationNode node) {
-    doFilter(node);
-    return node;
-  }
-
-  private static void doFilter(GenerationNode node) {
-    final String surroundedText = node.getSurroundedText();
-    if (surroundedText != null) {
-      node.setSurroundedText(PATTERN.matcher(surroundedText).replaceAll(""));
-    }
-    for (GenerationNode child : node.getChildren()) {
-      doFilter(child);
-    }
-  }
-}
diff --git a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/TemplateNode.java b/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/TemplateNode.java
deleted file mode 100644
index 7a9040d..0000000
--- a/xml/impl/src/com/intellij/codeInsight/template/zencoding/nodes/TemplateNode.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2000-2010 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.intellij.codeInsight.template.zencoding.nodes;
-
-import com.intellij.codeInsight.template.CustomTemplateCallback;
-import com.intellij.codeInsight.template.zencoding.tokens.TemplateToken;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * @author Eugene.Kudelevsky
- */
-public class TemplateNode extends ZenCodingNode {
-  private final TemplateToken myTemplateToken;
-
-  public TemplateNode(TemplateToken templateToken) {
-    myTemplateToken = templateToken;
-  }
-
-  public TemplateToken getTemplateToken() {
-    return myTemplateToken;
-  }
-
-  @NotNull
-  @Override
-  public List<GenerationNode> expand(int numberInIteration,
-                                     String surroundedText,
-                                     CustomTemplateCallback callback,
-                                     boolean insertSurroundedTextAtTheEnd) {
-    GenerationNode node =
-      new GenerationNode(myTemplateToken, new ArrayList<GenerationNode>(), numberInIteration, surroundedText, insertSurroundedTextAtTheEnd);
-    return Arrays.asList(node);
-  }
-}
diff --git a/xml/impl/src/com/intellij/html/index/Html5CustomAttributesIndex.java b/xml/impl/src/com/intellij/html/index/Html5CustomAttributesIndex.java
index 152018c..8669b60 100644
--- a/xml/impl/src/com/intellij/html/index/Html5CustomAttributesIndex.java
+++ b/xml/impl/src/com/intellij/html/index/Html5CustomAttributesIndex.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2010 JetBrains s.r.o.
+ * Copyright 2000-2013 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
 import com.intellij.lexer.HtmlHighlightingLexer;
 import com.intellij.lexer.Lexer;
 import com.intellij.lexer.XHtmlHighlightingLexer;
+import com.intellij.openapi.fileTypes.FileType;
 import com.intellij.openapi.fileTypes.LanguageFileType;
 import com.intellij.openapi.fileTypes.StdFileTypes;
 import com.intellij.openapi.vfs.LocalFileSystem;
@@ -78,8 +79,12 @@
   private final FileBasedIndex.InputFilter myInputFilter = new FileBasedIndex.InputFilter() {
     @Override
     public boolean acceptInput(final VirtualFile file) {
-      return (file.getFileSystem() == LocalFileSystem.getInstance() || file.getFileSystem() instanceof TempFileSystem) &&
-             file.getFileType() == StdFileTypes.HTML || file.getFileType() == StdFileTypes.XHTML;
+      if (file.getFileSystem() != LocalFileSystem.getInstance() && !(file.getFileSystem() instanceof TempFileSystem)) {
+        return false;
+      }
+
+      final FileType fileType = file.getFileType();
+      return fileType == StdFileTypes.HTML || fileType == StdFileTypes.XHTML;
     }
   };
 
diff --git a/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java b/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java
index 4702fe6..64729f6 100644
--- a/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java
+++ b/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2013 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -22,7 +22,6 @@
 import com.intellij.ide.browsers.impl.DefaultUrlOpener;
 import com.intellij.openapi.components.*;
 import com.intellij.openapi.util.Condition;
-import com.intellij.openapi.util.Conditions;
 import com.intellij.openapi.util.SystemInfo;
 import com.intellij.openapi.util.io.WindowsRegistryUtil;
 import com.intellij.util.containers.HashMap;
@@ -205,23 +204,29 @@
     }
   }
 
+  /** @deprecated use {@link DefaultUrlOpener} (to remove in IDEA 13) */
+  @SuppressWarnings("unused")
   public static void launchBrowser(final @NotNull BrowserFamily family, @NotNull final String url, String... parameters) {
-    launchBrowser(family, url, false, parameters);
+    DefaultUrlOpener.launchBrowser(family, url, false, parameters);
   }
 
+  /** @deprecated use {@link DefaultUrlOpener} (to remove in IDEA 13) */
+  @SuppressWarnings("unused")
   public static void launchBrowser(final @NotNull BrowserFamily family,
                                    @Nullable final String url,
                                    final boolean forceOpenNewInstanceOnMac,
                                    String... parameters) {
-    DefaultUrlOpener.launchBrowser(family, url, parameters, Conditions.<String>alwaysTrue(), forceOpenNewInstanceOnMac);
+    DefaultUrlOpener.launchBrowser(family, url, forceOpenNewInstanceOnMac, parameters);
   }
 
+  /** @deprecated use {@link DefaultUrlOpener} (to remove in IDEA 13) */
+  @SuppressWarnings("unused")
   public static void launchBrowser(final @NotNull BrowserFamily family,
                                    @NotNull final String url,
                                    final boolean forceOpenNewInstanceOnMac,
                                    final Condition<String> browserSpecificParametersFilter,
                                    String... parameters) {
-    DefaultUrlOpener.launchBrowser(family, url, parameters, browserSpecificParametersFilter, forceOpenNewInstanceOnMac);
+    DefaultUrlOpener.launchBrowser(family, url, forceOpenNewInstanceOnMac, parameters);
   }
 
   @Nullable
diff --git a/xml/impl/src/com/intellij/ide/browsers/impl/DefaultUrlOpener.java b/xml/impl/src/com/intellij/ide/browsers/impl/DefaultUrlOpener.java
index fc50f4d..ae37d74 100644
--- a/xml/impl/src/com/intellij/ide/browsers/impl/DefaultUrlOpener.java
+++ b/xml/impl/src/com/intellij/ide/browsers/impl/DefaultUrlOpener.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2013 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
  */
 package com.intellij.ide.browsers.impl;
 
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.configurations.GeneralCommandLine;
 import com.intellij.execution.util.ExecUtil;
 import com.intellij.ide.BrowserUtil;
 import com.intellij.ide.browsers.BrowserSpecificSettings;
@@ -24,17 +26,14 @@
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.ui.Messages;
 import com.intellij.openapi.util.Condition;
-import com.intellij.openapi.util.Conditions;
 import com.intellij.openapi.util.SystemInfo;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.util.ArrayUtil;
-import com.intellij.util.containers.ContainerUtil;
 import com.intellij.xml.XmlBundle;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.io.IOException;
-import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
@@ -43,71 +42,63 @@
 
   @Override
   public boolean openUrl(BrowsersConfiguration.BrowserFamily family, @Nullable String url) {
-    return launchBrowser(family, url, ArrayUtil.EMPTY_STRING_ARRAY, Conditions.<String>alwaysTrue(), false);
+    return launchBrowser(family, url, false);
   }
 
-  public static boolean launchBrowser(final BrowsersConfiguration.BrowserFamily family,
+  /** @deprecated use {@linkplain #launchBrowser(BrowsersConfiguration.BrowserFamily, String, boolean, String...)} (to remove in IDEA 13) */
+  @SuppressWarnings("unused")
+  public static boolean launchBrowser(@NotNull BrowsersConfiguration.BrowserFamily family,
                                       @Nullable String url,
                                       @NotNull String[] additionalParameters,
                                       @NotNull Condition<String> browserSpecificParametersFilter,
-                                      final boolean forceOpenNewInstanceOnMac) {
-    final WebBrowserSettings settings = BrowsersConfiguration.getInstance().getBrowserSettings(family);
-    final String path = settings.getPath();
+                                      boolean newWindowIfPossible) {
+    return launchBrowser(family, url, newWindowIfPossible, additionalParameters);
+  }
+
+  public static boolean launchBrowser(@NotNull BrowsersConfiguration.BrowserFamily family,
+                                      @Nullable String url,
+                                      boolean newWindowIfPossible,
+                                      @NotNull String... additionalParameters) {
+    WebBrowserSettings settings = BrowsersConfiguration.getInstance().getBrowserSettings(family);
+    String path = settings.getPath();
     if (StringUtil.isEmpty(path)) {
-      Messages.showErrorDialog(XmlBundle.message("browser.path.not.specified", family.getName()), XmlBundle.message("browser.path.not.specified.title"));
+      String message = XmlBundle.message("browser.path.not.specified", family.getName());
+      Messages.showErrorDialog(message, XmlBundle.message("browser.path.not.specified.title"));
       return false;
     }
 
+    List<String> command = BrowserUtil.getOpenBrowserCommand(path, newWindowIfPossible);
+    if (url != null) {
+      command.add(url);
+    }
+    addArgs(command, settings.getBrowserSpecificSettings(), additionalParameters);
+
     try {
-      BrowserSpecificSettings specificSettings = settings.getBrowserSpecificSettings();
-      List<String> parameters = specificSettings == null
-                                ? (additionalParameters.length == 0 ? Collections.<String>emptyList() : new ArrayList<String>())
-                                : ContainerUtil.findAll(specificSettings.getAdditionalParameters(), browserSpecificParametersFilter);
-      Collections.addAll(parameters, additionalParameters);
-      doLaunchBrowser(path, url == null ? null : BrowserUtil.escapeUrl(url), forceOpenNewInstanceOnMac, parameters);
+      new GeneralCommandLine(command).createProcess();
       return true;
     }
-    catch (IOException e) {
+    catch (ExecutionException e) {
       Messages.showErrorDialog(e.getMessage(), XmlBundle.message("browser.error"));
       return false;
     }
   }
 
-  private static void doLaunchBrowser(String browserPath, @Nullable String url, boolean forceOpenNewInstanceOnMac, List<String> browserArgs)
-    throws IOException {
-    List<String> command = BrowserUtil.getOpenBrowserCommand(browserPath);
-    addArgs(command, browserArgs, url, forceOpenNewInstanceOnMac);
-    if (LOG.isDebugEnabled()) {
-      LOG.debug("Launching browser: " + StringUtil.join(command, " "));
-    }
-    new ProcessBuilder(command).start();
-  }
+  private static void addArgs(List<String> command, @Nullable BrowserSpecificSettings settings, String[] additional) {
+    String[] specific = settings != null ? settings.getAdditionalParameters() : ArrayUtil.EMPTY_STRING_ARRAY;
 
-  private static void addArgs(List<String> command, List<String> browserArgs, @Nullable String url, boolean forceOpenNewInstanceOnMac) {
-    if (SystemInfo.isMac && ExecUtil.getOpenCommandPath().equals(command.get(0))) {
-      if (forceOpenNewInstanceOnMac) {
-        command.add("-n");
-      }
-      if (url != null) {
-        command.add(url);
-      }
-
-      if (!browserArgs.isEmpty()) {
-        if (BrowserUtil.isOpenCommandSupportArgs()) {
-          command.add("--args");
-          command.addAll(browserArgs);
+    if (specific.length + additional.length > 0) {
+      if (SystemInfo.isMac && ExecUtil.getOpenCommandPath().equals(command.get(0))) {
+        if (!BrowserUtil.isOpenCommandSupportArgs()) {
+          LOG.warn("'open' command doesn't allow to pass command line arguments so they will be ignored: " +
+                   Arrays.toString(specific) + " " + Arrays.toString(additional));
         }
         else {
-          LOG.warn(
-            "'open' command doesn't allow to pass command line arguments so they will be ignored: " + StringUtil.join(browserArgs, " "));
+          command.add("--args");
         }
       }
-    }
-    else {
-      if (url != null) {
-        command.add(url);
-      }
-      command.addAll(browserArgs);
+
+      Collections.addAll(command, specific);
+      Collections.addAll(command, additional);
     }
   }
 }
diff --git a/xml/impl/src/com/intellij/ide/structureView/impl/xml/XmlTagTreeElement.java b/xml/impl/src/com/intellij/ide/structureView/impl/xml/XmlTagTreeElement.java
index 86a6350..a2ecfd7 100644
--- a/xml/impl/src/com/intellij/ide/structureView/impl/xml/XmlTagTreeElement.java
+++ b/xml/impl/src/com/intellij/ide/structureView/impl/xml/XmlTagTreeElement.java
@@ -39,6 +39,7 @@
 
   public String getPresentableText() {
     final XmlTag element = getElement();
+    if (element == null) return "*invalid*";
     String id = element.getAttributeValue(ID_ATTR_NAME);
     if (id == null) id = element.getAttributeValue(NAME_ATTR_NAME);
     id = toCanonicalForm(id);
@@ -88,7 +89,7 @@
   }
 
   @Nullable
-  protected static String toCanonicalForm(@Nullable String id) {
+  public static String toCanonicalForm(@Nullable String id) {
     if (id != null) {
       id = id.trim();
       if (id.length() == 0) id = null;
diff --git a/xml/impl/src/com/intellij/javaee/ExternalResourceManagerImpl.java b/xml/impl/src/com/intellij/javaee/ExternalResourceManagerImpl.java
index 9e53742..de54dc3 100644
--- a/xml/impl/src/com/intellij/javaee/ExternalResourceManagerImpl.java
+++ b/xml/impl/src/com/intellij/javaee/ExternalResourceManagerImpl.java
@@ -381,7 +381,7 @@
     Element child = element.getChild(HTML_DEFAULT_DOCTYPE_ELEMENT);
     if (child != null) {
       String text = child.getText();
-      if (FileUtil.toSystemIndependentName(text).endsWith("idea.jar!/resources/html5-schema/html5.rnc")) {
+      if (FileUtil.toSystemIndependentName(text).endsWith(".jar!/resources/html5-schema/html5.rnc")) {
         text = HTML5_DOCTYPE_ELEMENT;
       }
       myDefaultHtmlDoctype = text;
diff --git a/xml/impl/src/com/intellij/javaee/MapExternalResourceDialog.java b/xml/impl/src/com/intellij/javaee/MapExternalResourceDialog.java
index eae3953..95f196d 100644
--- a/xml/impl/src/com/intellij/javaee/MapExternalResourceDialog.java
+++ b/xml/impl/src/com/intellij/javaee/MapExternalResourceDialog.java
@@ -98,7 +98,7 @@
       }
     };
     searcher.search();
-    new ConfigFilesTreeBuilder(mySchemasTree).buildTree(searcher, root);
+    new ConfigFilesTreeBuilder(mySchemasTree).buildTree(root, searcher);
     TreeUtil.expandAll(mySchemasTree);
     mySchemasTree.setRootVisible(false);
     mySchemasTree.setShowsRootHandles(true);
diff --git a/xml/impl/src/com/intellij/lang/html/HtmlStructureViewBuilderProvider.java b/xml/impl/src/com/intellij/lang/html/HtmlStructureViewBuilderProvider.java
deleted file mode 100644
index 19a063d..0000000
--- a/xml/impl/src/com/intellij/lang/html/HtmlStructureViewBuilderProvider.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.intellij.lang.html;
-
-import com.intellij.ide.highlighter.HtmlFileType;
-import com.intellij.ide.structureView.StructureViewBuilder;
-import com.intellij.ide.structureView.StructureViewModel;
-import com.intellij.ide.structureView.StructureViewTreeElement;
-import com.intellij.ide.structureView.TreeBasedStructureViewBuilder;
-import com.intellij.ide.structureView.impl.xml.XmlStructureViewTreeModel;
-import com.intellij.ide.structureView.xml.XmlStructureViewBuilderProvider;
-import com.intellij.ide.util.treeView.smartTree.Sorter;
-import com.intellij.psi.xml.XmlDocument;
-import com.intellij.psi.xml.XmlFile;
-import com.intellij.psi.xml.XmlTag;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-public class HtmlStructureViewBuilderProvider implements XmlStructureViewBuilderProvider {
-  @Nullable
-  public StructureViewBuilder createStructureViewBuilder(@NotNull final XmlFile file) {
-    if (file.getViewProvider().getVirtualFile().getFileType() != HtmlFileType.INSTANCE) return null;
-
-    return new TreeBasedStructureViewBuilder() {
-      public boolean isRootNodeShown() {
-        return false;
-      }
-
-      @NotNull
-      public StructureViewModel createStructureViewModel() {
-        return new XmlStructureViewTreeModel(file) {
-          @NotNull
-          public Sorter[] getSorters() {
-            return Sorter.EMPTY_ARRAY;
-          }
-
-          @NotNull
-          public StructureViewTreeElement getRoot() {
-            final XmlDocument document = ((XmlFile)getPsiFile()).getDocument();
-            final XmlTag rootTag = document == null ? null : document.getRootTag();
-
-            if (rootTag != null && "html".equalsIgnoreCase(rootTag.getLocalName())) {
-              final XmlTag[] subTags = rootTag.getSubTags();
-              if (subTags.length == 1 &&
-                  ("head".equalsIgnoreCase(subTags[0].getLocalName()) || "body".equalsIgnoreCase(subTags[0].getLocalName()))) {
-                return new HtmlStructureViewElementProvider.HtmlTagTreeElement(subTags[0]);
-              }
-
-              return new HtmlStructureViewElementProvider.HtmlTagTreeElement(rootTag);
-            }
-
-            return super.getRoot();
-          }
-        };
-      }
-    };
-  }
-}
diff --git a/xml/impl/src/com/intellij/lang/html/HtmlStructureViewElementProvider.java b/xml/impl/src/com/intellij/lang/html/HtmlStructureViewElementProvider.java
deleted file mode 100644
index 4be0765..0000000
--- a/xml/impl/src/com/intellij/lang/html/HtmlStructureViewElementProvider.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package com.intellij.lang.html;
-
-import com.intellij.ide.IdeBundle;
-import com.intellij.ide.highlighter.HtmlFileType;
-import com.intellij.ide.structureView.StructureViewTreeElement;
-import com.intellij.ide.structureView.impl.xml.XmlTagTreeElement;
-import com.intellij.ide.structureView.xml.XmlStructureViewElementProvider;
-import com.intellij.navigation.LocationPresentation;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.psi.xml.XmlTag;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Collections;
-import java.util.List;
-
-public class HtmlStructureViewElementProvider implements XmlStructureViewElementProvider {
-
-  private static int MAX_TEXT_LENGTH = 50;
-
-  @Nullable
-  public StructureViewTreeElement createCustomXmlTagTreeElement(@NotNull final XmlTag tag) {
-    if (tag.getContainingFile().getViewProvider().getVirtualFile().getFileType() != HtmlFileType.INSTANCE) return null;
-
-    return new HtmlTagTreeElement(tag);
-  }
-
-  static class HtmlTagTreeElement extends XmlTagTreeElement implements LocationPresentation {
-    public HtmlTagTreeElement(final XmlTag tag) {
-      super(tag);
-    }
-
-    public String getPresentableText() {
-      final XmlTag tag = getElement();
-      if (tag == null) return IdeBundle.message("node.structureview.invalid");
-
-      final String id = toCanonicalForm(tag.getAttributeValue("id"));
-
-      final String classValue = tag.getAttributeValue("class");
-      final List<String> classValues = classValue != null ? StringUtil.split(classValue, " ") : Collections.<String>emptyList();
-
-      final StringBuilder text = new StringBuilder(tag.getLocalName());
-
-      if (id != null) {
-        text.append("#").append(id);
-      }
-
-      if (!classValues.isEmpty()) {
-        text.append('.').append(StringUtil.join(classValues, "."));
-      }
-
-      return text.toString();
-    }
-
-    public String getLocationString() {
-      final XmlTag tag = getElement();
-      if (tag == null) return null;
-
-      final String text = normalizeSpaces(tag.getValue().getTrimmedText());
-      return text.isEmpty() ? null : shortenTextIfLong(text);
-    }
-
-    private static String normalizeSpaces(final String text) {
-      final StringBuilder buf = new StringBuilder();
-
-      for (char ch : text.toCharArray()) {
-        if (ch <= ' ' || Character.isSpaceChar(ch)) {
-          if (buf.length() == 0 || buf.charAt(buf.length() - 1) != ' ') {
-            buf.append(' ');
-          }
-        }
-        else {
-          buf.append(ch);
-        }
-      }
-
-      return buf.toString();
-    }
-
-    private static String shortenTextIfLong(final String text) {
-      if (text.length() <= MAX_TEXT_LENGTH) return text;
-
-      int index;
-      for (index = MAX_TEXT_LENGTH; index > MAX_TEXT_LENGTH - 20; index--) {
-        if (!Character.isLetter(text.charAt(index))) {
-          break;
-        }
-      }
-
-      final int endIndex = Character.isLetter(index) ? MAX_TEXT_LENGTH : index;
-      return text.substring(0, endIndex) + "...";
-    }
-
-    public String getLocationPrefix() {
-      return "  ";
-    }
-
-    public String getLocationSuffix() {
-      return "";
-    }
-  }
-}
diff --git a/xml/impl/src/com/intellij/lang/html/structureView/Html5SectionTreeElement.java b/xml/impl/src/com/intellij/lang/html/structureView/Html5SectionTreeElement.java
new file mode 100644
index 0000000..76b240e
--- /dev/null
+++ b/xml/impl/src/com/intellij/lang/html/structureView/Html5SectionTreeElement.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.lang.html.structureView;
+
+import com.intellij.ide.structureView.StructureViewTreeElement;
+import com.intellij.ide.structureView.impl.common.PsiTreeElementBase;
+import com.intellij.openapi.util.Computable;
+import com.intellij.psi.xml.XmlTag;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+
+class Html5SectionTreeElement extends PsiTreeElementBase<XmlTag> {
+
+  private final Computable<Collection<StructureViewTreeElement>> myChildrenComputable;
+  private final String myHeader;
+
+  public Html5SectionTreeElement(final XmlTag tag, final Computable<Collection<StructureViewTreeElement>> childrenComputable, final @Nullable String header) {
+    super(tag);
+    myChildrenComputable = childrenComputable;
+    myHeader = header;
+  }
+
+  @NotNull
+  public Collection<StructureViewTreeElement> getChildrenBase() {
+    return myChildrenComputable.compute();
+  }
+
+  public String getPresentableText() {
+    if (myHeader != null) {
+      return HtmlTagTreeElement.normalizeSpacesAndShortenIfLong(myHeader);
+    }
+
+    final XmlTag tag = getElement();
+    return tag == null ? null : HtmlTagTreeElement.normalizeSpacesAndShortenIfLong(tag.getValue().getTrimmedText());
+  }
+
+  public String getLocationString() {
+    final XmlTag tag = getElement();
+    if (tag == null) return null;
+
+    return HtmlTagTreeElement.getTagPresentation(tag);
+  }
+
+  public boolean isSearchInLocationString() {
+    return true;
+  }
+}
diff --git a/xml/impl/src/com/intellij/lang/html/structureView/Html5SectionsNodeProvider.java b/xml/impl/src/com/intellij/lang/html/structureView/Html5SectionsNodeProvider.java
new file mode 100644
index 0000000..184ceee
--- /dev/null
+++ b/xml/impl/src/com/intellij/lang/html/structureView/Html5SectionsNodeProvider.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.lang.html.structureView;
+
+import com.intellij.ide.util.FileStructureNodeProvider;
+import com.intellij.ide.util.treeView.smartTree.ActionPresentation;
+import com.intellij.ide.util.treeView.smartTree.ActionPresentationData;
+import com.intellij.ide.util.treeView.smartTree.TreeElement;
+import com.intellij.openapi.actionSystem.Shortcut;
+import com.intellij.openapi.keymap.KeymapManager;
+import com.intellij.openapi.util.PropertyOwner;
+import com.intellij.psi.xml.XmlFile;
+import com.intellij.psi.xml.XmlTag;
+import com.intellij.xml.XmlBundle;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+import java.util.Collections;
+
+public class Html5SectionsNodeProvider implements FileStructureNodeProvider<Html5SectionTreeElement>, PropertyOwner {
+
+  public static final String ACTION_ID = "HTML5_OUTLINE_MODE";
+  public static final String HTML5_OUTLINE_PROVIDER_PROPERTY = "html5.sections.node.provider";
+
+  @NotNull
+  public String getName() {
+    return ACTION_ID;
+  }
+
+  @NotNull
+  public ActionPresentation getPresentation() {
+    return new ActionPresentationData(XmlBundle.message("html5.outline.mode"), null, null);
+  }
+
+  public String getCheckBoxText() {
+    return XmlBundle.message("html5.outline.mode");
+  }
+
+  public Shortcut[] getShortcut() {
+    return KeymapManager.getInstance().getActiveKeymap().getShortcuts("FileStructurePopup");
+  }
+
+  @NotNull
+  public String getPropertyName() {
+    return HTML5_OUTLINE_PROVIDER_PROPERTY;
+  }
+
+  public Collection<Html5SectionTreeElement> provideNodes(final TreeElement node) {
+    if (!(node instanceof HtmlFileTreeElement)) return Collections.emptyList();
+
+    final XmlFile xmlFile = ((HtmlFileTreeElement)node).getElement();
+    final XmlTag rootTag = xmlFile == null ? null : xmlFile.getRootTag();
+    if (rootTag == null) return Collections.emptyList();
+
+    return Html5SectionsProcessor.processAndGetRootSections(rootTag);
+  }
+}
diff --git a/xml/impl/src/com/intellij/lang/html/structureView/Html5SectionsProcessor.java b/xml/impl/src/com/intellij/lang/html/structureView/Html5SectionsProcessor.java
new file mode 100644
index 0000000..0b9f5cb
--- /dev/null
+++ b/xml/impl/src/com/intellij/lang/html/structureView/Html5SectionsProcessor.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.lang.html.structureView;
+
+import com.intellij.ide.structureView.StructureViewTreeElement;
+import com.intellij.openapi.util.Computable;
+import com.intellij.psi.xml.XmlTag;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.containers.SortedList;
+import com.intellij.util.containers.Stack;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.LinkedList;
+
+
+// Algorithm described at http://www.w3.org/html/wg/drafts/html/master/sections.html#outlines
+// One of implementations: http://hoyois.github.com/html5outliner/ (https://github.com/hoyois/html5outliner)
+class Html5SectionsProcessor {
+
+  private static class SectionHolder {
+    private final XmlTag myTag;
+    private LinkedList<Section> myChildren = new LinkedList<Section>();
+
+    private SectionHolder(final XmlTag tag) {
+      myTag = tag;
+    }
+
+    public void addChildSection(final Section section) {
+      myChildren.add(section);
+    }
+
+    public LinkedList<Section> getChildren() {
+      return myChildren;
+    }
+
+    public XmlTag getTag() {
+      return myTag;
+    }
+  }
+
+  private static class Section extends SectionHolder {
+    private Section myParent = null;
+    private XmlTag myHeader = null;
+
+    public Section(final XmlTag tag) {
+      super(tag);
+    }
+
+    public void addChildSection(final Section section) {
+      section.myParent = this;
+      super.addChildSection(section);
+    }
+
+    public XmlTag getHeader() {
+      return myHeader;
+    }
+
+    public void setHeader(final XmlTag header) {
+      myHeader = header;
+    }
+
+    public Section getParent() {
+      return myParent;
+    }
+  }
+
+  private static final String[] SECTIONING_ROOT_ELEMENTS = {"blockquote", "body", "details", "dialog", "fieldset", "figure", "td"};
+  private static final String[] SECTIONING_CONTENT_ELEMENTS = {"article", "aside", "nav", "section"};
+  private static final String[] HEADER_ELEMENTS = {"h1", "h2", "h3", "h4", "h5", "h6"};
+  private static final String HGROUP_ELEMENT = "hgroup";
+
+  private final Collection<SectionHolder> myRootSectionHolders = new SortedList<SectionHolder>(new Comparator<SectionHolder>() {
+    public int compare(final SectionHolder first, final SectionHolder second) {
+      return first.getTag().getTextRange().getStartOffset() - second.getTag().getTextRange().getStartOffset();
+    }
+  });
+
+  private SectionHolder myCurrentOutlinee = null;
+  private Section myCurrentSection = null;
+  private final Stack<SectionHolder> myStack = new Stack<SectionHolder>();
+
+  public static Collection<Html5SectionTreeElement> processAndGetRootSections(final XmlTag rootTag) {
+    final Html5SectionsProcessor processor = new Html5SectionsProcessor();
+    processRecursively(rootTag, processor);
+    return processor.getRootSections();
+  }
+
+  private static void processRecursively(final XmlTag tag, final Html5SectionsProcessor processor) {
+    if (tag.getAttribute("hidden") != null) return;
+
+    processor.tagEntered(tag);
+
+    if (!isHeader(tag)) {
+      for (final XmlTag subTag : tag.getSubTags()) {
+        processRecursively(subTag, processor);
+      }
+    }
+
+    processor.tagExited(tag);
+  }
+
+  private void tagEntered(final XmlTag tag) {
+    if (isSectioningContentElement(tag) || isSectioningRootElement(tag)) {
+      if (myCurrentOutlinee != null) {
+        myStack.push(myCurrentOutlinee);
+      }
+
+      myCurrentOutlinee = new SectionHolder(tag);
+      myCurrentSection = new Section(tag);
+      myCurrentOutlinee.addChildSection(myCurrentSection);
+    }
+    else if (myCurrentOutlinee == null) {
+      // do nothing
+    }
+    else if (isHeader(tag)) {
+      if (myCurrentSection.getHeader() == null) {
+        myCurrentSection.setHeader(tag);
+      }
+      else if (myCurrentOutlinee.getChildren().getLast().getHeader() == null ||
+               compareHeaderRanks(tag, myCurrentOutlinee.getChildren().getLast().getHeader()) >= 0) {
+        myCurrentSection = new Section(tag);
+        myCurrentSection.setHeader(tag);
+        myCurrentOutlinee.addChildSection(myCurrentSection);
+      }
+      else {
+        Section candidateSection = myCurrentSection;
+        do {
+          if (compareHeaderRanks(tag, candidateSection.getHeader()) < 0) {
+            myCurrentSection = new Section(tag);
+            myCurrentSection.setHeader(tag);
+            candidateSection.addChildSection(myCurrentSection);
+            break;
+          }
+          candidateSection = candidateSection.getParent();
+        }
+        while (true);
+      }
+      //myStack.push(); not needed, because our iterator doesn't enter hidden elements
+    }
+  }
+
+  private void tagExited(final XmlTag tag) {
+    if (!myStack.isEmpty() && myStack.peek().getTag() == tag) {
+      assert false;
+    }
+    else if (!myStack.isEmpty() && isHeader(tag)) {
+      // do nothing
+    }
+    else if (!myStack.isEmpty() && isSectioningContentElement(tag)) {
+      final SectionHolder exitedSectioningContent = myCurrentOutlinee;
+      assert exitedSectioningContent.getTag() == tag;
+
+      myCurrentOutlinee = myStack.pop();
+      myCurrentSection = myCurrentOutlinee.getChildren().getLast();
+
+      for (Section section : exitedSectioningContent.getChildren()) {
+        myCurrentSection.addChildSection(section);
+      }
+    }
+    else if (!myStack.isEmpty() && isSectioningRootElement(tag)) {
+      final SectionHolder exitedSectioningRoot = myCurrentOutlinee;
+      assert exitedSectioningRoot.getTag() == tag;
+      myRootSectionHolders.add(exitedSectioningRoot);
+
+      myCurrentOutlinee = myStack.pop();
+
+      myCurrentSection = myCurrentOutlinee.getChildren().getLast();
+      while (!myCurrentSection.getChildren().isEmpty()) {
+        myCurrentSection = myCurrentSection.getChildren().getLast();
+      }
+    }
+    else if (isSectioningContentElement(tag) || isSectioningRootElement(tag)) {
+      assert myStack.isEmpty();
+
+      assert myCurrentOutlinee.getTag() == tag;
+      myRootSectionHolders.add(myCurrentOutlinee);
+
+      // reset algorithm
+      myCurrentOutlinee = null;
+      myCurrentSection = null;
+    }
+  }
+
+  private Collection<Html5SectionTreeElement> getRootSections() {
+    final Collection<Html5SectionTreeElement> result = new ArrayList<Html5SectionTreeElement>();
+    for (SectionHolder sectionHolder : myRootSectionHolders) {
+      for (Section section : sectionHolder.getChildren()) {
+        result.add(createHtml5SectionTreeElement(section));
+      }
+    }
+    return result;
+  }
+
+  private static Html5SectionTreeElement createHtml5SectionTreeElement(final Section section) {
+    return new Html5SectionTreeElement(section.getTag(),
+                                       createChildrenComputable(section.getChildren()),
+                                       getHeaderText(section.getHeader()));
+  }
+
+  private static Computable<Collection<StructureViewTreeElement>> createChildrenComputable(final Collection<Section> children) {
+    return new Computable<Collection<StructureViewTreeElement>>() {
+      public Collection<StructureViewTreeElement> compute() {
+        final Collection<StructureViewTreeElement> result = new ArrayList<StructureViewTreeElement>();
+        for (Section section : children) {
+          result.add(createHtml5SectionTreeElement(section));
+        }
+        return result;
+      }
+    };
+  }
+
+  private static String getHeaderText(final @Nullable XmlTag header) {
+    if (header == null) return null;
+
+    if (HGROUP_ELEMENT.equalsIgnoreCase(header.getLocalName())) {
+      final StringBuilder buf = new StringBuilder();
+      for (XmlTag subTag : header.getSubTags()) {
+        if (ArrayUtil.contains(subTag.getLocalName().toLowerCase(), HEADER_ELEMENTS)) {
+          if (buf.length() > 0) {
+            buf.append(" ");
+          }
+          buf.append(subTag.getValue().getTrimmedText());
+        }
+      }
+
+      return buf.toString();
+    }
+
+    return header.getValue().getTrimmedText();
+  }
+
+  private static boolean isSectioningRootElement(final XmlTag tag) {
+    return ArrayUtil.contains(tag.getLocalName().toLowerCase(), SECTIONING_ROOT_ELEMENTS);
+  }
+
+  private static boolean isSectioningContentElement(final XmlTag tag) {
+    return ArrayUtil.contains(tag.getLocalName().toLowerCase(), SECTIONING_CONTENT_ELEMENTS);
+  }
+
+  private static boolean isHeader(final XmlTag tag) {
+    return ArrayUtil.contains(tag.getLocalName().toLowerCase(), HEADER_ELEMENTS) || HGROUP_ELEMENT.equalsIgnoreCase(tag.getLocalName());
+  }
+
+  private static int compareHeaderRanks(final @NotNull XmlTag header1, final @NotNull XmlTag header2) {
+    return getHeaderRank(header2) - getHeaderRank(header1);
+  }
+
+  private static int getHeaderRank(final XmlTag header) {
+    if (HGROUP_ELEMENT.equalsIgnoreCase(header.getLocalName())) {
+      int minIndex = HEADER_ELEMENTS.length;
+
+      for (XmlTag subTag : header.getSubTags()) {
+        final int index = ArrayUtil.indexOf(HEADER_ELEMENTS, subTag.getLocalName().toLowerCase());
+        if (index < minIndex) {
+          minIndex = index;
+          if (minIndex == 0) break;
+        }
+      }
+
+      if (minIndex == HEADER_ELEMENTS.length) {
+        // no headers is equivalent to <h1>
+        minIndex = 0;
+      }
+
+      return minIndex + 1;
+    }
+
+    final int index = ArrayUtil.indexOf(HEADER_ELEMENTS, header.getLocalName().toLowerCase());
+    if (index < 0) throw new IllegalArgumentException(header.getName());
+    return index + 1;
+  }
+}
diff --git a/xml/impl/src/com/intellij/lang/html/structureView/HtmlFileTreeElement.java b/xml/impl/src/com/intellij/lang/html/structureView/HtmlFileTreeElement.java
new file mode 100644
index 0000000..07a4070
--- /dev/null
+++ b/xml/impl/src/com/intellij/lang/html/structureView/HtmlFileTreeElement.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.lang.html.structureView;
+
+import com.intellij.ide.structureView.StructureViewFactoryEx;
+import com.intellij.ide.structureView.StructureViewTreeElement;
+import com.intellij.ide.structureView.impl.common.PsiTreeElementBase;
+import com.intellij.ide.util.FileStructurePopup;
+import com.intellij.ide.util.PropertiesComponent;
+import com.intellij.psi.xml.XmlDocument;
+import com.intellij.psi.xml.XmlFile;
+import com.intellij.psi.xml.XmlTag;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+class HtmlFileTreeElement extends PsiTreeElementBase<XmlFile> {
+
+  private final boolean myInStructureViewPopup;
+
+  public HtmlFileTreeElement(final boolean inStructureViewPopup, final XmlFile xmlFile) {
+    super(xmlFile);
+    myInStructureViewPopup = inStructureViewPopup;
+  }
+
+  @NotNull
+  public Collection<StructureViewTreeElement> getChildrenBase() {
+    if (isHtml5SectionsMode()) {
+      return Collections.emptyList(); // Html5SectionsNodeProvider will return its structure
+    }
+
+    final XmlFile xmlFile = getElement();
+    if (xmlFile == null) return Collections.emptyList();
+
+    final XmlDocument document = xmlFile.getDocument();
+    final XmlTag rootTag = document == null ? null : document.getRootTag();
+
+    if (rootTag == null) return Collections.emptyList();
+
+    if ("html".equalsIgnoreCase(rootTag.getLocalName())) {
+      final XmlTag[] subTags = rootTag.getSubTags();
+      if (subTags.length == 1 &&
+          ("head".equalsIgnoreCase(subTags[0].getLocalName()) || "body".equalsIgnoreCase(subTags[0].getLocalName()))) {
+        return new HtmlTagTreeElement(subTags[0]).getChildrenBase();
+      }
+
+      return new HtmlTagTreeElement(rootTag).getChildrenBase();
+    }
+
+    return Arrays.<StructureViewTreeElement>asList(new HtmlTagTreeElement(rootTag));
+  }
+
+  private boolean isHtml5SectionsMode() {
+    final XmlFile xmlFile = getElement();
+    if (xmlFile == null) return false;
+
+    if (myInStructureViewPopup) {
+      final String propertyName = FileStructurePopup.getPropertyName(Html5SectionsNodeProvider.HTML5_OUTLINE_PROVIDER_PROPERTY);
+      if (PropertiesComponent.getInstance().getBoolean(propertyName, false)) {
+        return true;
+      }
+    }
+    else if (StructureViewFactoryEx.getInstanceEx(xmlFile.getProject()).isActionActive(Html5SectionsNodeProvider.ACTION_ID)) {
+      return true;
+    }
+
+    return false;
+  }
+
+  @Nullable
+  public String getPresentableText() {
+    return toString(); // root element is not visible
+  }
+}
diff --git a/xml/impl/src/com/intellij/lang/html/structureView/HtmlStructureViewBuilderProvider.java b/xml/impl/src/com/intellij/lang/html/structureView/HtmlStructureViewBuilderProvider.java
new file mode 100644
index 0000000..3243fe7
--- /dev/null
+++ b/xml/impl/src/com/intellij/lang/html/structureView/HtmlStructureViewBuilderProvider.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.lang.html.structureView;
+
+import com.intellij.ide.highlighter.HtmlFileType;
+import com.intellij.ide.structureView.StructureViewBuilder;
+import com.intellij.ide.structureView.StructureViewModel;
+import com.intellij.ide.structureView.TreeBasedStructureViewBuilder;
+import com.intellij.ide.structureView.xml.XmlStructureViewBuilderProvider;
+import com.intellij.psi.xml.XmlFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class HtmlStructureViewBuilderProvider implements XmlStructureViewBuilderProvider {
+  @Nullable
+  public StructureViewBuilder createStructureViewBuilder(@NotNull final XmlFile file) {
+    if (file.getViewProvider().getVirtualFile().getFileType() != HtmlFileType.INSTANCE) return null;
+
+    return new TreeBasedStructureViewBuilder() {
+      public boolean isRootNodeShown() {
+        return false;
+      }
+
+      @NotNull
+      public StructureViewModel createStructureViewModel() {
+        return new HtmlStructureViewTreeModel(file);
+      }
+    };
+  }
+}
diff --git a/xml/impl/src/com/intellij/lang/html/structureView/HtmlStructureViewTreeModel.java b/xml/impl/src/com/intellij/lang/html/structureView/HtmlStructureViewTreeModel.java
new file mode 100644
index 0000000..230a89a
--- /dev/null
+++ b/xml/impl/src/com/intellij/lang/html/structureView/HtmlStructureViewTreeModel.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.lang.html.structureView;
+
+import com.intellij.ide.actions.ViewStructureAction;
+import com.intellij.ide.structureView.StructureViewTreeElement;
+import com.intellij.ide.structureView.impl.xml.XmlStructureViewTreeModel;
+import com.intellij.ide.util.treeView.smartTree.NodeProvider;
+import com.intellij.ide.util.treeView.smartTree.Sorter;
+import com.intellij.psi.xml.XmlFile;
+import com.intellij.ui.PlaceHolder;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+class HtmlStructureViewTreeModel extends XmlStructureViewTreeModel implements PlaceHolder<String> {
+
+  private final Collection<NodeProvider> myNodeProviders;
+
+  private String myStructureViewPlace;
+
+  public HtmlStructureViewTreeModel(final XmlFile file) {
+    super(file);
+    myNodeProviders = Arrays.<NodeProvider>asList(new Html5SectionsNodeProvider());
+  }
+
+  public void setPlace(final String place) {
+    myStructureViewPlace = place;
+  }
+
+  public String getPlace() {
+    return myStructureViewPlace;
+  }
+
+  @NotNull
+  public Sorter[] getSorters() {
+    return Sorter.EMPTY_ARRAY;
+  }
+
+  @NotNull
+  public Collection<NodeProvider> getNodeProviders() {
+    return myNodeProviders;
+  }
+
+  @NotNull
+  public StructureViewTreeElement getRoot() {
+    return new HtmlFileTreeElement(ViewStructureAction.isInStructureViewPopup(this), (XmlFile)getPsiFile());
+  }
+}
diff --git a/xml/impl/src/com/intellij/lang/html/structureView/HtmlTagTreeElement.java b/xml/impl/src/com/intellij/lang/html/structureView/HtmlTagTreeElement.java
new file mode 100644
index 0000000..d53bcbc
--- /dev/null
+++ b/xml/impl/src/com/intellij/lang/html/structureView/HtmlTagTreeElement.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.lang.html.structureView;
+
+import com.intellij.ide.IdeBundle;
+import com.intellij.ide.structureView.StructureViewTreeElement;
+import com.intellij.ide.structureView.impl.common.PsiTreeElementBase;
+import com.intellij.ide.structureView.impl.xml.XmlTagTreeElement;
+import com.intellij.navigation.LocationPresentation;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.xml.XmlTag;
+import com.intellij.util.Function;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+class HtmlTagTreeElement extends PsiTreeElementBase<XmlTag> implements LocationPresentation {
+  private static final int MAX_TEXT_LENGTH = 50;
+
+  public HtmlTagTreeElement(final XmlTag tag) {
+    super(tag);
+  }
+
+  @NotNull
+  public Collection<StructureViewTreeElement> getChildrenBase() {
+    final XmlTag tag = getElement();
+    if (tag == null || !tag.isValid()) return Collections.emptyList();
+
+    return ContainerUtil.map2List(tag.getSubTags(), new Function<XmlTag, StructureViewTreeElement>() {
+      public StructureViewTreeElement fun(final XmlTag subTag) {
+        return new HtmlTagTreeElement(subTag);
+      }
+    });
+  }
+
+  public String getPresentableText() {
+    final XmlTag tag = getElement();
+    if (tag == null) return IdeBundle.message("node.structureview.invalid");
+
+    return getTagPresentation(tag);
+  }
+
+  public String getLocationString() {
+    final XmlTag tag = getElement();
+    if (tag == null) return null;
+
+    final String text = normalizeSpacesAndShortenIfLong(tag.getValue().getTrimmedText());
+    return text.isEmpty() ? null : text;
+  }
+
+  public boolean isSearchInLocationString() {
+    return true;
+  }
+
+  public static String getTagPresentation(final @NotNull XmlTag tag) {
+    final String id = XmlTagTreeElement.toCanonicalForm(tag.getAttributeValue("id"));
+
+    final String classValue = tag.getAttributeValue("class");
+    final List<String> classValues = classValue != null ? StringUtil.split(classValue, " ") : Collections.<String>emptyList();
+
+    final StringBuilder text = new StringBuilder(tag.getLocalName());
+
+    if (id != null) {
+      text.append("#").append(id);
+    }
+
+    if (!classValues.isEmpty()) {
+      text.append('.').append(StringUtil.join(classValues, "."));
+    }
+
+    return text.toString();
+  }
+
+  @NotNull
+  public static String normalizeSpacesAndShortenIfLong(final @NotNull String text) {
+    return shortenTextIfLong(normalizeSpaces(text));
+  }
+
+  private static String normalizeSpaces(final String text) {
+    final StringBuilder buf = new StringBuilder();
+
+    for (char ch : text.toCharArray()) {
+      if (ch <= ' ' || Character.isSpaceChar(ch)) {
+        if (buf.length() == 0 || buf.charAt(buf.length() - 1) != ' ') {
+          buf.append(' ');
+        }
+      }
+      else {
+        buf.append(ch);
+      }
+    }
+
+    return buf.toString();
+  }
+
+  private static String shortenTextIfLong(final String text) {
+    if (text.length() <= MAX_TEXT_LENGTH) return text;
+
+    int index;
+    for (index = MAX_TEXT_LENGTH; index > MAX_TEXT_LENGTH - 20; index--) {
+      if (!Character.isLetter(text.charAt(index))) {
+        break;
+      }
+    }
+
+    final int endIndex = Character.isLetter(index) ? MAX_TEXT_LENGTH : index;
+    return text.substring(0, endIndex) + "...";
+  }
+
+  public String getLocationPrefix() {
+    return "  ";
+  }
+
+  public String getLocationSuffix() {
+    return "";
+  }
+}
diff --git a/xml/impl/src/com/intellij/psi/filters/getters/XmlAttributeValueGetter.java b/xml/impl/src/com/intellij/psi/filters/getters/XmlAttributeValueGetter.java
index ddf656d..929162b 100644
--- a/xml/impl/src/com/intellij/psi/filters/getters/XmlAttributeValueGetter.java
+++ b/xml/impl/src/com/intellij/psi/filters/getters/XmlAttributeValueGetter.java
@@ -41,6 +41,17 @@
     return getApplicableAttributeVariants(context);
   }
 
+  @Nullable
+  public static String[] getEnumeratedValues(XmlAttribute attribute) {
+    final XmlAttributeDescriptor descriptor = attribute.getDescriptor();
+    if (descriptor == null) {
+      return ArrayUtil.EMPTY_STRING_ARRAY;
+    }
+
+    return descriptor instanceof BasicXmlAttributeDescriptor ?
+                      ((BasicXmlAttributeDescriptor)descriptor).getEnumeratedValues(attribute) : descriptor.getEnumeratedValues();
+  }
+
   private Object[] getApplicableAttributeVariants(PsiElement _context) {
     if (_context instanceof XmlTokenImpl && ((XmlTokenImpl)_context).getTokenType() == XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN) {
       XmlAttribute attr = PsiTreeUtil.getParentOfType(_context, XmlAttribute.class);
@@ -53,9 +64,7 @@
             return defaultValue == null ? ArrayUtil.EMPTY_OBJECT_ARRAY : new Object[]{defaultValue};
           }
 
-          String[] values = descriptor instanceof BasicXmlAttributeDescriptor ?
-                            ((BasicXmlAttributeDescriptor)descriptor).getEnumeratedValues(attr)
-                                                                              : descriptor.getEnumeratedValues();
+          String[] values = getEnumeratedValues(attr);
 
           final String[] strings = addSpecificCompletions(attr);
 
diff --git a/xml/impl/src/com/intellij/psi/formatter/xml/HtmlPolicy.java b/xml/impl/src/com/intellij/psi/formatter/xml/HtmlPolicy.java
index 48c1502..536575d 100644
--- a/xml/impl/src/com/intellij/psi/formatter/xml/HtmlPolicy.java
+++ b/xml/impl/src/com/intellij/psi/formatter/xml/HtmlPolicy.java
@@ -32,13 +32,12 @@
 import java.util.Map;
 
 public class HtmlPolicy extends XmlFormattingPolicy {
-  
+
   protected final CodeStyleSettings mySettings;
 
   public HtmlPolicy(final CodeStyleSettings settings, final FormattingDocumentModel documentModel) {
     super(documentModel);
     mySettings = settings;
-
   }
 
   public boolean indentChildrenOf(final XmlTag parentTag) {
@@ -55,8 +54,8 @@
       return false;
     }
 
-    if (mySettings.HTML_DO_NOT_ALIGN_CHILDREN_OF_MIN_LINES > 0 && getLines(parentTag) > mySettings.HTML_DO_NOT_ALIGN_CHILDREN_OF_MIN_LINES)
-    {
+    if (mySettings.HTML_DO_NOT_ALIGN_CHILDREN_OF_MIN_LINES > 0 &&
+        getLines(parentTag) > mySettings.HTML_DO_NOT_ALIGN_CHILDREN_OF_MIN_LINES) {
       return false;
     }
     else {
@@ -85,7 +84,7 @@
       prevNode = prevNode.getTreePrev();
     }
     if (prevNode == null) return false;
-    if (!(SourceTreeToPsiMap.treeElementToPsi(prevNode)instanceof XmlTag)) return false;
+    if (!(SourceTreeToPsiMap.treeElementToPsi(prevNode) instanceof XmlTag)) return false;
     return checkName(xmlTag, mySettings.HTML_ELEMENTS_TO_INSERT_NEW_LINE_BEFORE);
   }
 
@@ -180,7 +179,7 @@
 
   public boolean isTextElement(XmlTag tag) {
     return isInlineTag(tag);
-  }                               
+  }
 
   public int getTextWrap(final XmlTag tag) {
     return mySettings.HTML_TEXT_WRAP;
@@ -243,5 +242,4 @@
   public boolean shouldSaveSpacesBetweenTagAndText() {
     return true;
   }
-
 }
diff --git a/xml/impl/src/com/intellij/psi/impl/cache/impl/idCache/XmlFilterLexer.java b/xml/impl/src/com/intellij/psi/impl/cache/impl/idCache/XmlFilterLexer.java
index e8e75da..96985f4 100644
--- a/xml/impl/src/com/intellij/psi/impl/cache/impl/idCache/XmlFilterLexer.java
+++ b/xml/impl/src/com/intellij/psi/impl/cache/impl/idCache/XmlFilterLexer.java
@@ -69,6 +69,9 @@
     else if (tokenType == XmlElementType.XML_TEXT) {
       scanWordsInToken(UsageSearchContext.IN_PLAIN_TEXT | UsageSearchContext.IN_FOREIGN_LANGUAGES, false, false);
     }
+    else if (tokenType == XmlTokenType.XML_TAG_CHARACTERS) {
+      scanWordsInToken(UsageSearchContext.IN_PLAIN_TEXT | UsageSearchContext.IN_FOREIGN_LANGUAGES, false, false);
+    }
     else if (!ourNoWordsTokenSet.contains(tokenType)) {
       scanWordsInToken(UsageSearchContext.IN_PLAIN_TEXT, false, false);
     }
diff --git a/xml/impl/src/com/intellij/psi/impl/source/xml/TagNameReference.java b/xml/impl/src/com/intellij/psi/impl/source/xml/TagNameReference.java
index c89fb9b..be38440 100644
--- a/xml/impl/src/com/intellij/psi/impl/source/xml/TagNameReference.java
+++ b/xml/impl/src/com/intellij/psi/impl/source/xml/TagNameReference.java
@@ -37,6 +37,7 @@
 import com.intellij.psi.xml.XmlElement;
 import com.intellij.psi.xml.XmlTag;
 import com.intellij.util.ArrayUtil;
+import com.intellij.util.Function;
 import com.intellij.util.IncorrectOperationException;
 import com.intellij.util.NullableFunction;
 import com.intellij.util.containers.ContainerUtil;
@@ -237,6 +238,20 @@
                                             final Collection<String> namespaces,
                                             @Nullable List<String> nsInfo) {
 
+    final List<String> variants = getTagNameVariants(element, namespaces, nsInfo, new Function<XmlElementDescriptor, String>() {
+      @Override
+      public String fun(XmlElementDescriptor descriptor) {
+        return descriptor.getName(element);
+      }
+    });
+    return ArrayUtil.toStringArray(variants);
+  }
+  
+  public static <T> List<T> getTagNameVariants(final XmlTag element,
+                                               final Collection<String> namespaces,
+                                               @Nullable List<String> nsInfo,
+                                               final Function<XmlElementDescriptor, T> f) {
+
     XmlElementDescriptor elementDescriptor = null;
     String elementNamespace = null;
 
@@ -279,8 +294,8 @@
     }
 
     final boolean hasPrefix = StringUtil.isNotEmpty(element.getNamespacePrefix());
-    final List<String> list = ContainerUtil.mapNotNull(variants, new NullableFunction<XmlElementDescriptor, String>() {
-      public String fun(XmlElementDescriptor descriptor) {
+    return ContainerUtil.mapNotNull(variants, new NullableFunction<XmlElementDescriptor, T>() {
+      public T fun(XmlElementDescriptor descriptor) {
         if (descriptor instanceof AnyXmlElementDescriptor) {
           return null;
         }
@@ -289,10 +304,9 @@
           return null;
         }
 
-        return descriptor.getName(element);
+        return f.fun(descriptor);
       }
     });
-    return ArrayUtil.toStringArray(list);
   }
 
   private static void processVariantsInNamespace(final String namespace,
diff --git a/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTokenImpl.java b/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTokenImpl.java
index 822e615..fa9a9c8 100644
--- a/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTokenImpl.java
+++ b/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTokenImpl.java
@@ -23,6 +23,7 @@
 import com.intellij.psi.search.PsiElementProcessor;
 import com.intellij.psi.tree.IElementType;
 import com.intellij.psi.tree.xml.IDTDElementType;
+import com.intellij.psi.xml.XmlProcessingInstruction;
 import com.intellij.psi.xml.XmlToken;
 import com.intellij.psi.xml.XmlTokenType;
 import org.jetbrains.annotations.NotNull;
@@ -66,7 +67,8 @@
     final IElementType elementType = getElementType();
 
     if (elementType == XmlTokenType.XML_DATA_CHARACTERS ||
-        elementType == XmlTokenType.XML_CHAR_ENTITY_REF
+        elementType == XmlTokenType.XML_CHAR_ENTITY_REF ||
+        (elementType == XmlTokenType.XML_TAG_CHARACTERS && getParent() instanceof XmlProcessingInstruction)
       ) {
       return ReferenceProvidersRegistry.getReferencesFromProviders(this, XmlToken.class);
     } else if (elementType == XmlTokenType.XML_NAME && getParent() instanceof PsiErrorElement) {
diff --git a/xml/impl/src/com/intellij/xml/DefaultXmlExtension.java b/xml/impl/src/com/intellij/xml/DefaultXmlExtension.java
index d692afa..f024e87 100644
--- a/xml/impl/src/com/intellij/xml/DefaultXmlExtension.java
+++ b/xml/impl/src/com/intellij/xml/DefaultXmlExtension.java
@@ -94,6 +94,7 @@
         assert nsDescriptor != null;
         final XmlElementDescriptor[] elementDescriptors = nsDescriptor.getRootElementsDescriptors(document);
         for (XmlElementDescriptor elementDescriptor : elementDescriptors) {
+          LOG.assertTrue(elementDescriptor != null, "Null returned from " + nsDescriptor);
           if (hasTag(elementDescriptor, tagName, new HashSet<XmlElementDescriptor>())) {
             set.add(namespace);
             break;
@@ -104,7 +105,7 @@
     return set;
   }
 
-  private static boolean hasTag(XmlElementDescriptor elementDescriptor, String tagName, Set<XmlElementDescriptor> visited) {
+  private static boolean hasTag(@NotNull XmlElementDescriptor elementDescriptor, String tagName, Set<XmlElementDescriptor> visited) {
     final String name = elementDescriptor.getDefaultName();
     if (name.equals(tagName)) {
       return true;
diff --git a/xml/impl/src/com/intellij/xml/actions/GenerateXmlTagAction.java b/xml/impl/src/com/intellij/xml/actions/GenerateXmlTagAction.java
index 5a2b4ea..ff74f8f 100644
--- a/xml/impl/src/com/intellij/xml/actions/GenerateXmlTagAction.java
+++ b/xml/impl/src/com/intellij/xml/actions/GenerateXmlTagAction.java
@@ -300,7 +300,7 @@
   }
 
   @Override
-  protected boolean isValidForFile(Project project, Editor editor, PsiFile file) {
+  protected boolean isValidForFile(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
     if (!(file instanceof XmlFile)) return false;
     XmlTag contextTag = getContextTag(editor, file);
     return contextTag != null && contextTag.getDescriptor() != null;
diff --git a/xml/impl/src/com/intellij/xml/config/ConfigFilesTreeBuilder.java b/xml/impl/src/com/intellij/xml/config/ConfigFilesTreeBuilder.java
index f71505f..7cdf912 100644
--- a/xml/impl/src/com/intellij/xml/config/ConfigFilesTreeBuilder.java
+++ b/xml/impl/src/com/intellij/xml/config/ConfigFilesTreeBuilder.java
@@ -16,27 +16,26 @@
 package com.intellij.xml.config;
 
 import com.intellij.ide.presentation.VirtualFilePresentation;
+import com.intellij.openapi.fileTypes.FileType;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.module.ModuleType;
+import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.openapi.vfs.JarFileSystem;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.psi.PsiFile;
 import com.intellij.ui.ColoredTreeCellRenderer;
 import com.intellij.ui.SimpleTextAttributes;
 import com.intellij.ui.TreeSpeedSearch;
-import com.intellij.util.containers.Convertor;
-import com.intellij.util.containers.MultiMap;
+import com.intellij.util.containers.*;
+import org.jetbrains.annotations.NotNull;
 
 import javax.swing.*;
 import javax.swing.tree.DefaultMutableTreeNode;
 import javax.swing.tree.DefaultTreeModel;
 import javax.swing.tree.TreePath;
 import java.util.*;
+import java.util.HashSet;
 
-/**
- * @author Dmitry Avdeev
- *         Date: 7/17/12
- */
 public class ConfigFilesTreeBuilder {
 
   private final JTree myTree;
@@ -46,42 +45,48 @@
     installSearch(tree);
   }
 
-  public Set<PsiFile> buildTree(ConfigFileSearcher searcher, DefaultMutableTreeNode root) {
+  public Set<PsiFile> buildTree(DefaultMutableTreeNode root, ConfigFileSearcher... searchers) {
+    final Set<PsiFile> psiFiles = new com.intellij.util.containers.HashSet<PsiFile>();
 
-    final MultiMap<Module,PsiFile> files = searcher.getFilesByModules();
-    final MultiMap<VirtualFile, PsiFile> jars = searcher.getJars();
-    final Set<PsiFile> psiFiles = buildModuleNodes(files, jars, root);
-    final MultiMap<VirtualFile, PsiFile> virtualFiles = searcher.getVirtualFiles();
+    final MultiMap<Module, PsiFile> files = new MultiMap<Module, PsiFile>();
+    final MultiMap<VirtualFile, PsiFile> jars = new MultiMap<VirtualFile, PsiFile>();
+    final MultiMap<VirtualFile, PsiFile> virtualFiles = new MultiMap<VirtualFile, PsiFile>();
+
+    for (ConfigFileSearcher searcher : searchers) {
+      files.putAllValues(searcher.getFilesByModules());
+      jars.putAllValues(searcher.getJars());
+      virtualFiles.putAllValues(searcher.getVirtualFiles());
+    }
+
+    psiFiles.addAll(buildModuleNodes(files, jars, root));
 
     for (Map.Entry<VirtualFile, Collection<PsiFile>> entry : virtualFiles.entrySet()) {
       DefaultMutableTreeNode node = createFileNode(entry.getKey());
       List<PsiFile> list = new ArrayList<PsiFile>(entry.getValue());
-      Collections.sort(list, new Comparator<PsiFile>() {
-        @Override
-        public int compare(PsiFile o1, PsiFile o2) {
-          return o1.getName().compareToIgnoreCase(o2.getName());
-        }
-      });
+      Collections.sort(list, FILE_COMPARATOR);
       for (PsiFile file : list) {
         node.add(createFileNode(file));
       }
       root.add(node);
     }
+
     return psiFiles;
   }
 
 
-  public void addFile(VirtualFile file) {
+  public DefaultMutableTreeNode addFile(VirtualFile file) {
     final DefaultMutableTreeNode root = (DefaultMutableTreeNode)myTree.getModel().getRoot();
     final DefaultMutableTreeNode treeNode = createFileNode(file);
     root.add(treeNode);
     DefaultTreeModel model = (DefaultTreeModel)myTree.getModel();
     model.nodeStructureChanged(root);
+
+    return treeNode;
   }
 
-  public Set<PsiFile> buildModuleNodes(final MultiMap<Module,PsiFile> files,
-                               final MultiMap<VirtualFile, PsiFile> jars,
-                               DefaultMutableTreeNode root) {
+  public Set<PsiFile> buildModuleNodes(final MultiMap<Module, PsiFile> files,
+                                       final MultiMap<VirtualFile, PsiFile> jars,
+                                       DefaultMutableTreeNode root) {
 
     final HashSet<PsiFile> psiFiles = new HashSet<PsiFile>();
     final List<Module> modules = new ArrayList<Module>(files.keySet());
@@ -90,27 +95,35 @@
         return o1.getName().compareTo(o2.getName());
       }
     });
-    for (Module module: modules) {
+    for (Module module : modules) {
       DefaultMutableTreeNode moduleNode = createFileNode(module);
       root.add(moduleNode);
       if (files.containsKey(module)) {
         List<PsiFile> moduleFiles = new ArrayList<PsiFile>(files.get(module));
-        Collections.sort(moduleFiles, FILE_COMPARATOR);
-        for (PsiFile file: moduleFiles) {
-          final DefaultMutableTreeNode fileNode = createFileNode(file);
-          moduleNode.add(fileNode);
-          psiFiles.add(file);
+
+        MultiMap<FileType, PsiFile> filesByType = new MultiMap<FileType, PsiFile>();
+        for (PsiFile file : moduleFiles) {
+          filesByType.putValue(file.getFileType(), file);
+        }
+        if (hasNonEmptyGroups(filesByType)) {
+          for (Map.Entry<FileType, Collection<PsiFile>> entry : filesByType.entrySet()) {
+            DefaultMutableTreeNode fileTypeNode = createFileNode(entry.getKey());
+            moduleNode.add(fileTypeNode);
+            addChildrenFiles(psiFiles, fileTypeNode, new ArrayList<PsiFile>(entry.getValue()));
+          }
+        }  else {
+          addChildrenFiles(psiFiles, moduleNode, moduleFiles);
         }
       }
     }
-    for (VirtualFile file: jars.keySet()) {
+    for (VirtualFile file : jars.keySet()) {
       final List<PsiFile> list = new ArrayList<PsiFile>(jars.get(file));
       final PsiFile jar = list.get(0).getManager().findFile(file);
       if (jar != null) {
         final DefaultMutableTreeNode jarNode = createFileNode(jar);
         root.add(jarNode);
         Collections.sort(list, FILE_COMPARATOR);
-        for (PsiFile psiFile: list) {
+        for (PsiFile psiFile : list) {
           jarNode.add(createFileNode(psiFile));
           psiFiles.add(psiFile);
         }
@@ -119,6 +132,28 @@
     return psiFiles;
   }
 
+  private static String getFileTypeNodeName(FileType key) {
+    return StringUtil.capitalize(key.getDefaultExtension()) + " based context files" ;
+  }
+
+  private boolean hasNonEmptyGroups(MultiMap<FileType, PsiFile> filesByType) {
+    byte nonEmptyGroups = 0;
+    for (Map.Entry<FileType, Collection<PsiFile>> entry : filesByType.entrySet()) {
+      Collection<PsiFile> files = entry.getValue();
+      if (files != null && files.size() > 0) nonEmptyGroups++;
+    }
+    return nonEmptyGroups > 1;
+  }
+
+  private void addChildrenFiles(@NotNull Set<PsiFile> psiFiles, DefaultMutableTreeNode parentNode, @NotNull List<PsiFile> moduleFiles) {
+    Collections.sort(moduleFiles, FILE_COMPARATOR);
+    for (PsiFile file : moduleFiles) {
+      final DefaultMutableTreeNode fileNode = createFileNode(file);
+      parentNode.add(fileNode);
+      psiFiles.add(file);
+    }
+  }
+
   protected DefaultMutableTreeNode createFileNode(Object file) {
     return new DefaultMutableTreeNode(file);
   }
@@ -132,13 +167,19 @@
   public static void renderNode(Object value, boolean expanded, ColoredTreeCellRenderer renderer) {
     if (!(value instanceof DefaultMutableTreeNode)) return;
     final Object object = ((DefaultMutableTreeNode)value).getUserObject();
-    if (object instanceof Module) {
+    if (object instanceof FileType) {
+      final FileType fileType = (FileType)object;
+      final Icon icon = fileType.getIcon();
+      renderer.setIcon(icon);
+      renderer.append(getFileTypeNodeName(fileType), SimpleTextAttributes.REGULAR_ATTRIBUTES);
+    } if (object instanceof Module) {
       final Module module = (Module)object;
       final Icon icon = ModuleType.get(module).getIcon();
       renderer.setIcon(icon);
       final String moduleName = module.getName();
       renderer.append(moduleName, SimpleTextAttributes.REGULAR_ATTRIBUTES);
-    } else if (object instanceof PsiFile) {
+    }
+    else if (object instanceof PsiFile) {
       final PsiFile psiFile = (PsiFile)object;
       final Icon icon = psiFile.getIcon(0);
       renderer.setIcon(icon);
@@ -153,7 +194,8 @@
         }
         renderer.append(" (" + path + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES);
       }
-    } else if (object instanceof VirtualFile) {
+    }
+    else if (object instanceof VirtualFile) {
       VirtualFile file = (VirtualFile)object;
       renderer.setIcon(VirtualFilePresentation.getIcon(file));
       renderer.append(file.getName(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
@@ -172,11 +214,14 @@
         final Object object = ((DefaultMutableTreeNode)treePath.getLastPathComponent()).getUserObject();
         if (object instanceof Module) {
           return ((Module)object).getName();
-        } else if (object instanceof PsiFile) {
+        }
+        else if (object instanceof PsiFile) {
           return ((PsiFile)object).getName();
-        } else if (object instanceof VirtualFile) {
+        }
+        else if (object instanceof VirtualFile) {
           return ((VirtualFile)object).getName();
-        } else {
+        }
+        else {
           return "";
         }
       }
diff --git a/xml/impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java b/xml/impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java
index 8c1582f..e984357 100644
--- a/xml/impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java
+++ b/xml/impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java
@@ -34,6 +34,7 @@
 import com.intellij.psi.xml.XmlFile;
 import com.intellij.psi.xml.XmlTag;
 import com.intellij.util.ArrayUtil;
+import com.intellij.util.containers.ContainerUtil;
 import com.intellij.xml.XmlAttributeDescriptor;
 import com.intellij.xml.XmlElementDescriptor;
 import com.intellij.xml.XmlNSDescriptor;
@@ -674,7 +675,7 @@
       final List<XmlElementDescriptor> result = new ArrayList<XmlElementDescriptor>();
       
       public boolean execute(@NotNull final XmlTag element) {
-        result.add(getElementDescriptor(element.getAttributeValue("name"),getDefaultNamespace()));
+        ContainerUtil.addIfNotNull(result, getElementDescriptor(element.getAttributeValue("name"), getDefaultNamespace()));
         return true;
       }
     }
diff --git a/xml/impl/src/com/intellij/xml/util/HtmlUtil.java b/xml/impl/src/com/intellij/xml/util/HtmlUtil.java
index 653ad70..7d71cc4 100644
--- a/xml/impl/src/com/intellij/xml/util/HtmlUtil.java
+++ b/xml/impl/src/com/intellij/xml/util/HtmlUtil.java
@@ -127,7 +127,10 @@
   };
 
   // flow elements are block or inline, so they shuld not close <p> for example
-  @NonNls private static final String[] POSSIBLY_INLINE_TAGS = {"object", "applet", "ins", "del", "button", "nobr"};
+  @NonNls private static final String[] POSSIBLY_INLINE_TAGS = {"a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br", "button",
+    "cite", "code", "del", "dfn", "em", "font", "i", "iframe", "img", "input", "ins",
+    "kbd", "label", "map", "object", "q", "s", "samp", "select", "small", "span", "strike",
+    "strong", "sub", "sup", "textarea", "tt", "u", "var"};
 
   private static final Set<String> BLOCK_TAGS_MAP = new THashSet<String>();
 
diff --git a/xml/impl/src/com/intellij/xml/util/XmlDuplicatedIdInspection.java b/xml/impl/src/com/intellij/xml/util/XmlDuplicatedIdInspection.java
index e0a1854..19b2012 100644
--- a/xml/impl/src/com/intellij/xml/util/XmlDuplicatedIdInspection.java
+++ b/xml/impl/src/com/intellij/xml/util/XmlDuplicatedIdInspection.java
@@ -24,6 +24,7 @@
 import com.intellij.openapi.extensions.Extensions;
 import com.intellij.psi.*;
 import com.intellij.psi.html.HtmlTag;
+import com.intellij.psi.util.PsiUtilCore;
 import com.intellij.psi.xml.XmlAttribute;
 import com.intellij.psi.xml.XmlAttributeValue;
 import com.intellij.psi.xml.XmlFile;
@@ -50,6 +51,10 @@
         if (!(file instanceof XmlFile)) {
           return;
         }
+        PsiFile baseFile = PsiUtilCore.getTemplateLanguageFile(file);
+        if (baseFile != file && !(baseFile instanceof XmlFile)) {
+          return;
+        }
         final XmlRefCountHolder refHolder = XmlRefCountHolder.getRefCountHolder(value);
         if (refHolder == null) return;
 
diff --git a/xml/impl/xml.iml b/xml/impl/xml.iml
index 0395394..840cd2b 100644
--- a/xml/impl/xml.iml
+++ b/xml/impl/xml.iml
@@ -16,6 +16,7 @@
     <orderEntry type="library" name="XmlBeans" level="project" />
     <orderEntry type="module" module-name="platform-resources" />
     <orderEntry type="module" module-name="vcs-api" />
+    <orderEntry type="library" name="Guava" level="project" />
   </component>
   <component name="copyright">
     <Base>
diff --git a/xml/openapi/src/com/intellij/ide/browsers/WebBrowserService.java b/xml/openapi/src/com/intellij/ide/browsers/WebBrowserService.java
index 040d637..224eb9c 100644
--- a/xml/openapi/src/com/intellij/ide/browsers/WebBrowserService.java
+++ b/xml/openapi/src/com/intellij/ide/browsers/WebBrowserService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2011 JetBrains s.r.o.
+ * Copyright 2000-2013 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -35,5 +35,4 @@
 
   @Nullable
   public abstract String getUrlToOpen(@NotNull PsiElement psiElement, boolean preferLocalUrl) throws WebBrowserUrlProvider.BrowserException;
-
-}
+}
\ No newline at end of file
diff --git a/xml/openapi/src/com/intellij/openapi/editor/XmlHighlighterColors.java b/xml/openapi/src/com/intellij/openapi/editor/XmlHighlighterColors.java
index 17d1e1c..782f379 100644
--- a/xml/openapi/src/com/intellij/openapi/editor/XmlHighlighterColors.java
+++ b/xml/openapi/src/com/intellij/openapi/editor/XmlHighlighterColors.java
@@ -25,33 +25,38 @@
   }
 
   public static final TextAttributesKey
-    XML_PROLOGUE = com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey("XML_PROLOGUE");
+    XML_PROLOGUE = TextAttributesKey.createTextAttributesKey("XML_PROLOGUE", HighlighterColors.TEXT);
   public static final TextAttributesKey
-    XML_COMMENT = com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey("XML_COMMENT");
-  public static final TextAttributesKey XML_TAG = com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey("XML_TAG");
+    XML_COMMENT = TextAttributesKey.createTextAttributesKey("XML_COMMENT", DefaultLanguageHighlighterColors.LINE_COMMENT);
+  public static final TextAttributesKey XML_TAG =
+    TextAttributesKey.createTextAttributesKey("XML_TAG", DefaultLanguageHighlighterColors.MARKUP_TAG);
   public static final TextAttributesKey
-    XML_TAG_NAME = com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey("XML_TAG_NAME");
+    XML_TAG_NAME = TextAttributesKey.createTextAttributesKey("XML_TAG_NAME", DefaultLanguageHighlighterColors.KEYWORD);
   public static final TextAttributesKey
-    XML_ATTRIBUTE_NAME = com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey("XML_ATTRIBUTE_NAME");
+    XML_ATTRIBUTE_NAME = TextAttributesKey.createTextAttributesKey("XML_ATTRIBUTE_NAME", DefaultLanguageHighlighterColors.MARKUP_ATTRIBUTE);
   public static final TextAttributesKey
-    XML_ATTRIBUTE_VALUE = com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey("XML_ATTRIBUTE_VALUE");
+    XML_ATTRIBUTE_VALUE = TextAttributesKey.createTextAttributesKey("XML_ATTRIBUTE_VALUE", DefaultLanguageHighlighterColors.STRING);
   public static final TextAttributesKey
-    XML_TAG_DATA = com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey("XML_TAG_DATA");
+    XML_TAG_DATA = TextAttributesKey.createTextAttributesKey("XML_TAG_DATA", HighlighterColors.TEXT);
   public static final TextAttributesKey
-    XML_ENTITY_REFERENCE = com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey("XML_ENTITY_REFERENCE");
+    XML_ENTITY_REFERENCE =
+    TextAttributesKey.createTextAttributesKey("XML_ENTITY_REFERENCE", DefaultLanguageHighlighterColors.MARKUP_ENTITY);
 
   public static final TextAttributesKey
-    HTML_COMMENT = com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey("HTML_COMMENT");
-  public static final TextAttributesKey HTML_TAG = com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey("HTML_TAG");
+    HTML_COMMENT = TextAttributesKey.createTextAttributesKey("HTML_COMMENT", DefaultLanguageHighlighterColors.LINE_COMMENT);
+  public static final TextAttributesKey HTML_TAG =
+    TextAttributesKey.createTextAttributesKey("HTML_TAG", DefaultLanguageHighlighterColors.MARKUP_TAG);
   public static final TextAttributesKey
-    HTML_TAG_NAME = com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey("HTML_TAG_NAME");
+    HTML_TAG_NAME = TextAttributesKey.createTextAttributesKey("HTML_TAG_NAME", DefaultLanguageHighlighterColors.KEYWORD);
   public static final TextAttributesKey
-    HTML_ATTRIBUTE_NAME = com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey("HTML_ATTRIBUTE_NAME");
+    HTML_ATTRIBUTE_NAME =
+    TextAttributesKey.createTextAttributesKey("HTML_ATTRIBUTE_NAME", DefaultLanguageHighlighterColors.MARKUP_ATTRIBUTE);
   public static final TextAttributesKey
-    HTML_ATTRIBUTE_VALUE = com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey("HTML_ATTRIBUTE_VALUE");
+    HTML_ATTRIBUTE_VALUE = TextAttributesKey.createTextAttributesKey("HTML_ATTRIBUTE_VALUE", DefaultLanguageHighlighterColors.STRING);
   public static final TextAttributesKey
-    HTML_ENTITY_REFERENCE = com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey("HTML_ENTITY_REFERENCE");
+    HTML_ENTITY_REFERENCE =
+    TextAttributesKey.createTextAttributesKey("HTML_ENTITY_REFERENCE", DefaultLanguageHighlighterColors.MARKUP_ENTITY);
 
   public static final TextAttributesKey HTML_CODE =
-    TextAttributesKey.createTextAttributesKey("HTML_CODE", HighlighterColors.TEXT.getDefaultAttributes());
+    TextAttributesKey.createTextAttributesKey("HTML_CODE", HighlighterColors.TEXT);
 }
diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/RncFileType.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/RncFileType.java
index 1b5906e..4e5a501 100644
--- a/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/RncFileType.java
+++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/RncFileType.java
@@ -21,7 +21,6 @@
 import com.intellij.openapi.fileTypes.FileTypeConsumer;
 import com.intellij.openapi.fileTypes.FileTypeFactory;
 import com.intellij.openapi.fileTypes.LanguageFileType;
-import com.intellij.util.PairConsumer;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -36,7 +35,7 @@
 public class RncFileType extends LanguageFileType  {
   public static final String RNC_EXT = "rnc";
 
-  private static FileType INSTANCE;
+  private static final FileType INSTANCE = new RncFileType();
 
   private RncFileType() {
     super(RngCompactLanguage.INSTANCE);
@@ -64,20 +63,13 @@
     return AllIcons.FileTypes.Text;
   }
 
-  public static synchronized FileType getInstance() {
-    if (INSTANCE == null) {
-      INSTANCE = new RncFileType();
-    }
+  public static FileType getInstance() {
     return INSTANCE;
   }
 
   public static class Factory extends FileTypeFactory {
     public void createFileTypes(@NotNull FileTypeConsumer fileTypeConsumer) {
-      fileTypeConsumer.consume(getInstance(), RNC_EXT);
-    }
-
-    public void createFileTypes(@NotNull PairConsumer<FileType, String> consumer) {
-      consumer.consume(getInstance(), RNC_EXT);
+      fileTypeConsumer.consume(INSTANCE, RNC_EXT);
     }
   }
 }
diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/lexer/CompactSyntaxLexerAdapter.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/lexer/CompactSyntaxLexerAdapter.java
index 4bfc344..06ba2f2 100644
--- a/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/lexer/CompactSyntaxLexerAdapter.java
+++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/lexer/CompactSyntaxLexerAdapter.java
@@ -199,8 +199,8 @@
       final Class<CompactSyntaxTokenManager> managerClass = CompactSyntaxTokenManager.class;
       LOG.error("Unsupported version of RNGOM in classpath", e,
                 "Actual parameter types: " + Arrays.toString(managerClass.getConstructors()[0].getParameterTypes()),
-                "Location of " + managerClass.getName() + ": " + managerClass.getProtectionDomain().getCodeSource().getLocation(),
-                "Location of " + CharStream.class.getName() + ": " + CharStream.class.getProtectionDomain().getCodeSource().getLocation());
+                "Location of " + managerClass.getName() + ": " + managerClass.getProtectionDomain().getCodeSource(),
+                "Location of " + CharStream.class.getName() + ": " + CharStream.class.getProtectionDomain().getCodeSource());
       throw e;
     }
   }
diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/psi/impl/RncNameImpl.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/psi/impl/RncNameImpl.java
index 1c4b2f6..26d3507 100644
--- a/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/psi/impl/RncNameImpl.java
+++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/psi/impl/RncNameImpl.java
@@ -35,6 +35,7 @@
 import com.intellij.util.ArrayUtil;
 import com.intellij.util.IncorrectOperationException;
 import org.intellij.plugins.relaxNG.compact.RncElementTypes;
+import org.intellij.plugins.relaxNG.compact.RncFileType;
 import org.intellij.plugins.relaxNG.compact.RncTokenTypes;
 import org.intellij.plugins.relaxNG.compact.psi.*;
 import org.intellij.plugins.relaxNG.compact.psi.util.EscapeUtil;
@@ -49,20 +50,13 @@
  */
 public class RncNameImpl extends RncElementImpl implements RncName, PsiReference,
         EmptyResolveMessageProvider, QuickFixProvider<RncNameImpl> {
+
   private enum Kind {
     NAMESPACE, DATATYPES
   }
-  private final Kind myKind;
 
   public RncNameImpl(ASTNode node) {
     super(node);
-
-    final IElementType parent = node.getTreeParent().getElementType();
-    if (parent == RncElementTypes.DATATYPE_PATTERN) {
-      myKind = Kind.DATATYPES;
-    } else {
-      myKind = Kind.NAMESPACE;
-    }
   }
 
   @Nullable
@@ -97,11 +91,20 @@
 
   @Nullable
   public PsiElement resolve() {
-    final MyResolver resolver = new MyResolver(getPrefix(), myKind);
+    final MyResolver resolver = new MyResolver(getPrefix(), getKind());
     getContainingFile().processDeclarations(resolver, ResolveState.initial(), this, this);
     return resolver.getResult();
   }
 
+  private Kind getKind() {
+    final IElementType parent = getNode().getTreeParent().getElementType();
+    if (parent == RncElementTypes.DATATYPE_PATTERN) {
+      return Kind.DATATYPES;
+    } else {
+      return Kind.NAMESPACE;
+    }
+  }
+
   @NotNull
   public String getCanonicalText() {
     return getRangeInElement().substring(getText());
@@ -197,7 +200,7 @@
 
     @NotNull
       public String getFamilyName() {
-      return "Create " + myReference.myKind.name().toLowerCase() + " declaration";
+      return "Create " + myReference.getKind().name().toLowerCase() + " declaration";
     }
 
     public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
@@ -206,7 +209,10 @@
 
     public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
       final String prefix = myReference.getPrefix();
-      final RncFile psiFile = (RncFile)PsiFileFactory.getInstance(myReference.getProject()).createFileFromText("dummy.rnc", myReference.myKind.name().toLowerCase() + " " + prefix + " = \"###\"");
+      final PsiFileFactory factory = PsiFileFactory.getInstance(myReference.getProject());
+      final RncFile psiFile = (RncFile)factory.createFileFromText("dummy.rnc",
+                                                                  RncFileType.getInstance(),
+                                                                   myReference.getKind().name().toLowerCase() + " " + prefix + " = \"###\"");
       final RncFile rncFile = (RncFile)myReference.getContainingFile();
       final RncDecl[] declarations = rncFile.getDeclarations();
       final RncDecl decl = psiFile.getDeclarations()[0];
@@ -230,7 +236,7 @@
 
       CodeStyleManager.getInstance(e.getManager().getProject()).reformatNewlyAddedElement(blockNode, newNode);
 
-      final SmartPsiElementPointer<RncDecl> p = SmartPointerManager.getInstance(project).createLazyPointer(e);
+      final SmartPsiElementPointer<RncDecl> p = SmartPointerManager.getInstance(project).createSmartPsiElementPointer(e);
       PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument());
 
       final RncDecl d = p.getElement();
diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/model/resolve/RelaxIncludeProvider.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/model/resolve/RelaxIncludeProvider.java
index 657cb60..702626f 100644
--- a/xml/relaxng/src/org/intellij/plugins/relaxNG/model/resolve/RelaxIncludeProvider.java
+++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/model/resolve/RelaxIncludeProvider.java
@@ -81,7 +81,7 @@
       boolean isRngTag = ApplicationLoader.RNG_NAMESPACE.equals(nsURI);
       if (!isRNG) { // analyzing start tag
         if (!isRngTag) {
-          throw new NanoXmlUtil.ParserStoppedException();
+          stop();
         } else {
           isRNG = true;
         }
diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/model/resolve/RelaxSymbolIndex.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/model/resolve/RelaxSymbolIndex.java
index e92869d..29ff4e0 100644
--- a/xml/relaxng/src/org/intellij/plugins/relaxNG/model/resolve/RelaxSymbolIndex.java
+++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/model/resolve/RelaxSymbolIndex.java
@@ -6,6 +6,7 @@
 import com.intellij.navigation.NavigationItem;
 import com.intellij.navigation.PsiElementNavigationItem;
 import com.intellij.openapi.editor.colors.TextAttributesKey;
+import com.intellij.openapi.fileTypes.FileType;
 import com.intellij.openapi.fileTypes.StdFileTypes;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.vfs.JarFileSystem;
@@ -142,7 +143,8 @@
         if (file.getFileSystem() instanceof JarFileSystem) {
           return false; // there is lots and lots of custom XML inside zip files
         }
-        return file.getFileType() == StdFileTypes.XML || file.getFileType() == RncFileType.getInstance();
+        final FileType fileType = file.getFileType();
+        return fileType == StdFileTypes.XML || fileType == RncFileType.getInstance();
       }
     };
   }
diff --git a/xml/tests/src/com/intellij/xml/structureView/HtmlFileStructureTest.java b/xml/tests/src/com/intellij/xml/structureView/HtmlFileStructureTest.java
new file mode 100644
index 0000000..d3d79b2
--- /dev/null
+++ b/xml/tests/src/com/intellij/xml/structureView/HtmlFileStructureTest.java
@@ -0,0 +1,48 @@
+package com.intellij.xml.structureView;
+
+import com.intellij.ide.util.FileStructurePopup;
+import com.intellij.ide.util.PropertiesComponent;
+import com.intellij.lang.html.structureView.Html5SectionsNodeProvider;
+import com.intellij.testFramework.FileStructureTestBase;
+
+public class HtmlFileStructureTest extends FileStructureTestBase {
+
+  private boolean myHtml5OutlineModeDefault;
+
+  public void setUp() throws Exception {
+    super.setUp();
+    myHtml5OutlineModeDefault = PropertiesComponent.getInstance().getBoolean(getHtml5OutlineModePropertyName(), false);
+    setHtml5OutlineMode(true);
+  }
+
+  public void tearDown() throws Exception {
+    PropertiesComponent.getInstance().setValue(getHtml5OutlineModePropertyName(), String.valueOf(myHtml5OutlineModeDefault));
+    super.tearDown();
+  }
+
+  private static String getHtml5OutlineModePropertyName() {
+    return FileStructurePopup.getPropertyName(Html5SectionsNodeProvider.HTML5_OUTLINE_PROVIDER_PROPERTY);
+  }
+
+  protected String getFileExtension() {
+    return "html";
+  }
+
+  protected String getBasePath() {
+    return "/xml/tests/testData/structureView/";
+  }
+
+  protected boolean isCommunity() {
+    return true;
+  }
+
+  public void setHtml5OutlineMode(boolean enabled) throws Exception {
+    myPopup.setTreeActionState(Html5SectionsNodeProvider.class, enabled);
+    update();
+  }
+
+  public void testEmpty() throws Exception {checkTree();}
+  public void testSimple() throws Exception {checkTree();}
+  public void testNoSectioningRoot() throws Exception {checkTree();}
+  public void testImplicitSections() throws Exception {checkTree();}
+}
diff --git a/xml/tests/testData/structureView/Empty.html b/xml/tests/testData/structureView/Empty.html
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xml/tests/testData/structureView/Empty.html
diff --git a/xml/tests/testData/structureView/Empty.tree b/xml/tests/testData/structureView/Empty.tree
new file mode 100644
index 0000000..becaf0a
--- /dev/null
+++ b/xml/tests/testData/structureView/Empty.tree
@@ -0,0 +1 @@
++HtmlFile:Empty.html
\ No newline at end of file
diff --git a/xml/tests/testData/structureView/ImplicitSections.html b/xml/tests/testData/structureView/ImplicitSections.html
new file mode 100644
index 0000000..32314bf
--- /dev/null
+++ b/xml/tests/testData/structureView/ImplicitSections.html
@@ -0,0 +1,47 @@
+<html>
+<body>
+<article>
+  <div><h4>section</h4></div>
+  <h5>h5</h5>
+  <h4>h4</h4>
+  <h3>h3</h3>
+  <p>
+  <h4>hh4</h4>
+  <h5>hh5</h5>
+  <aside>
+    <div>
+      <hgroup>
+        <h4>h4</h4>
+
+        <h3>h3</h3>
+      </hgroup>
+      <h4>hh4</h4>
+      <h3>hh3</h3>
+      <figure>
+        <nav>
+          <div>
+            <hgroup>
+            </hgroup>
+            <h2>hhh2</h2>
+            <h1>hhh1</h1>
+          </div>
+        </nav>
+      </figure>
+    </div>
+  </aside>
+  <h6>hh6</h6>
+  <h6>hhh6</h6>
+  </p>
+  <h5>hhh5</h5>
+  <h4>g4</h4>
+  <h6>g6</h6>
+  <h3>g3</h3>
+  <h2>g2</h2>
+</article>
+<div>
+  <h3>body</h3>
+</div>
+<h1>body2</h1>
+<h2>body3</h2>
+</body>
+</html>
\ No newline at end of file
diff --git a/xml/tests/testData/structureView/ImplicitSections.tree b/xml/tests/testData/structureView/ImplicitSections.tree
new file mode 100644
index 0000000..9903463
--- /dev/null
+++ b/xml/tests/testData/structureView/ImplicitSections.tree
@@ -0,0 +1,24 @@
+-HtmlFile:ImplicitSections.html
+ -body
+  -[section]
+   h5
+  h4
+  -h3
+   -hh4
+    hh5
+   -h4 h3
+    hh4
+   hh3
+   hh6
+   hhh6
+   hhh5
+   -g4
+    g6
+  g3
+  g2
+ -body2
+  body3
+ -
+  -
+   hhh2
+  hhh1
\ No newline at end of file
diff --git a/xml/tests/testData/structureView/NoSectioningRoot.html b/xml/tests/testData/structureView/NoSectioningRoot.html
new file mode 100644
index 0000000..d0b4849
--- /dev/null
+++ b/xml/tests/testData/structureView/NoSectioningRoot.html
@@ -0,0 +1,17 @@
+<section>
+  <blockquote>blockquote</blockquote>
+  <body>body</body>
+  <details>details</details>
+  <dialog>dialog</dialog>
+  <fieldset>fieldset</fieldset>
+  <figure>figure</figure>
+  <td>td</td>
+  <hgroup>
+    <a/>
+    <h1>1</h1>
+    <h2>2</h2>
+    <div/>
+    <h3>3</h3>
+    <h4>4</h4>
+  </hgroup>
+</section>
\ No newline at end of file
diff --git a/xml/tests/testData/structureView/NoSectioningRoot.tree b/xml/tests/testData/structureView/NoSectioningRoot.tree
new file mode 100644
index 0000000..e63bb32
--- /dev/null
+++ b/xml/tests/testData/structureView/NoSectioningRoot.tree
@@ -0,0 +1,9 @@
+-HtmlFile:NoSectioningRoot.html
+ [1 2 3 4]
+ blockquote
+ body
+ details
+ dialog
+ fieldset
+ figure
+ td
\ No newline at end of file
diff --git a/xml/tests/testData/structureView/Simple.html b/xml/tests/testData/structureView/Simple.html
new file mode 100644
index 0000000..cb12824
--- /dev/null
+++ b/xml/tests/testData/structureView/Simple.html
@@ -0,0 +1,6 @@
+<html>
+<head><title>title</title></head>
+<body>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/xml/tests/testData/structureView/Simple.tree b/xml/tests/testData/structureView/Simple.tree
new file mode 100644
index 0000000..4f8e03e
--- /dev/null
+++ b/xml/tests/testData/structureView/Simple.tree
@@ -0,0 +1,2 @@
+-HtmlFile:Simple.html
+ []
\ No newline at end of file